如何使优化器正确地将变量放入寄存器?

ron*_*nag 1 c++ optimization visual-studio

我有一个简单的函数,它通过引用获取两个变量:

void foo(int*& it2,
         bit_reader<big_endian_tag>& reader2)
{
    for(/* ... */)
    {
        *it2++ = boo(reader2.next());
        // it2++ => 0x14001d890 add qword ptr [r12], 0x4
    }
}
Run Code Online (Sandbox Code Playgroud)

这里的问题是for it2reader2优化器使计算机在循环期间写入内存而不是寄存器.

但是,以下代码在循环期间将变量正确地放入寄存器中,但在循环之前和之后以不必要的副本的形式存在额外的开销:

void foo2(int*& it2,
         bit_reader<big_endian_tag>& reader2)
{
    auto reader = reader2;
    auto it     = it2;

    for(/* ... */)
    {
        *it++ = boo(reader.next());
        // it++ => 0x14001d890 add r15, 0x4
    }

    reader2 = reader;
    it2 = it;
}
Run Code Online (Sandbox Code Playgroud)

例如

如何使第一个示例生成与第二个示例相同的代码但没有额外的副本?

GMa*_*ckG 5

问题是编译器无法证明it2函数内部没有变化.(嗯,它可以,但这远远超出普通C++编译器的预期功能.)

它如何知道boo(reader2.next());不会改变价值?考虑:

int* i = 0;

struct foo
{
    int myInt;
    int blah() { i = &myInt; return 5; }
};

void bar(int*& ptr, const foo& f)
{
    *ptr = f.blah(); // changes value of ptr!
}

int otherInt;
i = &otherInt;

bar(i, foo());
Run Code Online (Sandbox Code Playgroud)

这不会分配任何内容otherInt,而在转换后它会:

void bar(int*& ptr, const foo& f)
{
    int* ptrCopy = ptr;
    *ptrCopy = f.blah(); // changes ptr, but not ptrCopy
}
Run Code Online (Sandbox Code Playgroud)

因此,除非编译器能够证明行为是相同的,否则它无法进行优化.

C99用restrict关键字解决了这个问题,但是C++没有等价物.但是,大多数C++编译器中都存在扩展,例如__restrict____restrict.

要在标准C++中执行此操作,您只需要明确并自己制作副本