我已经看过几次r10
这种奇怪的事了,所以让我们看看是否有人知道这些是什么。
采取这个简单的功能:
#define SZ 4
void sink(uint64_t *p);
void andpop(const uint64_t* a) {
uint64_t result[SZ];
for (unsigned i = 0; i < SZ; i++) {
result[i] = a[i] + 1;
}
sink(result);
}
它只是向传入数组的4个64位元素中的每一个添加1并将其存储在本地并在结果上调用sink()
(以避免整个函数被优化掉)。 / p>
这是corresponding汇编:
andpop(unsigned long const*):
lea r10, [rsp+8]
and rsp, -32
push QWORD PTR [r10-8]
push rbp
mov rbp, rsp
push r10
sub rsp, 40
vmovdqa ymm0, YMMWORD PTR .LC0[rip]
vpaddq ymm0, ymm0, YMMWORD PTR [rdi]
lea rdi, [rbp-48]
vmovdqa YMMWORD PTR [rbp-48], ymm0
vzeroupper
call sink(unsigned long*)
add rsp, 40
pop r10
pop rbp
lea rsp, [r10-8]
ret
很难理解r10
几乎发生的一切。首先,r10
设置为指向rsp + 8
,然后指向push QWORD PTR [r10-8]
,据我所知,它会在堆栈上推送返回地址的副本。然后,rbp
正常设置,最后r10
本身被推送。
要展开这一切,r10
会从堆栈中弹出,并用于将rsp
恢复为原始值。
一些观察结果:
rsp
之前简单地将ret
恢复为原始值的完全迂回方式 - 但通常是{{1}的结尾也会这样做(见mov rsp, rpb
)!clang
在这项任务中甚至没有帮助:这个值(返回地址?)显然从未使用过。push QWORD PTR [r10-8]
被推挤并弹出?该值在非常小的函数体中没有被破坏,并且没有套准压力。该怎么办?我之前已经多次看过它,它通常想要r10
,有时候r10
。看起来很可能与将堆栈对齐到32个字节有关,因为如果将r13
更改为小于4,则使用SZ
操作,问题就会消失。
以下xmm
例如:
SZ == 2
好多了!
答案 0 :(得分:3)
嗯,你回答了你的问题:在使用对齐的AVX2加载和存储访问堆栈指针之前,需要将堆栈指针对齐到32个字节,但ABI只提供16字节对齐。由于编译器无法知道对齐关闭多少,因此必须将堆栈指针保存在暂存寄存器中,然后将其恢复。但是保存的值必须比函数调用更长,因此必须将其放在堆栈上,并且必须创建堆栈帧。
某些x86-64 ABI有一个红色区域(堆栈指针下方的堆栈区域,信号处理程序不使用),因此,对于这样的短函数,根本不更改堆栈指针是可行的,但是GCC显然没有实现这种优化,但由于最后的函数调用,它无论如何都不适用。
此外,默认的堆栈对齐实现相当差。对于这种情况,-maccumulate-outgoing-args
使用GCC 6产生更好看的代码,只是在保存RBP后对齐RSP,而不是在保存RBP之前复制返回地址:
andpop:
pushq %rbp
movq %rsp, %rbp # make a traditional stack frame
andq $-32, %rsp # reserve 0 or 16 bytes
subq $32, %rsp
vmovdqu (%rdi), %xmm0 # split unaligned load from tune=generic
vinserti128 $0x1, 16(%rdi), %ymm0, %ymm0 # use -march=haswell instead
movq %rsp, %rdi
vpaddq .LC0(%rip), %ymm0, %ymm0
vmovdqa %ymm0, (%rsp)
vzeroupper
call sink@PLT
leave
ret
(编者注:gcc8及更高版本默认使用asm(Godbolt compiler explorer with gcc8, clang7, ICC19, and MSVC),即使没有-maccumulate-outgoing-args
)
当我们不得不为GCC __tls_get_addr
ABI bug实现变通方法时,最近出现了这个问题(GCC生成的堆栈对齐代码很差),最后我们手工编写了堆栈重组。
编辑还有另一个与RTL传递顺序相关的问题:在最终确定是否实际需要堆栈之前选择堆栈对齐,as BeeOnRope's second example shows。