Tyl*_*den 5 compiler-construction x86 assembly visual-c++
在VC++的这个反汇编中,正在进行函数调用.在推送寄存器之前,编译器将本地指针MOV转换为寄存器:
memcpy( nodeNewLocation, pNode, sizeCurrentNode );
0041A5DA 8B 45 F8 mov eax,dword ptr [ebp-8]
0041A5DD 50 push eax
0041A5DE 8B 4D 0C mov ecx,dword ptr [ebp+0Ch]
0041A5E1 51 push ecx
0041A5E2 8B 55 D4 mov edx,dword ptr [ebp-2Ch]
0041A5E5 52 push edx
0041A5E6 E8 67 92 FF FF call 00413852
0041A5EB 83 C4 0C add esp,0Ch
Run Code Online (Sandbox Code Playgroud)
为什么不直接推他们?即
push dword ptr [ebp-8]
Run Code Online (Sandbox Code Playgroud)
此外,如果您要单独执行推送,为什么不手动执行此操作.换句话说,不要做上面的"推送eax",而是做
mov [esp], eax
Run Code Online (Sandbox Code Playgroud)
等等.这样做的好处是,在执行3个mov之后,您可以执行单个减法来设置新的堆栈指针,而不是通过推送隐式减去三次.
更新---发布版本
这与为发布而编译的代码相同:
; 741 : memcpy( nodeNewLocation, pNode, sizeCurrentNode );
00087 8b 45 f8 mov eax, DWORD PTR _sizeCurrentNode$[ebp]
0008a 8b 7b 04 mov edi, DWORD PTR [ebx+4]
0008d 50 push eax
0008e 56 push esi
0008f 57 push edi
00090 e8 00 00 00 00 call _memcpy
00095 83 c4 0c add esp, 12 ; 0000000cH
Run Code Online (Sandbox Code Playgroud)
绝对比调试版本更有效,但它仍然在做一个MOV/PUSH组合.
这是一个优化.英特尔处理器手册第4卷第12.3.3.6节明确提到了这一点:
在Intel Atom微体系结构中,使用PUSH/POP指令管理堆栈空间和函数调用/返回之间的地址调整将比使用ENTER/LEAVE替代方案更优化.这是因为PUSH/POP不需要MSROM流,而堆栈指针地址更新在AGU完成.当被调用函数需要返回给调用者时,被调用者可以发出POP指令来恢复数据并从EBP恢复堆栈指针.
汇编/编译器编码规则19.(MH影响,M一般性)对于Intel Atom处理器,请使用PUSH/POP的寄存器形式并避免使用LEAVE; 使用LEA调整ESP而不是ADD/SUB.
手册的其余部分并不清楚原因,但确实提到了隐式ESP调整可能的3周期AGU失速.
我其实已经明白其中的原因了。它与 Pentium MMX 上的指令流水线方式有关。有两个管道,U 和 V,允许 MMX 处理器一次处理 2 条指令(如果它们可配对)。PUSH 不能相互配对,但可以与 MOV 配对。所以,如果你写:
mov eax, [indirect]
mov esi, [indirect]
push eax
push esi
Run Code Online (Sandbox Code Playgroud)
然后,发生的情况是指令 #1 和 #3 配对,#2 和 #4 配对,因此,实际上,这四个指令与单个 mov/push 运行相同数量的周期,并且单个 mov/push 是比两次推送[间接]更快。第 4.3 节第 14 页详细描述了这种具体情况。41,Agner Fog 的微架构优化指南的示例 4.11a 和 4.11b,可在互联网上广泛获取。
归档时间: |
|
查看次数: |
560 次 |
最近记录: |