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
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