【问题标题】:Any advantage of XOR AL,AL + MOVZX EAX, AL over XOR EAX,EAX?XOR AL,AL + MOVZX EAX, AL 比 XOR EAX,EAX 有什么优势吗?
【发布时间】:2017-11-08 21:06:21
【问题描述】:

我有一些在 Release 版本中编译的未知 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 编译器。

【问题讨论】:

  • 它是否可能是从cmp 重复的循环的一部分,因此al 在后续迭代中不再为零?
  • @Jester:不,IDA 没有显示循环。
  • IDA 反汇编可能有问题(非常不可能,但可能)。也可能只是编译器错过了优化,可能被过于复杂的 C++ 源代码或一些无用的数据类型弄糊涂了,这些数据类型不能很好地编译。 xor eax,eax 在这种情况下会更好,完全避免 movzx。也可能是某种手动调整的“nop”填充,但我怀疑,使用普通的多字节 nop 变体更好。
  • @Ped7g:我稍后会得到源代码。这是一个简短的演示程序(C++ 控制台,可能只有 20 行代码)。 Stud_PE 签名扫描没有发现任何东西,但可能是 Visual Studio 2013 或 2015 编译器。
  • 顺便说一句,如果它不在循环中,并且它不是某种高频交易机器人,或者其他具有实时要求和硬限制的东西,那么没关系,总可执行时间最多增加了 2-3 个周期......但它在编译器的优化阶段可能节省了数千个 CPU 周期;)

标签: c++ assembly x86


【解决方案1】:

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 之后,并且它没有注意到它可能只是在eax 之前xor-zeroed cmp .

要么是something like Jester's suggestion,要么是movzx,其中movzx 是一个分支目标。即使是这样,xor eax,eax 仍然会更好,因为在此代码路径上无条件地向 eax 进行零扩展。

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

【讨论】:

  • 会不会暗示有一行 C++ 代码,例如 byte x=something; 而不是例如int x=something;? (可能,当然,不确定)
  • @ThomasWeller:我什至不会尝试从您展示的小片段中猜测。这是有道理的。我在想也许一个布尔条件被提升为int,而编译器只是证明它总是为时已晚去修复其余代码是错误的? IDK,MSVC 没有做出最有效的代码。我很少看它的输出,所以 IDK 什么样的来源可以把它骗成这样。
  • 呵呵,好的。至少我对 ASM 代码的理解似乎很好,深夜没有明显的人脑问题 :-)。谢谢。
  • @ThomasWeller:相关:tweaking C source to hand-hold compilers into making better asm。有时,当编译器缺少您可以在 asm 中看到的优化时,您可以更改源代码。 IDK 关于这样的案例,它甚至不是算法,只是愚蠢的。
  • 谢谢 - 也许这对我来说太多了。当我得到它时,我会发布 C++ MCVE。
猜你喜欢
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 2013-02-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多