Skip to content

Commit

Permalink
[Clang][LoongArch] Fix ABI handling of empty structs in C++ to match …
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
SixWeining committed Jul 25, 2023
1 parent 669d2bb commit c299efb
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 7 deletions.
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Expand Up @@ -891,6 +891,8 @@ LoongArch Support
on LoongArch.
- Unaligned memory accesses can be toggled by ``-m[no-]unaligned-access`` or the
aliases ``-m[no-]strict-align``.
- An ABI mismatch between GCC and Clang related to the handling of empty structs
in C++ parameter passing under ``lp64d`` ABI was fixed.

RISC-V Support
^^^^^^^^^^^^^^
Expand Down
9 changes: 8 additions & 1 deletion clang/lib/CodeGen/Targets/LoongArch.cpp
Expand Up @@ -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,
Expand All @@ -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).
Expand Down
11 changes: 5 additions & 6 deletions clang/test/CodeGen/LoongArch/abi-lp64d-empty-structs.c
Expand Up @@ -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
Expand All @@ -16,31 +15,31 @@ 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;
}

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;
}

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;
}

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;
}
Expand Down Expand Up @@ -77,7 +76,7 @@ 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;
}

0 comments on commit c299efb

Please sign in to comment.