【问题标题】:Why the difference in code generation for bool = bool ? int : int为什么 bool = bool 的代码生成不同?整数:整数
【发布时间】:2017-05-10 11:39:14
【问题描述】:

这段代码...

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

【问题讨论】:

  • 可能是因为不同的人编写了编译器代码。形式上不强制转换为汇编器:可执行的 C 代码只需要符合标准即可。所有这些都受编译器优化设置的影响。哪个通行证? C 代码有预处理器阶段,但编译器是一次性的。
  • 《安娜卡列尼娜》有很多英文翻译,但即使是基本句子,它们也使用不同的词。你会认为对于一个常见的句子,他们会使用完全相同的词。
  • @RaymondChen,@WeatherVane。抱歉这么不精确。而且我的问题仍然含糊不清,因为我希望有人能启发我了解如何在编译器中选择条件指令。 (安娜卡列尼娜的比喻很棒)。我应得的。 :-)
  • @RaymondChen 他们确实都针对相同的调用约定(即 SYS V x64 ABI),但这无关紧要。正如你所说,没有理由相信三个不同的编译器给出相同的输出:)
  • @PeterCordes 确实如此。我的观点是编译器之间的这些差异是由于一个相当具体的情况。正如 OP 的问题一样,将其一般地推断为“三元运算符”似乎有些牵强。

标签: assembly x86 x86-64 compiler-optimization


【解决方案1】:

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

我猜 gcc 决定对条件的两边进行布尔化处理工作量太大,因此决定使用分支。也许它没有意识到这是相同的工作,而表达式实际上可以以另一种方式完成(选择正确的输入,然后对其进行布尔化)。

它编写的代码会布尔化b,然后才测试条件并布尔化a。所以当cond 为真时,它实际上同时运行test / setnz 对。

这听起来像是一个错过优化的错误。 (或者一个优化运行异常错误,它通过将返回类型应用到?: 的两个输入而不是只应用到结果而自取其辱)。

报告为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;
}

【讨论】:

  • 我没有想到 bool 需要在寄存器中表示为 1 或 0 的事实;因此额外的说明。使用 int 作为返回类型,确实会产生“相同”的代码。我目前没有 gcc bugzilla 帐户,我对编译器的理解是“零散的”。你能提出问题吗?我保证自己提交问题,下次遇到可能的 gcc 错误时。
  • @dannas:完成。我认为 gcc bugzilla 帐户创建仍然由于垃圾邮件的原因而关闭,所以即使你愿意,也可以使用 IDK:/
  • 创建bugzilla账号还是可以的,过程简单手动了,要联系监督者。
猜你喜欢
  • 2016-10-23
  • 2022-01-18
  • 1970-01-01
  • 2015-11-05
  • 1970-01-01
  • 2019-04-18
  • 2013-10-15
  • 2021-11-24
  • 1970-01-01
相关资源
最近更新 更多