c++ - 编译器在 eax 上来回生成 mov

标签 c++ gcc assembly x86-64 micro-optimization

int test1(int a, int b) {
    if (__builtin_expect(a < b, 0))
        return a / b;
    return b;
}

由 clang 使用 -O3 -march=native 编译为

test1(int, int):                             # @test1(int, int)
        cmp     edi, esi
        jl      .LBB0_1
        mov     eax, esi
        ret
.LBB0_1:
        mov     eax, edi
        cdq
        idiv    esi
        mov     esi, eax
        mov     eax, esi  # moving eax back and forth
        ret

为什么 eaxidiv 之后来回移动?

gcc 有类似的行为,所以这似乎是有意为之。

gcc with -O3 -march=native 将代码编译为

test1(int, int):
        mov     r8d, esi
        cmp     edi, esi
        jl      .L4
        mov     eax, r8d
        ret
.L4:
        mov     eax, edi
        cdq
        idiv    esi
        mov     r8d, eax
        mov     eax, r8d  #back and forth mov
        ret

godbolt

最佳答案

这不是拼图的完整解决方案,但应该提供一些线索。

没有 __builtin_expect,clang 生成:

test2(int, int):                             # @test2(int, int)
        mov     ecx, esi
        cmp     edi, esi
        jge     .LBB1_2
        mov     eax, edi
        cdq
        idiv    ecx
        mov     ecx, eax
.LBB1_2:
        mov     eax, ecx
        ret

虽然寄存器分配在这里仍然很奇怪,但它至少是有道理的:如果分支被采用,ecx 中的 b 的值被转移到 eax 作为返回值。如果不采用,则除法结果(在 eax 中)必须传输到 ecx 以与其他情况相同的寄存器中。

可能是 __builtin_expect 说服编译器处理特殊情况,即在编译过程中分支被延迟的情况,孤立 .LBB1_2 标签并导致它最终缺席 assembly 。

关于c++ - 编译器在 eax 上来回生成 mov,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55166749/

相关文章:

c - 如何使用 getopt 检索一个选项的多个参数

assembly - PowerPC 中应该对有效地址 'wrap' 求和吗?如果是这样,怎么办?

c - gcc/g++ 有 x64 微软寄存器的调用约定吗?

c++ - C 和 C++ 使用 goto 时汇编代码中的 jmp 指令差异

c++ - 结构体中的指针问题

c++ - 检测 C++ 二进制文件是否被优化

c - ARM gcc 无法识别 CPU

c++ - 在 C++ 中对命令行参数进行排序

c++ - 使用 boost 命令行解析器处理未知命令

c++ - 了解 "template argument is invalid"错误消息