Index: clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- clang/lib/CodeGen/TargetInfo.cpp +++ clang/lib/CodeGen/TargetInfo.cpp @@ -1051,6 +1051,7 @@ bool IsWin32StructABI; bool IsSoftFloatABI; bool IsMCUABI; + bool IsLinuxABI; unsigned DefaultNumRegisterParameters; static bool isRegisterSize(unsigned Size) { @@ -1116,6 +1117,7 @@ IsWin32StructABI(Win32StructABI), IsSoftFloatABI(SoftFloatABI), IsMCUABI(CGT.getTarget().getTriple().isOSIAMCU()), + IsLinuxABI(CGT.getTarget().getTriple().isOSLinux()), DefaultNumRegisterParameters(NumRegisterParameters) {} bool shouldPassIndirectlyForSwift(ArrayRef scalars, @@ -1536,8 +1538,42 @@ if (Align <= MinABIStackAlignInBytes) return 0; // Use default alignment. + 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. + // + // If the type is a struct/union/class type + if (const RecordType *RT = Ty->getAs()) { + unsigned MaxAlignment = 0; + const RecordDecl *RD = RT->getDecl(); + + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) { + QualType QT = i->getType(); + unsigned TempAlignment = 0; + if (isAggregateTypeForABI(QT)) { + if (const auto *AT = QT->getAsArrayTypeUnsafe()) + TempAlignment = getContext().getTypeAlign(AT->getElementType()) / 8; + else // recursively to get each type's alignment + TempAlignment = getTypeStackAlignInBytes(QT, getContext().getTypeAlign(QT) / 8); + } else + TempAlignment = getContext().getTypeAlign(QT) / 8; + MaxAlignment = std::max(MaxAlignment, TempAlignment); + } + if (MaxAlignment >= 16) + return std::max(MaxAlignment, Align); + else // return 4 when all the type alignments less than 16 bytes + return 4; + } else if (Align < 16) + return MinABIStackAlignInBytes; + else // Otherwise + return Align; + } // On non-Darwin, the stack type alignment is always 4. - if (!IsDarwinVectorABI) { + else if (!IsDarwinVectorABI) { // Set explicit alignment, since we may need to realign the top. return MinABIStackAlignInBytes; } Index: clang/test/CodeGen/x86_32-align-linux.c =================================================================== --- /dev/null +++ clang/test/CodeGen/x86_32-align-linux.c @@ -0,0 +1,96 @@ +// RUN: %clang_cc1 -w -fblocks -ffreestanding -triple i386-pc-linux-gnu -emit-llvm -o %t %s +// RUN: FileCheck < %t %s + +#include + +typedef union { + int d[4]; + __m128 m; +} M128; + +typedef __attribute__((aligned(16))) int alignedint16; +typedef __attribute__((aligned(64))) int alignedint64; + +struct __attribute__((aligned(64))) X1 { + struct __attribute__((aligned(32))) { + int a1; + } a; + int b; +}; + + +struct __attribute__((aligned(64))) X2 { + struct __attribute__((aligned(32))) { + int a1; + alignedint16 a2; + } a; + int b; +}; + +struct __attribute__((aligned(32))) X3 { + struct __attribute__((aligned(64))) { + int a1; + alignedint16 a2; + } a; + int b; +}; + +struct __attribute__((aligned(16))) X4 { + struct __attribute__((aligned(32))) { + int a1; + alignedint64 a2; + } a; + int b; +}; + +struct __attribute__((aligned(64))) X5 { + int x; +}; + +struct __attribute__((aligned(64))) X6 { + int x; + alignedint64 y; +}; + +union U1 { + struct __attribute__((aligned(32))) { + int i; + __m128 m; + }; + int b; +}; + +extern void foo(int, ...); + +M128 a; +struct X1 x1; +struct X2 x2; +struct X3 x3; +struct X4 x4; +struct X5 x5; +struct X6 x6; +union U1 u1; + +// CHECK-LABEL: define void @test +// CHECK: entry: +// CHECK: call void (i32, ...) @foo(i32 1, %union.M128* byval(%union.M128) align 16 +// CHECK: call void (i32, ...) @foo(i32 1, <4 x float> +// CHECK: call void (i32, ...) @foo(i32 1, %struct.X1* byval(%struct.X1) align 4 +// CHECK: call void (i32, ...) @foo(i32 1, %struct.X2* byval(%struct.X2) align 64 +// CHECK: call void (i32, ...) @foo(i32 1, %struct.X3* byval(%struct.X3) align 64 +// CHECK: call void (i32, ...) @foo(i32 1, %struct.X4* byval(%struct.X4) align 64 +// CHECK: call void (i32, ...) @foo(i32 1, %struct.X5* byval(%struct.X5) align 4 +// CHECK: call void (i32, ...) @foo(i32 1, %struct.X6* byval(%struct.X6) align 64 +// CHECK: call void (i32, ...) @foo(i32 1, %union.U1* byval(%union.U1) align 32 +void test(void) +{ + foo(1, a); + foo(1, a.m); + foo(1, x1); + foo(1, x2); + foo(1, x3); + foo(1, x4); + foo(1, x5); + foo(1, x6); + foo(1, u1); +} Index: clang/test/CodeGen/x86_32-align-linux.cpp =================================================================== --- /dev/null +++ clang/test/CodeGen/x86_32-align-linux.cpp @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 -w -fblocks -ffreestanding -triple i386-pc-linux-gnu -emit-llvm -o %t %s +// RUN: FileCheck < %t %s + +#include + +typedef __attribute__((aligned(16))) int alignedint16; +typedef __attribute__((aligned(64))) int alignedint64; + +class __attribute__((aligned(64))) X1 { + class __attribute__((aligned(32))) { + __m128 a1; + } a; + int b; +}; + +class __attribute__((aligned(64))) X2 { + class __attribute__((aligned(32))) { + int a1; + alignedint16 a2; + } a; + int b; +}; + +class __attribute__((aligned(32))) X3 { + class __attribute__((aligned(64))) { + int a1; + alignedint16 a2; + } a; + int b; +}; + +class __attribute__((aligned(16))) X4 { + class __attribute__((aligned(32))) { + int a1; + alignedint64 a2; + } a; + int b; +}; + +class __attribute__((aligned(64))) X5 { + int x; +}; + +class __attribute__((aligned(64))) X6 { + int x; + alignedint64 y; +}; + +extern void foo(int, ...); + +class X1 x1; +class X2 x2; +class X3 x3; +class X4 x4; +class X5 x5; +class X6 x6; + +// CHECK-LABEL: define void @_Z4testv() +// CHECK: entry: +// CHECK: call void (i32, ...) @_Z3fooiz(i32 1, %class.X1* byval(%class.X1) align 64 +// CHECK: call void (i32, ...) @_Z3fooiz(i32 1, %class.X2* byval(%class.X2) align 64 +// CHECK: call void (i32, ...) @_Z3fooiz(i32 1, %class.X3* byval(%class.X3) align 64 +// CHECK: call void (i32, ...) @_Z3fooiz(i32 1, %class.X4* byval(%class.X4) align 64 +// CHECK: call void (i32, ...) @_Z3fooiz(i32 1, %class.X5* byval(%class.X5) align 4 +// CHECK: call void (i32, ...) @_Z3fooiz(i32 1, %class.X6* byval(%class.X6) align 64 + +void test(void) +{ + foo(1, x1); + foo(1, x2); + foo(1, x3); + foo(1, x4); + foo(1, x5); + foo(1, x6); +} Index: clang/test/CodeGen/x86_32-arguments-linux.c =================================================================== --- clang/test/CodeGen/x86_32-arguments-linux.c +++ clang/test/CodeGen/x86_32-arguments-linux.c @@ -5,19 +5,19 @@ // CHECK: i8 signext %a0, %struct.s56_0* byval(%struct.s56_0) align 4 %a1, // CHECK: i64 %a2.coerce, %struct.s56_1* byval(%struct.s56_1) align 4 %0, // CHECK: <1 x double> %a4, %struct.s56_2* byval(%struct.s56_2) align 4 %1, -// CHECK: <4 x i32> %a6, %struct.s56_3* byval(%struct.s56_3) align 4 %2, -// CHECK: <2 x double> %a8, %struct.s56_4* byval(%struct.s56_4) align 4 %3, -// CHECK: <8 x i32> %a10, %struct.s56_5* byval(%struct.s56_5) align 4 %4, -// CHECK: <4 x double> %a12, %struct.s56_6* byval(%struct.s56_6) align 4 %5) +// CHECK: <4 x i32> %a6, %struct.s56_3* byval(%struct.s56_3) align 16 %a7, +// CHECK: <2 x double> %a8, %struct.s56_4* byval(%struct.s56_4) align 16 %a9, +// CHECK: <8 x i32> %a10, %struct.s56_5* byval(%struct.s56_5) align 32 %a11, +// CHECK: <4 x double> %a12, %struct.s56_6* byval(%struct.s56_6) align 32 %a13) // CHECK: call void (i32, ...) @f56_0(i32 1, // CHECK: i32 %{{.*}}, %struct.s56_0* byval(%struct.s56_0) align 4 %{{[^ ]*}}, // CHECK: i64 %{{[^ ]*}}, %struct.s56_1* byval(%struct.s56_1) align 4 %{{[^ ]*}}, // CHECK: <1 x double> %{{[^ ]*}}, %struct.s56_2* byval(%struct.s56_2) align 4 %{{[^ ]*}}, -// CHECK: <4 x i32> %{{[^ ]*}}, %struct.s56_3* byval(%struct.s56_3) align 4 %{{[^ ]*}}, -// CHECK: <2 x double> %{{[^ ]*}}, %struct.s56_4* byval(%struct.s56_4) align 4 %{{[^ ]*}}, -// CHECK: <8 x i32> %{{[^ ]*}}, %struct.s56_5* byval(%struct.s56_5) align 4 %{{[^ ]*}}, -// CHECK: <4 x double> %{{[^ ]*}}, %struct.s56_6* byval(%struct.s56_6) align 4 %{{[^ ]*}}) +// CHECK: <4 x i32> %{{[^ ]*}}, %struct.s56_3* byval(%struct.s56_3) align 16 %{{[^ ]*}}, +// CHECK: <2 x double> %{{[^ ]*}}, %struct.s56_4* byval(%struct.s56_4) align 16 %{{[^ ]*}}, +// CHECK: <8 x i32> %{{[^ ]*}}, %struct.s56_5* byval(%struct.s56_5) align 32 %{{[^ ]*}}, +// CHECK: <4 x double> %{{[^ ]*}}, %struct.s56_6* byval(%struct.s56_6) align 32 %{{[^ ]*}}) // CHECK: } // // [i386] clang misaligns long double in structures