aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Dunbar <daniel@zuster.org>2010-09-16 20:42:06 +0000
committerDaniel Dunbar <daniel@zuster.org>2010-09-16 20:42:06 +0000
commite59d8585bb40a8bae6b847ad258536a2c01f20ea (patch)
tree6b0e92b4821daf71e640e55780a2c755f1d6d23f
parentcf3b6f2504596812db1fcef0df8ce5b3449c4aac (diff)
IRgen/ABI/x86-32: Realign indirect arguments when the ABI requires us to pass
them with a smaller alignment than the rest of codegen expects. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@114115 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/CodeGen/TargetInfo.cpp39
-rw-r--r--test/CodeGen/x86_32-arguments-darwin.c20
-rw-r--r--test/CodeGen/x86_32-arguments-linux.c24
-rw-r--r--test/CodeGen/x86_32-arguments-realign.c11
4 files changed, 57 insertions, 37 deletions
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 3ee4d1ad6d..34a6d37726 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -353,7 +353,7 @@ class X86_32ABIInfo : public ABIInfo {
ABIArgInfo getIndirectResult(QualType Ty, bool ByVal = true) const;
/// \brief Return the alignment to use for the given type on the stack.
- unsigned getTypeStackAlignInBytes(QualType Ty) const;
+ unsigned getTypeStackAlignInBytes(QualType Ty, unsigned Align) const;
public:
@@ -580,16 +580,18 @@ static bool isRecordWithSSEVectorType(ASTContext &Context, QualType Ty) {
return false;
}
-unsigned X86_32ABIInfo::getTypeStackAlignInBytes(QualType Ty) const {
- // On non-Darwin, the stack type alignment is always 4.
- if (!IsDarwinVectorABI)
- return MinABIStackAlignInBytes;
-
- // Otherwise, if the alignment is less than or equal to 4, use the minimum ABI
- // alignment.
- unsigned Align = getContext().getTypeAlign(Ty) / 8;
+unsigned X86_32ABIInfo::getTypeStackAlignInBytes(QualType Ty,
+ unsigned Align) const {
+ // Otherwise, if the alignment is less than or equal to the minimum ABI
+ // alignment, just use the default; the backend will handle this.
if (Align <= MinABIStackAlignInBytes)
+ return 0; // Use default alignment.
+
+ // On non-Darwin, the stack type alignment is always 4.
+ if (!IsDarwinVectorABI) {
+ // Set explicit alignment, since we may need to realign the top.
return MinABIStackAlignInBytes;
+ }
// Otherwise, if the type contains an SSE vector type, the alignment is 16.
if (isRecordWithSSEVectorType(getContext(), Ty))
@@ -602,12 +604,19 @@ ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal) const {
if (!ByVal)
return ABIArgInfo::getIndirect(0, false);
- // Compute the byval alignment. We trust the back-end to honor the
- // minimum ABI alignment for byval, to make cleaner IR.
- unsigned Align = getTypeStackAlignInBytes(Ty);
- if (Align > MinABIStackAlignInBytes)
- return ABIArgInfo::getIndirect(Align);
- return ABIArgInfo::getIndirect(0);
+ // Compute the byval alignment.
+ unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8;
+ unsigned StackAlign = getTypeStackAlignInBytes(Ty, TypeAlign);
+ if (StackAlign == 0)
+ return ABIArgInfo::getIndirect(0);
+
+ // If the stack alignment is less than the type alignment, realign the
+ // argument.
+ if (StackAlign < TypeAlign)
+ return ABIArgInfo::getIndirect(StackAlign, /*ByVal=*/true,
+ /*Realign=*/true);
+
+ return ABIArgInfo::getIndirect(StackAlign);
}
ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const {
diff --git a/test/CodeGen/x86_32-arguments-darwin.c b/test/CodeGen/x86_32-arguments-darwin.c
index 531ae1df69..3566834bdc 100644
--- a/test/CodeGen/x86_32-arguments-darwin.c
+++ b/test/CodeGen/x86_32-arguments-darwin.c
@@ -202,13 +202,13 @@ void f50(struct s50 a0) { }
struct s51 { vvbp f0; int f1; };
void f51(struct s51 a0) { }
-// CHECK: define void @f52(%struct.s52* byval %x)
+// CHECK: define void @f52(%struct.s52* byval align 4)
struct s52 {
long double a;
};
void f52(struct s52 x) {}
-// CHECK: define void @f53(%struct.s53* byval %x)
+// CHECK: define void @f53(%struct.s53* byval align 4)
struct __attribute__((aligned(32))) s53 {
int x;
int y;
@@ -230,21 +230,21 @@ v4i32 f55(v4i32 arg) { return arg+arg; }
// CHECK: define void @f56(
// CHECK: i8 signext %a0, %struct.s56_0* byval %a1,
-// CHECK: <2 x i32> %a2, %struct.s56_1* byval %a3,
-// CHECK: i64 %a4.coerce, %struct.s56_2* byval %a5,
+// CHECK: <2 x i32> %a2, %struct.s56_1* byval align 4,
+// CHECK: i64 %a4.coerce, %struct.s56_2* byval align 4,
// CHECK: <4 x i32> %a6, %struct.s39* byval align 16 %a7,
// CHECK: <2 x double> %a8, %struct.s56_4* byval align 16 %a9,
-// CHECK: <8 x i32> %a10, %struct.s56_5* byval %a11,
-// CHECK: <4 x double> %a12, %struct.s56_6* byval %a13)
+// CHECK: <8 x i32> %a10, %struct.s56_5* byval align 4,
+// CHECK: <4 x double> %a12, %struct.s56_6* byval align 4)
// CHECK: call void (i32, ...)* @f56_0(i32 1,
// CHECK: i32 %{{[^ ]*}}, %struct.s56_0* byval %{{[^ ]*}},
-// CHECK: <2 x i32> %{{[^ ]*}}, %struct.s56_1* byval %{{[^ ]*}},
-// CHECK: i64 %{{[^ ]*}}, %struct.s56_2* byval %{{[^ ]*}},
+// CHECK: <2 x i32> %{{[^ ]*}}, %struct.s56_1* byval align 4 %{{[^ ]*}},
+// CHECK: i64 %{{[^ ]*}}, %struct.s56_2* byval align 4 %{{[^ ]*}},
// CHECK: <4 x i32> %{{[^ ]*}}, %struct.s39* byval align 16 %{{[^ ]*}},
// CHECK: <2 x double> %{{[^ ]*}}, %struct.s56_4* byval align 16 %{{[^ ]*}},
-// CHECK: <8 x i32> {{[^ ]*}}, %struct.s56_5* byval %{{[^ ]*}},
-// CHECK: <4 x double> {{[^ ]*}}, %struct.s56_6* byval %{{[^ ]*}})
+// CHECK: <8 x i32> {{[^ ]*}}, %struct.s56_5* byval align 4 %{{[^ ]*}},
+// CHECK: <4 x double> {{[^ ]*}}, %struct.s56_6* byval align 4 %{{[^ ]*}})
// CHECK: }
//
// <rdar://problem/7964854> [i386] clang misaligns long double in structures
diff --git a/test/CodeGen/x86_32-arguments-linux.c b/test/CodeGen/x86_32-arguments-linux.c
index 31b184c37e..0e3a05cbf8 100644
--- a/test/CodeGen/x86_32-arguments-linux.c
+++ b/test/CodeGen/x86_32-arguments-linux.c
@@ -3,21 +3,21 @@
// CHECK: define void @f56(
// CHECK: i8 signext %a0, %struct.s56_0* byval %a1,
-// CHECK: <2 x i32> %a2, %struct.s56_1* byval %a3,
-// CHECK: <1 x double> %a4, %struct.s56_2* byval %a5,
-// CHECK: <4 x i32> %a6, %struct.s56_3* byval %a7,
-// CHECK: <2 x double> %a8, %struct.s56_4* byval %a9,
-// CHECK: <8 x i32> %a10, %struct.s56_5* byval %a11,
-// CHECK: <4 x double> %a12, %struct.s56_6* byval %a13)
+// CHECK: <2 x i32> %a2, %struct.s56_1* byval align 4,
+// CHECK: <1 x double> %a4, %struct.s56_2* byval align 4,
+// CHECK: <4 x i32> %a6, %struct.s56_3* byval align 4,
+// CHECK: <2 x double> %a8, %struct.s56_4* byval align 4,
+// CHECK: <8 x i32> %a10, %struct.s56_5* byval align 4,
+// CHECK: <4 x double> %a12, %struct.s56_6* byval align 4)
// CHECK: call void (i32, ...)* @f56_0(i32 1,
// CHECK: i32 %{{.*}}, %struct.s56_0* byval %{{[^ ]*}},
-// CHECK: <2 x i32> %{{[^ ]*}}, %struct.s56_1* byval %{{[^ ]*}},
-// CHECK: <1 x double> %{{[^ ]*}}, %struct.s56_2* byval %{{[^ ]*}},
-// CHECK: <4 x i32> %{{[^ ]*}}, %struct.s56_3* byval %{{[^ ]*}},
-// CHECK: <2 x double> %{{[^ ]*}}, %struct.s56_4* byval %{{[^ ]*}},
-// CHECK: <8 x i32> %{{[^ ]*}}, %struct.s56_5* byval %{{[^ ]*}},
-// CHECK: <4 x double> %{{[^ ]*}}, %struct.s56_6* byval %{{[^ ]*}})
+// CHECK: <2 x i32> %{{[^ ]*}}, %struct.s56_1* byval align 4 %{{[^ ]*}},
+// CHECK: <1 x double> %{{[^ ]*}}, %struct.s56_2* byval align 4 %{{[^ ]*}},
+// CHECK: <4 x i32> %{{[^ ]*}}, %struct.s56_3* byval align 4 %{{[^ ]*}},
+// CHECK: <2 x double> %{{[^ ]*}}, %struct.s56_4* byval align 4 %{{[^ ]*}},
+// CHECK: <8 x i32> %{{[^ ]*}}, %struct.s56_5* byval align 4 %{{[^ ]*}},
+// CHECK: <4 x double> %{{[^ ]*}}, %struct.s56_6* byval align 4 %{{[^ ]*}})
// CHECK: }
//
// <rdar://problem/7964854> [i386] clang misaligns long double in structures
diff --git a/test/CodeGen/x86_32-arguments-realign.c b/test/CodeGen/x86_32-arguments-realign.c
new file mode 100644
index 0000000000..b08862ee43
--- /dev/null
+++ b/test/CodeGen/x86_32-arguments-realign.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -w -fblocks -triple i386-apple-darwin9 -emit-llvm -o %t %s
+// RUN: FileCheck < %t %s
+
+// CHECK: define void @f0(%struct.s0* byval align 4)
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %{{.*}}, i8* %{{.*}}, i32 16, i32 4, i1 false)
+// CHECK: }
+struct s0 { long double a; };
+void f0(struct s0 a0) {
+ extern long double f0_g0;
+ f0_g0 = a0.a;
+}