movsbl near ret 对性能有好处吗?

Is movsbl near ret good for performance?

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

gcc 将它编译成类似

的东西
movzbl  c(%rip), %eax
xorl    , %eax
movsbl  %al, %eax
ret

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

不,那是 GCC 遗漏的优化; C 可以合法地首先进行符号扩展加载。您应该使用关键字 "missed-optimization".

在 GCC bugzilla 上报告它

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

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

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

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

我猜 GCC 可能决定只加载 1 个字节并在 之后而不是之前进行符号扩展。 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      , %eax                                      #10.18
        movsbq    %al, %rax                                     #11.12
        ret                                                     #11.12