【转载】当代的IA32汇编指令优化手册【zklhp版】(感觉标题不够长)
当代的IA32汇编指令优化手册;*****************************************************************************************************************
;作者:zklhp
;Email:zklhp@
;QQ:493165744
;版权所有 转载请保持完整
;*****************************************************************************************************************
好罢 我是标题党 这个【当代】二字其实很不恰当 因为本文所有的测试均在一个Intel Core 2 Duo T5750 2GHz 上进行 而且还是测试的32位模式 这恐怕不能很好的代表当代的CPU的情况
但是相比那些以386 486来讨论的文章 本文更接近当代CPU的情况 还算是比较实用的
以下的优化技巧来自一些以往的优化文章及本人的积累 文章的数据来自这个测试程序 http://www. 本文对那个程序做了一些修改 但是原理是一样的 测试程序本贴也提供了 呵呵
说明一下 这个测试程序是以nop也就是空指令为基准计算其他指令的用时 下文中所有的指令用时数据都是这个 并不是指令用的周期数 而且 呵呵 测试都是在我上面提到的CPU上进行的
数据并没有用统计方法处理 但是是运行过几次的一个比较公平的数据 只是用来反映指令的快慢情况这种精度足够了
可能会不断补充的 先发写出来的罢 期待其他CPU的测试数据 欢迎拍板砖。。。
寄存器清零
程序代码:
mov eax,0 ;长度:5字节 用时:3.77 ;一条占用5字节而且用时最多的写法 出现在程序中是找喷的 xor eax,eax ;长度:2字节 用时:1.58 sub eax,eax ;长度:2字节 用时:1.57
肯定要用xor或sub法
PS:很有意思的是 某些时候sub法用时小于1 较小概率随机出现 原因未知 有待进一步测试
寄存器赋1
程序代码:
mov eax,1 ;长度:5字节 用时:3.79 sub eax,eax inc eax ;长度:3字节 用时:2.51 ;两条指令比一条指令要好 xor eax,eax inc eax ;长度:3字节 用时:2.52 mov eax,edx ;已知为0的寄存器 inc eax ;长度:3字节 用时:2.52 lea eax,ds:[1] ;长度:6字节 用时:4.65 ;也是一种写法
寄存器赋-1
程序代码:
mov eax,0FFFFFFFFH ;长度:5字节 用时:3.79 ;已经没有人这么写了罢 xor eax,eax dec eax ;长度:3字节 用时:2.49 stc sbb eax,eax ;长度:3字节 用时:2.50 ;比较怪异的写法 貌似没有速度上的收获
寄存器加1
程序代码:
add eax,1 ;长度:3字节 用时:3.04 inc eax ;长度:1字节 用时:3.01 ;优势在指令长度 速度不明显 lea eax,[eax+1] ;长度:3字节 用时:2.96
可以认为三者的速度是一样的 但是长度3字节的写法和一字节的inc比差了点
有兴趣的可以用统计的方法看看lea是不是比普通的写法快
寄存器加立即数
程序代码:
add eax,1234 ;长度:5字节 用时:3.86 adc eax,1234 ;长度:5字节 用时:6.07 lea eax,[eax+1234] ;长度:6字节 用时:4.61
lea在这里不好用
寄存器与0比
程序代码:
test eax,eax ;长度:2字节 用时:1.56 or eax,eax ;长度:2字节 用时:3.01 ;慢 cmp eax,0 ;长度:3字节 用时:2.26 ;谁会用这个呢。。
出现立即数的写法一贯不好
寄存器与-1比
程序代码:
cmp eax,0ffffffffh ;长度:3字节 用时:2.33 ;编译出来是cmp eax,0ffh inc eax dec eax ;长度:2字节 用时:5.96 ;比较的时候肯定会接一个跳转指令 但我这个测试方法没法做这样的测试 所以就比较不加跳转的 都少一个跳转的情况下可以比 ;这个写法中间有一个je的 以上的比较测试都有跳转指令的
寄存器赋一个字节的立即数(感觉这个描述很别扭)
程序代码:
mov eax,88 ;长度:5字节 用时:3.82 push 88 pop eax ;长度:3字节 用时:7.72 ;慢但是在这种情况下能省字节 ;这是立即数是字节时的一种小技巧
乘以一个数
程序代码:
mov ebx,8888 mul ebx ;长度:7字节 用时:13.26 mov ebx,8888 imul ebx ;长度:7字节 用时:13.58 imul eax,eax,8888 ;长度:6字节 用时:9.26 ;IMUL Reg, Reg/Mem ;80386+ Reg1 ← Reg1×Reg2 或 Reg1 ← Reg1×Mem 各操作数的位数要一致 shl eax,3 ;长度:3字节 用时:3.06 ;用位移代替乘法能大大提高速度 但是只能是乘2的次方的时候才能用 ;这里用来做个对照
要优先使用 IMUL Reg, Reg/Mem
shl的用法
程序代码:
shl eax,2 ;长度:3字节 用时:3.04 shl eax,1 shl eax,1 ;长度:4字节 用时:6.01
我曾经这样写过 弄巧成拙
xchg的好处
程序代码:
xchg ebx,edx ;长度:2字节 用时:6.03 mov eax,ebx mov ebx,edx mov edx,eax ;长度:6字节 用时:6.16 xor ebx,edx xor edx,ebx xor ebx,edx ;长度:6字节 用时:9.10 push ebx push edx pop edx pop ebx ;长度:4字节 用时:15.19
eax=ecx*4+3
程序代码:
mov eax,ecx shl eax,2 add eax,3 ;长度:8字节 用时:6.44 lea eax,[ecx*4+3] ;长度:7字节 用时:5.38
lea应该这么用
测试用的程序 代码+可执行文件+MasmPlus工程
InsBMT.zip
(11.76 KB)
★★★★★★★★★★★★★★★★★★★★★★★★★★以上是12月18日的★★★★★★★★★★★★★★★★★★★★★★★★★★
寄存器加2
程序代码:
add eax,2 ;长度:3字节 用时:3.04 inc eax inc eax ;长度:2字节 用时:5.99
差强人意 省了1字节 虽然这点时间和这点空间都不大、、、
寄存器和内存比较时的顺序问题
程序代码:
cmp eax,DWORD ptr [buffer] ;也就是一个内存变量啦 ;长度:6字节 用时:4.63 cmp DWORD ptr [buffer],eax ;长度:6字节 用时:4.70 ;有人说能省一个字节的。。 cmp ebx,DWORD ptr [buffer] ;长度:6字节 用时:4.60 cmp DWORD ptr [buffer],ebx ;长度:6字节 用时:4.56
这里也出现了和第一个一样的现象
▲▲▲注意▲▲▲
关于这个现象我更正一下 上面的描述其实是错误的或者说是与事实不符的 上面的我就不改了 以这个为准。。
我观察到的现象是 某些时候运行这个程序得到的
相对nop的比值:4.647061
在某些时候会明显偏小 比如这个cmp可能会出现2点几的数
开始我就把它描述成了【某些时候sub法用时小于1】 理解成了指令在某些时候会运行的特别快 用时短
但是明显不对啊 我这里相当于执行了1G个指令 如果有偶然的偏差对于整体数据的影响应该是微乎其微的 所以应该跟指令没关系
我觉得可能的原因是某些东西拖慢了nop的执行速度 唉 我当时没看上面两个数。。 我再多试几次看看能不能重现这个问题罢。。。
导致这个的原因有可能有好多喽 操作系统或运行着的其他程序带来的影响 或者 因为我是在MasmPlus按运行执行的 是不是和这个有关系呢 或者是代码的问题 抑或是除法算出来不对? 都可能
这其实就是很多人说的我这种测试方式带来的弊端 不过罢 可以用各种方式接近真实结果 消除这些误差 我想的一个方法是可以看下面的例子
对了 看来测试需要重启电脑并关闭其他程序才行 我上面的都没这么做。。。
inc eax 和 lea eax,[eax+1] 哪个快?
不需要对代码做大的修改 用批处理里面的循环+cvs+Excel来研究一下就好了。。
程序代码:
@echo off for /l %%i in (1,1,50) do console >> 50.csv pause
批处理里for的用法可以用for /?来看 呵呵
代码改输出格式 变成这样(突然发现程序的注释写错了 你们明白就好了)
程序代码:
invoke printf,CTXT('%lu,'),[dqTime1] invoke printf,CTXT('%lu,'),[dqTime2] invoke printf,CTXT('%f',0dh,0ah),[fTimes]
改成这样让它输出成 基准用时,指令用时,比值 的形式 配合上面的 可以导入到excel里用统计的方法看到底哪个快
50次测试 数据不传了 直接放结论
inc eax 2.98846542±0.021641592 (平均值±标准差)
lea eax,[eax+1] 2.9813342±0.016966188 (平均值±标准差)
不用什么显著性差异也可以知道 没区别 一样快。。
[ 本帖最后由 zklhp 于 2011-12-18 17:27 编辑 ]