【问题标题】:disable return-value-optimization for one function禁用一个函数的返回值优化
【发布时间】:2015-11-02 10:18:32
【问题描述】:
struct X {
  void * a;
  void * b;
};

X foo( void * u, void * v);
  • foo() 在汇编器 (i386) 中实现
  • X 类型返回值的地址作为隐藏参数传递给 foo()

  • 如果使用 -O0 编译测试代码,则代码按预期工作

  • 如果编译时出现 -O3 分段错误(返回值已优化)
  • 如果使用 -O3 -fno-elide-constructors 编译,代码将再次按预期工作

如何强制编译器不只为 foo() 添加 RVO(也就是不强制 -fno-elide-constructors)?

更新1: 该代码必须适用于任意编译器(至少 gcc、clang、msvc), 示例代码:

void * vp = bar();
X x = foo( vp, 0);
x = foo( x.a, 0);
x = foo( x.a, 0);

更新2: 问题是,编译器优化了 x 的实例

X x = foo( vp, 0);
x = foo( x.a, 0);
x = foo( x.a, 0)

X x1 = foo( vp, 0);
X x2 = foo( x1.a, 0);
X x3 = foo( x2.a, 0)

没关系。例如,发生段错误是因为

X x2 = foo( x1.a, 0);

x1 已优化,实现尝试访问第一个参数 ,这是一个空指针。

【问题讨论】:

  • 没有通用的方法,你应该指出你使用的编译器,这里如何使用gcc:gcc.gnu.org/onlinedocs/gcc/…
  • 如果foo 是在汇编中实现的,那么-fno-elide-constructors 应该不会对它产生任何影响。 -fno-elide-constructors 影响 C++ 转换为程序集的方式。如果您一开始就没有 C++ 代码,则无需修改程序集生成。您能否编辑您的问题以提供minimal reproducible example - 即您的程序集foo 函数和一个调用该函数的最小程序,该程序在-O3 处出现您描述的段错误?
  • @hvd: foo() 太复杂了,不能在这里展示
  • 问题一定出在其他地方。如果编译器不是也编译foo 的编译器,而且如果 id 在调用位置无法访问foo 的源或foo (lto) 的IR,那么它只是不能应用 RVO。这是不可能的,因为它必须修改创建X 的位置内存。进一步检查代码,问题不是 RVO,至少不是提供的代码。
  • "bar() 创建堆栈,foo 在两个堆栈之间切换..." 可能是您的程序过度设计?

标签: c++ assembly return-value-optimization rvo nrvo


【解决方案1】:

您也可以在 GCC 中为单个函数设置优化级别:

X foo(void *u, void *v) __attribute__((optimize("no-elide-constructors");

optimize 属性用于指定使用不同于命令行指定的优化选项来编译函数。参数可以是数字或字符串。数字被假定为优化级别。以 O 开头的字符串被假定为优化选项,而其他选项被假定与 -f 前缀一起使用。您还可以使用“#pragma GCC optimize”杂注来设置影响多个函数的优化选项。有关“#pragma GCC optimize”编译指示的详细信息,请参阅函数特定选项编译指示。

这可以用于例如使用更积极的优化选项编译频繁执行的函数,从而生成更快和更大的代码,而其他函数可以使用不那么积极的选项进行编译。

https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html

你也可以试试#pragma variant:

#pragma GCC push_options
#pragma GCC optimize ("no-elide-constructors")

X foo(void *u, void *v);

#pragma GCC pop_options

【讨论】:

  • 代码必须独立于编译器 - 抱歉我没注意到
  • X Plain Old Data?你能篡改foo 的代码并让X 成为“正确”的参数吗?
  • @xlrg,除了我之前的问题,答案是否在 GCC 中有效,还是完全错误?
  • 它适用于 GCC 但 Clang.seams 不支持属性优化
  • 请尝试使用#pragma GCC optimize ("no-elide-constructors") 的变体(刚刚添加到我的答案中)。
猜你喜欢
  • 2012-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-17
  • 2010-09-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多