创建一个始终返回零的函数,但优化器不知道 [英] Create a function that always returns zero, but the optimizer doesn't know

查看:81
本文介绍了创建一个始终返回零的函数,但优化器不知道的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个始终返回零的函数,但是对于优化器来说,这一事实应该并不明显,因此由于已知零"状态,使用该值进行的后续计算将不会不断折叠. /p>

在没有链接时优化的情况下,这通常就像将其放入自己的编译单元中一样简单:

int zero() {
  return 0;
}

优化器看不到单位,因此不会发现该函数的始终为零的性质.

但是,我需要与LTO一起使用的东西以及将来可能进行的尽可能多的聪明优化.我考虑过从全球阅读:

int x;

int zero() {
  return x;
}

...但是在我看来,足够聪明的编译器可能会注意到从未写入x并仍然确定zero()始终为零.

我考虑使用volatile,例如:

int zero() {
  volatile int x = 0;
  return x;
}

...但是,volatile读取所需副作用的实际语义尚不清楚,并且似乎无法排除函数仍返回零的可能性.

这样的始终为零但不是在编译时的值在几种情况下很有用,例如在两个值之间强制使用no-op依赖性.像这样的内容:a += b & zero()导致a依赖最终二进制文件中的b,但不会更改a的值.

不要通过告诉我标准不能保证采取任何方式做到这一点"来回答这个问题-我很清楚,我正在寻找实用的答案,而不是标准的语言.

解决方案

首先,我想:OP的第三条建议:

int zero() {
  volatile int x = 0;
  return x;
}

实际上可以工作(但这不是我的答案;请参见下文).两周前,此功能完全相同,是 https://godbolt.org/g/SA7k5P .


我的答案是在上面添加static,即:

int zero() {
  static volatile int x;
  return x;
}

在此处查看一些测试: https://godbolt.org/g/qzWYJt .

现在,添加static后,可观察到的行为"的抽象概念变得更加可信.通过一点点工作,我可以弄清楚x的地址,特别是如果我禁用了地址空间布局随机化.这可能在.bss段中.然后,再做一些工作,我可以将调试器/黑客工具附加到正在运行的进程中,然后 change x.并使用volatile告诉编译器我可以执行此操作,因此不允许通过优化x来更改此可观察到的行为". (也许可以通过内联将 call 优化为zero,但我不在乎.)

是否允许编译器优化局部变量?有点误导,因为讨论的重点是x位于 stack 而不是局部变量.因此,此处不适用.但是我们可以将x从本地范围更改为文件范围,甚至更改为全局范围,如下所示:

volatile int x;
int zero() {
  return x;
}

这不会改变我的观点.


进一步的讨论:

是的,volatile有时会出现问题:例如,请参见此处显示的指向易失性的问题 https://godbolt.org/g/s6JhpL 易碎的结构损坏报告了一个错误,该错误优化了易失性访问在gcc和Clang中都消失了. (它在三个小时内固定.)一位评论员引用了该标准(添加了重点):

"6.7.3 ...对具有volatile限定类型的对象的访问构成为实现定义."

Regehr同意,但补充说,在非边缘案件中如何使用它已达成共识:

是的,实现定义是对易失性变量的访问.但是您错过了以下事实:所有合理的C实现都将对volatile变量的读取视为读取访问,将对volatile变量的写入视为写入访问.

以获取更多参考.看到:

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆