diff options
author | Pengfei Wang <pengfei.wang@intel.com> | 2019-05-29 08:42:35 +0000 |
---|---|---|
committer | Pengfei Wang <pengfei.wang@intel.com> | 2019-05-29 08:42:35 +0000 |
commit | d61cb749f4ac2c90244906d756e80a5c4a7ffa89 (patch) | |
tree | 19ae589c7adcebd0b0ec17507e2e44cc0002a591 | |
parent | 4f58ad4e720df4c265271907758b3daffbf764d2 (diff) | |
download | bcm5719-llvm-d61cb749f4ac2c90244906d756e80a5c4a7ffa89.tar.gz bcm5719-llvm-d61cb749f4ac2c90244906d756e80a5c4a7ffa89.zip |
[X86] Fix i386 struct and union parameter alignment
According to i386 System V ABI 2.1: Structures and unions assume the
alignment of their most strictly aligned component. But current
implementation always takes them as 4-byte aligned which will result
in incorrect code, e.g:
1 #include <immintrin.h>
2 typedef union {
3 int d[4];
4 __m128 m;
5 } M128;
6 extern void foo(int, ...);
7 void test(void)
8 {
9 M128 a;
10 foo(1, a);
11 foo(1, a.m);
12 }
The first call (line 10) takes the second arg as 4-byte aligned while
the second call (line 11) takes the second arg as 16-byte aligned.
There is oxymoron for the alignment of the 2 calls because they should
be the same.
This patch fixes the bug by following i386 System V ABI and apply it to
Linux only since other System V OS (e.g Darwin, PS4 and FreeBSD) don't
want to spend any effort dealing with the ramifications of ABI breaks
at present.
Patch by Wei Xiao (wxiao3)
Differential Revision: https://reviews.llvm.org/D60748
llvm-svn: 361934
-rw-r--r-- | clang/lib/CodeGen/TargetInfo.cpp | 13 | ||||
-rw-r--r-- | clang/test/CodeGen/x86_32-align-linux.c | 25 | ||||
-rw-r--r-- | clang/test/CodeGen/x86_32-arguments-linux.c | 24 |
3 files changed, 48 insertions, 14 deletions
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 24b7b9f97f9..4b96aa13d00 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -1010,6 +1010,7 @@ class X86_32ABIInfo : public SwiftABIInfo { bool IsWin32StructABI; bool IsSoftFloatABI; bool IsMCUABI; + bool IsLinuxABI; unsigned DefaultNumRegisterParameters; static bool isRegisterSize(unsigned Size) { @@ -1076,6 +1077,7 @@ public: IsWin32StructABI(Win32StructABI), IsSoftFloatABI(SoftFloatABI), IsMCUABI(CGT.getTarget().getTriple().isOSIAMCU()), + IsLinuxABI(CGT.getTarget().getTriple().isOSLinux()), DefaultNumRegisterParameters(NumRegisterParameters) {} bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> scalars, @@ -1492,8 +1494,15 @@ unsigned X86_32ABIInfo::getTypeStackAlignInBytes(QualType Ty, if (Align <= MinABIStackAlignInBytes) return 0; // Use default alignment. - // On non-Darwin, the stack type alignment is always 4. - if (!IsDarwinVectorABI) { + if (IsLinuxABI) { + // i386 System V ABI 2.1: Structures and unions assume the alignment of their + // most strictly aligned component. + // + // Exclude other System V OS (e.g Darwin, PS4 and FreeBSD) since we don't + // want to spend any effort dealing with the ramifications of ABI breaks. + return Align; + } else if (!IsDarwinVectorABI) { + // On non-Darwin and non-Linux, the stack type alignment is always 4. // Set explicit alignment, since we may need to realign the top. return MinABIStackAlignInBytes; } diff --git a/clang/test/CodeGen/x86_32-align-linux.c b/clang/test/CodeGen/x86_32-align-linux.c new file mode 100644 index 00000000000..5fce3f5f295 --- /dev/null +++ b/clang/test/CodeGen/x86_32-align-linux.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -w -fblocks -ffreestanding -triple i386-pc-linux-gnu -emit-llvm -o %t %s +// RUN: FileCheck < %t %s + +#include <immintrin.h> + +typedef union { + int d[4]; + __m128 m; +} M128; + +extern void foo(int, ...); + +M128 a; + +// CHECK-LABEL: define void @test +// CHECK: entry: +// CHECK: call void (i32, ...) @foo(i32 1, %union.M128* byval align 16 +// CHECK: call void (i32, ...) @foo(i32 1, <4 x float> + +void test(void) +{ + foo(1, a); + foo(1, a.m); +} + diff --git a/clang/test/CodeGen/x86_32-arguments-linux.c b/clang/test/CodeGen/x86_32-arguments-linux.c index 02eac51216a..3718980ba16 100644 --- a/clang/test/CodeGen/x86_32-arguments-linux.c +++ b/clang/test/CodeGen/x86_32-arguments-linux.c @@ -3,21 +3,21 @@ // CHECK-LABEL: define void @f56( // CHECK: i8 signext %a0, %struct.s56_0* byval align 4 %a1, -// CHECK: i64 %a2.coerce, %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: i64 %a2.coerce, %struct.s56_1* byval align 8 %a3, +// CHECK: <1 x double> %a4, %struct.s56_2* byval align 8 %a5, +// CHECK: <4 x i32> %a6, %struct.s56_3* 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 align 32 %a11, +// CHECK: <4 x double> %a12, %struct.s56_6* byval align 32 %a13) // CHECK: call void (i32, ...) @f56_0(i32 1, // CHECK: i32 %{{.*}}, %struct.s56_0* byval align 4 %{{[^ ]*}}, -// CHECK: i64 %{{[^ ]*}}, %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: i64 %{{[^ ]*}}, %struct.s56_1* byval align 8 %{{[^ ]*}}, +// CHECK: <1 x double> %{{[^ ]*}}, %struct.s56_2* byval align 8 %{{[^ ]*}}, +// CHECK: <4 x i32> %{{[^ ]*}}, %struct.s56_3* byval align 16 %{{[^ ]*}}, +// CHECK: <2 x double> %{{[^ ]*}}, %struct.s56_4* byval align 16 %{{[^ ]*}}, +// CHECK: <8 x i32> %{{[^ ]*}}, %struct.s56_5* byval align 32 %{{[^ ]*}}, +// CHECK: <4 x double> %{{[^ ]*}}, %struct.s56_6* byval align 32 %{{[^ ]*}}) // CHECK: } // // <rdar://problem/7964854> [i386] clang misaligns long double in structures |