禁用一个函数的返回值优化

xlr*_*lrg 2 c++ assembly return-value-optimization rvo nrvo

struct X {
  void * a;
  void * b;
};

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

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

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

如何强制编译器不为foo()添加RVO(又名强制-fno-elide-constructors)?

Update1:代码必须适用于任意编译器(至少gcc,clang,msvc),示例代码:

void * vp = bar();
X x = foo( vp, 0);
x = foo( x.a, 0);
x = foo( x.a, 0);
Run Code Online (Sandbox Code Playgroud)

Update2:问题是,编译器优化了x的实例

X x = foo( vp, 0);
x = foo( x.a, 0);
x = foo( x.a, 0)
Run Code Online (Sandbox Code Playgroud)

要么

X x1 = foo( vp, 0);
X x2 = foo( x1.a, 0);
X x3 = foo( x2.a, 0)
Run Code Online (Sandbox Code Playgroud)

无所谓.例如,段错误是因为

X x2 = foo( x1.a, 0);
Run Code Online (Sandbox Code Playgroud)

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

kay*_*kay 6

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

X foo(void *u, void *v) __attribute__((optimize("no-elide-constructors");
Run Code Online (Sandbox Code Playgroud)

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

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

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

您也可以尝试#pragma变体:

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

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

#pragma GCC pop_options
Run Code Online (Sandbox Code Playgroud)