From: Tim Northover Date: Fri, 7 Nov 2014 22:30:50 +0000 (+0000) Subject: ARM ABI: simplify decisions on whether args can be expanded. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4efc4104f171d384f16664450974c0d86d4f9201;p=clang ARM ABI: simplify decisions on whether args can be expanded. Homogeneous aggregates on AAPCS_VFP ARM need to be passed *without* being flattened (e.g. [2 x float] rather than "float, float") for various weird ABI reasons. However, this isn't the case for anything else; further, we know at the ABIArgInfo::getDirect callsites whether this flattening is allowed. So, we can get more unified ARM code, with a simpler Clang, by just using that knowledge directly. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@221559 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index c51a48646f..870e392807 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -4546,9 +4546,6 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const { // unallocated are marked as unavailable. resetAllocatedRegs(); - const bool isAAPCS_VFP = - getABIKind() == ARMABIInfo::AAPCS_VFP && !FI.isVariadic(); - if (getCXXABI().classifyReturnType(FI)) { if (FI.getReturnInfo().isIndirect()) markAllocatedGPRs(1, 1); @@ -4578,11 +4575,11 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const { llvm::Type *PaddingTy = llvm::ArrayType::get( llvm::Type::getInt32Ty(getVMContext()), NumGPRs - PreAllocationGPRs); if (I.info.canHaveCoerceToType()) { - I.info = ABIArgInfo::getDirect(I.info.getCoerceToType() /* type */, 0 /* offset */, - PaddingTy, !isAAPCS_VFP); + I.info = ABIArgInfo::getDirect(I.info.getCoerceToType() /* type */, + 0 /* offset */, PaddingTy, true); } else { I.info = ABIArgInfo::getDirect(nullptr /* type */, 0 /* offset */, - PaddingTy, !isAAPCS_VFP); + PaddingTy, true); } } } @@ -4693,9 +4690,7 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic, // with a Base Type of a single- or double-precision floating-point type, // 64-bit containerized vectors or 128-bit containerized vectors with one // to four Elements. - - const bool isAAPCS_VFP = - getABIKind() == ARMABIInfo::AAPCS_VFP && !isVariadic; + bool IsEffectivelyAAPCS_VFP = getABIKind() == AAPCS_VFP && !isVariadic; // Handle illegal vector types here. if (isIllegalVectorType(Ty)) { @@ -4704,7 +4699,7 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic, llvm::Type *ResType = llvm::Type::getInt32Ty(getVMContext()); markAllocatedGPRs(1, 1); - return ABIArgInfo::getDirect(ResType, 0, nullptr, !isAAPCS_VFP); + return ABIArgInfo::getDirect(ResType); } if (Size == 64) { llvm::Type *ResType = llvm::VectorType::get( @@ -4715,7 +4710,7 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic, markAllocatedVFPs(2, 2); IsCPRC = true; } - return ABIArgInfo::getDirect(ResType, 0, nullptr, !isAAPCS_VFP); + return ABIArgInfo::getDirect(ResType); } if (Size == 128) { llvm::Type *ResType = llvm::VectorType::get( @@ -4726,7 +4721,7 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic, markAllocatedVFPs(4, 4); IsCPRC = true; } - return ABIArgInfo::getDirect(ResType, 0, nullptr, !isAAPCS_VFP); + return ABIArgInfo::getDirect(ResType); } markAllocatedGPRs(1, 1); return ABIArgInfo::getIndirect(0, /*ByVal=*/false); @@ -4765,9 +4760,8 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic, unsigned Size = getContext().getTypeSize(Ty); if (!IsCPRC) markAllocatedGPRs(Size > 32 ? 2 : 1, (Size + 31) / 32); - return (Ty->isPromotableIntegerType() - ? ABIArgInfo::getExtend() - : ABIArgInfo::getDirect(nullptr, 0, nullptr, !isAAPCS_VFP)); + return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() + : ABIArgInfo::getDirect()); } if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { @@ -4779,7 +4773,7 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic, if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); - if (isAAPCS_VFP) { + if (IsEffectivelyAAPCS_VFP) { // Homogeneous Aggregates need to be expanded when we can fit the aggregate // into VFP registers. const Type *Base = nullptr; @@ -4800,7 +4794,7 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic, markAllocatedVFPs(2, Members * 2); } IsCPRC = true; - return ABIArgInfo::getDirect(nullptr, 0, nullptr, !isAAPCS_VFP); + return ABIArgInfo::getDirect(nullptr, 0, nullptr, false); } } @@ -4838,9 +4832,7 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic, markAllocatedGPRs(2, SizeRegs * 2); } - llvm::Type *STy = - llvm::StructType::get(llvm::ArrayType::get(ElemTy, SizeRegs), NULL); - return ABIArgInfo::getDirect(STy, 0, nullptr, !isAAPCS_VFP); + return ABIArgInfo::getDirect(llvm::ArrayType::get(ElemTy, SizeRegs)); } static bool isIntegerLikeType(QualType Ty, ASTContext &Context, @@ -4930,8 +4922,7 @@ static bool isIntegerLikeType(QualType Ty, ASTContext &Context, ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, bool isVariadic) const { - const bool isAAPCS_VFP = - getABIKind() == ARMABIInfo::AAPCS_VFP && !isVariadic; + bool IsEffectivelyAAPCS_VFP = getABIKind() == AAPCS_VFP && !isVariadic; if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); @@ -4947,9 +4938,8 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); - return (RetTy->isPromotableIntegerType() - ? ABIArgInfo::getExtend() - : ABIArgInfo::getDirect(nullptr, 0, nullptr, !isAAPCS_VFP)); + return RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend() + : ABIArgInfo::getDirect(); } // Are we following APCS? @@ -4987,13 +4977,13 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, return ABIArgInfo::getIgnore(); // Check for homogeneous aggregates with AAPCS-VFP. - if (getABIKind() == AAPCS_VFP && !isVariadic) { + if (IsEffectivelyAAPCS_VFP) { const Type *Base = nullptr; uint64_t Members; if (isHomogeneousAggregate(RetTy, Base, Members)) { assert(Base && "Base class should be set for homogeneous aggregate"); // Homogeneous Aggregates are returned directly. - return ABIArgInfo::getDirect(nullptr, 0, nullptr, !isAAPCS_VFP); + return ABIArgInfo::getDirect(nullptr, 0, nullptr, false); } } @@ -5003,18 +4993,14 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, if (Size <= 32) { if (getDataLayout().isBigEndian()) // Return in 32 bit integer integer type (as if loaded by LDR, AAPCS 5.4) - return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()), 0, - nullptr, !isAAPCS_VFP); + return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); // Return in the smallest viable integer type. if (Size <= 8) - return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext()), 0, - nullptr, !isAAPCS_VFP); + return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext())); if (Size <= 16) - return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()), 0, - nullptr, !isAAPCS_VFP); - return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()), 0, - nullptr, !isAAPCS_VFP); + return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext())); + return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); } markAllocatedGPRs(1, 1); diff --git a/test/CodeGen/arm-aapcs-vfp.c b/test/CodeGen/arm-aapcs-vfp.c index eea6ab2f15..8a494a0da5 100644 --- a/test/CodeGen/arm-aapcs-vfp.c +++ b/test/CodeGen/arm-aapcs-vfp.c @@ -72,7 +72,7 @@ struct big_struct { float f3; float f4; }; -// CHECK: define arm_aapcs_vfpcc void @test_big({ [5 x i32] } %{{.*}}) +// CHECK: define arm_aapcs_vfpcc void @test_big([5 x i32] %{{.*}}) // CHECK64: define void @test_big(%struct.big_struct* %{{.*}}) // CHECK64: call void @llvm.memcpy // CHECK64: call void @big_callee(%struct.big_struct* @@ -88,7 +88,7 @@ struct heterogeneous_struct { float f1; int i2; }; -// CHECK: define arm_aapcs_vfpcc void @test_hetero({ [2 x i32] } %{{.*}}) +// CHECK: define arm_aapcs_vfpcc void @test_hetero([2 x i32] %{{.*}}) // CHECK64: define void @test_hetero(i64 %{{.*}}) extern void hetero_callee(struct heterogeneous_struct); void test_hetero(struct heterogeneous_struct arg) { @@ -125,25 +125,25 @@ typedef struct { long long x; int y; } struct_long_long_int; // CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_1(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, i32 %j, i64 %k, i32 %l) void test_vfp_stack_gpr_split_1(double a, double b, double c, double d, double e, double f, double g, double h, double i, int j, long long k, int l) {} -// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_2(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, i32 %j, [3 x i32], { [2 x i64] } %k.coerce) +// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_2(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, i32 %j, [3 x i32], [2 x i64] %k.coerce) void test_vfp_stack_gpr_split_2(double a, double b, double c, double d, double e, double f, double g, double h, double i, int j, struct_long_long_int k) {} -// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_3(%struct.struct_long_long_int* noalias sret %agg.result, double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, [3 x i32], { [2 x i64] } %k.coerce) +// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_3(%struct.struct_long_long_int* noalias sret %agg.result, double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, [3 x i32], [2 x i64] %k.coerce) struct_long_long_int test_vfp_stack_gpr_split_3(double a, double b, double c, double d, double e, double f, double g, double h, double i, struct_long_long_int k) {} typedef struct { int a; int b:4; int c; } struct_int_bitfield_int; -// CHECK: define arm_aapcs_vfpcc void @test_test_vfp_stack_gpr_split_bitfield(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, i32 %j, i32 %k, [2 x i32], { [3 x i32] } %l.coerce) +// CHECK: define arm_aapcs_vfpcc void @test_test_vfp_stack_gpr_split_bitfield(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, i32 %j, i32 %k, [2 x i32], [3 x i32] %l.coerce) void test_test_vfp_stack_gpr_split_bitfield(double a, double b, double c, double d, double e, double f, double g, double h, double i, int j, int k, struct_int_bitfield_int l) {} // Note: this struct requires internal padding typedef struct { int x; long long y; } struct_int_long_long; -// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_4(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, i32 %j, [3 x i32], { [2 x i64] } %k.coerce) +// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_4(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, i32 %j, [3 x i32], [2 x i64] %k.coerce) void test_vfp_stack_gpr_split_4(double a, double b, double c, double d, double e, double f, double g, double h, double i, int j, struct_int_long_long k) {} // This very large struct (passed byval) uses up the GPRs, so no padding is needed typedef struct { int x[17]; } struct_seventeen_ints; typedef struct { int x[4]; } struct_four_ints; -// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_5(%struct.struct_seventeen_ints* byval align 4 %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, double %j, { [4 x i32] } %k.coerce) +// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_5(%struct.struct_seventeen_ints* byval align 4 %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, double %j, [4 x i32] %k.coerce) void test_vfp_stack_gpr_split_5(struct_seventeen_ints a, double b, double c, double d, double e, double f, double g, double h, double i, double j, struct_four_ints k) {} // Here, parameter k would need padding to prevent it from being split, but it diff --git a/test/CodeGen/arm-arguments.c b/test/CodeGen/arm-arguments.c index 2c5df91c58..e4a10fd9e2 100644 --- a/test/CodeGen/arm-arguments.c +++ b/test/CodeGen/arm-arguments.c @@ -183,14 +183,9 @@ void f33(struct s33 s) { } struct s34 { char c; }; void f34(struct s34 s); void g34(struct s34 *s) { f34(*s); } -// APCS-GNU: @g34(%struct.s34* %s) -// APCS-GNU: %[[a:.*]] = alloca { [1 x i32] } -// APCS-GNU: %[[gep:.*]] = getelementptr { [1 x i32] }* %[[a]], i32 0, i32 0 -// APCS-GNU: load [1 x i32]* %[[gep]] // AAPCS: @g34(%struct.s34* %s) -// AAPCS: %[[a:.*]] = alloca { [1 x i32] } -// AAPCS: %[[gep:.*]] = getelementptr { [1 x i32] }* %[[a]], i32 0, i32 0 -// AAPCS: load [1 x i32]* %[[gep]] +// AAPCS: %[[a:.*]] = alloca [1 x i32] +// AAPCS: load [1 x i32]* %[[a]] // rdar://12596507 struct s35 diff --git a/test/CodeGen/arm-homogenous.c b/test/CodeGen/arm-homogenous.c index 897f9e6fe8..2ab6c105a5 100644 --- a/test/CodeGen/arm-homogenous.c +++ b/test/CodeGen/arm-homogenous.c @@ -22,7 +22,7 @@ extern union_with_first_floats returns_union_with_first_floats(void); void test_union_with_first_floats(void) { takes_union_with_first_floats(g_u_f); } -// CHECK: declare arm_aapcs_vfpcc void @takes_union_with_first_floats({ [4 x i32] }) +// CHECK: declare arm_aapcs_vfpcc void @takes_union_with_first_floats([4 x i32]) void test_return_union_with_first_floats(void) { g_u_f = returns_union_with_first_floats(); @@ -42,7 +42,7 @@ extern union_with_non_first_floats returns_union_with_non_first_floats(void); void test_union_with_non_first_floats(void) { takes_union_with_non_first_floats(g_u_nf_f); } -// CHECK: declare arm_aapcs_vfpcc void @takes_union_with_non_first_floats({ [4 x i32] }) +// CHECK: declare arm_aapcs_vfpcc void @takes_union_with_non_first_floats([4 x i32]) void test_return_union_with_non_first_floats(void) { g_u_nf_f = returns_union_with_non_first_floats(); @@ -62,7 +62,7 @@ extern struct_with_union_with_first_floats returns_struct_with_union_with_first_ void test_struct_with_union_with_first_floats(void) { takes_struct_with_union_with_first_floats(g_s_f); } -// CHECK: declare arm_aapcs_vfpcc void @takes_struct_with_union_with_first_floats({ [5 x i32] }) +// CHECK: declare arm_aapcs_vfpcc void @takes_struct_with_union_with_first_floats([5 x i32]) void test_return_struct_with_union_with_first_floats(void) { g_s_f = returns_struct_with_union_with_first_floats(); @@ -82,7 +82,7 @@ extern struct_with_union_with_non_first_floats returns_struct_with_union_with_no void test_struct_with_union_with_non_first_floats(void) { takes_struct_with_union_with_non_first_floats(g_s_nf_f); } -// CHECK: declare arm_aapcs_vfpcc void @takes_struct_with_union_with_non_first_floats({ [5 x i32] }) +// CHECK: declare arm_aapcs_vfpcc void @takes_struct_with_union_with_non_first_floats([5 x i32]) void test_return_struct_with_union_with_non_first_floats(void) { g_s_nf_f = returns_struct_with_union_with_non_first_floats(); diff --git a/test/CodeGenCXX/homogeneous-aggregates.cpp b/test/CodeGenCXX/homogeneous-aggregates.cpp index 5a34c87cad..4800aacbfe 100644 --- a/test/CodeGenCXX/homogeneous-aggregates.cpp +++ b/test/CodeGenCXX/homogeneous-aggregates.cpp @@ -39,7 +39,7 @@ struct I3 : Base2 {}; struct D5 : I1, I2, I3 {}; // homogeneous aggregate // PPC: define void @_Z7func_D12D1(%struct.D1* noalias sret %agg.result, [3 x i64] %x.coerce) -// ARM32: define arm_aapcs_vfpcc void @_Z7func_D12D1(%struct.D1* noalias sret %agg.result, { [3 x i64] } %x.coerce) +// ARM32: define arm_aapcs_vfpcc void @_Z7func_D12D1(%struct.D1* noalias sret %agg.result, [3 x i64] %x.coerce) // ARM64: define void @_Z7func_D12D1(%struct.D1* noalias sret %agg.result, %struct.D1* %x) // X64: define x86_vectorcallcc void @"\01_Z7func_D12D1@@24"(%struct.D1* noalias sret %agg.result, %struct.D1* %x) D1 CC func_D1(D1 x) { return x; } @@ -51,7 +51,7 @@ D1 CC func_D1(D1 x) { return x; } D2 CC func_D2(D2 x) { return x; } // PPC: define void @_Z7func_D32D3(%struct.D3* noalias sret %agg.result, [4 x i64] %x.coerce) -// ARM32: define arm_aapcs_vfpcc void @_Z7func_D32D3(%struct.D3* noalias sret %agg.result, { [4 x i64] } %x.coerce) +// ARM32: define arm_aapcs_vfpcc void @_Z7func_D32D3(%struct.D3* noalias sret %agg.result, [4 x i64] %x.coerce) // ARM64: define void @_Z7func_D32D3(%struct.D3* noalias sret %agg.result, %struct.D3* %x) D3 CC func_D3(D3 x) { return x; }