我只是想在x86汇编,使基于非常快的计算程序,但我需要调用过程之前推累加器,计数器和数据寄存器。更快手动推他们:
push eax
push ecx
push edx
或者只是使用,
pushad
并用相同的弹出。谢谢
如果你关心性能,pusha
/ popa
是几乎从来没有用。他们以速度为代价优化代码大小的时候是唯一有用的,例如保存/身边的功能恢复寄存器。但它对于非void
功能非常不方便,因为他们重新加载所有的寄存器,所以你必须存储在内存中的返回值(例如,在将被装载到eax
,或别的地方popad
后重新加载堆栈插槽)。
只有推动所有需要保存,或者说你想传递的函数参数的寄存器。或者,在inline-assembly,只是让编译器通过声明"=r"(dummy1)
伪输出操作数的任何临时暂存器为您管理寄存器或特定的寄存器使用则会覆盖。通常情况下,编译器可以选择寄存器,它可以让你揍不保存。 (或笨重的MSVC式内联汇编,编译器不能为你分配寄存器,所以你必须手动挑选,编译器解析你的汇编找到则会覆盖。)
通常你并不需要保存/恢复eax
;性能你应该mov esi, eax
/电话/在esi
使用的值,如果你不能在第一时间在esi
计算值。即使用呼叫保留的寄存器为需要生存call
值,让你的重要价值的存储/重装不在关键路径上。取而代之的是,店/重装主叫呼叫保存完好的寄存器中的一个的关键路径上,你(或编译器)push
/ pop
周围的整体功能,任何环路以外。
即使你确实想推动所有8个整数寄存器(包括esp
!),用8所独立push
说明实际上快于现代的CPU是。 PUSHA /波帕都进行了微,which can be a problem for the front-end。 (虽然8单字节指令可为微指令缓存的问题了。但是,在实际的代码,你通常只需要按下几个寄存器,不是所有的人。)
如果你正在优化过时的CPU(如原始的有序的Pentium和Pentium II / III),PUSHA /波帕是快8 push r
或8 pop r
,实际上减少微指令,因为他们没有一个堆栈引擎消除ESP更新微指令。
从Agner Fog's instruction tables:现代CPU具有单UOP push reg
和pop reg
,因为这些指令由编译器使用的所有的时间,因此对于性能非常重要。压入/弹出吞吐量典型地匹配存储/加载吞吐量(每时钟经常1个商店或每时钟2个负载)。但pusha
/ popa
不使用的编译器,所以CPU的设计师不具备的特殊支持,使他们快。 popa
吞吐量限于每个时钟只有1负载如果只是运行popa
。 (我想在Intel的CPU,用于测量性能的最有可能的解释是,popa
不使用栈引擎,因此它的瓶颈上esp
的依赖。)
英特尔:
pusha
:11个微指令,8C吞吐量。 popa
:18个微指令/ 8C吞吐量。pusha
:16个微指令/ 8C吞吐量。 popa
:18个微指令/ 9C吞吐量。pusha
:18个微指令/ 8C吞吐量。 popa
:10个微指令/ 8C吞吐量。pusha
:10个微指令/ 10C吞吐量。 popa
:17个微指令/ 14C吞吐量。pusha
:4/10微指令/ 19C吞吐量。 popa
:4/16微指令/ 14C吞吐量。AMD:pusha
/ popa
是一些AMD的CPU,特别是K8出奇的好。
pusha
:9个微指令,8C吞吐量。 popa
:9个微指令,4C吞吐量。 (与英特尔不同,AMD的新设计具有popa
不超过8倍pop
更糟。)pusha
:9级的微指令/ 8C吞吐量。 popa
:9周的uop / 8C吞吐量。 (美洲虎只能做每个时钟一个负载正常。)pusha
:9级的微指令/ 9C吞吐量。 popa
:14个微指令/ 8C吞吐量。 (昂纳列出定期pop reg
吞吐量1元时钟推土机家族,但我认为他们有一个栈引擎,可以做到每时钟2个负荷。也许堆栈引擎只能同时处理一个堆栈指令?)pusha
:9级的微指令/ 4C吞吐量! (IDK如何,这是可能的,无论这是在表中的错误或错字,或K8合并32位寄存器并执行4个64位存储)。 popa
:9周的uop / 4C吞吐量。这些数字似乎是真实的:InstLatx86 measurements同意4C吞吐量上与Clawhammer pushad
/ popad
(第一代K8微架构)。所以很明显AMD放一些精力投入到优化pushad
。您标记此inline-assembly。通常你应该避免内联汇编使用call
,所以C编译器知道该呼叫。