c - if (!boolvar) { ... 在 1 个 asm 指令中可以做吗?

标签 c assembly x86

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

是否可以重写 C 代码 if ( !boolvar ) { ... 以便将其编译为 1 个 cpu 指令?

我尝试从理论上思考这个问题,这就是我想出的:

if ( !boolvar ) { ...

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

if ( boolvar == false ) { ...

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

if ( boolvar != true ) { ...

需要将 true 的值加载到寄存器中,然后根据该值进行分支(“如果不相等则分支”)-> 2 条指令(加载 + “如果不相等则分支”)

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

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

P.S.: 当然,我也搜索过 google 和 SO,但是搜索词这么短,我真的找不到任何有用的东西

P.P.S.:我会接受语义上等效但句法上不等效的版本,例如不使用 if


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


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

最佳答案

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

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

不过有一个异常(exception):如果 ecx/rcx 寄存器为零,则 j*cxz 指令集会跳转。为此,您需要确保您的 boolvar 使用 ecx 寄存器。您可以通过将其专门分配给该寄存器来实现这一点

register int boolvar asm ("ecx");

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

test ecx, ecx
jz ...

在处理器上更快。

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

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

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

关于c - if (!boolvar) { ... 在 1 个 asm 指令中可以做吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18516009/

相关文章:

assembly - 是什么导致此引导加载程序在硬件上失败但在 DOSBOX 中没有?它显示所有寄存器

c++ - block 内变量的生命周期是多少?

c - 在不使用 gcc 内联汇编的情况下访问寄存器

ios - 在 Apple 程序集中重复字节?

.net - 针对同一 VS2012 项目中的 x86 和 x64 程序集;引用

c - 插入节点(二叉搜索树)C

c - 在 C 中交换方矩阵名称

objective-c - 在 forwar 类对象 CALayer 中找不到属性 anchorPoint

将动态分配的 int 指针转换为结构指针

c - 汇编语言前缀和问题