乱序执行如何与条件指令一起工作,例如:Intel 中的 CMOVcc 或 ARM 中的 ADDNE(加法不等于)

How does Out of Order execution work with conditional instructions, Ex: CMOVcc in Intel or ADDNE (Add not equal) in ARM

我知道它们只有在 Re-Order Buffer 中它们之前的指令被提交后才能正确执行。我的疑问是,现代处理器是否会保留它们直到它们在 ROB 中排在最后或进行任何预测 counters/structures 甚至用于预测标志值,如零标志或进位标志,如果它们被错误预测,则重做它们

I know they can only correctly execute after instructions before them in Re-Order Buffer are committed.

不,他们只需要准备好自己的输入:那些特定的先前指令已执行,而不是退役/提交。

条件移动指令(和 ARM 谓词执行)将标志输入视为 数据 依赖项,就像带进位的加法或整数输入寄存器一样。在所有 3 个输入都就绪 1 之前,条件指令无法发送到执行单元。 (或者在 ARM 上,标志 + 无论谓词指令通常有多少输入。)

与控制依赖项(分支)不同,它们不会预测或推测标志将是什么,因此 cmovcc 而不是 jcc 可以创建循环携带的依赖链并最终比可预测的分支更糟糕。 就是一个例子。

Linus Torvalds 更详细地解释了为什么 cmov 经常很糟糕:https://yarchive.net/comp/linux/cmov.html

(ARM 预测执行的处理方式可能略有不同。它必须在逻辑上 NOP 指令,即使是加载或存储到无效地址。这可能仅通过条件加载的故障抑制来处理。我不知道带有错误谓词的指令是否仍然在目标寄存器的依赖链中花费任何延迟。)


脚注 1:这就是为什么 cmovccadc 在 Broadwell 之前在 Intel 上是 2 微指令:单个微指令不能有 3 个输入依赖项。 Haswell 引入了对 FMA 的 3 输入微指令的支持。

cmov 读取 CF 和 SPAZO 标志之一的指令(即读取 CF 和 ZF 的 cmovacmovbe)实际上在 Skylake 上仍然是 2 微指令。请参阅 this Q&A for detail: it seems that those two separately-renamed groups of flags are both separate inputs, avoiding flag-merging. See also https://uops.info/ 了解 uop 计数。

另请参阅 http://agner.org/optimize/, and https://whosebug.com/tags/x86/info 了解有关 x86 微架构的详细信息和优化指南。