首页 > 解决方案 > movsbl near ret 对性能有好处吗?

问题描述

char c;
int f()
{
    return c ^ 1;
}

gcc 把它编译成类似的东西

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

由于一些乱序或超标量特性,它有用吗?

标签: gcccpux86-64micro-optimization

解决方案


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

clang、ICC 和 MSVC(在 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 个字节并在之后而不是之前进行符号扩展。IDK 为什么它认为这是一个好主意。但无论如何,为了避免对 RAX 旧值的错误依赖,需要对 32 位进行某种扩展。

以这种方式编写 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

推荐阅读