c++ - XOR AL,AL + MOVZX EAX, AL 比 XOR EAX,EAX 有什么优势?

标签 c++ assembly x86

我有一些未知的 C++ 代码是在发布版本中编译的,因此对其进行了优化。我正在努力解决的问题是:

xor     al, al
add     esp, 8
cmp     byte ptr [ebp+userinput], 31h
movzx   eax, al

这是我的理解:

xor     al, al    ; set eax to 0x??????00 (clear last byte)
add     esp, 8    ; for some unclear reason, set the stack pointer higher
cmp     byte ptr [ebp+userinput], 31h ; set zero flag if user input was "1"
movzx   eax, al   ; set eax to AL and extend with zeros, so eax = 0x000000??

我不关心第 2 行和第 3 行。出于流水线的原因,它们可能按此顺序存在,恕我直言,与 EAX 无关。

但是,我不明白为什么我会先清除AL,只是为了稍后清除其余的EAX。恕我直言,结果将始终是 EAX = 0,所以这也可能是

xor eax, eax

相反。那段代码的优势或“优化”是什么?

一些背景信息:

稍后我会拿到源码。这是一个简短的 C++ 控制台演示程序,可能只有 20 行代码,所以没有什么我称之为“复杂”的代码。 IDA 在那个程序中显示了一个循环,但没有围绕这个片段。 Stud_PE 签名扫描未发现任何内容,但可能是 Visual Studio 2013 或 2015 编译器。

最佳答案

xor al,al 在大多数 CPU 上已经比 xor eax,eax 慢。例如on Haswell/Skylake it needs an ALU uop and doesn't break the dependency on the old value of eax/rax。它在 AMD CPU 或 Atom/Silvermont 上同样糟糕。 (好吧,也许不一样,因为 AMD 没有在问题/重命名时消除 xor eax,eax,但它仍然有一个错误的依赖关系,它可以使用任何使用的 eax< 序列化新的依赖关系链 最后)。

在将 al 与寄存器的其余部分分开重命名的 CPU 上(Intel pre-IvyBridge),xor al,al 可能仍被识别为 as a zeroing idiom ,但除非如果您想保留寄存器的高位字节,将 al 归零的最佳方法是 xor eax,eax

在此基础上执行 movzx 只会让情况变得更糟。


我猜你的编译器不知何故感到困惑并决定它需要一个 1 字节的零,但随后意识到它需要将其提升为 32 位。 xor 设置标志,因此它不能在 cmp 之后 xor-zero ,并且它没有注意到它可能只是在 cmp 之前对 eax 进行了异或归零。

或者是 something like Jester's suggestion ,其中 movzx 是一个分支目标。即使是这种情况,xor eax,eax 仍然会更好,因为在此代码路径上无条件地遵循零扩展到 eax。

我很好奇是什么编译器从什么来源生成的。

关于c++ - XOR AL,AL + MOVZX EAX, AL 比 XOR EAX,EAX 有什么优势?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47189701/

相关文章:

c++ - CreateThread 后跟 TerminateThread 留下大量内存

visual-c++ - 使用 Visual C++ Express 2010 64 位编译程序集

operating-system - 装配 OUTB 功能如何导致三重故障?

assembly - 在 Linux 中哪些寄存器不受用户空间的影响?

java - C++ 等价于 java 的 instanceof

C++ - 将代码实现分成不同的部分

c++ - 在 C++ 中创建具有随机枚举类型的 Card 对象

c++ - 非 native 长度的有符号和无符号整数的性能差异

c++ - 如何在汇编中传递参数?

c++ - 为什么clang和GCC不使用xchg来实现std::swap?