Skip to content

Commit

Permalink
[RISCV] Handle empty structs/unions passing in C++ (llvm#97315)
Browse files Browse the repository at this point in the history
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 llvm#97285
  • Loading branch information
svs-quic authored Jul 9, 2024
1 parent f1905f0 commit d65f423
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 4 deletions.
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/CodeGen/Targets/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
55 changes: 55 additions & 0 deletions clang/test/CodeGen/RISCV/abi-empty-structs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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: {{.*}}

0 comments on commit d65f423

Please sign in to comment.