Skip to content

Commit c299efb

Browse files
committed
[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
1 parent 669d2bb commit c299efb

File tree

3 files changed

+15
-7
lines changed

3 files changed

+15
-7
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,8 @@ LoongArch Support
891891
on LoongArch.
892892
- Unaligned memory accesses can be toggled by ``-m[no-]unaligned-access`` or the
893893
aliases ``-m[no-]strict-align``.
894+
- An ABI mismatch between GCC and Clang related to the handling of empty structs
895+
in C++ parameter passing under ``lp64d`` ABI was fixed.
894896

895897
RISC-V Support
896898
^^^^^^^^^^^^^^

clang/lib/CodeGen/Targets/LoongArch.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,13 @@ bool LoongArchABIInfo::detectFARsEligibleStructHelper(
148148
if (const ConstantArrayType *ATy = getContext().getAsConstantArrayType(Ty)) {
149149
uint64_t ArraySize = ATy->getSize().getZExtValue();
150150
QualType EltTy = ATy->getElementType();
151+
// Non-zero-length arrays of empty records make the struct ineligible to be
152+
// passed via FARs in C++.
153+
if (const auto *RTy = EltTy->getAs<RecordType>()) {
154+
if (ArraySize != 0 && isa<CXXRecordDecl>(RTy->getDecl()) &&
155+
isEmptyRecord(getContext(), EltTy, true, true))
156+
return false;
157+
}
151158
CharUnits EltSize = getContext().getTypeSizeInChars(EltTy);
152159
for (uint64_t i = 0; i < ArraySize; ++i) {
153160
if (!detectFARsEligibleStructHelper(EltTy, CurOff, Field1Ty, Field1Off,
@@ -163,7 +170,7 @@ bool LoongArchABIInfo::detectFARsEligibleStructHelper(
163170
// copy constructor are not eligible for the FP calling convention.
164171
if (getRecordArgABI(Ty, CGT.getCXXABI()))
165172
return false;
166-
if (isEmptyRecord(getContext(), Ty, true))
173+
if (isEmptyRecord(getContext(), Ty, true, true))
167174
return true;
168175
const RecordDecl *RD = RTy->getDecl();
169176
// Unions aren't eligible unless they're empty (which is caught above).

clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// RUN: %clang_cc1 -triple loongarch64 -target-feature +f -target-feature +d -target-abi lp64d -emit-llvm %s -o - -x c++ | \
44
// RUN: FileCheck --check-prefix=CHECK-CXX %s
55

6-
// FIXME: This isn't currently respected.
76
// Fields containing empty structs or unions are ignored when flattening
87
// structs to examine whether the structs can be passed via FARs, even in C++.
98
// But there is an exception that non-zero-length array of empty structures are
@@ -16,31 +15,31 @@ struct empty { struct { struct { } e; }; };
1615
struct s1 { struct empty e; float f; };
1716

1817
// CHECK-C: define{{.*}} float @test_s1(float {{.*}})
19-
// CHECK-CXX: define{{.*}} i64 @_Z7test_s12s1(i64 {{.*}})
18+
// CHECK-CXX: define{{.*}} float @_Z7test_s12s1(float {{.*}})
2019
struct s1 test_s1(struct s1 a) {
2120
return a;
2221
}
2322

2423
struct s2 { struct empty e; int32_t i; float f; };
2524

2625
// CHECK-C: define{{.*}} { i32, float } @test_s2(i32 {{.*}}, float {{.*}})
27-
// CHECK-CXX: define{{.*}} [2 x i64] @_Z7test_s22s2([2 x i64] {{.*}})
26+
// CHECK-CXX: define{{.*}} { i32, float } @_Z7test_s22s2(i32 {{.*}}, float {{.*}})
2827
struct s2 test_s2(struct s2 a) {
2928
return a;
3029
}
3130

3231
struct s3 { struct empty e; float f; float g; };
3332

3433
// CHECK-C: define{{.*}} { float, float } @test_s3(float {{.*}}, float {{.*}})
35-
// CHECK-CXX: define{{.*}} [2 x i64] @_Z7test_s32s3([2 x i64] {{.*}})
34+
// CHECK-CXX: define{{.*}} { float, float } @_Z7test_s32s3(float {{.*}}, float {{.*}})
3635
struct s3 test_s3(struct s3 a) {
3736
return a;
3837
}
3938

4039
struct s4 { struct empty e; float __complex__ c; };
4140

4241
// CHECK-C: define{{.*}} { float, float } @test_s4(float {{.*}}, float {{.*}})
43-
// CHECK-CXX: define{{.*}} [2 x i64] @_Z7test_s42s4([2 x i64] {{.*}})
42+
// CHECK-CXX: define{{.*}} { float, float } @_Z7test_s42s4(float {{.*}}, float {{.*}})
4443
struct s4 test_s4(struct s4 a) {
4544
return a;
4645
}
@@ -77,7 +76,7 @@ struct empty_arr0 { struct { struct { } e[0]; }; };
7776
struct s8 { struct empty_arr0 e; float f; };
7877

7978
// CHECK-C: define{{.*}} float @test_s8(float {{.*}})
80-
// CHECK-CXX: define{{.*}} i64 @_Z7test_s82s8(i64 {{.*}})
79+
// CHECK-CXX: define{{.*}} float @_Z7test_s82s8(float {{.*}})
8180
struct s8 test_s8(struct s8 a) {
8281
return a;
8382
}

0 commit comments

Comments
 (0)