我想创建一个总是返回零的函数,但这一事实对于优化器来说不应该是显而易见的,这样使用该值的后续计算就不会因为“已知零”状态而不断折叠。
在缺乏链接时间优化的情况下,通常只需将此代码放入其自己的编译单元:
int zero() {
return 0;
}
优化器不能看到所有的单元,所以这个函数始终为零的特性不会被发现。
然而,我需要一些与LTO和尽可能多的未来智能优化工作的东西。我考虑读一篇全球版的文章:
int x;
int zero() {
return x;
}
..。但在我看来,一个足够聪明的编译器可以注意到x
永远不会被写入,并且仍然决定zero()
始终为零。
我考虑过使用volatile
,比如:
int zero() {
volatile int x = 0;
return x;
}
..。但是,易失性读取所需副作用的实际语义并不完全清楚,并且似乎不排除函数仍然返回零的可能性。
这种始终为零但在编译时不为零的值在几种情况下都很有用,例如强制两个值之间存在无操作依赖关系。例如:a += b & zero()
使a
在最终的二进制文件中依赖于b
,但不会更改a
的值。
不要通过告诉我“标准不能保证任何方式来做到这一点”来回答这个问题--我很清楚,我正在寻找一个实用的答案,而不是标准中的语言。
发布于 2018-07-23 13:48:32
如果编译器能弄清楚这一点,我会很惊讶:
int not_a_zero_honest_guv()
{
// static makes sure the initialization code only gets called once
static int const i = std::ifstream("") ? 1:0;
return i;
}
int main()
{
std::cout << not_a_zero_honest_guv();
}
这使用了函数局部静态的复杂的(不可预测的)运行时初始化。如果顽皮的小编译器发现一个空的文件名总是会失败,那么就在里面放一些非法的文件名。
发布于 2018-07-23 14:09:31
你会发现每个编译器都有一个扩展来实现这一点。
GCC:
__attribute__((noinline))
int zero()
{
return 0;
}
MSVC:
__declspec(noinline)
int zero()
{
return 0;
}
发布于 2018-07-23 20:57:27
在clang和gcc中,敲打一个变量是可行的,但会增加一些开销
int zero()
{
int i = 0;
asm volatile(""::"g"(&i):"memory");
return i;
}
在gcc的O3下被编译成
mov DWORD PTR [rsp-4], 0
lea rax, [rsp-4]
mov eax, DWORD PTR [rsp-4]
ret
然后在当当
mov dword ptr [rsp - 12], 0
lea rax, [rsp - 12]
mov qword ptr [rsp - 8], rax
mov eax, dword ptr [rsp - 12]
ret
Live。
https://stackoverflow.com/questions/51471889
复制相似问题