解决windows调用保留约定的xmm寄存器的问题?
在Windows上有没有办法解决XMM寄存器保留在函数调用中的要求?(除了在汇编中编写之外) 我有很多AVX2的内在函数,不幸的是,这些函数都被这个函数膨胀了 例如,编译器(MSVC)将其置于函数顶部: 00007FF9D0EBC602 vmovaps xmmword ptr[rsp+1490h],xmm6解决windows调用保留约定的xmm寄存器的问题?,windows,assembly,sse,calling-convention,abi,Windows,Assembly,Sse,Calling Convention,Abi,在Windows上有没有办法解决XMM寄存器保留在函数调用中的要求?(除了在汇编中编写之外) 我有很多AVX2的内在函数,不幸的是,这些函数都被这个函数膨胀了 例如,编译器(MSVC)将其置于函数顶部: 00007FF9D0EBC602 vmovaps xmmword ptr[rsp+1490h],xmm6 00007FF9D0EBC60B vmovaps xmmword ptr[rsp+1480h],xmm7 00007FF9D0EBC614 vmovaps xmmword ptr[rsp+1
00007FF9D0EBC60B vmovaps xmmword ptr[rsp+1480h],xmm7
00007FF9D0EBC614 vmovaps xmmword ptr[rsp+1470h],xmm8
00007FF9D0EBC61D vmovaps xmmword ptr[rsp+1460h],xmm9
00007FF9D0EBC626 vmovaps xmmword ptr[rsp+1450h],xmm10
00007FF9D0EBC62F vmovaps xmmword ptr[rsp+1440h],xmm11
00007FF9D0EBC638 vmovaps xmmword ptr[rsp+1430h],xmm12
00007FF9D0EBC641 vmovaps xmmword ptr[rsp+1420h],xmm13
00007FF9D0EBC64A vmovaps xmmword ptr[rsp+1410h],xmm14
00007FF9D0EBC653 vmovaps xmmword ptr[rsp+1400h],xmm15 然后在函数的末尾 00007FF9D0EBD6E6 vmovaps xmm6,xmmword ptr[r11-10h]
00007FF9D0EBD6EC vmovaps xmm7,xmmword ptr[r11-20h]
00007FF9D0EBD6F2 vmovaps xmm8,xmmword ptr[r11-30h]
00007FF9D0EBD6F8 vmovaps xmm9,xmmword ptr[r11-40h]
00007FF9D0EBD6FE vmovaps xmm10,xmmword ptr[r11-50h]
00007FF9D0EBD704 vmovaps xmm11,xmmword ptr[r11-60h]
00007FF9D0EBD70A vmovaps xmm12,xmmword ptr[r11-70h]
00007FF9D0EBD710 vmovaps xmm13,xmmword ptr[r11-80h]
00007FF9D0EBD716 vmovaps xmm14,xmmword ptr[r11-90h]
00007FF9D0EBD71F vmovaps xmm15,xmmword ptr[r11-0A0h] 这是20条指令,它们什么也不做,因为我不需要保留XMM的状态。我有100个这样的函数,编译器像这样膨胀。它们都是通过函数指针从同一调用站点调用的
我尝试更改调用约定(uu vectorcall/cdecl/fastcall),但这似乎没有任何作用。使用x86-64 System V调用约定处理您希望通过函数指针组合在一起的助手函数。在该调用约定中,所有xmm/ymm0..15和zmm0..31都被调用截断,因此即使是需要5个以上向量寄存器的辅助函数也不必保存/恢复任何向量寄存器 调用它们的外部解释器函数仍应使用Windows x64 fastcall或vectorcall,因此从外部来看,它完全尊重调用约定 这将把XMM6..15的所有保存/恢复提升到该调用者中,而不是提升到每个助手函数中。这减少了静态代码大小,并通过函数指针分摊了多次调用的运行时成本
另外,MSVC不支持将函数标记为使用x86-64 System V调用约定,只支持fastcall与vectorcall,因此必须使用clang (ICC有缺陷,在调用System V ABI函数时无法保存/恢复XMM6..15) 对于溢出的
\uuuum256
,因此将GCC与-march=
一起使用通常不安全
对函数和函数指针声明使用
\uuuuu属性(sysv\u abi))
或\uuuu属性(ms\u abi))
我认为ms\u abi
是\u快速呼叫
,而不是\u向量呼叫
。Clang可能也支持\uuuuuuuuuu属性((vectorcall))
,但我还没有尝试过。谷歌搜索结果主要是功能请求/讨论
void (*helpers[10])(float *, float*) __attribute__((sysv_abi));
__attribute__((ms_abi))
void outer(float *p) {
helpers[0](p, p+10);
helpers[1](p, p+10);
helpers[2](p+20, p+30);
}
编译如下-O3-march=skylake
。(Godbolt target Linux上的gcc/clang,但我在函数和函数指针上都使用了显式的ms_abi
和sysv_abi
,因此代码生成不依赖于默认值为sysv_abi
这一事实。显然,您希望使用Windows gcc或clang构建函数,因此对其他函数的调用将使用该工具ht调用约定和有用的对象文件格式等)
请注意,gcc/clang为outer()
发出代码,该代码需要RCX(Windows x64)中的传入指针arg,但将其传递给RDI和RSI(x86-64 System V)中的被调用方
GCC生成的代码基本相同。但是WindowsGCC在AVX上有缺陷
ICC19生成了类似的代码,但没有xmm6..15的保存/恢复。这是一个显示错误;如果任何被调用方像被允许的那样对这些regs进行重击,那么从这个函数返回将违反其调用约定
这使得clang成为唯一可以使用的编译器。那很好;叮当声很好
如果您的被调用方不需要所有的YMM寄存器,那么在外部函数中保存/恢复所有的YMM寄存器就太过分了。但现有的工具链没有中间立场;例如,您必须在asm中手工编写
outer
,以利用您知道没有任何可能的被调用方会碰到XMM15的优势
请注意,从内部
outer()
调用其他MS-ABI函数完全可以。GCC/clang也会(排除bug)为此发出正确的代码,如果被调用的函数选择不销毁xmm6..15,这也没关系。通常,这些内在函数是内联的。为什么在您的代码中不是这样?您确定编译器优化已打开吗?“VM”是什么意思?如果函数不小,那么保存和恢复寄存器有什么问题?调用代码假定寄存器被保留。如果不保留它们,调用函数(或它的调用者,或它的调用者的调用者,…)的行为可能会不稳定。@Frogles我对你的心智能力没有任何假设。但考虑到你没有提供任何细节,也没有回答你的问题,我不得不猜测实际情况是什么。也许下次试着问一个更好的问题,而不是感觉不舒服
outer: # @outer
push r14
push rsi
push rdi
push rbx
sub rsp, 168
vmovaps xmmword ptr [rsp + 144], xmm15 # 16-byte Spill
vmovaps xmmword ptr [rsp + 128], xmm14 # 16-byte Spill
vmovaps xmmword ptr [rsp + 112], xmm13 # 16-byte Spill
vmovaps xmmword ptr [rsp + 96], xmm12 # 16-byte Spill
vmovaps xmmword ptr [rsp + 80], xmm11 # 16-byte Spill
vmovaps xmmword ptr [rsp + 64], xmm10 # 16-byte Spill
vmovaps xmmword ptr [rsp + 48], xmm9 # 16-byte Spill
vmovaps xmmword ptr [rsp + 32], xmm8 # 16-byte Spill
vmovaps xmmword ptr [rsp + 16], xmm7 # 16-byte Spill
vmovaps xmmword ptr [rsp], xmm6 # 16-byte Spill
mov rbx, rcx # save p
lea r14, [rcx + 40]
mov rdi, rcx
mov rsi, r14
call qword ptr [rip + helpers]
mov rdi, rbx
mov rsi, r14
call qword ptr [rip + helpers+8]
lea rdi, [rbx + 80]
lea rsi, [rbx + 120]
call qword ptr [rip + helpers+16]
vmovaps xmm6, xmmword ptr [rsp] # 16-byte Reload
vmovaps xmm7, xmmword ptr [rsp + 16] # 16-byte Reload
vmovaps xmm8, xmmword ptr [rsp + 32] # 16-byte Reload
vmovaps xmm9, xmmword ptr [rsp + 48] # 16-byte Reload
vmovaps xmm10, xmmword ptr [rsp + 64] # 16-byte Reload
vmovaps xmm11, xmmword ptr [rsp + 80] # 16-byte Reload
vmovaps xmm12, xmmword ptr [rsp + 96] # 16-byte Reload
vmovaps xmm13, xmmword ptr [rsp + 112] # 16-byte Reload
vmovaps xmm14, xmmword ptr [rsp + 128] # 16-byte Reload
vmovaps xmm15, xmmword ptr [rsp + 144] # 16-byte Reload
add rsp, 168
pop rbx
pop rdi
pop rsi
pop r14
ret