diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -1837,25 +1837,35 @@ } } - // Regcall uses the concept of a homogenous vector aggregate, similar - // to other targets. - const Type *Base = nullptr; - uint64_t NumElts = 0; - if ((IsRegCall || IsVectorCall) && - isHomogeneousAggregate(Ty, Base, NumElts)) { - if (State.FreeSSERegs >= NumElts) { - State.FreeSSERegs -= NumElts; - - // Vectorcall passes HVAs directly and does not flatten them, but regcall - // does. - if (IsVectorCall) - return getDirectX86Hva(); - - if (Ty->isBuiltinType() || Ty->isVectorType()) - return ABIArgInfo::getDirect(); - return ABIArgInfo::getExpand(); + if (IsRegCall || IsVectorCall) { + // Regcall uses the concept of a homogenous vector aggregate, similar + // to other targets. + const Type *Base = nullptr; + uint64_t NumElts = 0; + bool IsInReg = false; + if (isHomogeneousAggregate(Ty, Base, NumElts)) { + if (State.FreeSSERegs >= NumElts) { + State.FreeSSERegs -= NumElts; + IsInReg = true; + } + if (IsRegCall) { + if (IsInReg) { + // Regcall passes HVAs directly and flattens them. + if (Ty->isBuiltinType() || Ty->isVectorType()) + return ABIArgInfo::getDirect(); + return ABIArgInfo::getExpand(); + } + } else { + // Vectorcall passes floating types directly no matter if they can be + // passed in register or not. + if (Ty->isFloatingType()) + return ABIArgInfo::getDirect(); + // Vectorcall passes HVAs directly and does not flatten them. + if (IsInReg) + return getDirectX86Hva(); + } + return getIndirectResult(Ty, /*ByVal=*/false, State); } - return getIndirectResult(Ty, /*ByVal=*/false, State); } if (isAggregateTypeForABI(Ty)) { diff --git a/clang/test/CodeGen/vectorcall.c b/clang/test/CodeGen/vectorcall.c --- a/clang/test/CodeGen/vectorcall.c +++ b/clang/test/CodeGen/vectorcall.c @@ -140,4 +140,33 @@ // X86-SAME: <4 x float>* inreg noundef %0, // X86-SAME: i32 inreg noundef %edx, // X86-SAME: <4 x float>* noundef %1) + +// The passing format of floating-point types are different from vector when SSE registers exhausted. +// They are passed indirectly by value rather than address. +void __vectorcall vectorcall_indirect_fp( + double xmm0, double xmm1, double xmm2, double xmm3, double xmm4, + v4f32 xmm5, double stack) { +} +// X86: define dso_local x86_vectorcallcc void @"\01vectorcall_indirect_fp@@{{[0-9]+}}" +// X86-SAME: (double inreg noundef %xmm0, +// X86-SAME: double inreg noundef %xmm1, +// X86-SAME: double inreg noundef %xmm2, +// X86-SAME: double inreg noundef %xmm3, +// X86-SAME: double inreg noundef %xmm4, +// X86-SAME: <4 x float> inreg noundef %xmm5, +// X86-SAME: double noundef %stack) + +// Make sure HFA is passed indirectly by address. +void __vectorcall vectorcall_indirect_hfa( + double xmm0, double xmm1, double xmm2, double xmm3, double xmm4, + v4f32 xmm5, struct HFA2 hfa2) { +} +// X86: define dso_local x86_vectorcallcc void @"\01vectorcall_indirect_hfa@@{{[0-9]+}}" +// X86-SAME: (double inreg noundef %xmm0, +// X86-SAME: double inreg noundef %xmm1, +// X86-SAME: double inreg noundef %xmm2, +// X86-SAME: double inreg noundef %xmm3, +// X86-SAME: double inreg noundef %xmm4, +// X86-SAME: <4 x float> inreg noundef %xmm5, +// X86-SAME: %struct.HFA2* inreg noundef %hfa2) #endif