是否有扩展让优化器假设const-ref参数将保持const?

时间:2018-03-12 02:59:55

标签: c++

与我以前的问题相关:Are compilers not allowed to assume const-ref parameters will stay const?

我的新问题是:是否有特定于编译器的非标准扩展或语法告诉GCC / Clang / MSVC对象不可写?例如,这里有一些我想写的假代码:

void f(const int& i) {

    // At this point, compiler doesn't know if "i" can be mutated or not,
    // so it assumes it can

    // Fake-ish -- compiler now assumes "i" cannot be mutated and optimizes accordingly
    __assume(readonly i);

    // ...

}

2 个答案:

答案 0 :(得分:4)

如果i应该保留整个函数的常量,并且f()没有副作用,则可以使用__attribute__((pure))声明它:

int f(const int&) __attribute__((pure));

请注意,pure函数返回void没有意义,因此我将其更改为int

虽然这不会影响f()的编译方式,但它会影响调用它的函数(在godbolt上查看):

#include <iostream>

int f(const int& i) __attribute__((pure));

int main() {
    int i = 40;
    f(i);
    if (i != 40) {
        std::cout << "not 40" << std::endl;
    }
}

此处__attribute__((pure))告诉编译器f()不会更改i,因此编译器不会生成对std::cout << ...的调用。

如果没有__attribute__((pure)),即使声明f()采用const int& i参数,编译器也必须假设i的值可能会发生变化,并生成{ {1}}以及对if的调用。

答案 1 :(得分:1)

我不知道允许编译器承担不变性的非标准方法,但如果我正确地阅读标准,我认为有一种标准方法可以这样做(改编自你的其他问题):

void f(const int&);

struct ImmutableInt {
    // it is UB to change val, because it is itself const
    // not just a const reference
    const int val;    
};

void g3(const ImmutableInt & i) {
    if (i.val == 42) f(i.val);
    if (i.val == 42) f(i.val); // the compiler could assume i.val has not changed
}

问题是,目前编译器checked没有利用这些知识来实际省略重新加载值。

我认为这没有任何根本问题,因为clang使用类似且更复杂的推理来实现devirtualization虚拟表指针。这种推理有点复杂,因为vptr在构造期间会改变,因此不完全是const。用于此的llvm元数据称为invariant.group,但我不知道您是否可以在C ++中自己设置它。