我有一个简单的函数,它通过引用获取两个变量:
void foo(int*& it2,
bit_reader<big_endian_tag>& reader2)
{
for(/* ... */)
{
*it2++ = boo(reader2.next());
// it2++ => 0x14001d890 add qword ptr [r12], 0x4
}
}
这里的问题是,对于 it2
和 reader2
,优化器使计算机在循环期间写入内存而不是寄存器。
但是,以下代码在循环期间将变量正确地放入寄存器,但在循环前后以不必要的拷贝形式存在额外开销:
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;
}
例如
如何让第一个示例生成与第二个示例相同的代码,但没有额外的拷贝?
最佳答案
问题是编译器无法证明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());
这不会为 otherInt
分配任何内容,而在转换之后它将:
void bar(int*& ptr, const foo& f)
{
int* ptrCopy = ptr;
*ptrCopy = f.blah(); // changes ptr, but not ptrCopy
}
因此,除非编译器能够证明行为相同,否则无法进行优化。
C99 使用 restrict
关键字解决了这个问题,但 C++ 没有等效项。不过,大多数 C++ 编译器中都存在一些扩展,例如 __restrict__
或 __restrict
。
要在标准 C++ 中执行此操作,您只需明确并自己制作拷贝
关于c++ - 如何让优化器正确地将变量放入寄存器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11977625/