Vararg x86-64 ABI。寄存器中浮点参数的数量

问题描述 投票:0回答:1

我正在查看x86-64 ABI,并对x86-64Figure 3.31中的示例有疑问:

Figure 3.32

据说,当将参数传递给int a, b; long double ld; double m, n; __m256 u, y; __m512 v, z; extern void func (int a, double m, __m256 u, __m512 v, ...); func (a, m, u, v, b, ld, y, z, n); 函数时func包含3,但是我只能看到寄存器中传递了2个浮点值:%raxld。因此,我实现了以下示例:

m

impl.c

#include <immintrin.h> unsigned long func(int a, double m, __m256 u, __m512 v, ...){ unsigned long rax; __asm__ __volatile__( "" : "=a" (rax) : : ); return rax; }

main.c

是错字吗?因此,寄存器#include <immintrin.h> #include <stdio.h> unsigned long func(int a, double m, __m256 u, __m512 v, ...); int main(void){ int a = 10, b = 20; long double ld = 30.0; double m = 40.0, n = 50.0; __m256 u, y; __m512 v, z; printf("%lu\n", func(a, m, u, v, b, ld, y, z, n)); //prints 2 } 的正确内容应该是%rax而不是2

c assembly x86-64 abi
1个回答
1
投票

ABI文档有一个错误:该示例应为3。当添加AVX512 al=4时,此图仅得到部分更新。例如__m512之前是正确的。 al=3不带固定的in the 0.99.7 revision of the ABI参数。

[@ AnttiHaapala是正确的,他们也无法更新3.32以在堆栈上的__m512上显示z

64:被认为是向量regs中的args的总数,包括固定的args。 这包括XMM寄存器中的any arg,无论是标量还是alcan都是可变参数传递的。或对于固定args,还包括__m128__m256 。 (用于可变参数函数的矢量在堆栈上传递;(可能)在__m512上使用va_arg的可变函数不需要转储所有YMM reg,而仅转储XMM。传递的用例很少。可变SIMD向量。)但是请注意,在XMM寄存器中传递了80位__m256。 SSE / AVX指令对80位x87扩展精度数据无法执行任何操作,因此强制将功能复制到XMM reg /从XMM reg复制,然后再将其复制回x87堆栈reg是没有意义的。

注意,被呼叫者必须忽略RAX的高字节。调用者通常很方便地使用long double ld而不是mov eax, 3,以避免出现虚假依赖关系的可能性。 ABI文档的图表基于GCC的正常行为,实际上应该说mov al,3,而不是%al



为什么GCC对于较旧的ABI使用值2?

因为您在编译时忘记了实际启用AVX(和AVX512)。

[ABI文档假定%rax变量仅在具有YMM寄存器(支持AVX)的机器上使用,因此可以在寄存器中传递。如果您错了,GCC会警告您:

__m256

使用<source>: In function 'void caller()': <source>:11:9: warning: AVX vector argument without AVX enabled changes the ABI [-Wpsabi] 11 | func (a, m, u, v, b, ld, y, z, n); | ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~ <source>:11:9: note: the ABI for passing parameters with 32-byte alignment has changed in GCC 4.6 <source>:11:9: warning: AVX512F vector argument without AVX512F enabled changes the ABI [-Wpsabi] 进行编译会发出该警告,并在ASM中将gcc -O3包含在mov eax,2中,该caller()包含来自ABI文档的func()调用。

gcc -O3 -march=skylake-avx512(或-mavx512f编译)得到4。如果要省去向量寄存器中的一个参数,则单击3

通常,可以肯定的是,GCC正确实施了ABI,因此您只需查看其代码即可查看会发生什么。为实际的

print

RAX构建复杂的方法要复杂得多,并且使您无法注意到您的代码未使用AVX512。

void caller() { func (a, m, u, v, b, ld, y, z, n); } 正确编译为该asm(

Godbolt, gcc9.2 -O3 -march=skylake-avx512

):

-O3 -march=skylake-avx512向量reg中的4个arg,AL = 4。

© www.soinside.com 2019 - 2024. All rights reserved.