【问题标题】:clang vs gcc: different code for volatile accessclang vs gcc:可变访问的不同代码
【发布时间】:2018-10-06 23:15:30
【问题描述】:

考虑这个例子:

volatile unsigned int x;
unsigned int y;

void f() {
    x /= 2;
}
void g() {
    y /= 2;
}

当使用 -Os 编译时,clang-6.0 在 x64 上为 f 和 g 生成相同的 shrl <offset>(%rip) 指令模式(参见 https://godbolt.org/g/hUPprL),而 gcc-7.3 为 f() 生成这个(参见 https://godbolt.org/g/vMcKVV) :

 mov 0x200b67(%rip),%eax # 601034 <x>
 shr %eax
 mov %eax,0x200b5f(%rip) # 601034 <x>

这只是错过的优化还是 gcc 有理由拒绝 shrl &lt;offset&gt;(%rip) 在易失性访问的情况下?谁错了?

【问题讨论】:

  • 如果它们都正常工作,那么它们都没有错,它们只是不同。
  • @PasserBy:我认为 OP 知道这一点,他在问这是否是一个错过的优化。
  • 谢谢迈克尔。如果两者都产生相同的行为,那么 gcc 就会暴露一个“错过优化错误”,因为它清楚地知道如何对 'y/=2' 进行大小优化。

标签: c++ gcc assembly clang volatile


【解决方案1】:

这只是 gcc 错过的优化。两种实现都精确地保留了对x 的读取和写入,因此是正确的。

在内存操作数上操作的“幕后”执行与更长的实现相同的加载和存储。

【讨论】:

  • 是的,gcc 不喜欢将 volatile 加载/存储折叠到其他操作中。在这种情况下,它也是一个错过的性能优化,根据Agner Fog's testing:Sandybridge-family 将shr [mem], imm 运行为 3 个融合域 uop,与单独的加载/shr/store 相同,更紧凑的代码通常更适合 L1i 缓存密度和 uop-cache 密度。 (Agner 的 Haswell/Skylake 表似乎是错误的;对于 port0 或内存目标转移仍然只有 1 ALU uop。他说 2p06 p237 p4,但我在 SKL 上测试过,它真的是 p06 p23 p237 p4
猜你喜欢
  • 2016-01-23
  • 1970-01-01
  • 2015-04-23
  • 1970-01-01
  • 1970-01-01
  • 2016-12-13
  • 2013-08-21
  • 2011-08-30
  • 1970-01-01
相关资源
最近更新 更多