summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver Stannard <oliver.stannard@arm.com>2014-06-27 13:59:27 +0000
committerOliver Stannard <oliver.stannard@arm.com>2014-06-27 13:59:27 +0000
commitdc111a9e363412c7b1a3387333cb81049678c738 (patch)
treeeeb3fa54607fae7cc0d3bcadbfca47f1c9574fca
parent69f87edbebe7dc9b450482a4af0a3d6b55ef5c23 (diff)
downloadclang-dc111a9e363412c7b1a3387333cb81049678c738.tar.gz
clang-dc111a9e363412c7b1a3387333cb81049678c738.tar.bz2
clang-dc111a9e363412c7b1a3387333cb81049678c738.tar.xz
[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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@211898 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/CodeGen/TargetInfo.cpp9
-rw-r--r--test/CodeGen/arm-aapcs-vfp.c6
2 files changed, 12 insertions, 3 deletions
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 29899eec2e..16dee574fd 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -4054,7 +4054,7 @@ void ARMABIInfo::markAllocatedVFPs(unsigned Alignment,
/// 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::classifyArgumentType(QualType Ty, bool isVariadic,
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);
}
diff --git a/test/CodeGen/arm-aapcs-vfp.c b/test/CodeGen/arm-aapcs-vfp.c
index 96fd625701..7bc1b1e55c 100644
--- a/test/CodeGen/arm-aapcs-vfp.c
+++ b/test/CodeGen/arm-aapcs-vfp.c
@@ -139,3 +139,9 @@ void test_test_vfp_stack_gpr_split_bitfield(double a, double b, double c, double
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) {}