From e1978b80258c81a6d398533dfed4da50d9c09c0b Mon Sep 17 00:00:00 2001 From: Amara Emerson Date: Tue, 28 Jan 2014 10:56:36 +0000 Subject: [PATCH] [ARM] Fix AAPCS-VFP non-compliance when returning HFA from variadic functions. Arguments and return values must always be marshalled as for the base AAPCS when the callee is a variadic function. Patch by Oliver Stannard! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@200307 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/TargetInfo.cpp | 18 ++++++++++-------- test/CodeGen/arm-aapcs-vfp.c | 5 +++++ test/CodeGen/arm-homogenous.c | 8 ++++++++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index ba8b483052..c538234d00 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -3099,10 +3099,10 @@ public: ABIKind getABIKind() const { return Kind; } private: - ABIArgInfo classifyReturnType(QualType RetTy) const; + ABIArgInfo classifyReturnType(QualType RetTy, bool isVariadic) const; ABIArgInfo classifyArgumentType(QualType RetTy, int *VFPRegs, unsigned &AllocatedVFP, - bool &IsHA) const; + bool &IsHA, bool isVariadic) const; bool isIllegalVectorType(QualType Ty) const; virtual void computeInfo(CGFunctionInfo &FI) const; @@ -3198,7 +3198,7 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const { // unallocated are marked as unavailable. unsigned AllocatedVFP = 0; int VFPRegs[16] = { 0 }; - FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), FI.isVariadic()); for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) { unsigned PreAllocation = AllocatedVFP; @@ -3206,10 +3206,12 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const { // 6.1.2.3 There is one VFP co-processor register class using registers // s0-s15 (d0-d7) for passing arguments. const unsigned NumVFPs = 16; - it->info = classifyArgumentType(it->type, VFPRegs, AllocatedVFP, IsHA); + it->info = classifyArgumentType(it->type, VFPRegs, AllocatedVFP, IsHA, FI.isVariadic()); // If we do not have enough VFP registers for the HA, any VFP registers // that are unallocated are marked as unavailable. To achieve this, we add // padding of (NumVFPs - PreAllocation) floats. + // Note that IsHA will only be set when using the AAPCS-VFP calling convention, + // and the callee is not variadic. if (IsHA && AllocatedVFP > NumVFPs && PreAllocation < NumVFPs) { llvm::Type *PaddingTy = llvm::ArrayType::get( llvm::Type::getFloatTy(getVMContext()), NumVFPs - PreAllocation); @@ -3360,7 +3362,7 @@ static void markAllocatedVFPs(int *VFPRegs, unsigned &AllocatedVFP, ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, int *VFPRegs, unsigned &AllocatedVFP, - bool &IsHA) const { + bool &IsHA, bool isVariadic) const { // We update number of allocated VFPs according to // 6.1.2.1 The following argument types are VFP CPRCs: // A single-precision floating-point type (including promoted @@ -3424,7 +3426,7 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, int *VFPRegs, if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); - if (getABIKind() == ARMABIInfo::AAPCS_VFP) { + if (getABIKind() == ARMABIInfo::AAPCS_VFP && !isVariadic) { // Homogeneous Aggregates need to be expanded when we can fit the aggregate // into VFP registers. const Type *Base = 0; @@ -3566,7 +3568,7 @@ static bool isIntegerLikeType(QualType Ty, ASTContext &Context, return true; } -ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const { +ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, bool isVariadic) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); @@ -3622,7 +3624,7 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const { return ABIArgInfo::getIgnore(); // Check for homogeneous aggregates with AAPCS-VFP. - if (getABIKind() == AAPCS_VFP) { + if (getABIKind() == AAPCS_VFP && !isVariadic) { const Type *Base = 0; if (isHomogeneousAggregate(RetTy, Base, getContext())) { assert(Base && "Base class should be set for homogeneous aggregate"); diff --git a/test/CodeGen/arm-aapcs-vfp.c b/test/CodeGen/arm-aapcs-vfp.c index 0e102f35ed..071b7cf91b 100644 --- a/test/CodeGen/arm-aapcs-vfp.c +++ b/test/CodeGen/arm-aapcs-vfp.c @@ -25,6 +25,11 @@ struct homogeneous_struct test_struct(struct homogeneous_struct arg) { return struct_callee(arg); } +// CHECK: define arm_aapcs_vfpcc void @test_struct_variadic(%struct.homogeneous_struct* {{.*}}, [4 x i32] %{{.*}}, ...) +struct homogeneous_struct test_struct_variadic(struct homogeneous_struct arg, ...) { + return struct_callee(arg); +} + struct nested_array { double d[4]; }; diff --git a/test/CodeGen/arm-homogenous.c b/test/CodeGen/arm-homogenous.c index 5d21088eba..0b6f9a5094 100644 --- a/test/CodeGen/arm-homogenous.c +++ b/test/CodeGen/arm-homogenous.c @@ -173,6 +173,14 @@ void test_struct_of_four_doubles(void) { takes_struct_of_four_doubles(3.0, g_s4d, g_s4d, 4.0); } +extern void takes_struct_of_four_doubles_variadic(double a, struct_of_four_doubles b, struct_of_four_doubles c, double d, ...); + +void test_struct_of_four_doubles_variadic(void) { +// CHECK: test_struct_of_four_doubles_variadic +// CHECK: call arm_aapcs_vfpcc void (double, [4 x i64], [4 x i64], double, ...)* @takes_struct_of_four_doubles_variadic(double {{.*}}, [4 x i64] {{.*}}, [4 x i64] {{.*}}, double {{.*}}) + takes_struct_of_four_doubles_variadic(3.0, g_s4d, g_s4d, 4.0); +} + extern void takes_struct_with_backfill(float f1, double a, float f2, struct_of_four_doubles b, struct_of_four_doubles c, double d); void test_struct_with_backfill(void) { // CHECK: test_struct_with_backfill -- 2.40.0