[clang] 774ab60 - Add option to use older clang ABI behavior when passing certain union types as function arguments

Douglas Yung via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 19 18:25:44 PDT 2020


Author: Douglas Yung
Date: 2020-10-19T18:17:34-07:00
New Revision: 774ab60125eeaeac8bf2470b7aaa6aa428d68453

URL: https://github.com/llvm/llvm-project/commit/774ab60125eeaeac8bf2470b7aaa6aa428d68453
DIFF: https://github.com/llvm/llvm-project/commit/774ab60125eeaeac8bf2470b7aaa6aa428d68453.diff

LOG: Add option to use older clang ABI behavior when passing certain union types as function arguments

Recently commit D78699 (commit 26cfb6e562f1), fixed clang's behavior with respect
to passing a union type through a register to correctly follow the ABI. However,
this is an ABI breaking change with earlier versions of the clang compiler, so we
should add an -fclang-abi-compat option to address this. Additionally, the PS4 ABI
requires the older behavior, so that is added as well.

This change adds a Ver11 value to the ClangABI enum that when it is set (or the
target is the PS4 triple), we skip the ABI fix introduced in D78699.

Differential Revision: https://reviews.llvm.org/D89747

Added: 
    

Modified: 
    clang/include/clang/Basic/LangOptions.h
    clang/lib/CodeGen/TargetInfo.cpp
    clang/lib/Frontend/CompilerInvocation.cpp
    clang/test/CodeGen/X86/avx-union.c

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 84d25c359c55..860b97aace54 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -153,6 +153,11 @@ class LangOptions : public LangOptionsBase {
     /// 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
index 83b97775b96c..e211a0214eb4 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -3061,7 +3061,11 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
 
     // 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
index c518606456dc..7cbd5b310dd3 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3460,6 +3460,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
         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
index 398db2b3f292..17ffb77300ff 100644
--- 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 foo1(union M256 A);
 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);


        


More information about the cfe-commits mailing list