为什么bool = bool代码生成的差异? int:int

时间:2016-12-25 19:26:01

标签: assembly x86 x86-64 compiler-optimization

此代码......

bool condSet(int cond, int a, int b) {
    return cond ? a : b;
}

..生成gcc 6.3 ...

    test    edx, edx
    setne   al 
    test    edi, edi
    jne     .L6
    rep ret
.L6:
    test    esi, esi
    setne   al
    ret

..对于icc 17 ......

    test      edi, edi
    cmovne    edx, esi
    mov       eax, 1
    test      edx, edx
    cmove     eax, edx
    ret       

..对于clang 3.9

    test    edi, edi
    cmove   esi, edx
    test    esi, esi
    setne   al
    ret

为什么我们对代码模式有所不同,我希望它们是常见的?它们都依赖于条件指令,setne,cmovne,cmove,但gcc也有一个分支,它们都使用不同的指令和参数顺序

编译器中的哪些代码负责此代码生成?区别在于寄存器分配的完成方式;如何进行一般数据流分析;或者在生成代码时,编译器模式是否与此模式匹配?

代码和asm列表:https://godbolt.org/g/7heVGz

1 个答案:

答案 0 :(得分:4)

使用int策略将返回类型更改为test/cmov会导致所有三个编译器的无分支代码。

我猜gcc决定对条件的两边进行布尔化会产生太多的工作,并决定使用分支。也许它没有意识到它是相同的工作,并且表达式实际上可以通过其他方式完成(选择正确的输入然后booleanize)。

它所做的代码确实是booleanize b,然后才测试条件并对a进行布尔化。因此,当cond为真时,它实际上会同时运行test / setnz对。

这闻起来像是一个错过优化的错误。 (或者是一个优化运行错误的bug,它通过将返回类型应用于?:的两个输入而不仅仅是结果来自行射击。

报告为GCC Bug 78947

在修复之前,您可以get gcc to make code like clang / icc将其分为两个步骤:

bool condSet(int cond, int a, int b) {
  int tmp = cond ? a : b;       // better asm from gcc this way
  return tmp;
}