[clang] d65f423 - [RISCV] Handle empty structs/unions passing in C++ (#97315)

via cfe-commits cfe-commits at lists.llvm.org
Mon Jul 8 18:17:54 PDT 2024


Author: Sudharsan Veeravalli
Date: 2024-07-08T18:17:51-07:00
New Revision: d65f4232026a6c0fcd2431e1d28a7ad49127f6e5

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

LOG: [RISCV] Handle empty structs/unions passing in C++ (#97315)

According to RISC-V integer calling convention empty structs or union
arguments or return values are ignored by C compilers which support them
as a non-standard extension. This is not the case for C++, which
requires them to be sized types.

Fixes #97285

Added: 
    

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

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 838cb69f647ee..e086b4fa43743 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1084,6 +1084,7 @@ RISC-V Support
 
 - ``__attribute__((rvv_vector_bits(N)))`` is now supported for RVV vbool*_t types.
 - Profile names in ``-march`` option are now supported.
+- Passing empty structs/unions as arguments in C++ is now handled correctly. The behavior is similar to GCC's.
 
 CUDA/HIP Language Changes
 ^^^^^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp
index a4c5ec315b8df..f2add9351c03c 100644
--- a/clang/lib/CodeGen/Targets/RISCV.cpp
+++ b/clang/lib/CodeGen/Targets/RISCV.cpp
@@ -361,12 +361,13 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
                                            CGCXXABI::RAA_DirectInMemory);
   }
 
-  // Ignore empty structs/unions.
-  if (isEmptyRecord(getContext(), Ty, true))
-    return ABIArgInfo::getIgnore();
-
   uint64_t Size = getContext().getTypeSize(Ty);
 
+  // Ignore empty structs/unions whose size is zero. According to the calling
+  // convention empty structs/unions are required to be sized types in C++.
+  if (isEmptyRecord(getContext(), Ty, true) && Size == 0)
+    return ABIArgInfo::getIgnore();
+
   // Pass floating point values via FPRs if possible.
   if (IsFixed && Ty->isFloatingType() && !Ty->isComplexType() &&
       FLen >= Size && ArgFPRsLeft) {

diff  --git a/clang/test/CodeGen/RISCV/abi-empty-structs.c b/clang/test/CodeGen/RISCV/abi-empty-structs.c
index c48a2891627d4..5157165787fcb 100644
--- a/clang/test/CodeGen/RISCV/abi-empty-structs.c
+++ b/clang/test/CodeGen/RISCV/abi-empty-structs.c
@@ -167,6 +167,61 @@ struct s9 {
 //
 void test_s9(struct s9 a) {}
 
+struct s10 { };
+// CHECK-C-LABEL: define dso_local void @test_s10
+// CHECK-C-SAME: () #[[ATTR0]] {
+// CHECK-C:  entry:
+//
+// CHECK32-CXX-LABEL: define dso_local i32 @_Z8test_s103s10
+// CHECK32-CXX-SAME: (i32 [[A_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK32-CXX:  entry:
+//
+// CHECK64-CXX-LABEL: define dso_local i64 @_Z8test_s103s10
+// CHECK64-CXX-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK64-CXX:  entry:
+//
+struct s10 test_s10(struct s10 a) {
+  return a;
+}
+
+struct s11 { int : 0; };
+// CHECK-C-LABEL: define dso_local void @test_s11
+// CHECK-C-SAME: () #[[ATTR0]] {
+// CHECK-C:  entry:
+//
+// CHECK32-CXX-LABEL: define dso_local i32 @_Z8test_s113s11
+// CHECK32-CXX-SAME: (i32 [[A_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK32-CXX:  entry:
+//
+// CHECK64-CXX-LABEL: define dso_local i64 @_Z8test_s113s11
+// CHECK64-CXX-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK64-CXX:  entry:
+//
+struct s11 test_s11(struct s11 a) {
+  return a;
+}
+
+struct s12 {int x[0];};
+// CHECK32-C-LABEL: define dso_local i32 @test_s12
+// CHECK32-C-SAME: (i32 noundef [[I1:%.*]], i32 noundef [[I2:%.*]]) #[[ATTR0]] {
+// CHECK32-C:  entry:
+//
+// CHECK64-C-LABEL: define dso_local signext i32 @test_s12
+// CHECK64-C-SAME: (i32 noundef signext [[I1:%.*]], i32 noundef signext [[I2:%.*]]) #[[ATTR0]] {
+// CHECK64-C:  entry:
+//
+// CHECK32-CXX-LABEL: define dso_local noundef i32 @_Z8test_s12i3s12i
+// CHECK32-CXX-SAME: (i32 noundef [[I1:%.*]], i32 noundef [[I2:%.*]]) #[[ATTR0]] {
+// CHECK32-CXX:  entry:
+//
+// CHECK64-CXX-LABEL: define dso_local noundef signext i32 @_Z8test_s12i3s12i
+// CHECK64-CXX-SAME: (i32 noundef signext [[I1:%.*]], i32 noundef signext [[I2:%.*]]) #[[ATTR0]] {
+// CHECK64-CXX:  entry:
+//
+int test_s12(int32_t i1, struct s12 a, int32_t i2) {
+  return i2;
+}
+
 //// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
 // CHECK32-C: {{.*}}
 // CHECK64-C: {{.*}}


        


More information about the cfe-commits mailing list