可以做 if (!boolvar) { ... in 1 asm 指令?

gri*_*fin 5 c x86 assembly

这个问题更多是出于好奇而不是必要:

是否有可能以if ( !boolvar ) { ...某种方式重写 c 代码,以便将其编译为 1 个 cpu 指令?

我试过在理论层面上思考这个问题,这就是我想出的:

if ( !boolvar ) { ...

需要首先否定变量,然后根据该 -> 2 条指令进行分支(否定 + 分支)

if ( boolvar == false ) { ...

需要将 false 的值加载到寄存器中,然后根据该值进行分支 -> 2 条指令(加载 + 分支)

if ( boolvar != true ) { ...

需要将 true 的值加载到寄存器中,然后根据 -> 2 条指令进行分支(“branch-if-not-equal”)(加载 +“branch-if-not-equal”)

我的假设错了吗?有什么我忽略的吗?

我知道我可以生成程序的中间 asm 版本,但我不知道如何以某种方式使用它,因此我可以一方面打开编译器优化,同时没有if优化掉一个空语句(或者有if 语句与其内容一起优化,给出一些非通用的答案)

PS:当然,我也为此搜索了 google 和 SO,但是搜索词如此短,我真的找不到任何有用的东西

PPS:我可以使用语义等效的版本,该版本不是语法等效的,例如不使用if.


编辑:如果我对发出的 asm 指令的假设是错误的,请随时纠正我。


Edit2:我实际上在大约 15 年前学习了 asm,并在大约 5 年前为 alpha 架构重新学习了它,但我希望我的问题仍然足够清楚,可以弄清楚我在问什么。此外,如果有助于找到一个好的答案,您可以自由假设消费者 CPU 中常见的任何类型的处理器扩展,直到 AVX2(截至撰写本文时的当前 Haswell CPU)。

Ser*_* L. 3

在我的文章的最后,它会说明为什么你不应该以这种行为为目标(在 x86 上)。

正如 Jerry Coffin 所写,x86 中的大多数跳转取决于标志寄存器。

但有一个例外:如果/寄存器为零j*cxz则跳转的指令集。为了实现这一点,您需要确保您使用寄存器。您可以通过将其专门分配给该寄存器来实现ecxrcxboolvarecx

register int boolvar asm ("ecx");
Run Code Online (Sandbox Code Playgroud)

但到目前为止,并非所有编译器都使用该j*cxz指令集。有一个标志可以icc让它这样做,但通常不建议这样做。Intel手册指出两条指令

test ecx, ecx
jz ...
Run Code Online (Sandbox Code Playgroud)

处理器速度更快。

之所以如此,是因为 x86 是 CISC(复杂)指令集。在实际的硬件中,处理器会将汇编中显示为一条指令的复杂指令拆分为多个微指令,然后以 RISC 风格执行。这就是为什么并非所有指令都需要相同的执行时间,有时多个小指令比一个大指令更快的原因。

testjz是单个微指令,但jecxz无论如何都会被分解为这两个微指令。

指令集存在的唯一原因j*cxz是如果您想在不修改标志寄存器的情况下进行条件跳转。