别名 - clang 优化器害怕什么?

Ofe*_*lon 2 c++ llvm clang compiler-optimization

拿这个玩具代码(godbolt链接):

int somefunc(const int&);
void nothing();

int f(int i) {
    i = somefunc(i);
    i++;
    nothing();
    i++;
    nothing();
    i++;
    return i;
}
Run Code Online (Sandbox Code Playgroud)

从链接处的反汇编中可以看出,编译器i从堆栈重新加载 3 次,递增并存储回来。

如果somefunc修改为int按值接受,则不会发生这种情况

(1) 优化器是否“害怕”既然somefunc可以访问is 地址,就可以间接修改它?您能给出一个定义明确的代码示例吗?(请记住,const_cast'ing 和修改是未定义的行为)。

(2) 即使这是真的,我也希望装饰somefunc能够__attribute__((pure))阻止这种悲观情绪。事实并非如此。为什么?

这些 llvm 是否错过了优化?


编辑:如果somefunc返回 void,__attribute__((pure))则按预期启动:

void somefunc(const int&) __attribute__((pure));
void nothing();

int f(int i) {
    somefunc(i);
    i++;
    nothing();
    i++;
    nothing();
    i++;
    return i;
}
Run Code Online (Sandbox Code Playgroud)

也许这个属性有点半生不熟(在实践中很少见)。

Sne*_*tel 6

正如评论中提到的,使用const_cast删除对定义为非常量的对象的引用的常量性是明确定义的。事实上,这是它唯一的真正用途。

至于__attribute__((pure)):谁知道呢。nothing()需要调用这些电话来重现该情况;如果这些被标记,pure那么就完成了适当的优化;的调用somefunc对这种情况没有太大影响。基本上,编译器往往相当保守,除非代码块中的所有内容都是纯粹的。虽然它应该能够推断出这nothing()不会影响i,但这在很大程度上是一个“尽力而为”的优化领域,而不是正确优化的代码应该依赖的东西。

  • @OfekShilon,实现没有责任_知道_它是否具有明确定义的行为。这将是开发商的责任。 (5认同)
  • 程序员必须确定。例如通过代码文档。如果它最初被定义为“非常量”,那么行为是明确定义的。`const_cast` 是一个高级(=危险,如果你不小心的话)工具。 (3认同)
  • @OfekShilon:您使用 `const_cast` 来抛弃 const 并修改指向的对象的事实让编译器假设原始对象是非 `const` 的。否则就是 UB,并且在这种情况下任何事情都可以发生,因此优化器可以假设 UB 没有发生。(即编写适用于有效情况的代码,而不关心无效情况下会发生什么。)这基本上是声明 UB 的要点,而不是需要实现来检测和打印错误消息的错误。(`clang -fsanitize=undefined` *可能*这样做 (3认同)