diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -153,6 +153,11 @@ /// NetBSD. Ver9, + /// Attempt to be ABI-compatible with code generated by Clang 11.0.x + /// (git 2e10b7a39b93). This causes clang to pass unions with a 256-bit + /// vector member on the stack instead of using registers. + Ver11, + /// Conform to the underlying platform's C and C++ ABIs as closely /// as we can. Latest diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -3061,7 +3061,11 @@ // Classify the fields one at a time, merging the results. unsigned idx = 0; - bool IsUnion = RT->isUnionType(); + bool UseClang11Compat = getContext().getLangOpts().getClangABICompat() <= + LangOptions::ClangABI::Ver11 || + getContext().getTargetInfo().getTriple().isPS4(); + bool IsUnion = RT->isUnionType() && !UseClang11Compat; + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i, ++idx) { uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3460,6 +3460,8 @@ Opts.setClangABICompat(LangOptions::ClangABI::Ver7); else if (Major <= 9) Opts.setClangABICompat(LangOptions::ClangABI::Ver9); + else if (Major <= 11) + Opts.setClangABICompat(LangOptions::ClangABI::Ver11); } else if (Ver != "latest") { Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(); diff --git a/clang/test/CodeGen/X86/avx-union.c b/clang/test/CodeGen/X86/avx-union.c --- a/clang/test/CodeGen/X86/avx-union.c +++ b/clang/test/CodeGen/X86/avx-union.c @@ -1,5 +1,11 @@ // RUN: %clang_cc1 -w -ffreestanding -triple x86_64-linux-gnu -target-feature +avx -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=AVX // RUN: %clang_cc1 -w -ffreestanding -triple x86_64-linux-gnu -target-feature +avx512f -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=AVX512 + +// Test Clang 11 and earlier behavior +// RUN: %clang_cc1 -w -ffreestanding -triple x86_64-linux-gnu -target-feature +avx -fclang-abi-compat=10.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=AVX --check-prefix=CHECK-LEGACY +// RUN: %clang_cc1 -w -ffreestanding -triple x86_64-linux-gnu -target-feature +avx512f -fclang-abi-compat=11.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-LEGACY --check-prefix=AVX512-LEGACY +// RUN: %clang_cc1 -w -ffreestanding -triple x86_64-scei-ps4 -target-feature +avx -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-LEGACY --check-prefix=AVX-LEGACY + // This tests verifies that a union parameter should pass by a vector regitster whose first eightbyte is SSE and the other eightbytes are SSEUP. typedef int __m256 __attribute__ ((__vector_size__ (32))); @@ -19,10 +25,12 @@ extern void foo2(union M512 A); union M256 m1; union M512 m2; -// CHECK-LABEL: define void @test() -// CHECK: call void @foo1(<4 x double> -// AVX: call void @foo2(%union.M512* byval(%union.M512) align 64 -// AVX512: call void @foo2(<8 x double> +// CHECK-LABEL: define void @test() +// CHECK: call void @foo1(<4 x double> +// CHECK-LEGACY: call void @foo1(%union.M256* byval(%union.M256) align 32 +// AVX: call void @foo2(%union.M512* byval(%union.M512) align 64 +// AVX512: call void @foo2(<8 x double> +// AVX512-LEGACY: call void @foo2(%union.M512* byval(%union.M512) align 64 void test() { foo1(m1); foo2(m2);