【发布时间】:2018-09-03 14:35:01
【问题描述】:
struct Big {
int a[8];
};
void foo(Big a);
Big getStuff();
void test1() {
foo(getStuff());
}
编译(在 Linux 上使用 clang 6.0.0 for x86_64 so System V ABI,标志:-O3 -march=broadwell)到
test1(): # @test1()
sub rsp, 72
lea rdi, [rsp + 40]
call getStuff()
vmovups ymm0, ymmword ptr [rsp + 40]
vmovups ymmword ptr [rsp], ymm0
vzeroupper
call foo(Big)
add rsp, 72
ret
如果我没看错,这就是正在发生的事情:
-
getStuff被传递了一个指向foo的堆栈(rsp + 40) 的指针以用作它的返回值,所以在getStuff返回rsp + 40到rsp + 71之后包含getStuff的结果。李> - 然后,此结果会立即复制到较低的堆栈地址
rsp一直到rsp + 31。 -
然后调用
foo,它将从rsp中读取其参数。
为什么下面的代码不完全等价(为什么编译器不生成它)?
test1(): # @test1()
sub rsp, 32
mov rdi, rsp
call getStuff()
call foo(Big)
add rsp, 32
ret
想法是:让getStuff 直接写入堆栈中foo 将读取的位置。
还有: 这是 vc++ 在 windows for x64 上编译的相同代码(用 12 个整数而不是 8 个整数)的结果,这似乎更糟,因为 windows x64 ABI 通过引用传递和返回,因此副本完全未使用!
_TEXT SEGMENT
$T3 = 32
$T1 = 32
?bar@@YAHXZ PROC ; bar, COMDAT
$LN4:
sub rsp, 88 ; 00000058H
lea rcx, QWORD PTR $T1[rsp]
call ?getStuff@@YA?AUBig@@XZ ; getStuff
lea rcx, QWORD PTR $T3[rsp]
movups xmm0, XMMWORD PTR [rax]
movaps XMMWORD PTR $T3[rsp], xmm0
movups xmm1, XMMWORD PTR [rax+16]
movaps XMMWORD PTR $T3[rsp+16], xmm1
movups xmm0, XMMWORD PTR [rax+32]
movaps XMMWORD PTR $T3[rsp+32], xmm0
call ?foo@@YAHUBig@@@Z ; foo
add rsp, 88 ; 00000058H
ret 0
【问题讨论】:
-
你能提供你正在编译的调用约定吗?
-
System V amd64,已将该信息添加到问题中。
-
不确定这是否有帮助,但标准说函数参数不能是 NRVO 的。所以至少有一个省略是不可能发生的(当然,除非在 as-if 规则下。)
-
根据 System V ABI
struct Big并不是很大。它实际上是INTEGER类的边界大小。你可以试试更大的尺寸吗? -
我的立场已得到纠正,显然
int成员的错位导致结构被归类为MEMORY
标签: c++ clang x86-64 compiler-optimization abi