[llvm-branch-commits] [clang] ed4284a - [Clang][LoongArch] Fix ABI handling of empty structs in C++ to match GCC behaviour

Tobias Hieta via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Aug 8 00:58:07 PDT 2023


Author: Weining Lu
Date: 2023-08-08T09:57:50+02:00
New Revision: ed4284a91f819e83bb0a021d8c76d85bf91036f9

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

LOG: [Clang][LoongArch] Fix ABI handling of empty structs in C++ to match GCC behaviour

GCC doesn't ignore non-zero-length array of empty structures in C++
while clang does. What this patch did is to match GCC's behaviour
although this rule is not documented in psABI.

Similar to D142327 for RISCV.

Reviewed By: xry111, xen0n

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

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/CodeGen/Targets/LoongArch.cpp
    clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 1b1c52ca2a3c2b..58348bcdf13ee3 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -921,6 +921,8 @@ LoongArch Support
 
 - Patchable function entry (``-fpatchable-function-entry``) is now supported
   on LoongArch.
+- An ABI mismatch between GCC and Clang related to the handling of empty structs
+  in C++ parameter passing under ``lp64d`` ABI was fixed.
 - Unaligned memory accesses can be toggled by ``-m[no-]unaligned-access`` or the
   aliases ``-m[no-]strict-align``.
 - Non ``$``-prefixed GPR names (e.g. ``r4`` and ``a0``) are allowed in inlineasm

diff  --git a/clang/lib/CodeGen/Targets/LoongArch.cpp b/clang/lib/CodeGen/Targets/LoongArch.cpp
index 6391a8aeaa67cd..7483bf6d6d1e8e 100644
--- a/clang/lib/CodeGen/Targets/LoongArch.cpp
+++ b/clang/lib/CodeGen/Targets/LoongArch.cpp
@@ -148,6 +148,13 @@ bool LoongArchABIInfo::detectFARsEligibleStructHelper(
   if (const ConstantArrayType *ATy = getContext().getAsConstantArrayType(Ty)) {
     uint64_t ArraySize = ATy->getSize().getZExtValue();
     QualType EltTy = ATy->getElementType();
+    // Non-zero-length arrays of empty records make the struct ineligible to be
+    // passed via FARs in C++.
+    if (const auto *RTy = EltTy->getAs<RecordType>()) {
+      if (ArraySize != 0 && isa<CXXRecordDecl>(RTy->getDecl()) &&
+          isEmptyRecord(getContext(), EltTy, true, true))
+        return false;
+    }
     CharUnits EltSize = getContext().getTypeSizeInChars(EltTy);
     for (uint64_t i = 0; i < ArraySize; ++i) {
       if (!detectFARsEligibleStructHelper(EltTy, CurOff, Field1Ty, Field1Off,
@@ -163,7 +170,7 @@ bool LoongArchABIInfo::detectFARsEligibleStructHelper(
     // copy constructor are not eligible for the FP calling convention.
     if (getRecordArgABI(Ty, CGT.getCXXABI()))
       return false;
-    if (isEmptyRecord(getContext(), Ty, true))
+    if (isEmptyRecord(getContext(), Ty, true, true))
       return true;
     const RecordDecl *RD = RTy->getDecl();
     // Unions aren't eligible unless they're empty (which is caught above).
@@ -222,6 +229,8 @@ bool LoongArchABIInfo::detectFARsEligibleStruct(
   if (!detectFARsEligibleStructHelper(Ty, CharUnits::Zero(), Field1Ty,
                                       Field1Off, Field2Ty, Field2Off))
     return false;
+  if (!Field1Ty)
+    return false;
   // Not really a candidate if we have a single int but no float.
   if (Field1Ty && !Field2Ty && !Field1Ty->isFloatingPointTy())
     return false;

diff  --git a/clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c b/clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c
index 3a65b90e48e0e0..fb90bf556c19b2 100644
--- a/clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c
+++ b/clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c
@@ -3,7 +3,6 @@
 // RUN: %clang_cc1 -triple loongarch64 -target-feature +f -target-feature +d -target-abi lp64d -emit-llvm %s -o - -x c++ | \
 // RUN:   FileCheck --check-prefix=CHECK-CXX %s
 
-// FIXME: This isn't currently respected.
 // Fields containing empty structs or unions are ignored when flattening
 // structs to examine whether the structs can be passed via FARs, even in C++.
 // But there is an exception that non-zero-length array of empty structures are
@@ -16,7 +15,7 @@ struct empty { struct { struct { } e; }; };
 struct s1 { struct empty e; float f; };
 
 // CHECK-C: define{{.*}} float @test_s1(float {{.*}})
-// CHECK-CXX: define{{.*}} i64 @_Z7test_s12s1(i64 {{.*}})
+// CHECK-CXX: define{{.*}} float @_Z7test_s12s1(float {{.*}})
 struct s1 test_s1(struct s1 a) {
   return a;
 }
@@ -24,7 +23,7 @@ struct s1 test_s1(struct s1 a) {
 struct s2 { struct empty e; int32_t i; float f; };
 
 // CHECK-C: define{{.*}} { i32, float } @test_s2(i32 {{.*}}, float {{.*}})
-// CHECK-CXX: define{{.*}} [2 x i64] @_Z7test_s22s2([2 x i64] {{.*}})
+// CHECK-CXX: define{{.*}} { i32, float } @_Z7test_s22s2(i32 {{.*}}, float {{.*}})
 struct s2 test_s2(struct s2 a) {
   return a;
 }
@@ -32,7 +31,7 @@ struct s2 test_s2(struct s2 a) {
 struct s3 { struct empty e; float f; float g; };
 
 // CHECK-C: define{{.*}} { float, float } @test_s3(float {{.*}}, float {{.*}})
-// CHECK-CXX: define{{.*}} [2 x i64] @_Z7test_s32s3([2 x i64] {{.*}})
+// CHECK-CXX: define{{.*}} { float, float } @_Z7test_s32s3(float {{.*}}, float {{.*}})
 struct s3 test_s3(struct s3 a) {
   return a;
 }
@@ -40,7 +39,7 @@ struct s3 test_s3(struct s3 a) {
 struct s4 { struct empty e; float __complex__ c; };
 
 // CHECK-C: define{{.*}} { float, float } @test_s4(float {{.*}}, float {{.*}})
-// CHECK-CXX: define{{.*}} [2 x i64] @_Z7test_s42s4([2 x i64] {{.*}})
+// CHECK-CXX: define{{.*}} { float, float } @_Z7test_s42s4(float {{.*}}, float {{.*}})
 struct s4 test_s4(struct s4 a) {
   return a;
 }
@@ -77,7 +76,14 @@ struct empty_arr0 { struct { struct { } e[0]; }; };
 struct s8 { struct empty_arr0 e; float f; };
 
 // CHECK-C: define{{.*}} float @test_s8(float {{.*}})
-// CHECK-CXX: define{{.*}} i64 @_Z7test_s82s8(i64 {{.*}})
+// CHECK-CXX: define{{.*}} float @_Z7test_s82s8(float {{.*}})
 struct s8 test_s8(struct s8 a) {
   return a;
 }
+
+// CHECK-C: define{{.*}} void @test_s9()
+// CHECK-CXX: define{{.*}} i64 @_Z7test_s92s9(i64 {{.*}})
+struct s9 { struct empty e; };
+struct s9 test_s9(struct s9 a) {
+  return a;
+}


        


More information about the llvm-branch-commits mailing list