C 为什么两个double的结构通过寄存器传递,而三个double的结构通过堆栈传递?

C 为什么两个double的结构通过寄存器传递,而三个double的结构通过堆栈传递?,c,struct,calling-convention,cdecl,C,Struct,Calling Convention,Cdecl,以下代码: struct Double2{ 双a; 双b; }; 结构双重3{ 双a; 双b; 双c; }; double double2(结构double2 x){ 返回x.a+x.b; } double double3(结构double3 x){ 返回x.a+x.b+x.c; } 双双参数(双a、双b、双c){ 返回a+b+c; } 编译成 double2: addsd xmm0, xmm1 ret double3: movsd xm

以下代码:

struct Double2{
双a;
双b;
};
结构双重3{
双a;
双b;
双c;
};
double double2(结构double2 x){
返回x.a+x.b;
}
double double3(结构double3 x){
返回x.a+x.b+x.c;
}
双双参数(双a、双b、双c){
返回a+b+c;
}
编译成

double2:
        addsd   xmm0, xmm1
        ret
double3:
        movsd   xmm0, QWORD PTR [rsp+8]
        addsd   xmm0, QWORD PTR [rsp+16]
        addsd   xmm0, QWORD PTR [rsp+24]
        ret
double_args:
        addsd   xmm0, xmm1
        addsd   xmm0, xmm2
        ret
在Linux上,x86-64和GCC 9.2以及-O3()

为什么两个双精度(
Double2
)的结构通过寄存器
xmm0
xmm1
传递,而三个双精度(
Double3
)的结构通过堆栈传递
double_args()
说明编译器至少能够通过寄存器传递三个double


这是C调用约定的一部分吗?相关规则是什么?

您需要找到所使用的实现的(ABI)。调用约定依赖于实现,C规范对此没有任何说明。这是编译器开发人员的决定。显然,对于三个双精度的结构,没有足够的寄存器。@user3386109我想你是对的。它可能在这个文件中的某个地方被指定:例如,查看[System V ABI[draft version]](System V ABI[draft version]),一个三重结构有三个SSE类成员(第19页),然后,由于结构超过了“两个八字节”,后两个不在SSEUP类中,整个参数被传递到内存中(第21页第5项)。但是我已经有一段时间没有阅读/使用/解释这个ABI了,所以我可能会离开。你需要找到你正在使用的实现的(ABI)。调用约定依赖于实现,C规范对此没有任何说明。这是编译器开发人员的决定。显然,对于三个双精度的结构,没有足够的寄存器。@user3386109我想你是对的。它可能在这个文件中的某个地方被指定:例如,查看[System V ABI[draft version]](System V ABI[draft version]),一个三重结构有三个SSE类成员(第19页),然后,由于结构超过了“两个八字节”,后两个不在SSEUP类中,整个参数被传递到内存中(第21页第5项)。但是我已经有一段时间没有阅读/使用/解释这个ABI了,所以我可能会离开。