【问题标题】:Is movsbl near ret good for performance?movsbl near ret 对性能有好处吗?
【发布时间】:2019-04-03 13:48:12
【问题描述】:
char c;
int f()
{
    return c ^ 1;
}

gcc 把它编译成类似的东西

movzbl  c(%rip), %eax
xorl    $1, %eax
movsbl  %al, %eax
ret

是否因为某些乱序或超标量特性而有用?

【问题讨论】:

    标签: gcc cpu x86-64 micro-optimization


    【解决方案1】:

    不,这是 GCC 错过的优化; C 首先可以合法地进行符号扩展负载。您应该使用关键字“missed-optimization”在 GCC bugzilla 上报告它。

    clang、ICC 和 MSVC (on Godbolt) 将其编译为预期

    f:
            movsbl  c(%rip), %eax           # sign extend first
            xorl    $1, %eax
            retq
    

    即使尝试使用此 C 将 GCC 手动放入该代码生成器也无法让 GCC 做到这一点:

    int f() {
        int tmp = c;
        tmp ^= 1;
        return tmp;
    }
    

    我猜可能 GCC 决定只加载 1 个字节并在 after 而不是之前进行符号扩展。 IDK 为什么它认为这是一个好主意。但无论如何,有必要对 32 位进行某种扩展,以避免对 RAX 旧值的错误依赖。

    以这种方式编写 C 会使 ICC 错失优化,而不是 MSVC 或 clang。他们仍然将其优化为首先进行符号扩展,因为他们知道 XOR 不能更改任何高位。

    int extend_after() {
        char tmp = c^1;
        return tmp;
    }
    

    现在 ICC 就像 GCC,但由于某种原因符号一直扩展到 64 位:

    extend_after:
            movzbl    c(%rip), %eax                                 #10.16
            xorl      $1, %eax                                      #10.18
            movsbq    %al, %rax                                     #11.12
            ret                                                     #11.12
    

    【讨论】:

    • 我很难相信 gcc 会错过这么简单的优化。更难相信 icc 会犯类似的错误。
    • @ntysdd:编译器总是错过明显简单的优化,但是是的,这对 gcc 来说有点令人惊讶。不过,如果您已经看过 ICC 的代码生成,您不会对此感到惊讶!它非常擅长自动矢量化,但通常不擅长从代码中挤出所有指令。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-12
    • 2010-11-20
    • 1970-01-01
    • 2022-06-23
    • 2013-04-21
    相关资源
    最近更新 更多