Index: clang/include/clang/Basic/LangOptions.def =================================================================== --- clang/include/clang/Basic/LangOptions.def +++ clang/include/clang/Basic/LangOptions.def @@ -350,6 +350,8 @@ COMPATIBLE_VALUE_LANGOPT(MaxTokens, 32, 0, "Max number of tokens per TU or 0") +VALUE_LANGOPT(AlignPassingAggregate, 1, 0, "Compatible with gcc default passing struct and union (x86 only).") + #undef LANGOPT #undef COMPATIBLE_LANGOPT #undef BENIGN_LANGOPT Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -2229,6 +2229,8 @@ def mno_inline_all_stringops : Flag<["-"], "mno-inline-all-stringops">, Group; def malign_double : Flag<["-"], "malign-double">, Group, Flags<[CC1Option]>, HelpText<"Align doubles to two words in structs (x86 only)">; +def malign_pass_aggregate : Flag<["-"], "malign-pass-aggregate">, Group, Flags<[CC1Option]>, + HelpText<"Compatible with gcc default passing struct and union (x86 only).">; def mfloat_abi_EQ : Joined<["-"], "mfloat-abi=">, Group, Values<"soft,softfp,hard">; def mfpmath_EQ : Joined<["-"], "mfpmath=">, Group; def mfpu_EQ : Joined<["-"], "mfpu=">, Group; Index: clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- clang/lib/CodeGen/TargetInfo.cpp +++ clang/lib/CodeGen/TargetInfo.cpp @@ -1093,6 +1093,10 @@ bool canExpandIndirectArgument(QualType Ty) const; + bool alignAggregate() const { + return getTarget().getTriple().isOSLinux() && + getContext().getLangOpts().AlignPassingAggregate; + } /// Rewrite the function info so that all memory arguments use /// inalloca. void rewriteWithInAlloca(CGFunctionInfo &FI) const; @@ -1536,8 +1540,43 @@ if (Align <= MinABIStackAlignInBytes) return 0; // Use default alignment. + // Check if we need to compatible with gcc default(Linux only). + if (alignAggregate()) { + // 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/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -2968,6 +2968,7 @@ llvm::sort(Opts.ModuleFeatures); Opts.NativeHalfType |= Args.hasArg(OPT_fnative_half_type); Opts.NativeHalfArgsAndReturns |= Args.hasArg(OPT_fnative_half_arguments_and_returns); + Opts.AlignPassingAggregate = Args.hasArg(OPT_malign_pass_aggregate); // Enable HalfArgsAndReturns if present in Args or if NativeHalfArgsAndReturns // is enabled. Opts.HalfArgsAndReturns = Args.hasArg(OPT_fallow_half_arguments_and_returns) 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 -malign-pass-aggregate -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 -malign-pass-aggregate -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); +}