llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Folkert de Vries (folkertdev) <details> <summary>Changes</summary> fixes https://github.com/llvm/llvm-project/issues/212109 A return of `_Complex {integer}` is now packed into a single GPR when that fits, matching GCC. The `-fclang-abi-compat=23` flag still gives the old behavior of using 2 GPRs, if compatibility with older clang version for this type is needed somewhere. --- Full diff: https://github.com/llvm/llvm-project/pull/212119.diff 4 Files Affected: - (modified) clang/docs/ReleaseNotes.md (+6) - (modified) clang/include/clang/Basic/ABIVersions.def (+2) - (modified) clang/lib/CodeGen/Targets/Mips.cpp (+27-1) - (added) clang/test/CodeGen/mips-complex-abi.c (+80) ``````````diff diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 61e8378b1704a..25b8ef1c8d604 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -62,6 +62,12 @@ honored, and calls use the caller's features, matching GCC. Per-function features cannot lower the translation-unit ABI level; `-fclang-abi-compat=23` restores the previous behavior. (#GH193298) +- On MIPS, a `_Complex` value with an integer element type is now returned in + a single GPR if possible, matching GCC. A `_Complex char` or `_Complex short` (and, + on N32/N64, a `_Complex int`) fits in a single GPR and is no longer returned + using one GPR per part. `-fclang-abi-compat=23` restores the previous + behavior. (#GH212109) + ### AST Dumping Potentially Breaking Changes ### Clang Frontend Potentially Breaking Changes diff --git a/clang/include/clang/Basic/ABIVersions.def b/clang/include/clang/Basic/ABIVersions.def index b55e8dfa2bbc1..c094c2124d3e1 100644 --- a/clang/include/clang/Basic/ABIVersions.def +++ b/clang/include/clang/Basic/ABIVersions.def @@ -149,6 +149,8 @@ ABI_VER_MAJOR(22) /// This causes clang to: /// - Ignore per-function target attributes when determining the x86 AVX ABI /// level. +/// - On MIPS, return a `_Complex` value with an integer element type in one +/// GPR per part, instead of packing it into as few GPRs as possible. ABI_VER_MAJOR(23) /// Conform to the underlying platform's C and C++ ABIs as closely as we can. diff --git a/clang/lib/CodeGen/Targets/Mips.cpp b/clang/lib/CodeGen/Targets/Mips.cpp index 22fdcd95ea8fa..32d22523300d8 100644 --- a/clang/lib/CodeGen/Targets/Mips.cpp +++ b/clang/lib/CodeGen/Targets/Mips.cpp @@ -26,6 +26,18 @@ class MipsABIInfo : public ABIInfo { llvm::Type* HandleAggregates(QualType Ty, uint64_t TySize) const; llvm::Type* returnAggregateInRegs(QualType RetTy, uint64_t Size) const; llvm::Type* getPaddingType(uint64_t Align, uint64_t Offset) const; + + /// Whether `_Complex` values with an integer element type are returned the + /// way GCC returns them. Clang 23 and earlier returned the real and the + /// imaginary part in two separate GPRs, later versions match GCC and pack + /// them into one when possible. + bool isComplexGnuABI() const { + return !getContext().getLangOpts().isCompatibleWith( + LangOptions::ClangABI::Ver23); + } + + ABIArgInfo classifyComplexReturnType(QualType RetTy, uint64_t Size) const; + public: MipsABIInfo(CodeGenTypes &CGT, bool _IsO32) : ABIInfo(CGT), IsO32(_IsO32), MinABIStackAlignInBytes(IsO32 ? 4 : 8), @@ -301,6 +313,20 @@ MipsABIInfo::returnAggregateInRegs(QualType RetTy, uint64_t Size) const { return llvm::StructType::get(getVMContext(), RTList); } +ABIArgInfo MipsABIInfo::classifyComplexReturnType(QualType RetTy, + uint64_t Size) const { + // A `_Complex` value with a floating-point element type is returned in FPRs, + // `_Complex long long` is returned in 2 GPRs. For older ABI versions all + // `_Complex {integer}` types are returned in 2 GPRs. + uint64_t RegisterWidth = MinABIStackAlignInBytes * 8; + if (!isComplexGnuABI() || RetTy->isFloatingType() || Size > RegisterWidth) + return ABIArgInfo::getDirect(); + + // Match GCC for `_Complex int`, `_Complex short` and `_Complex char` by + // packing the real and imaginary field into one GPR. + return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); +} + ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const { uint64_t Size = getContext().getTypeSize(RetTy); @@ -315,7 +341,7 @@ ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const { if (isAggregateTypeForABI(RetTy) || RetTy->isVectorType()) { if (Size <= 128) { if (RetTy->isAnyComplexType()) - return ABIArgInfo::getDirect(); + return classifyComplexReturnType(RetTy, Size); // O32 returns integer vectors in registers and N32/N64 returns all small // aggregates in registers. diff --git a/clang/test/CodeGen/mips-complex-abi.c b/clang/test/CodeGen/mips-complex-abi.c new file mode 100644 index 0000000000000..8262e9aa60906 --- /dev/null +++ b/clang/test/CodeGen/mips-complex-abi.c @@ -0,0 +1,80 @@ +// RUN: %clang_cc1 -triple mips-none-linux-gnu -emit-llvm -o - %s \ +// RUN: | FileCheck %s --check-prefix=GPR32 +// RUN: %clang_cc1 -triple mipsel-none-linux-gnu -emit-llvm -o - %s \ +// RUN: | FileCheck %s --check-prefix=GPR32 + +// RUN: %clang_cc1 -triple mips64-none-linux-gnu -target-abi n32 -emit-llvm -o - %s \ +// RUN: | FileCheck %s --check-prefix=GPR64 +// RUN: %clang_cc1 -triple mips64-none-linux-gnu -target-abi n64 -emit-llvm -o - %s \ +// RUN: | FileCheck %s --check-prefix=GPR64 +// RUN: %clang_cc1 -triple mips64el-none-linux-gnu -target-abi n64 -emit-llvm -o - %s \ +// RUN: | FileCheck %s --check-prefix=GPR64 + +// RUN: %clang_cc1 -triple mips-none-linux-gnu -fclang-abi-compat=23 -emit-llvm -o - %s \ +// RUN: | FileCheck %s --check-prefix=COMPAT23 +// RUN: %clang_cc1 -triple mips64-none-linux-gnu -target-abi n64 -fclang-abi-compat=23 \ +// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefix=COMPAT23 + +// Test how MIPS passes and returns `_Complex` values. + +// With Clang 23 and before, `_Complex {integer}` was passed in 2 registers. +// Later versions are compatible with GCC and pack such types into a single +// GPR if possible. + +// GPR32-LABEL: define{{.*}} i16 @ret_complex_char( +// GPR64-LABEL: define{{.*}} i16 @ret_complex_char( +// COMPAT23-LABEL: define{{.*}} { i8, i8 } @ret_complex_char( +_Complex char ret_complex_char(void) { return 0; } + +// GPR32-LABEL: define{{.*}} i32 @ret_complex_short( +// GPR64-LABEL: define{{.*}} i32 @ret_complex_short( +// COMPAT23-LABEL: define{{.*}} { i16, i16 } @ret_complex_short( +_Complex short ret_complex_short(void) { return 0; } + +// GPR32-LABEL: define{{.*}} { i32, i32 } @ret_complex_int( +// GPR64-LABEL: define{{.*}} i64 @ret_complex_int( +// COMPAT23-LABEL: define{{.*}} { i32, i32 } @ret_complex_int( +_Complex int ret_complex_int(void) { return 0; } + +// GPR32-LABEL: define{{.*}} { i64, i64 } @ret_complex_long_long( +// GPR64-LABEL: define{{.*}} { i64, i64 } @ret_complex_long_long( +// COMPAT23-LABEL: define{{.*}} { i64, i64 } @ret_complex_long_long( +_Complex long long ret_complex_long_long(void) { return 0; } + +// A `_Complex` value with a floating-point element type is returned in FPRs. + +// GPR32-LABEL: define{{.*}} { float, float } @ret_complex_float( +// GPR64-LABEL: define{{.*}} { float, float } @ret_complex_float( +// COMPAT23-LABEL: define{{.*}} { float, float } @ret_complex_float( +_Complex float ret_complex_float(void) { return 0; } + +// GPR32-LABEL: define{{.*}} { double, double } @ret_complex_double( +// GPR64-LABEL: define{{.*}} { double, double } @ret_complex_double( +// COMPAT23-LABEL: define{{.*}} { double, double } @ret_complex_double( +_Complex double ret_complex_double(void) { return 0; } + +// Arguments + +// GPR32-LABEL: define{{.*}} void @arg_complex_char(i16 inreg noundef %c.coerce) +// GPR64-LABEL: define{{.*}} void @arg_complex_char(i16 inreg noundef %c.coerce) +void arg_complex_char(_Complex char c) {} + +// GPR32-LABEL: define{{.*}} void @arg_complex_short(i32 inreg noundef %c.coerce) +// GPR64-LABEL: define{{.*}} void @arg_complex_short(i32 inreg noundef %c.coerce) +void arg_complex_short(_Complex short c) {} + +// GPR32-LABEL: define{{.*}} void @arg_complex_int(i32 inreg noundef %c.coerce0, i32 inreg noundef %c.coerce1) +// GPR64-LABEL: define{{.*}} void @arg_complex_int(i64 inreg noundef %c.coerce) +void arg_complex_int(_Complex int c) {} + +// GPR32-LABEL: define{{.*}} void @arg_complex_long_long(i32 inreg noundef %c.coerce0, i32 inreg noundef %c.coerce1, i32 inreg noundef %c.coerce2, i32 inreg noundef %c.coerce3) +// GPR64-LABEL: define{{.*}} void @arg_complex_long_long(i64 inreg noundef %c.coerce0, i64 inreg noundef %c.coerce1) +void arg_complex_long_long(_Complex long long c) {} + +// GPR32-LABEL: define{{.*}} void @arg_complex_float(i32 inreg noundef %c.coerce0, i32 inreg noundef %c.coerce1) +// GPR64-LABEL: define{{.*}} void @arg_complex_float(float inreg noundef %c.coerce0, float inreg noundef %c.coerce1) +void arg_complex_float(_Complex float c) {} + +// GPR32-LABEL: define{{.*}} void @arg_complex_double(i32 inreg noundef %c.coerce0, i32 inreg noundef %c.coerce1, i32 inreg noundef %c.coerce2, i32 inreg noundef %c.coerce3) +// GPR64-LABEL: define{{.*}} void @arg_complex_double(double inreg noundef %c.coerce0, double inreg noundef %c.coerce1) +void arg_complex_double(_Complex double c) {} `````````` </details> https://github.com/llvm/llvm-project/pull/212119 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
