【发布时间】: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
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
不,这是 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
【讨论】: