Author: Weining Lu Date: 2023-08-08T09:07:11+08:00 New Revision: e7a8a7d4977627ebc43e9ed43462aebad4a66e8d
URL: https://github.com/llvm/llvm-project/commit/e7a8a7d4977627ebc43e9ed43462aebad4a66e8d DIFF: https://github.com/llvm/llvm-project/commit/e7a8a7d4977627ebc43e9ed43462aebad4a66e8d.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 949e3fe7d2c8d7..44f6ad807daf8f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -192,6 +192,9 @@ Windows Support LoongArch Support ^^^^^^^^^^^^^^^^^ +- 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 ^^^^^^^^^^^^^^ - Unaligned memory accesses can be toggled by ``-m[no-]unaligned-access`` or the 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; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits