【发布时间】: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