XOR AL,AL + MOVZX EAX,AL优于XOR EAX,EAX的任何优势?

Tho*_*ler 5 c++ x86 assembly

我有一些在Release版本中编译的未知C++代码,因此它已经过优化.我正在努力的一点是:

xor     al, al
add     esp, 8
cmp     byte ptr [ebp+userinput], 31h
movzx   eax, al
Run Code Online (Sandbox Code Playgroud)

这是我的理解:

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??
Run Code Online (Sandbox Code Playgroud)

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

但是,我不明白为什么我会首先清除AL,以便稍后清除EAX的其余部分.结果将恕我直言EAX = 0,所以这也可能

xor eax, eax
Run Code Online (Sandbox Code Playgroud)

代替.这段代码的优势或"优化"是什么?

一些背景信息:

我稍后会得到源代码.这是一个简短的C++控制台演示程序,可能只有20行代码,所以我称之为"复杂"代码.IDA在该程序中显示单个循环,但不包括此部分.Stud_PE签名扫描没有找到任何内容,但可能是Visual Studio 2013或2015编译器.

Pet*_*des 3

xor al,al已经比xor eax,eax大多数 CPU 慢了。例如,在 Haswell/Skylake 上,它需要 ALU uop 并且不会破坏对eax/rax旧值的依赖。对于 AMD CPU 或 Atom/Silvermont 来说,情况同样糟糕。(好吧,也许不一样,因为 AMD 没有消除xor eax,eax问题/重命名,但它仍然有一个错误的依赖关系,可以使用eax最后使用的任何内容序列化新的依赖关系链)。

al在与寄存器的其余部分分开重命名的CPU (Intel pre-IvyBridge)上,xor al,al可能仍被识别为归零习惯用法,但除非您主动想要保留寄存器的高字节,否则最好的归零方法alxor eax,eax

movzx除此之外,这样做只会让事情变得更糟。


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

或者是这样,或者类似于 Jester 的建议,其中movzx是分支目标。即使是这种情况,xor eax,eax仍然会更好,因为在此代码路径上无条件地进行到 eax 的零扩展。

我很好奇哪个编译器从什么来源生成了这个。