【问题标题】:Aliasing - what is the clang optimizer afraid of?别名 - clang 优化器害怕什么?
【发布时间】:2022-01-09 18:46:31
【问题描述】:

拿这个玩具代码(godbolt link):

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

int f(int i) {
    i = somefunc(i);
    i++;
    nothing();
    i++;
    nothing();
    i++;
    return i;
}

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

如果将somefunc 修改为按值接受int,则this doesn't happen

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

(2) 即使这是真的,我希望用__attribute__((pure)) 装饰somefunc 会停止这种悲观情绪。 It doesn't。为什么?

这些 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;
}

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

【问题讨论】:

  • const_cast'ing away 实际上是 allowed 如果原始对象没有定义为 const
  • 如果你定义somefunc inline 以便编译器看到它没有const_cast 那么它将被优化。如果原始对象不是 const (不在您的示例中),该语言允许 const_cast 。如果不允许,则 const_cast 就不会出现在该语言中。
  • "(请记住 const_cast'ing 和修改是未定义的行为)" 这似乎是您问题的基础,它是不正确的。 const_cast存在于语言中,因为有有效的用途,可以在这里使用。
  • “转义分析”:i 通过somefunc 转义(可以将其地址存储在全局变量中),因此可以被nothing 使用(读/写)。该属性似乎对 gcc 有帮助,也许您可​​以向 llvm 报告错过的优化?
  • @MarcGlisse 谢谢,我刚刚做了:github.com/llvm/llvm-project/issues/53102

标签: c++ clang llvm compiler-optimization


【解决方案1】:

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

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

【讨论】:

  • somefunc 在不同的翻译单元中的实现无法知道作为参数传递的 int 最初是如何定义的。这样的实现 const_cast 怎么可能仍然具有明确定义的行为?
  • @OfekShilon 实现的责任不在于知道它是否具有明确定义的行为。那将是开发人员的责任。
  • 程序员必须确保。例如。通过代码文档。如果它最初定义为non-const,那么行为是明确定义的。 const_cast 是一个高级(=危险,如果你不小心的话)工具。
  • @OfekShilon:您使用 const_cast 来抛弃 const 并修改指向的对象这一事实让编译器假定原始对象不是const。否则它将是 UB,并且在这种情况下实际上允许发生任何事情,因此优化器可以假设 UB 没有发生。 (即,编写适用于有效情况的代码,而不关心在无效情况下会发生什么。)这基本上是声明事物 UB 的重点,而不是错误,需要实现来检测和打印错误消息。 (clang -fsanitize=undefined可能这样做
猜你喜欢
  • 2013-06-16
  • 2013-03-10
  • 2014-03-16
  • 2014-01-09
  • 2018-11-01
  • 2014-07-13
  • 2017-03-05
  • 1970-01-01
相关资源
最近更新 更多