在clang中声明变量无别名?

时间:2016-12-26 13:55:36

标签: c++ clang compiler-optimization strict-aliasing

有没有办法在clang中声明变量是非别名的,以允许在使用变量的地方进行更多优化?

我理解restrict可用于将指针声明为非别名。

但是,我也想知道可以指向的变量。我猜(也许是错误的)编译器必须小心假设可以允许它缓存变量的值而不是每次都重新获取它。

示例:

class Data
{   
public:
    void updateVal() {
        // Updates m_val with some value each time it's called (value may differ across different calls)
        ...
    }
    int complicatedCalculation() const {
        return 3 * m_val + 2;
    }
    int m_val;
};

class User
{
    User(Data& data) : m_data{data} {}
    void f()
    {
        m_data.updateVal();
        for (int i=0; i<1000; ++i)
            g();
    }
    void g()
    {
        // Will the optimizer be able to cache calc's value for use in all the calls to g() from f()?
        int calc = m_data.complicatedCalculation();

        // Do more work
        ...
    }

    Data& m_data;
};

即使示例代码中的问题答案为&#34;是&#34;,也可能不会更改为&#34; no&#34;如果代码更复杂(例如工作在// Do more work下),由于指针内容可能被修改,指针可能指向m_data.m_val?或者这是编译器假设从未发生的事情,除非它看到m_val的地址被带到代码中的某个地方?

如果它没有假设,或者甚至它,但m_val 的地址在某个地方被占用(但我们知道它的内容不会被修改),那么能够将m_val标记为&#34; safe&#34;来自别名问题,因此可以假定其值不会被指针访问更改。

1 个答案:

答案 0 :(得分:0)

编译器将在calc中分配一个寄存器来存储g,除非它确定有更好的其他更热的变量存储在寄存器中。

现在,即使calc存储在寄存器中,仍可能需要对complicatedCalculation进行函数调用,并对m_val进行内存访问。编译器可以内联complicatedCalculation并消除函数调用,但它不能消除内存访问,除非它可以确定m_val实际上始终是一个常量。

您真正想要的是消除m_val中的f而不是g中对g的不必要的内存访问。为此,编译器必须认为f有资格在m_val中进行内联。只有在内联时,编译器才能消除不必要的内存访问。即使g直接修改calc,编译器仍然可以在寄存器中分配g并相应地修改它。这里唯一需要注意的是m_val 可能会抛出异常。如果抛出异常,则必须在允许传播异常之前将内存版本的m_val更新为最新值。编译器必须发出代码以确保这一点。如果没有此代码,则必须在每次迭代中更新内存版本的m_value。我不知道哪个版本的clang使用哪种方法。您必须检查生成的汇编代码。

如果restrict的地址在代码中的任何位置,则编译器可能无法消除对它的任何内存访问。在这种情况下,使用m_value可能会有所帮助。不应该通过任何其他指针修改ngOnInit,因为这违反了标准并导致未定义的行为。确保这一点是你的责任。

我希望您关心这一点,因为您已经通过实验确定这是代码中的性能瓶颈,或者您只是好奇,而不是出于任何其他原因。