дҪҝз”ЁFPUе’ҢMMXеҜ„еӯҳеҷЁдҪңдёәвҖңйҖҡз”ЁеҜ„еӯҳеҷЁвҖқ

9

大多数汇编程序使用4个通用寄存器eaxebxecxedx,但我发现很多时候我需要使用超过4个寄存器才能轻松完成任务,而不必从堆栈中频繁地pushpop。由于我的程序没有使用FPU或MMX寄存器进行浮点运算或其“预期用途”,因此在程序中使用这些额外的寄存器是否被认为是可接受的呢?

例如,使用mm0作为循环增量计数器,释放ecx寄存器来执行其他任务。


你可以做任何你想做的事情。如果你发现使用xmm寄存器比溢出到堆栈更快,那就去做吧。 - Mysticial
2
很少有人告诉我“在编程方面我可以做任何我想做的事情”。我喜欢这种感觉 :) - user99545
3
x86_64有额外的8个通用寄存器可供使用。 - Dietrich Epp
对于使用内存的厌恶,在你升级到比“Hello world”更复杂的算法时,将会成为相当大的障碍。最好学会如何使用内存(提示:PUSH/POP不是正确的方法)。还有,ESI、EDI、EBP。如果你很疯狂,那就用ESP吧。 - Seva Alekseyev
1
更响亮的提示:进入函数时设置堆栈帧,并将 EBP 设置为指向该帧。然后,通过在堆栈帧中分配它们,您可以拥有实际上任意数量的私有内存位置。我的个人经验是,如果我有一些由寄存器中的指针访问的数据结构(通常情况下),我基本上只能使用 6 个寄存器(我将 EBP 用于堆栈帧指针),只需要偶尔进行 push 和 pop 操作。是的,当我更改代码以利用/适应修订代码的新限制时,我会频繁重写我的代码。 - Ira Baxter
1
为什么不先编写一个简单的 C 版本,以查看编译器如何溢出寄存器。但是如果必须使用大量寄存器,则建议切换到 x86_64。 - phuclv
3个回答

4
为什么是四个?你可以使用所有这些:eax, ebx, ecx, edx, esi, ediebp。那是七个。或者这还不够吗?
由于FPU和MMX寄存器只能从自身和内存中加载,也只能将它们自己和内存中的数据存储回去,所以它们使用起来有些棘手。您不能自由地在它们和通用寄存器之间移动数据,也没有能够同时操作这两种类型寄存器的指令。
如果七个通用寄存器还不够用,可以使用本地/堆栈变量。例如,您可以直接在内存中递减一个计数器变量,也可以直接将其与常量或另一个寄存器进行比较。很可能,这样做不会比以奇怪的方式使用FPU或MMX寄存器慢(可能更快)。

不,七个寄存器并不比使用全部寄存器更快。MMX寄存器非常有用。 - Ben Voigt
@BenVoigt:公正地说,它们不适用于*作为循环计数器而不是ecx*。基于MMX寄存器变为零的分支比dec ecx / jnz要低效得多,并且在那一点上需要一个备用整数寄存器。但是,如果您想使用XMM寄存器和paddd / movd存储填充数组,则可以使用它们来填充递增序列。或者更好的是,使用paddd / movdqu存储一次填充4个元素。但是这样做只是以向量寄存器的正常方式向量化循环。 - Peter Cordes
1
但是,在32位代码中(寄存器压力更大的地方),特别是当您无条件执行某些与整数寄存器中的值无关的整数操作时,使用向量寄存器的低元素作为标量可能是有意义的。特别是复制内存。请记住,MMX特别需要在某些点上进行emms,这将花费与XMM寄存器的SSE2相比的周期。 - Peter Cordes

1

你需要多经常使用一个寄存器的全部32位?对于像小计数器之类的东西,可以自由地使用通用寄存器的字节大小的四分之一:AH/AL、BH/BL、CH/CL、DH/DL。通过一些位运算技巧,你也可以将通用寄存器的上16位用作字长变量的中间存储。

在实模式下(即DOS下),你还可以使用段寄存器ES、FS和GS作为中间值存储。但在受保护模式的操作系统(Windows、Linux、*nix)下,代码会崩溃。


2
这只是在英特尔CPU上的好主意(它将AH与其他寄存器分开重命名)。 在AMD上,inc ahinc al彼此存在虚假依赖关系。请参见为什么GCC不使用部分寄存器?。即使在英特尔上(自Haswell或更高版本以来),写入AL实际上是合并到RAX中,这意味着mov al,6不是破坏依赖性,而mov eax,6是。(它不会强制合并单独重命名的AH,因此至少不会耦合这些dep链) - Peter Cordes

-2

当然,还有SI和DI,而在x64上,您还有额外的寄存器,但您可以将FP寄存器用于任何您想要的东西。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接