This is a fix to the code in clang which inserts padding arguments to ensure
that the ARM backend can emit AAPCS-VFP compliant code. This code needs to
track the number of registers which have been allocated in order to do this.
When passing a very large struct (>64 bytes) by value, clang emits IR which
takes a pointer to the struct, but the backend converts this back to passing
the struct in registers and on the stack. The bug was that this was being
considered by clang to only use one register, meaning that there were
situations in which padding arguments were incorrectly emitted by clang.
http://reviews.llvm.org/D4294
Files:
lib/CodeGen/TargetInfo.cpp
test/CodeGen/arm-aapcs-vfp.c
Index: lib/CodeGen/TargetInfo.cpp
===================================================================
--- lib/CodeGen/TargetInfo.cpp
+++ lib/CodeGen/TargetInfo.cpp
@@ -4054,7 +4054,7 @@
/// which have been allocated. It is valid for AllocatedGPRs to go above 4,
/// this represents arguments being stored on the stack.
void ARMABIInfo::markAllocatedGPRs(unsigned Alignment,
- unsigned NumRequired) const {
+ unsigned NumRequired) const {
assert((Alignment == 1 || Alignment == 2) && "Alignment must be 4 or 8
bytes");
if (Alignment == 2 && AllocatedGPRs & 0x1)
@@ -4198,7 +4198,14 @@
ABIAlign = std::min(std::max(TyAlign, (uint64_t)4), (uint64_t)8);
if (getContext().getTypeSizeInChars(Ty) > CharUnits::fromQuantity(64)) {
// Update Allocated GPRs
- markAllocatedGPRs(1, 1);
+ unsigned NumRegs;
+ if (getContext().getTypeAlign(Ty) <= 32) {
+ NumRegs = (getContext().getTypeSize(Ty) + 31) / 32;
+ markAllocatedGPRs(1, NumRegs);
+ } else {
+ NumRegs = (getContext().getTypeSize(Ty) + 63) / 64;
+ markAllocatedGPRs(2, NumRegs * 2);
+ }
return ABIArgInfo::getIndirect(TyAlign, /*ByVal=*/true,
/*Realign=*/TyAlign > ABIAlign);
}
Index: test/CodeGen/arm-aapcs-vfp.c
===================================================================
--- test/CodeGen/arm-aapcs-vfp.c
+++ test/CodeGen/arm-aapcs-vfp.c
@@ -139,3 +139,9 @@
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)
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)
+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) {}
Index: lib/CodeGen/TargetInfo.cpp
===================================================================
--- lib/CodeGen/TargetInfo.cpp
+++ lib/CodeGen/TargetInfo.cpp
@@ -4054,7 +4054,7 @@
/// which have been allocated. It is valid for AllocatedGPRs to go above 4,
/// this represents arguments being stored on the stack.
void ARMABIInfo::markAllocatedGPRs(unsigned Alignment,
- unsigned NumRequired) const {
+ unsigned NumRequired) const {
assert((Alignment == 1 || Alignment == 2) && "Alignment must be 4 or 8 bytes");
if (Alignment == 2 && AllocatedGPRs & 0x1)
@@ -4198,7 +4198,14 @@
ABIAlign = std::min(std::max(TyAlign, (uint64_t)4), (uint64_t)8);
if (getContext().getTypeSizeInChars(Ty) > CharUnits::fromQuantity(64)) {
// Update Allocated GPRs
- markAllocatedGPRs(1, 1);
+ unsigned NumRegs;
+ if (getContext().getTypeAlign(Ty) <= 32) {
+ NumRegs = (getContext().getTypeSize(Ty) + 31) / 32;
+ markAllocatedGPRs(1, NumRegs);
+ } else {
+ NumRegs = (getContext().getTypeSize(Ty) + 63) / 64;
+ markAllocatedGPRs(2, NumRegs * 2);
+ }
return ABIArgInfo::getIndirect(TyAlign, /*ByVal=*/true,
/*Realign=*/TyAlign > ABIAlign);
}
Index: test/CodeGen/arm-aapcs-vfp.c
===================================================================
--- test/CodeGen/arm-aapcs-vfp.c
+++ test/CodeGen/arm-aapcs-vfp.c
@@ -139,3 +139,9 @@
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)
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)
+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) {}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits