APP下载

基于汇编语言教学中优化语言代码方法探讨与研究

2017-08-07李忠武

电子测试 2017年10期
关键词:汇编语言浮点寄存器

李忠武

(保山学院,云南保山,678000)

基于汇编语言教学中优化语言代码方法探讨与研究

李忠武

(保山学院,云南保山,678000)

本文讨论一些优化X86汇编语言代码的简单编程技巧。建议把这些技巧应用在运行于Intel最新微架构(包括Haswell、Sandy Bridge和Nehalem)代码中。大多数技巧同样适用于更早的微架构。可以把优化技巧和辅助性的指导方针分为五大类:基本优化、浮点算术、程序分支、数据对齐、SIMD技巧。

基本优化;浮点算术;程序分支;数据对齐;SIMD技巧

0 引言

需要谨记的一个要点是,接下来的基本优化、浮点算术、程序分支、数据对齐、SIMD技巧优化技巧都必须谨慎使用。[1]例如,如果仅为避免使用不推荐的指令形式一次,就增加多条额外的push和pop指令,那么是没有意义的。

1 基本优化

下面列出了一些常用于提高X86汇编语言代码性能的基本优化技巧。

(1)尽可能使用test指令,而不是cmp指令。

(2)尽可能避免使用内存与立即数形式的cmp和test指令(例如,cmp dword ptr[ebp+16],100或者test byte ptr[r12],0fh)。最好先将内存值载入寄存器,然后使用寄存器与立即数形式的cmp和test指令(如mov eax,dword ptr[ebp+16],接着cmp eax,100)。

(3)使用add或者sub指令,而不是inc或者dec指令,特别是在性能关键的循环中。后面的两个指令不会更新EFLAGS寄存器中的所有标志位,通常会慢一些。

(4)使用or、sub、pxor、xorps等指令将一个寄存器置0,而不是用数据传送指令。例如,xor eax,eax和xorps xmm0, xmm0比mov eax,0和movaps xmm0,xmmword ptr[XmmZero]要好。

(5)在所有操作数宽度前缀的指令中,避免使用16位立即数,而应该使用对应的32位或者8位立即数。例如,使用mov edx,42而不是mov dx,42。

(6)展开(或者部分展开)循环次数是常数的小循环。(7)将在计算中多次使用的内存值载入寄存器。如果一个内存值只在一次计算中用到,用寄存器到内存形式的计算指令。如表1显示了几个例子。

表1 一次使用和多次使用内存值的指令形式

下面优化技巧适用于x86-64代码。

(1)当操作数是32时,使用32位通用寄存器和指令形式。

(2)操作32位宽数值时,优先使用通用寄存器EAX、ECX、EDX、ESI、EDI,而不是寄存器R8D-R15D。对于后面的寄存器组,指令解码要多一个字节。

(3)利用额外的通用寄存器和SIMD寄存器,以减少数据依赖和寄存器溢出。

(4)如果不需要完成的128位结果,用两操作数或三制作数形式的imul指令进行两个64位整数乘法。

2 浮点算术

使用汇编语言进行浮点算术运算时,应考虑下面的指导方针:首先,在新代码中使用x86-SSE或者x86-AVX而不是x86 FPU的标题浮点指令;其次,在算术运算中,尽可能避免算术下溢和非正规值;三是避免使用非正规浮点常量;最后是如果预知会有多次算术下溢,考虑启用清洗到零(MXCSR.FZ)和非正规为零(MXCSR.DAX)模式。

3 程序分支

程序分支指令如jmp、call和ret在执行时是潜在的耗时操作,因为它们可能影响前端流水线和内部缓存的内容。考虑到使用的频率,条件跳转指令jcc也可能带来性能问题。下面的优化技巧能最小化分支指令对性能的影响,并且提高分支预测单元的准确性。

(1)组织代码,尽量少使用分支指令。

(2)使用setcc和cmovcc指令,以消除不可预测的数据相关的分支。

(3)在性能关键的循环中,对齐分支目标的边界到16字节。

(4)将不太可能执行的条件代码(例如错误处理代码)移到另外的程序段或内存页。

当预测一个分支语句的目标时,分支预测单元采用静态和动态技术。当包含条件跳转指令的代码能够组织成与分支预测单元的静态预测算法一致时,那么错误的分支预测就可以被最小化。

(1)当贯代码可能被执行时,使用向前的条件跳转。

(2)当贯穿代码不可能被执行时,使用身后条件跳转。

向前条件跳转方法经常用在检查函数参数的代码块中。向后条件跳转技术可以用在程序循环代码块的底部(紧跟着一个计数器更新或者其他循环结束判断)。清单1包含了一小段汇编语言函数,展示了这些实践经验的细节。

清单1 使用符合静态分支预测算法的条件跳转指令

model flat,c

code

;extern ”c” bool CalcReslut_(double* des,const double* src,int n);

CalcReslut_proc

push ebp

mov ebp,esp

push esi

push edi

;本代码使用向前条件跳转,因为贯穿的情况可能发生

mov edi,[ebp+8]

test edi,0fh

jnz Error

mov esi,[ebp+12]

test esi,0fh

jnz Error

test ecx,2

jl Error

test ecx,1

jnz Error

;简单的数据处理循环

xor eax,eax

@@:movapd xmm0,xmmword ptr[esi+eax]

mulpd xmm0,xmm0

movapd xmmword ptr[edi+eax],xmm0

;本段代码使用向后条件跳转,因为贯穿的情况更不能发生

add eax,16

sub ecx,2

jnz @B

mov eax,1

pop edi

pop esi

pop dbp

ret

;错误处理代码,不太可能执行

Error:xor eax,eax

pop edi

pop esi

pop ebp

ret

CalcReslut_ endp

end

4 数据对齐

操作对齐错误数据时,可能导致处理器介绍费额外的内存周期和执行更多微指令,这将会给整个系统的性能带来负面影响。下面的数据对齐实践应该被认为是普遍真理并一直遵守。

(1)将多字节整数和浮点数对齐到自然的边界。

(2)将64、128和256位宽的组合数据对齐到它们本身的边界。

(3)必要时填补数据结构,以保证正确对齐。

(4)使用恰当的编译器指令和库函数,以对齐高层代码分配的数据项。例如_declspec(align(n))指示器和_aligned_ malloc函数能用来正确地对齐Visual C++函数中分配的数据项。[2]

(5)更多地使用存储对齐,而不是加载对齐。

下面这些对齐技巧也推荐使用:将小数组和短字符串对齐安置在数据结构中,以避免缓存行分割。评估不同的数据布局对性能的影响,例如数组结构与结构数组。

5 SIMD技巧[3]

在任何函数中,用x86-SSE和x86-AVX计算资源时应该考察下面这些技巧是否适用。

(1)消除寄存器依赖,以利用执行引擎的多个执行单元。

(2)用组合的单精度浮点数代替双精度浮点数。

(3)将多次使用的内存操作数和组织常量加载到寄存器。

(4)用对齐的传送指令存储和加载组织数据,例如movdqa、movaps、movapd等。

(5)用小的数据块处理SIMD数组,以最大化重用驻留缓存数据。

(6)在x86-AVX代码中,使用数据混合而不是数据重组。

(7)当需要避免x86-AVX到x86-SSE状态迁移的损失时,使用vzeroupper指令。

(8)使用x86-AVX vgather指令的双字形式,而不是四字形式。在数据要用到之前就完成需要的收集操作。

(9)下面的这些实践可以用于提高特定算法性能(进行SIMD编码和解码操作):

(10)使用无时态存储指令(如movntdqa、movntpd、movntps等),以最小化缓存污染。

(11)使用数据项预取指令(例如perfecht0,perfetchnta等),以通知处理器预期要使用的数据项。

6 结束语

使用汇编语言优化代码是一件困难,而且技巧性很强的工作。很多编译器能够生成为处理器进行过特殊优化处理的代码,一旦进行修改,这些特殊优化可能就会被破坏而失效。因此,在你决定使用自己的汇编代码之前,一定要测试一下,到底是编译器生成的那段代码更好,还是你的更好。

[1] Kusswurm,D.现代X86汇编语言程序设计[M].北京:机械工业出版社,2016:446.

[2]黄永才.Visual C++程序设计[M].北京:清华大学出版社,2017:251.

[3]高伟.SIMD自动向量化编译优化概述[J]. 软件学报,2015,(6):1269-1276.

Discussion and Research on the method of optimizing language code in assembly language teaching

Li Zhongwu
(Baoshan college,Baoshan Yunan, 678000)

This article discusses some simple programming techniques for optimizing X86 assembly language code It is recommended that these techniques be applied to code running in the latest Intel micro architectures (including Haswell, Sandy, Bridge, and Nehalem) Most techniques apply equally well to earlier architectures. Tuning and assistive guidelines can be divided into five broad categories: basic optimization, floating point arithmetic, program branching, data alignment, and SIMD techniques

basic optimizations; floating-point arithmetic; program branches; data alignment; SIMD techniques

猜你喜欢

汇编语言浮点寄存器
LEO星座增强GNSS PPP模糊度浮点解与固定解性能评估
高等学校计算机专业课程教学改革实践——以汇编语言与接口技术课程为例
Lite寄存器模型的设计与实现
基于浮点DSP的铁路FSK信号检测
汇编语言与C语言的混合程序设计技术研究
提高《汇编语言程序设计》教学效率的思考与实践
分簇结构向量寄存器分配策略研究*
基于FPGA的浮点FIR滤波器设计
试论汇编语言与C语言的混合程序设计技术
改进的Goldschmidt双精度浮点除法器