r211898 - [ARM] Fix AAPCS non-compliance caused by very large structs

Oliver Stannard oliver.stannard at arm.com
Fri Jun 27 06:59:27 PDT 2014

Author: olista01
Date: Fri Jun 27 08:59:27 2014
New Revision: 211898

URL: http://llvm.org/viewvc/llvm-project?rev=211898&view=rev
[ARM] Fix AAPCS non-compliance caused by very large structs

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.


Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=211898&r1=211897&r2=211898&view=diff
--- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Fri Jun 27 08:59:27 2014
@@ -4054,7 +4054,7 @@ void ARMABIInfo::markAllocatedVFPs(unsig
 /// 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)
@@ -4197,8 +4197,11 @@ ABIArgInfo ARMABIInfo::classifyArgumentT
       getABIKind() == ARMABIInfo::AAPCS)
     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);
+    // Update Allocated GPRs. Since this is only used when the size of the
+    // argument is greater than 64 bytes, this will always use up any available
+    // registers (of which there are 4). We also don't care about getting the
+    // alignment right, because general-purpose registers cannot be back-filled.
+    markAllocatedGPRs(1, 4);
     return ABIArgInfo::getIndirect(TyAlign, /*ByVal=*/true,
            /*Realign=*/TyAlign > ABIAlign);

Modified: cfe/trunk/test/CodeGen/arm-aapcs-vfp.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/arm-aapcs-vfp.c?rev=211898&r1=211897&r2=211898&view=diff
--- cfe/trunk/test/CodeGen/arm-aapcs-vfp.c (original)
+++ cfe/trunk/test/CodeGen/arm-aapcs-vfp.c Fri Jun 27 08:59:27 2014
@@ -139,3 +139,9 @@ void test_test_vfp_stack_gpr_split_bitfi
 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) {}

More information about the cfe-commits mailing list