https://github.com/folkertdev updated https://github.com/llvm/llvm-project/pull/212340
>From b60616cf6a51a109f256d4eb7bd50cb73ef0c358 Mon Sep 17 00:00:00 2001 From: Folkert de Vries <[email protected]> Date: Mon, 27 Jul 2026 22:19:23 +0200 Subject: [PATCH 1/6] [Sparc][clang] make `_Complex` ABI GCC-compatible --- clang/docs/ReleaseNotes.md | 11 ++ clang/include/clang/Basic/ABIVersions.def | 6 ++ clang/lib/CodeGen/Targets/Sparc.cpp | 48 ++++++++- clang/test/CodeGen/Sparc/sparc-complex-abi.c | 104 +++++++++++++++++++ 4 files changed, 166 insertions(+), 3 deletions(-) create mode 100644 clang/test/CodeGen/Sparc/sparc-complex-abi.c diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 61e8378b1704a..a47270ea5219c 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -62,6 +62,17 @@ 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 SPARC, a `_Complex` value with an integer element type is now passed and + returned packed into the one or two integer registers it fits in, matching GCC. + Clang previously passed such a value indirectly and returned it with one part + per register. + `-fclang-abi-compat=23` restores the previous behavior. + +- On SPARC64, a `_Complex char` or `_Complex short` is now + right-justified in its slot in the parameter array, like every other scalar + narrower than a slot, rather than left-justified the way a small struct is. + `-fclang-abi-compat=23` restores the previous behavior. + ### 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..8d0e15ffc527a 100644 --- a/clang/include/clang/Basic/ABIVersions.def +++ b/clang/include/clang/Basic/ABIVersions.def @@ -149,6 +149,12 @@ ABI_VER_MAJOR(22) /// This causes clang to: /// - Ignore per-function target attributes when determining the x86 AVX ABI /// level. +/// - On SPARC, pass a `_Complex` value with an integer element type +/// indirectly, and return it with one part per integer register, instead of +/// packing it into the one or two registers it fits in. +/// - On SPARC64, left-justify a `_Complex` value with an integer element type +/// that is narrower than a parameter array slot, instead of right-justifying +/// it the way every other sub-slot scalar is passed. 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/Sparc.cpp b/clang/lib/CodeGen/Targets/Sparc.cpp index 3fa4e84823d51..abc72468316f8 100644 --- a/clang/lib/CodeGen/Targets/Sparc.cpp +++ b/clang/lib/CodeGen/Targets/Sparc.cpp @@ -13,6 +13,13 @@ using namespace clang; using namespace clang::CodeGen; +/// Whether `_Complex` values with an integer element type are passed and +/// returned the way GCC passes and returns them. +static bool isComplexGnuABI(const ABIInfo &Info) { + return !Info.getContext().getLangOpts().isCompatibleWith( + LangOptions::ClangABI::Ver23); +} + //===----------------------------------------------------------------------===// // SPARC v8 ABI Implementation. // Based on the SPARC Compliance Definition version 2.4.1. @@ -25,12 +32,30 @@ class SparcV8ABIInfo : public DefaultABIInfo { SparcV8ABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} private: + llvm::Type *getComplexIntCoerceType(QualType Ty) const; ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType Ty) const; void computeInfo(CGFunctionInfo &FI) const override; }; } // end anonymous namespace +llvm::Type *SparcV8ABIInfo::getComplexIntCoerceType(QualType Ty) const { + if (!isComplexGnuABI(*this)) + return nullptr; + + const auto *CT = Ty->getAs<ComplexType>(); + if (!CT || !CT->getElementType()->isIntegerType()) + return nullptr; + + // The default path already does the right thing for `long long _Complex`. + uint64_t Size = getContext().getTypeSize(Ty); + if (Size > 64) + return nullptr; + + // Coerce to an integer to get the correct scalar-like behavior. + return llvm::IntegerType::get(getVMContext(), Size); +} + ABIArgInfo SparcV8ABIInfo::classifyReturnType(QualType Ty) const { const auto *CT = Ty->getAs<ComplexType>(); const auto *BT = Ty->getAs<BuiltinType>(); @@ -39,9 +64,13 @@ ABIArgInfo SparcV8ABIInfo::classifyReturnType(QualType Ty) const { bool IsLongDouble = BT && BT->getKind() == BuiltinType::LongDouble; // long double _Complex is special in that it should be marked as inreg. - if (CT) - return IsLongDouble ? ABIArgInfo::getDirectInReg() - : ABIArgInfo::getDirect(); + if (CT) { + if (IsLongDouble) + return ABIArgInfo::getDirectInReg(); + if (llvm::Type *CoerceTy = getComplexIntCoerceType(Ty)) + return ABIArgInfo::getDirect(CoerceTy); + return ABIArgInfo::getDirect(); + } if (IsLongDouble) return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(), @@ -55,6 +84,10 @@ ABIArgInfo SparcV8ABIInfo::classifyArgumentType(QualType Ty) const { BT && BT->getKind() == BuiltinType::LongDouble) return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace()); + // Complex integers go in registers. + if (llvm::Type *CoerceTy = getComplexIntCoerceType(Ty)) + return ABIArgInfo::getDirect(CoerceTy); + return DefaultABIInfo::classifyArgumentType(Ty); } @@ -277,6 +310,15 @@ ABIArgInfo SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit, return ABIArgInfo::getExtend(Ty); } + // When being GCC-compatible, cast a complex integer to an integer type + // of the right size to get the correct scalar-like behavior. + if (isComplexGnuABI(*this)) + if (const auto *CT = Ty->getAs<ComplexType>(); + CT && Size < 64 && CT->getElementType()->isIntegerType()) { + RegOffset += 1; + return ABIArgInfo::getDirect(llvm::IntegerType::get(VMContext, Size)); + } + // Other non-aggregates go in registers. if (!isAggregateTypeForABI(Ty)) { RegOffset += Size / 64; diff --git a/clang/test/CodeGen/Sparc/sparc-complex-abi.c b/clang/test/CodeGen/Sparc/sparc-complex-abi.c new file mode 100644 index 0000000000000..6f822134bdb0b --- /dev/null +++ b/clang/test/CodeGen/Sparc/sparc-complex-abi.c @@ -0,0 +1,104 @@ +// RUN: %clang_cc1 -triple sparc-unknown-linux-gnu -emit-llvm -o - %s \ +// RUN: | FileCheck %s --check-prefix=V8 +// RUN: %clang_cc1 -triple sparcv9-unknown-linux-gnu -emit-llvm -o - %s \ +// RUN: | FileCheck %s --check-prefix=V9 + +// RUN: %clang_cc1 -triple sparc-unknown-linux-gnu -fclang-abi-compat=23 \ +// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefix=COMPAT23-V8 +// RUN: %clang_cc1 -triple sparcv9-unknown-linux-gnu -fclang-abi-compat=23 \ +// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefix=COMPAT23-V9 + +// Test how SPARC passes and returns `_Complex` values. + +// Returns. +// +// A `_Complex` value with an integer element type is returned packed into whole +// integer registers. Clang 23 and before instead gave each part a register of +// its own on v8, and on v9 left-justified a value narrower than a register the +// way a small struct is returned. The new behavior matches GCC. + +// COMPAT23-V8-LABEL: define{{.*}} { i8, i8 } @ret_complex_char( +// V8-LABEL: define{{.*}} i16 @ret_complex_char( +// COMPAT23-V9-LABEL: define{{.*}} i64 @ret_complex_char( +// V9-LABEL: define{{.*}} i16 @ret_complex_char( +_Complex char ret_complex_char(void) { return 0; } + +// COMPAT23-V8-LABEL: define{{.*}} { i16, i16 } @ret_complex_short( +// V8-LABEL: define{{.*}} i32 @ret_complex_short( +// COMPAT23-V9-LABEL: define{{.*}} i64 @ret_complex_short( +// V9-LABEL: define{{.*}} i32 @ret_complex_short( +_Complex short ret_complex_short(void) { return 0; } + +// COMPAT23-V8-LABEL: define{{.*}} { i32, i32 } @ret_complex_int( +// V8-LABEL: define{{.*}} i64 @ret_complex_int( +// COMPAT23-V9-LABEL: define{{.*}} i64 @ret_complex_int( +// V9-LABEL: define{{.*}} i64 @ret_complex_int( +_Complex int ret_complex_int(void) { return 0; } + +// COMPAT23-V8-LABEL: define{{.*}} { i64, i64 } @ret_complex_long_long( +// V8-LABEL: define{{.*}} { i64, i64 } @ret_complex_long_long( +// COMPAT23-V9-LABEL: define{{.*}} { i64, i64 } @ret_complex_long_long( +// V9-LABEL: define{{.*}} { i64, i64 } @ret_complex_long_long( +_Complex long long ret_complex_long_long(void) { return 0; } + +// COMPAT23-V8-LABEL: define{{.*}} { float, float } @ret_complex_float( +// V8-LABEL: define{{.*}} { float, float } @ret_complex_float( +// COMPAT23-V9-LABEL: define{{.*}} inreg { float, float } @ret_complex_float( +// V9-LABEL: define{{.*}} inreg { float, float } @ret_complex_float( +_Complex float ret_complex_float(void) { return 0; } + +// COMPAT23-V8-LABEL: define{{.*}} { double, double } @ret_complex_double( +// V8-LABEL: define{{.*}} { double, double } @ret_complex_double( +// COMPAT23-V9-LABEL: define{{.*}} { double, double } @ret_complex_double( +// V9-LABEL: define{{.*}} { double, double } @ret_complex_double( +_Complex double ret_complex_double(void) { return 0; } + +// COMPAT23-V8-LABEL: define{{.*}} inreg { fp128, fp128 } @ret_complex_long_double( +// V8-LABEL: define{{.*}} inreg { fp128, fp128 } @ret_complex_long_double( +// COMPAT23-V9-LABEL: define{{.*}} { fp128, fp128 } @ret_complex_long_double( +// V9-LABEL: define{{.*}} { fp128, fp128 } @ret_complex_long_double( +_Complex long double ret_complex_long_double(void) { return 0; } + +// Arguments. + +// COMPAT23-V8-LABEL: define{{.*}} void @arg_complex_char(ptr noundef byval({ i8, i8 }) align 1 %c) +// V8-LABEL: define{{.*}} void @arg_complex_char(i16 noundef %c.coerce) +// COMPAT23-V9-LABEL: define{{.*}} void @arg_complex_char(i64 %c.coerce) +// V9-LABEL: define{{.*}} void @arg_complex_char(i16 noundef %c.coerce) +void arg_complex_char(_Complex char c) {} + +// COMPAT23-V8-LABEL: define{{.*}} void @arg_complex_short(ptr noundef byval({ i16, i16 }) align 2 %c) +// V8-LABEL: define{{.*}} void @arg_complex_short(i32 noundef %c.coerce) +// COMPAT23-V9-LABEL: define{{.*}} void @arg_complex_short(i64 %c.coerce) +// V9-LABEL: define{{.*}} void @arg_complex_short(i32 noundef %c.coerce) +void arg_complex_short(_Complex short c) {} + +// COMPAT23-V8-LABEL: define{{.*}} void @arg_complex_int(ptr noundef byval({ i32, i32 }) align 4 %c) +// V8-LABEL: define{{.*}} void @arg_complex_int(i64 noundef %c.coerce) +// COMPAT23-V9-LABEL: define{{.*}} void @arg_complex_int(i64 noundef %c.coerce) +// V9-LABEL: define{{.*}} void @arg_complex_int(i64 noundef %c.coerce) +void arg_complex_int(_Complex int c) {} + +// COMPAT23-V8-LABEL: define{{.*}} void @arg_complex_long_long(ptr noundef byval({ i64, i64 }) align 8 %c) +// V8-LABEL: define{{.*}} void @arg_complex_long_long(ptr noundef byval({ i64, i64 }) align 8 %c) +// COMPAT23-V9-LABEL: define{{.*}} void @arg_complex_long_long(i64 noundef %c.coerce0, i64 noundef %c.coerce1) +// V9-LABEL: define{{.*}} void @arg_complex_long_long(i64 noundef %c.coerce0, i64 noundef %c.coerce1) +void arg_complex_long_long(_Complex long long c) {} + +// COMPAT23-V8-LABEL: define{{.*}} void @arg_complex_float(ptr noundef byval({ float, float }) align 4 %c) +// V8-LABEL: define{{.*}} void @arg_complex_float(ptr noundef byval({ float, float }) align 4 %c) +// COMPAT23-V9-LABEL: define{{.*}} void @arg_complex_float(float inreg noundef %c.coerce0, float inreg noundef %c.coerce1) +// V9-LABEL: define{{.*}} void @arg_complex_float(float inreg noundef %c.coerce0, float inreg noundef %c.coerce1) +void arg_complex_float(_Complex float c) {} + +// COMPAT23-V8-LABEL: define{{.*}} void @arg_complex_double(ptr noundef byval({ double, double }) align 8 %c) +// V8-LABEL: define{{.*}} void @arg_complex_double(ptr noundef byval({ double, double }) align 8 %c) +// COMPAT23-V9-LABEL: define{{.*}} void @arg_complex_double(double noundef %c.coerce0, double noundef %c.coerce1) +// V9-LABEL: define{{.*}} void @arg_complex_double(double noundef %c.coerce0, double noundef %c.coerce1) +void arg_complex_double(_Complex double c) {} + +// COMPAT23-V8-LABEL: define{{.*}} void @arg_complex_long_double(ptr noundef byval({ fp128, fp128 }) align 8 %c) +// V8-LABEL: define{{.*}} void @arg_complex_long_double(ptr noundef byval({ fp128, fp128 }) align 8 %c) +// COMPAT23-V9-LABEL: define{{.*}} void @arg_complex_long_double(ptr noundef align 16 dead_on_return %c) +// V9-LABEL: define{{.*}} void @arg_complex_long_double(ptr noundef align 16 dead_on_return %c) +void arg_complex_long_double(_Complex long double c) {} >From f8a3c8ffec62cc9eb19e40ecfa47d6629ef8c1c0 Mon Sep 17 00:00:00 2001 From: Folkert de Vries <[email protected]> Date: Sat, 1 Aug 2026 22:31:04 +0200 Subject: [PATCH 2/6] update test --- clang/test/CodeGen/Sparc/sparc-complex-abi.c | 641 ++++++++++++++++--- 1 file changed, 561 insertions(+), 80 deletions(-) diff --git a/clang/test/CodeGen/Sparc/sparc-complex-abi.c b/clang/test/CodeGen/Sparc/sparc-complex-abi.c index 6f822134bdb0b..55605032be17b 100644 --- a/clang/test/CodeGen/Sparc/sparc-complex-abi.c +++ b/clang/test/CodeGen/Sparc/sparc-complex-abi.c @@ -1,3 +1,4 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6 // RUN: %clang_cc1 -triple sparc-unknown-linux-gnu -emit-llvm -o - %s \ // RUN: | FileCheck %s --check-prefix=V8 // RUN: %clang_cc1 -triple sparcv9-unknown-linux-gnu -emit-llvm -o - %s \ @@ -10,95 +11,575 @@ // Test how SPARC passes and returns `_Complex` values. -// Returns. -// // A `_Complex` value with an integer element type is returned packed into whole // integer registers. Clang 23 and before instead gave each part a register of // its own on v8, and on v9 left-justified a value narrower than a register the // way a small struct is returned. The new behavior matches GCC. -// COMPAT23-V8-LABEL: define{{.*}} { i8, i8 } @ret_complex_char( -// V8-LABEL: define{{.*}} i16 @ret_complex_char( -// COMPAT23-V9-LABEL: define{{.*}} i64 @ret_complex_char( -// V9-LABEL: define{{.*}} i16 @ret_complex_char( -_Complex char ret_complex_char(void) { return 0; } - -// COMPAT23-V8-LABEL: define{{.*}} { i16, i16 } @ret_complex_short( -// V8-LABEL: define{{.*}} i32 @ret_complex_short( -// COMPAT23-V9-LABEL: define{{.*}} i64 @ret_complex_short( -// V9-LABEL: define{{.*}} i32 @ret_complex_short( -_Complex short ret_complex_short(void) { return 0; } - -// COMPAT23-V8-LABEL: define{{.*}} { i32, i32 } @ret_complex_int( -// V8-LABEL: define{{.*}} i64 @ret_complex_int( -// COMPAT23-V9-LABEL: define{{.*}} i64 @ret_complex_int( -// V9-LABEL: define{{.*}} i64 @ret_complex_int( -_Complex int ret_complex_int(void) { return 0; } - -// COMPAT23-V8-LABEL: define{{.*}} { i64, i64 } @ret_complex_long_long( -// V8-LABEL: define{{.*}} { i64, i64 } @ret_complex_long_long( -// COMPAT23-V9-LABEL: define{{.*}} { i64, i64 } @ret_complex_long_long( -// V9-LABEL: define{{.*}} { i64, i64 } @ret_complex_long_long( -_Complex long long ret_complex_long_long(void) { return 0; } - -// COMPAT23-V8-LABEL: define{{.*}} { float, float } @ret_complex_float( -// V8-LABEL: define{{.*}} { float, float } @ret_complex_float( -// COMPAT23-V9-LABEL: define{{.*}} inreg { float, float } @ret_complex_float( -// V9-LABEL: define{{.*}} inreg { float, float } @ret_complex_float( -_Complex float ret_complex_float(void) { return 0; } - -// COMPAT23-V8-LABEL: define{{.*}} { double, double } @ret_complex_double( -// V8-LABEL: define{{.*}} { double, double } @ret_complex_double( -// COMPAT23-V9-LABEL: define{{.*}} { double, double } @ret_complex_double( -// V9-LABEL: define{{.*}} { double, double } @ret_complex_double( -_Complex double ret_complex_double(void) { return 0; } - -// COMPAT23-V8-LABEL: define{{.*}} inreg { fp128, fp128 } @ret_complex_long_double( -// V8-LABEL: define{{.*}} inreg { fp128, fp128 } @ret_complex_long_double( -// COMPAT23-V9-LABEL: define{{.*}} { fp128, fp128 } @ret_complex_long_double( -// V9-LABEL: define{{.*}} { fp128, fp128 } @ret_complex_long_double( -_Complex long double ret_complex_long_double(void) { return 0; } - -// Arguments. +// V8-LABEL: define dso_local i16 @complex_char( +// V8-SAME: i16 noundef [[C_COERCE:%.*]]) #[[ATTR0:[0-9]+]] { +// V8-NEXT: [[ENTRY:.*:]] +// V8-NEXT: [[RETVAL:%.*]] = alloca { i8, i8 }, align 1 +// V8-NEXT: [[C:%.*]] = alloca { i8, i8 }, align 1 +// V8-NEXT: store i16 [[C_COERCE]], ptr [[C]], align 1 +// V8-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[C]], i32 0, i32 0 +// V8-NEXT: [[C_REAL:%.*]] = load i8, ptr [[C_REALP]], align 1 +// V8-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[C]], i32 0, i32 1 +// V8-NEXT: [[C_IMAG:%.*]] = load i8, ptr [[C_IMAGP]], align 1 +// V8-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[RETVAL]], i32 0, i32 0 +// V8-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[RETVAL]], i32 0, i32 1 +// V8-NEXT: store i8 [[C_REAL]], ptr [[RETVAL_REALP]], align 1 +// V8-NEXT: store i8 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 1 +// V8-NEXT: [[TMP0:%.*]] = load i16, ptr [[RETVAL]], align 1 +// V8-NEXT: ret i16 [[TMP0]] +// +// V9-LABEL: define dso_local i16 @complex_char( +// V9-SAME: i16 noundef [[C_COERCE:%.*]]) #[[ATTR0:[0-9]+]] { +// V9-NEXT: [[ENTRY:.*:]] +// V9-NEXT: [[RETVAL:%.*]] = alloca { i8, i8 }, align 1 +// V9-NEXT: [[C:%.*]] = alloca { i8, i8 }, align 1 +// V9-NEXT: store i16 [[C_COERCE]], ptr [[C]], align 1 +// V9-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[C]], i32 0, i32 0 +// V9-NEXT: [[C_REAL:%.*]] = load i8, ptr [[C_REALP]], align 1 +// V9-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[C]], i32 0, i32 1 +// V9-NEXT: [[C_IMAG:%.*]] = load i8, ptr [[C_IMAGP]], align 1 +// V9-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[RETVAL]], i32 0, i32 0 +// V9-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[RETVAL]], i32 0, i32 1 +// V9-NEXT: store i8 [[C_REAL]], ptr [[RETVAL_REALP]], align 1 +// V9-NEXT: store i8 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 1 +// V9-NEXT: [[TMP0:%.*]] = load i16, ptr [[RETVAL]], align 1 +// V9-NEXT: ret i16 [[TMP0]] +// +// COMPAT23-V8-LABEL: define dso_local { i8, i8 } @complex_char( +// COMPAT23-V8-SAME: ptr noundef byval({ i8, i8 }) align 1 [[C:%.*]]) #[[ATTR0:[0-9]+]] { +// COMPAT23-V8-NEXT: [[ENTRY:.*:]] +// COMPAT23-V8-NEXT: [[RETVAL:%.*]] = alloca { i8, i8 }, align 1 +// COMPAT23-V8-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V8-NEXT: [[C_REAL:%.*]] = load i8, ptr [[C_REALP]], align 1 +// COMPAT23-V8-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V8-NEXT: [[C_IMAG:%.*]] = load i8, ptr [[C_IMAGP]], align 1 +// COMPAT23-V8-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[RETVAL]], i32 0, i32 0 +// COMPAT23-V8-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[RETVAL]], i32 0, i32 1 +// COMPAT23-V8-NEXT: store i8 [[C_REAL]], ptr [[RETVAL_REALP]], align 1 +// COMPAT23-V8-NEXT: store i8 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 1 +// COMPAT23-V8-NEXT: [[TMP0:%.*]] = load { i8, i8 }, ptr [[RETVAL]], align 1 +// COMPAT23-V8-NEXT: ret { i8, i8 } [[TMP0]] +// +// COMPAT23-V9-LABEL: define dso_local i64 @complex_char( +// COMPAT23-V9-SAME: i64 [[C_COERCE:%.*]]) #[[ATTR0:[0-9]+]] { +// COMPAT23-V9-NEXT: [[ENTRY:.*:]] +// COMPAT23-V9-NEXT: [[RETVAL:%.*]] = alloca { i8, i8 }, align 1 +// COMPAT23-V9-NEXT: [[C:%.*]] = alloca { i8, i8 }, align 1 +// COMPAT23-V9-NEXT: [[RETVAL_COERCE:%.*]] = alloca i64, align 8 +// COMPAT23-V9-NEXT: [[COERCE_HIGHBITS:%.*]] = lshr i64 [[C_COERCE]], 48 +// COMPAT23-V9-NEXT: [[COERCE_VAL_II:%.*]] = trunc i64 [[COERCE_HIGHBITS]] to i16 +// COMPAT23-V9-NEXT: store i16 [[COERCE_VAL_II]], ptr [[C]], align 1 +// COMPAT23-V9-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V9-NEXT: [[C_REAL:%.*]] = load i8, ptr [[C_REALP]], align 1 +// COMPAT23-V9-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V9-NEXT: [[C_IMAG:%.*]] = load i8, ptr [[C_IMAGP]], align 1 +// COMPAT23-V9-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[RETVAL]], i32 0, i32 0 +// COMPAT23-V9-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[RETVAL]], i32 0, i32 1 +// COMPAT23-V9-NEXT: store i8 [[C_REAL]], ptr [[RETVAL_REALP]], align 1 +// COMPAT23-V9-NEXT: store i8 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 1 +// COMPAT23-V9-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL_COERCE]], ptr align 1 [[RETVAL]], i64 2, i1 false) +// COMPAT23-V9-NEXT: [[TMP0:%.*]] = load i64, ptr [[RETVAL_COERCE]], align 8 +// COMPAT23-V9-NEXT: ret i64 [[TMP0]] +// +_Complex char complex_char(_Complex char c) { return c; } -// COMPAT23-V8-LABEL: define{{.*}} void @arg_complex_char(ptr noundef byval({ i8, i8 }) align 1 %c) -// V8-LABEL: define{{.*}} void @arg_complex_char(i16 noundef %c.coerce) -// COMPAT23-V9-LABEL: define{{.*}} void @arg_complex_char(i64 %c.coerce) -// V9-LABEL: define{{.*}} void @arg_complex_char(i16 noundef %c.coerce) -void arg_complex_char(_Complex char c) {} +// V8-LABEL: define dso_local i32 @complex_short( +// V8-SAME: i32 noundef [[C_COERCE:%.*]]) #[[ATTR0]] { +// V8-NEXT: [[ENTRY:.*:]] +// V8-NEXT: [[RETVAL:%.*]] = alloca { i16, i16 }, align 2 +// V8-NEXT: [[C:%.*]] = alloca { i16, i16 }, align 2 +// V8-NEXT: store i32 [[C_COERCE]], ptr [[C]], align 2 +// V8-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i16, i16 }, ptr [[C]], i32 0, i32 0 +// V8-NEXT: [[C_REAL:%.*]] = load i16, ptr [[C_REALP]], align 2 +// V8-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i16, i16 }, ptr [[C]], i32 0, i32 1 +// V8-NEXT: [[C_IMAG:%.*]] = load i16, ptr [[C_IMAGP]], align 2 +// V8-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i16, i16 }, ptr [[RETVAL]], i32 0, i32 0 +// V8-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i16, i16 }, ptr [[RETVAL]], i32 0, i32 1 +// V8-NEXT: store i16 [[C_REAL]], ptr [[RETVAL_REALP]], align 2 +// V8-NEXT: store i16 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 2 +// V8-NEXT: [[TMP0:%.*]] = load i32, ptr [[RETVAL]], align 2 +// V8-NEXT: ret i32 [[TMP0]] +// +// V9-LABEL: define dso_local i32 @complex_short( +// V9-SAME: i32 noundef [[C_COERCE:%.*]]) #[[ATTR0]] { +// V9-NEXT: [[ENTRY:.*:]] +// V9-NEXT: [[RETVAL:%.*]] = alloca { i16, i16 }, align 2 +// V9-NEXT: [[C:%.*]] = alloca { i16, i16 }, align 2 +// V9-NEXT: store i32 [[C_COERCE]], ptr [[C]], align 2 +// V9-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i16, i16 }, ptr [[C]], i32 0, i32 0 +// V9-NEXT: [[C_REAL:%.*]] = load i16, ptr [[C_REALP]], align 2 +// V9-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i16, i16 }, ptr [[C]], i32 0, i32 1 +// V9-NEXT: [[C_IMAG:%.*]] = load i16, ptr [[C_IMAGP]], align 2 +// V9-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i16, i16 }, ptr [[RETVAL]], i32 0, i32 0 +// V9-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i16, i16 }, ptr [[RETVAL]], i32 0, i32 1 +// V9-NEXT: store i16 [[C_REAL]], ptr [[RETVAL_REALP]], align 2 +// V9-NEXT: store i16 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 2 +// V9-NEXT: [[TMP0:%.*]] = load i32, ptr [[RETVAL]], align 2 +// V9-NEXT: ret i32 [[TMP0]] +// +// COMPAT23-V8-LABEL: define dso_local { i16, i16 } @complex_short( +// COMPAT23-V8-SAME: ptr noundef byval({ i16, i16 }) align 2 [[C:%.*]]) #[[ATTR0]] { +// COMPAT23-V8-NEXT: [[ENTRY:.*:]] +// COMPAT23-V8-NEXT: [[RETVAL:%.*]] = alloca { i16, i16 }, align 2 +// COMPAT23-V8-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i16, i16 }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V8-NEXT: [[C_REAL:%.*]] = load i16, ptr [[C_REALP]], align 2 +// COMPAT23-V8-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i16, i16 }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V8-NEXT: [[C_IMAG:%.*]] = load i16, ptr [[C_IMAGP]], align 2 +// COMPAT23-V8-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i16, i16 }, ptr [[RETVAL]], i32 0, i32 0 +// COMPAT23-V8-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i16, i16 }, ptr [[RETVAL]], i32 0, i32 1 +// COMPAT23-V8-NEXT: store i16 [[C_REAL]], ptr [[RETVAL_REALP]], align 2 +// COMPAT23-V8-NEXT: store i16 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 2 +// COMPAT23-V8-NEXT: [[TMP0:%.*]] = load { i16, i16 }, ptr [[RETVAL]], align 2 +// COMPAT23-V8-NEXT: ret { i16, i16 } [[TMP0]] +// +// COMPAT23-V9-LABEL: define dso_local i64 @complex_short( +// COMPAT23-V9-SAME: i64 [[C_COERCE:%.*]]) #[[ATTR0]] { +// COMPAT23-V9-NEXT: [[ENTRY:.*:]] +// COMPAT23-V9-NEXT: [[RETVAL:%.*]] = alloca { i16, i16 }, align 2 +// COMPAT23-V9-NEXT: [[C:%.*]] = alloca { i16, i16 }, align 2 +// COMPAT23-V9-NEXT: [[RETVAL_COERCE:%.*]] = alloca i64, align 8 +// COMPAT23-V9-NEXT: [[COERCE_HIGHBITS:%.*]] = lshr i64 [[C_COERCE]], 32 +// COMPAT23-V9-NEXT: [[COERCE_VAL_II:%.*]] = trunc i64 [[COERCE_HIGHBITS]] to i32 +// COMPAT23-V9-NEXT: store i32 [[COERCE_VAL_II]], ptr [[C]], align 2 +// COMPAT23-V9-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i16, i16 }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V9-NEXT: [[C_REAL:%.*]] = load i16, ptr [[C_REALP]], align 2 +// COMPAT23-V9-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i16, i16 }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V9-NEXT: [[C_IMAG:%.*]] = load i16, ptr [[C_IMAGP]], align 2 +// COMPAT23-V9-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i16, i16 }, ptr [[RETVAL]], i32 0, i32 0 +// COMPAT23-V9-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i16, i16 }, ptr [[RETVAL]], i32 0, i32 1 +// COMPAT23-V9-NEXT: store i16 [[C_REAL]], ptr [[RETVAL_REALP]], align 2 +// COMPAT23-V9-NEXT: store i16 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 2 +// COMPAT23-V9-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL_COERCE]], ptr align 2 [[RETVAL]], i64 4, i1 false) +// COMPAT23-V9-NEXT: [[TMP0:%.*]] = load i64, ptr [[RETVAL_COERCE]], align 8 +// COMPAT23-V9-NEXT: ret i64 [[TMP0]] +// +_Complex short complex_short(_Complex short c) { return c; } -// COMPAT23-V8-LABEL: define{{.*}} void @arg_complex_short(ptr noundef byval({ i16, i16 }) align 2 %c) -// V8-LABEL: define{{.*}} void @arg_complex_short(i32 noundef %c.coerce) -// COMPAT23-V9-LABEL: define{{.*}} void @arg_complex_short(i64 %c.coerce) -// V9-LABEL: define{{.*}} void @arg_complex_short(i32 noundef %c.coerce) -void arg_complex_short(_Complex short c) {} +// V8-LABEL: define dso_local i64 @complex_int( +// V8-SAME: i64 noundef [[C_COERCE:%.*]]) #[[ATTR0]] { +// V8-NEXT: [[ENTRY:.*:]] +// V8-NEXT: [[RETVAL:%.*]] = alloca { i32, i32 }, align 4 +// V8-NEXT: [[C:%.*]] = alloca { i32, i32 }, align 4 +// V8-NEXT: store i64 [[C_COERCE]], ptr [[C]], align 4 +// V8-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[C]], i32 0, i32 0 +// V8-NEXT: [[C_REAL:%.*]] = load i32, ptr [[C_REALP]], align 4 +// V8-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[C]], i32 0, i32 1 +// V8-NEXT: [[C_IMAG:%.*]] = load i32, ptr [[C_IMAGP]], align 4 +// V8-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[RETVAL]], i32 0, i32 0 +// V8-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[RETVAL]], i32 0, i32 1 +// V8-NEXT: store i32 [[C_REAL]], ptr [[RETVAL_REALP]], align 4 +// V8-NEXT: store i32 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 4 +// V8-NEXT: [[TMP0:%.*]] = load i64, ptr [[RETVAL]], align 4 +// V8-NEXT: ret i64 [[TMP0]] +// +// V9-LABEL: define dso_local i64 @complex_int( +// V9-SAME: i64 noundef [[C_COERCE:%.*]]) #[[ATTR0]] { +// V9-NEXT: [[ENTRY:.*:]] +// V9-NEXT: [[RETVAL:%.*]] = alloca { i32, i32 }, align 4 +// V9-NEXT: [[C:%.*]] = alloca { i32, i32 }, align 4 +// V9-NEXT: store i64 [[C_COERCE]], ptr [[C]], align 4 +// V9-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[C]], i32 0, i32 0 +// V9-NEXT: [[C_REAL:%.*]] = load i32, ptr [[C_REALP]], align 4 +// V9-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[C]], i32 0, i32 1 +// V9-NEXT: [[C_IMAG:%.*]] = load i32, ptr [[C_IMAGP]], align 4 +// V9-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[RETVAL]], i32 0, i32 0 +// V9-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[RETVAL]], i32 0, i32 1 +// V9-NEXT: store i32 [[C_REAL]], ptr [[RETVAL_REALP]], align 4 +// V9-NEXT: store i32 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 4 +// V9-NEXT: [[TMP0:%.*]] = load i64, ptr [[RETVAL]], align 4 +// V9-NEXT: ret i64 [[TMP0]] +// +// COMPAT23-V8-LABEL: define dso_local { i32, i32 } @complex_int( +// COMPAT23-V8-SAME: ptr noundef byval({ i32, i32 }) align 4 [[C:%.*]]) #[[ATTR0]] { +// COMPAT23-V8-NEXT: [[ENTRY:.*:]] +// COMPAT23-V8-NEXT: [[RETVAL:%.*]] = alloca { i32, i32 }, align 4 +// COMPAT23-V8-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V8-NEXT: [[C_REAL:%.*]] = load i32, ptr [[C_REALP]], align 4 +// COMPAT23-V8-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V8-NEXT: [[C_IMAG:%.*]] = load i32, ptr [[C_IMAGP]], align 4 +// COMPAT23-V8-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[RETVAL]], i32 0, i32 0 +// COMPAT23-V8-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[RETVAL]], i32 0, i32 1 +// COMPAT23-V8-NEXT: store i32 [[C_REAL]], ptr [[RETVAL_REALP]], align 4 +// COMPAT23-V8-NEXT: store i32 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 4 +// COMPAT23-V8-NEXT: [[TMP0:%.*]] = load { i32, i32 }, ptr [[RETVAL]], align 4 +// COMPAT23-V8-NEXT: ret { i32, i32 } [[TMP0]] +// +// COMPAT23-V9-LABEL: define dso_local i64 @complex_int( +// COMPAT23-V9-SAME: i64 noundef [[C_COERCE:%.*]]) #[[ATTR0]] { +// COMPAT23-V9-NEXT: [[ENTRY:.*:]] +// COMPAT23-V9-NEXT: [[RETVAL:%.*]] = alloca { i32, i32 }, align 4 +// COMPAT23-V9-NEXT: [[C:%.*]] = alloca { i32, i32 }, align 4 +// COMPAT23-V9-NEXT: store i64 [[C_COERCE]], ptr [[C]], align 4 +// COMPAT23-V9-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V9-NEXT: [[C_REAL:%.*]] = load i32, ptr [[C_REALP]], align 4 +// COMPAT23-V9-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V9-NEXT: [[C_IMAG:%.*]] = load i32, ptr [[C_IMAGP]], align 4 +// COMPAT23-V9-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[RETVAL]], i32 0, i32 0 +// COMPAT23-V9-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[RETVAL]], i32 0, i32 1 +// COMPAT23-V9-NEXT: store i32 [[C_REAL]], ptr [[RETVAL_REALP]], align 4 +// COMPAT23-V9-NEXT: store i32 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 4 +// COMPAT23-V9-NEXT: [[TMP0:%.*]] = load i64, ptr [[RETVAL]], align 4 +// COMPAT23-V9-NEXT: ret i64 [[TMP0]] +// +_Complex int complex_int(_Complex int c) { return c; } -// COMPAT23-V8-LABEL: define{{.*}} void @arg_complex_int(ptr noundef byval({ i32, i32 }) align 4 %c) -// V8-LABEL: define{{.*}} void @arg_complex_int(i64 noundef %c.coerce) -// COMPAT23-V9-LABEL: define{{.*}} void @arg_complex_int(i64 noundef %c.coerce) -// V9-LABEL: define{{.*}} void @arg_complex_int(i64 noundef %c.coerce) -void arg_complex_int(_Complex int c) {} +// V8-LABEL: define dso_local i64 @complex_long( +// V8-SAME: i64 noundef [[C_COERCE:%.*]]) #[[ATTR0]] { +// V8-NEXT: [[ENTRY:.*:]] +// V8-NEXT: [[RETVAL:%.*]] = alloca { i32, i32 }, align 4 +// V8-NEXT: [[C:%.*]] = alloca { i32, i32 }, align 4 +// V8-NEXT: store i64 [[C_COERCE]], ptr [[C]], align 4 +// V8-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[C]], i32 0, i32 0 +// V8-NEXT: [[C_REAL:%.*]] = load i32, ptr [[C_REALP]], align 4 +// V8-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[C]], i32 0, i32 1 +// V8-NEXT: [[C_IMAG:%.*]] = load i32, ptr [[C_IMAGP]], align 4 +// V8-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[RETVAL]], i32 0, i32 0 +// V8-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[RETVAL]], i32 0, i32 1 +// V8-NEXT: store i32 [[C_REAL]], ptr [[RETVAL_REALP]], align 4 +// V8-NEXT: store i32 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 4 +// V8-NEXT: [[TMP0:%.*]] = load i64, ptr [[RETVAL]], align 4 +// V8-NEXT: ret i64 [[TMP0]] +// +// V9-LABEL: define dso_local { i64, i64 } @complex_long( +// V9-SAME: i64 noundef [[C_COERCE0:%.*]], i64 noundef [[C_COERCE1:%.*]]) #[[ATTR0]] { +// V9-NEXT: [[ENTRY:.*:]] +// V9-NEXT: [[RETVAL:%.*]] = alloca { i64, i64 }, align 8 +// V9-NEXT: [[C:%.*]] = alloca { i64, i64 }, align 8 +// V9-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 0 +// V9-NEXT: store i64 [[C_COERCE0]], ptr [[TMP0]], align 8 +// V9-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 1 +// V9-NEXT: store i64 [[C_COERCE1]], ptr [[TMP1]], align 8 +// V9-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 0 +// V9-NEXT: [[C_REAL:%.*]] = load i64, ptr [[C_REALP]], align 8 +// V9-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 1 +// V9-NEXT: [[C_IMAG:%.*]] = load i64, ptr [[C_IMAGP]], align 8 +// V9-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[RETVAL]], i32 0, i32 0 +// V9-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[RETVAL]], i32 0, i32 1 +// V9-NEXT: store i64 [[C_REAL]], ptr [[RETVAL_REALP]], align 8 +// V9-NEXT: store i64 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 8 +// V9-NEXT: [[TMP2:%.*]] = load { i64, i64 }, ptr [[RETVAL]], align 8 +// V9-NEXT: ret { i64, i64 } [[TMP2]] +// +// COMPAT23-V8-LABEL: define dso_local { i32, i32 } @complex_long( +// COMPAT23-V8-SAME: ptr noundef byval({ i32, i32 }) align 4 [[C:%.*]]) #[[ATTR0]] { +// COMPAT23-V8-NEXT: [[ENTRY:.*:]] +// COMPAT23-V8-NEXT: [[RETVAL:%.*]] = alloca { i32, i32 }, align 4 +// COMPAT23-V8-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V8-NEXT: [[C_REAL:%.*]] = load i32, ptr [[C_REALP]], align 4 +// COMPAT23-V8-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V8-NEXT: [[C_IMAG:%.*]] = load i32, ptr [[C_IMAGP]], align 4 +// COMPAT23-V8-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[RETVAL]], i32 0, i32 0 +// COMPAT23-V8-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[RETVAL]], i32 0, i32 1 +// COMPAT23-V8-NEXT: store i32 [[C_REAL]], ptr [[RETVAL_REALP]], align 4 +// COMPAT23-V8-NEXT: store i32 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 4 +// COMPAT23-V8-NEXT: [[TMP0:%.*]] = load { i32, i32 }, ptr [[RETVAL]], align 4 +// COMPAT23-V8-NEXT: ret { i32, i32 } [[TMP0]] +// +// COMPAT23-V9-LABEL: define dso_local { i64, i64 } @complex_long( +// COMPAT23-V9-SAME: i64 noundef [[C_COERCE0:%.*]], i64 noundef [[C_COERCE1:%.*]]) #[[ATTR0]] { +// COMPAT23-V9-NEXT: [[ENTRY:.*:]] +// COMPAT23-V9-NEXT: [[RETVAL:%.*]] = alloca { i64, i64 }, align 8 +// COMPAT23-V9-NEXT: [[C:%.*]] = alloca { i64, i64 }, align 8 +// COMPAT23-V9-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V9-NEXT: store i64 [[C_COERCE0]], ptr [[TMP0]], align 8 +// COMPAT23-V9-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V9-NEXT: store i64 [[C_COERCE1]], ptr [[TMP1]], align 8 +// COMPAT23-V9-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V9-NEXT: [[C_REAL:%.*]] = load i64, ptr [[C_REALP]], align 8 +// COMPAT23-V9-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V9-NEXT: [[C_IMAG:%.*]] = load i64, ptr [[C_IMAGP]], align 8 +// COMPAT23-V9-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[RETVAL]], i32 0, i32 0 +// COMPAT23-V9-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[RETVAL]], i32 0, i32 1 +// COMPAT23-V9-NEXT: store i64 [[C_REAL]], ptr [[RETVAL_REALP]], align 8 +// COMPAT23-V9-NEXT: store i64 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 8 +// COMPAT23-V9-NEXT: [[TMP2:%.*]] = load { i64, i64 }, ptr [[RETVAL]], align 8 +// COMPAT23-V9-NEXT: ret { i64, i64 } [[TMP2]] +// +_Complex long complex_long(_Complex long c) { return c; } -// COMPAT23-V8-LABEL: define{{.*}} void @arg_complex_long_long(ptr noundef byval({ i64, i64 }) align 8 %c) -// V8-LABEL: define{{.*}} void @arg_complex_long_long(ptr noundef byval({ i64, i64 }) align 8 %c) -// COMPAT23-V9-LABEL: define{{.*}} void @arg_complex_long_long(i64 noundef %c.coerce0, i64 noundef %c.coerce1) -// V9-LABEL: define{{.*}} void @arg_complex_long_long(i64 noundef %c.coerce0, i64 noundef %c.coerce1) -void arg_complex_long_long(_Complex long long c) {} +// V8-LABEL: define dso_local { i64, i64 } @complex_long_long( +// V8-SAME: ptr noundef byval({ i64, i64 }) align 8 [[C:%.*]]) #[[ATTR0]] { +// V8-NEXT: [[ENTRY:.*:]] +// V8-NEXT: [[RETVAL:%.*]] = alloca { i64, i64 }, align 8 +// V8-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 0 +// V8-NEXT: [[C_REAL:%.*]] = load i64, ptr [[C_REALP]], align 8 +// V8-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 1 +// V8-NEXT: [[C_IMAG:%.*]] = load i64, ptr [[C_IMAGP]], align 8 +// V8-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[RETVAL]], i32 0, i32 0 +// V8-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[RETVAL]], i32 0, i32 1 +// V8-NEXT: store i64 [[C_REAL]], ptr [[RETVAL_REALP]], align 8 +// V8-NEXT: store i64 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 8 +// V8-NEXT: [[TMP0:%.*]] = load { i64, i64 }, ptr [[RETVAL]], align 8 +// V8-NEXT: ret { i64, i64 } [[TMP0]] +// +// V9-LABEL: define dso_local { i64, i64 } @complex_long_long( +// V9-SAME: i64 noundef [[C_COERCE0:%.*]], i64 noundef [[C_COERCE1:%.*]]) #[[ATTR0]] { +// V9-NEXT: [[ENTRY:.*:]] +// V9-NEXT: [[RETVAL:%.*]] = alloca { i64, i64 }, align 8 +// V9-NEXT: [[C:%.*]] = alloca { i64, i64 }, align 8 +// V9-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 0 +// V9-NEXT: store i64 [[C_COERCE0]], ptr [[TMP0]], align 8 +// V9-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 1 +// V9-NEXT: store i64 [[C_COERCE1]], ptr [[TMP1]], align 8 +// V9-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 0 +// V9-NEXT: [[C_REAL:%.*]] = load i64, ptr [[C_REALP]], align 8 +// V9-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 1 +// V9-NEXT: [[C_IMAG:%.*]] = load i64, ptr [[C_IMAGP]], align 8 +// V9-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[RETVAL]], i32 0, i32 0 +// V9-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[RETVAL]], i32 0, i32 1 +// V9-NEXT: store i64 [[C_REAL]], ptr [[RETVAL_REALP]], align 8 +// V9-NEXT: store i64 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 8 +// V9-NEXT: [[TMP2:%.*]] = load { i64, i64 }, ptr [[RETVAL]], align 8 +// V9-NEXT: ret { i64, i64 } [[TMP2]] +// +// COMPAT23-V8-LABEL: define dso_local { i64, i64 } @complex_long_long( +// COMPAT23-V8-SAME: ptr noundef byval({ i64, i64 }) align 8 [[C:%.*]]) #[[ATTR0]] { +// COMPAT23-V8-NEXT: [[ENTRY:.*:]] +// COMPAT23-V8-NEXT: [[RETVAL:%.*]] = alloca { i64, i64 }, align 8 +// COMPAT23-V8-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V8-NEXT: [[C_REAL:%.*]] = load i64, ptr [[C_REALP]], align 8 +// COMPAT23-V8-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V8-NEXT: [[C_IMAG:%.*]] = load i64, ptr [[C_IMAGP]], align 8 +// COMPAT23-V8-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[RETVAL]], i32 0, i32 0 +// COMPAT23-V8-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[RETVAL]], i32 0, i32 1 +// COMPAT23-V8-NEXT: store i64 [[C_REAL]], ptr [[RETVAL_REALP]], align 8 +// COMPAT23-V8-NEXT: store i64 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 8 +// COMPAT23-V8-NEXT: [[TMP0:%.*]] = load { i64, i64 }, ptr [[RETVAL]], align 8 +// COMPAT23-V8-NEXT: ret { i64, i64 } [[TMP0]] +// +// COMPAT23-V9-LABEL: define dso_local { i64, i64 } @complex_long_long( +// COMPAT23-V9-SAME: i64 noundef [[C_COERCE0:%.*]], i64 noundef [[C_COERCE1:%.*]]) #[[ATTR0]] { +// COMPAT23-V9-NEXT: [[ENTRY:.*:]] +// COMPAT23-V9-NEXT: [[RETVAL:%.*]] = alloca { i64, i64 }, align 8 +// COMPAT23-V9-NEXT: [[C:%.*]] = alloca { i64, i64 }, align 8 +// COMPAT23-V9-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V9-NEXT: store i64 [[C_COERCE0]], ptr [[TMP0]], align 8 +// COMPAT23-V9-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V9-NEXT: store i64 [[C_COERCE1]], ptr [[TMP1]], align 8 +// COMPAT23-V9-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V9-NEXT: [[C_REAL:%.*]] = load i64, ptr [[C_REALP]], align 8 +// COMPAT23-V9-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V9-NEXT: [[C_IMAG:%.*]] = load i64, ptr [[C_IMAGP]], align 8 +// COMPAT23-V9-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[RETVAL]], i32 0, i32 0 +// COMPAT23-V9-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[RETVAL]], i32 0, i32 1 +// COMPAT23-V9-NEXT: store i64 [[C_REAL]], ptr [[RETVAL_REALP]], align 8 +// COMPAT23-V9-NEXT: store i64 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 8 +// COMPAT23-V9-NEXT: [[TMP2:%.*]] = load { i64, i64 }, ptr [[RETVAL]], align 8 +// COMPAT23-V9-NEXT: ret { i64, i64 } [[TMP2]] +// +_Complex long long complex_long_long(_Complex long long c) { return c; } -// COMPAT23-V8-LABEL: define{{.*}} void @arg_complex_float(ptr noundef byval({ float, float }) align 4 %c) -// V8-LABEL: define{{.*}} void @arg_complex_float(ptr noundef byval({ float, float }) align 4 %c) -// COMPAT23-V9-LABEL: define{{.*}} void @arg_complex_float(float inreg noundef %c.coerce0, float inreg noundef %c.coerce1) -// V9-LABEL: define{{.*}} void @arg_complex_float(float inreg noundef %c.coerce0, float inreg noundef %c.coerce1) -void arg_complex_float(_Complex float c) {} +// V8-LABEL: define dso_local { float, float } @complex_float( +// V8-SAME: ptr noundef byval({ float, float }) align 4 [[C:%.*]]) #[[ATTR0]] { +// V8-NEXT: [[ENTRY:.*:]] +// V8-NEXT: [[RETVAL:%.*]] = alloca { float, float }, align 4 +// V8-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[C]], i32 0, i32 0 +// V8-NEXT: [[C_REAL:%.*]] = load float, ptr [[C_REALP]], align 4 +// V8-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[C]], i32 0, i32 1 +// V8-NEXT: [[C_IMAG:%.*]] = load float, ptr [[C_IMAGP]], align 4 +// V8-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[RETVAL]], i32 0, i32 0 +// V8-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[RETVAL]], i32 0, i32 1 +// V8-NEXT: store float [[C_REAL]], ptr [[RETVAL_REALP]], align 4 +// V8-NEXT: store float [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 4 +// V8-NEXT: [[TMP0:%.*]] = load { float, float }, ptr [[RETVAL]], align 4 +// V8-NEXT: ret { float, float } [[TMP0]] +// +// V9-LABEL: define dso_local inreg { float, float } @complex_float( +// V9-SAME: float inreg noundef [[C_COERCE0:%.*]], float inreg noundef [[C_COERCE1:%.*]]) #[[ATTR0]] { +// V9-NEXT: [[ENTRY:.*:]] +// V9-NEXT: [[RETVAL:%.*]] = alloca { float, float }, align 4 +// V9-NEXT: [[C:%.*]] = alloca { float, float }, align 4 +// V9-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[C]], i32 0, i32 0 +// V9-NEXT: store float [[C_COERCE0]], ptr [[TMP0]], align 4 +// V9-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[C]], i32 0, i32 1 +// V9-NEXT: store float [[C_COERCE1]], ptr [[TMP1]], align 4 +// V9-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[C]], i32 0, i32 0 +// V9-NEXT: [[C_REAL:%.*]] = load float, ptr [[C_REALP]], align 4 +// V9-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[C]], i32 0, i32 1 +// V9-NEXT: [[C_IMAG:%.*]] = load float, ptr [[C_IMAGP]], align 4 +// V9-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[RETVAL]], i32 0, i32 0 +// V9-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[RETVAL]], i32 0, i32 1 +// V9-NEXT: store float [[C_REAL]], ptr [[RETVAL_REALP]], align 4 +// V9-NEXT: store float [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 4 +// V9-NEXT: [[TMP2:%.*]] = load { float, float }, ptr [[RETVAL]], align 4 +// V9-NEXT: ret { float, float } [[TMP2]] +// +// COMPAT23-V8-LABEL: define dso_local { float, float } @complex_float( +// COMPAT23-V8-SAME: ptr noundef byval({ float, float }) align 4 [[C:%.*]]) #[[ATTR0]] { +// COMPAT23-V8-NEXT: [[ENTRY:.*:]] +// COMPAT23-V8-NEXT: [[RETVAL:%.*]] = alloca { float, float }, align 4 +// COMPAT23-V8-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V8-NEXT: [[C_REAL:%.*]] = load float, ptr [[C_REALP]], align 4 +// COMPAT23-V8-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V8-NEXT: [[C_IMAG:%.*]] = load float, ptr [[C_IMAGP]], align 4 +// COMPAT23-V8-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[RETVAL]], i32 0, i32 0 +// COMPAT23-V8-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[RETVAL]], i32 0, i32 1 +// COMPAT23-V8-NEXT: store float [[C_REAL]], ptr [[RETVAL_REALP]], align 4 +// COMPAT23-V8-NEXT: store float [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 4 +// COMPAT23-V8-NEXT: [[TMP0:%.*]] = load { float, float }, ptr [[RETVAL]], align 4 +// COMPAT23-V8-NEXT: ret { float, float } [[TMP0]] +// +// COMPAT23-V9-LABEL: define dso_local inreg { float, float } @complex_float( +// COMPAT23-V9-SAME: float inreg noundef [[C_COERCE0:%.*]], float inreg noundef [[C_COERCE1:%.*]]) #[[ATTR0]] { +// COMPAT23-V9-NEXT: [[ENTRY:.*:]] +// COMPAT23-V9-NEXT: [[RETVAL:%.*]] = alloca { float, float }, align 4 +// COMPAT23-V9-NEXT: [[C:%.*]] = alloca { float, float }, align 4 +// COMPAT23-V9-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V9-NEXT: store float [[C_COERCE0]], ptr [[TMP0]], align 4 +// COMPAT23-V9-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V9-NEXT: store float [[C_COERCE1]], ptr [[TMP1]], align 4 +// COMPAT23-V9-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V9-NEXT: [[C_REAL:%.*]] = load float, ptr [[C_REALP]], align 4 +// COMPAT23-V9-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V9-NEXT: [[C_IMAG:%.*]] = load float, ptr [[C_IMAGP]], align 4 +// COMPAT23-V9-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[RETVAL]], i32 0, i32 0 +// COMPAT23-V9-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[RETVAL]], i32 0, i32 1 +// COMPAT23-V9-NEXT: store float [[C_REAL]], ptr [[RETVAL_REALP]], align 4 +// COMPAT23-V9-NEXT: store float [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 4 +// COMPAT23-V9-NEXT: [[TMP2:%.*]] = load { float, float }, ptr [[RETVAL]], align 4 +// COMPAT23-V9-NEXT: ret { float, float } [[TMP2]] +// +_Complex float complex_float(_Complex float c) { return c; } -// COMPAT23-V8-LABEL: define{{.*}} void @arg_complex_double(ptr noundef byval({ double, double }) align 8 %c) -// V8-LABEL: define{{.*}} void @arg_complex_double(ptr noundef byval({ double, double }) align 8 %c) -// COMPAT23-V9-LABEL: define{{.*}} void @arg_complex_double(double noundef %c.coerce0, double noundef %c.coerce1) -// V9-LABEL: define{{.*}} void @arg_complex_double(double noundef %c.coerce0, double noundef %c.coerce1) -void arg_complex_double(_Complex double c) {} +// V8-LABEL: define dso_local { double, double } @complex_double( +// V8-SAME: ptr noundef byval({ double, double }) align 8 [[C:%.*]]) #[[ATTR0]] { +// V8-NEXT: [[ENTRY:.*:]] +// V8-NEXT: [[RETVAL:%.*]] = alloca { double, double }, align 8 +// V8-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[C]], i32 0, i32 0 +// V8-NEXT: [[C_REAL:%.*]] = load double, ptr [[C_REALP]], align 8 +// V8-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[C]], i32 0, i32 1 +// V8-NEXT: [[C_IMAG:%.*]] = load double, ptr [[C_IMAGP]], align 8 +// V8-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 0 +// V8-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 1 +// V8-NEXT: store double [[C_REAL]], ptr [[RETVAL_REALP]], align 8 +// V8-NEXT: store double [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 8 +// V8-NEXT: [[TMP0:%.*]] = load { double, double }, ptr [[RETVAL]], align 8 +// V8-NEXT: ret { double, double } [[TMP0]] +// +// V9-LABEL: define dso_local { double, double } @complex_double( +// V9-SAME: double noundef [[C_COERCE0:%.*]], double noundef [[C_COERCE1:%.*]]) #[[ATTR0]] { +// V9-NEXT: [[ENTRY:.*:]] +// V9-NEXT: [[RETVAL:%.*]] = alloca { double, double }, align 8 +// V9-NEXT: [[C:%.*]] = alloca { double, double }, align 8 +// V9-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[C]], i32 0, i32 0 +// V9-NEXT: store double [[C_COERCE0]], ptr [[TMP0]], align 8 +// V9-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[C]], i32 0, i32 1 +// V9-NEXT: store double [[C_COERCE1]], ptr [[TMP1]], align 8 +// V9-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[C]], i32 0, i32 0 +// V9-NEXT: [[C_REAL:%.*]] = load double, ptr [[C_REALP]], align 8 +// V9-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[C]], i32 0, i32 1 +// V9-NEXT: [[C_IMAG:%.*]] = load double, ptr [[C_IMAGP]], align 8 +// V9-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 0 +// V9-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 1 +// V9-NEXT: store double [[C_REAL]], ptr [[RETVAL_REALP]], align 8 +// V9-NEXT: store double [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 8 +// V9-NEXT: [[TMP2:%.*]] = load { double, double }, ptr [[RETVAL]], align 8 +// V9-NEXT: ret { double, double } [[TMP2]] +// +// COMPAT23-V8-LABEL: define dso_local { double, double } @complex_double( +// COMPAT23-V8-SAME: ptr noundef byval({ double, double }) align 8 [[C:%.*]]) #[[ATTR0]] { +// COMPAT23-V8-NEXT: [[ENTRY:.*:]] +// COMPAT23-V8-NEXT: [[RETVAL:%.*]] = alloca { double, double }, align 8 +// COMPAT23-V8-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V8-NEXT: [[C_REAL:%.*]] = load double, ptr [[C_REALP]], align 8 +// COMPAT23-V8-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V8-NEXT: [[C_IMAG:%.*]] = load double, ptr [[C_IMAGP]], align 8 +// COMPAT23-V8-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 0 +// COMPAT23-V8-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 1 +// COMPAT23-V8-NEXT: store double [[C_REAL]], ptr [[RETVAL_REALP]], align 8 +// COMPAT23-V8-NEXT: store double [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 8 +// COMPAT23-V8-NEXT: [[TMP0:%.*]] = load { double, double }, ptr [[RETVAL]], align 8 +// COMPAT23-V8-NEXT: ret { double, double } [[TMP0]] +// +// COMPAT23-V9-LABEL: define dso_local { double, double } @complex_double( +// COMPAT23-V9-SAME: double noundef [[C_COERCE0:%.*]], double noundef [[C_COERCE1:%.*]]) #[[ATTR0]] { +// COMPAT23-V9-NEXT: [[ENTRY:.*:]] +// COMPAT23-V9-NEXT: [[RETVAL:%.*]] = alloca { double, double }, align 8 +// COMPAT23-V9-NEXT: [[C:%.*]] = alloca { double, double }, align 8 +// COMPAT23-V9-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V9-NEXT: store double [[C_COERCE0]], ptr [[TMP0]], align 8 +// COMPAT23-V9-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V9-NEXT: store double [[C_COERCE1]], ptr [[TMP1]], align 8 +// COMPAT23-V9-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V9-NEXT: [[C_REAL:%.*]] = load double, ptr [[C_REALP]], align 8 +// COMPAT23-V9-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V9-NEXT: [[C_IMAG:%.*]] = load double, ptr [[C_IMAGP]], align 8 +// COMPAT23-V9-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 0 +// COMPAT23-V9-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 1 +// COMPAT23-V9-NEXT: store double [[C_REAL]], ptr [[RETVAL_REALP]], align 8 +// COMPAT23-V9-NEXT: store double [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 8 +// COMPAT23-V9-NEXT: [[TMP2:%.*]] = load { double, double }, ptr [[RETVAL]], align 8 +// COMPAT23-V9-NEXT: ret { double, double } [[TMP2]] +// +_Complex double complex_double(_Complex double c) { return c; } -// COMPAT23-V8-LABEL: define{{.*}} void @arg_complex_long_double(ptr noundef byval({ fp128, fp128 }) align 8 %c) -// V8-LABEL: define{{.*}} void @arg_complex_long_double(ptr noundef byval({ fp128, fp128 }) align 8 %c) -// COMPAT23-V9-LABEL: define{{.*}} void @arg_complex_long_double(ptr noundef align 16 dead_on_return %c) -// V9-LABEL: define{{.*}} void @arg_complex_long_double(ptr noundef align 16 dead_on_return %c) -void arg_complex_long_double(_Complex long double c) {} +// V8-LABEL: define dso_local inreg { fp128, fp128 } @complex_long_double( +// V8-SAME: ptr noundef byval({ fp128, fp128 }) align 8 [[C:%.*]]) #[[ATTR0]] { +// V8-NEXT: [[ENTRY:.*:]] +// V8-NEXT: [[RETVAL:%.*]] = alloca { fp128, fp128 }, align 8 +// V8-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[C]], i32 0, i32 0 +// V8-NEXT: [[C_REAL:%.*]] = load fp128, ptr [[C_REALP]], align 8 +// V8-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[C]], i32 0, i32 1 +// V8-NEXT: [[C_IMAG:%.*]] = load fp128, ptr [[C_IMAGP]], align 8 +// V8-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[RETVAL]], i32 0, i32 0 +// V8-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[RETVAL]], i32 0, i32 1 +// V8-NEXT: store fp128 [[C_REAL]], ptr [[RETVAL_REALP]], align 8 +// V8-NEXT: store fp128 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 8 +// V8-NEXT: [[TMP0:%.*]] = load { fp128, fp128 }, ptr [[RETVAL]], align 8 +// V8-NEXT: ret { fp128, fp128 } [[TMP0]] +// +// V9-LABEL: define dso_local { fp128, fp128 } @complex_long_double( +// V9-SAME: ptr noundef align 16 dead_on_return [[C:%.*]]) #[[ATTR0]] { +// V9-NEXT: [[ENTRY:.*:]] +// V9-NEXT: [[RETVAL:%.*]] = alloca { fp128, fp128 }, align 16 +// V9-NEXT: [[C_INDIRECT_ADDR:%.*]] = alloca ptr, align 8 +// V9-NEXT: store ptr [[C]], ptr [[C_INDIRECT_ADDR]], align 8 +// V9-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[C]], i32 0, i32 0 +// V9-NEXT: [[C_REAL:%.*]] = load fp128, ptr [[C_REALP]], align 16 +// V9-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[C]], i32 0, i32 1 +// V9-NEXT: [[C_IMAG:%.*]] = load fp128, ptr [[C_IMAGP]], align 16 +// V9-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[RETVAL]], i32 0, i32 0 +// V9-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[RETVAL]], i32 0, i32 1 +// V9-NEXT: store fp128 [[C_REAL]], ptr [[RETVAL_REALP]], align 16 +// V9-NEXT: store fp128 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 16 +// V9-NEXT: [[TMP0:%.*]] = load { fp128, fp128 }, ptr [[RETVAL]], align 16 +// V9-NEXT: ret { fp128, fp128 } [[TMP0]] +// +// COMPAT23-V8-LABEL: define dso_local inreg { fp128, fp128 } @complex_long_double( +// COMPAT23-V8-SAME: ptr noundef byval({ fp128, fp128 }) align 8 [[C:%.*]]) #[[ATTR0]] { +// COMPAT23-V8-NEXT: [[ENTRY:.*:]] +// COMPAT23-V8-NEXT: [[RETVAL:%.*]] = alloca { fp128, fp128 }, align 8 +// COMPAT23-V8-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V8-NEXT: [[C_REAL:%.*]] = load fp128, ptr [[C_REALP]], align 8 +// COMPAT23-V8-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V8-NEXT: [[C_IMAG:%.*]] = load fp128, ptr [[C_IMAGP]], align 8 +// COMPAT23-V8-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[RETVAL]], i32 0, i32 0 +// COMPAT23-V8-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[RETVAL]], i32 0, i32 1 +// COMPAT23-V8-NEXT: store fp128 [[C_REAL]], ptr [[RETVAL_REALP]], align 8 +// COMPAT23-V8-NEXT: store fp128 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 8 +// COMPAT23-V8-NEXT: [[TMP0:%.*]] = load { fp128, fp128 }, ptr [[RETVAL]], align 8 +// COMPAT23-V8-NEXT: ret { fp128, fp128 } [[TMP0]] +// +// COMPAT23-V9-LABEL: define dso_local { fp128, fp128 } @complex_long_double( +// COMPAT23-V9-SAME: ptr noundef align 16 dead_on_return [[C:%.*]]) #[[ATTR0]] { +// COMPAT23-V9-NEXT: [[ENTRY:.*:]] +// COMPAT23-V9-NEXT: [[RETVAL:%.*]] = alloca { fp128, fp128 }, align 16 +// COMPAT23-V9-NEXT: [[C_INDIRECT_ADDR:%.*]] = alloca ptr, align 8 +// COMPAT23-V9-NEXT: store ptr [[C]], ptr [[C_INDIRECT_ADDR]], align 8 +// COMPAT23-V9-NEXT: [[C_REALP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[C]], i32 0, i32 0 +// COMPAT23-V9-NEXT: [[C_REAL:%.*]] = load fp128, ptr [[C_REALP]], align 16 +// COMPAT23-V9-NEXT: [[C_IMAGP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[C]], i32 0, i32 1 +// COMPAT23-V9-NEXT: [[C_IMAG:%.*]] = load fp128, ptr [[C_IMAGP]], align 16 +// COMPAT23-V9-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[RETVAL]], i32 0, i32 0 +// COMPAT23-V9-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[RETVAL]], i32 0, i32 1 +// COMPAT23-V9-NEXT: store fp128 [[C_REAL]], ptr [[RETVAL_REALP]], align 16 +// COMPAT23-V9-NEXT: store fp128 [[C_IMAG]], ptr [[RETVAL_IMAGP]], align 16 +// COMPAT23-V9-NEXT: [[TMP0:%.*]] = load { fp128, fp128 }, ptr [[RETVAL]], align 16 +// COMPAT23-V9-NEXT: ret { fp128, fp128 } [[TMP0]] +// +_Complex long double complex_long_double(_Complex long double c) { return c; } >From 16581565671b23dee2433c37745b3f98d8bf95fe Mon Sep 17 00:00:00 2001 From: Folkert de Vries <[email protected]> Date: Sat, 1 Aug 2026 23:29:29 +0200 Subject: [PATCH 3/6] make isComplexGnuABI a member variable --- clang/lib/CodeGen/Targets/Sparc.cpp | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp b/clang/lib/CodeGen/Targets/Sparc.cpp index abc72468316f8..2ea5c1a4ea2d5 100644 --- a/clang/lib/CodeGen/Targets/Sparc.cpp +++ b/clang/lib/CodeGen/Targets/Sparc.cpp @@ -13,13 +13,6 @@ using namespace clang; using namespace clang::CodeGen; -/// Whether `_Complex` values with an integer element type are passed and -/// returned the way GCC passes and returns them. -static bool isComplexGnuABI(const ABIInfo &Info) { - return !Info.getContext().getLangOpts().isCompatibleWith( - LangOptions::ClangABI::Ver23); -} - //===----------------------------------------------------------------------===// // SPARC v8 ABI Implementation. // Based on the SPARC Compliance Definition version 2.4.1. @@ -29,9 +22,15 @@ static bool isComplexGnuABI(const ABIInfo &Info) { namespace { class SparcV8ABIInfo : public DefaultABIInfo { public: - SparcV8ABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} + SparcV8ABIInfo(CodeGenTypes &CGT) + : DefaultABIInfo(CGT), + IsComplexGnuABI(!CGT.getContext().getLangOpts().isCompatibleWith( + LangOptions::ClangABI::Ver23)) {} private: + /// Whether how `_Complex` values are passed and returned is GCC-compatible. + bool IsComplexGnuABI; + llvm::Type *getComplexIntCoerceType(QualType Ty) const; ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType Ty) const; @@ -40,7 +39,7 @@ class SparcV8ABIInfo : public DefaultABIInfo { } // end anonymous namespace llvm::Type *SparcV8ABIInfo::getComplexIntCoerceType(QualType Ty) const { - if (!isComplexGnuABI(*this)) + if (!IsComplexGnuABI) return nullptr; const auto *CT = Ty->getAs<ComplexType>(); @@ -156,9 +155,15 @@ class SparcV8TargetCodeGenInfo : public TargetCodeGenInfo { namespace { class SparcV9ABIInfo : public ABIInfo { public: - SparcV9ABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {} + SparcV9ABIInfo(CodeGenTypes &CGT) + : ABIInfo(CGT), + IsComplexGnuABI(!CGT.getContext().getLangOpts().isCompatibleWith( + LangOptions::ClangABI::Ver23)) {} private: + /// Whether how `_Complex` values are passed and returned is GCC-compatible. + bool IsComplexGnuABI; + ABIArgInfo classifyType(QualType RetTy, unsigned SizeLimit, unsigned &RegOffset) const; void computeInfo(CGFunctionInfo &FI) const override; @@ -312,7 +317,7 @@ ABIArgInfo SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit, // When being GCC-compatible, cast a complex integer to an integer type // of the right size to get the correct scalar-like behavior. - if (isComplexGnuABI(*this)) + if (IsComplexGnuABI) if (const auto *CT = Ty->getAs<ComplexType>(); CT && Size < 64 && CT->getElementType()->isIntegerType()) { RegOffset += 1; >From f4c19de19fe9c2b731dee69285f1370279b95dfd Mon Sep 17 00:00:00 2001 From: Folkert de Vries <[email protected]> Date: Sat, 1 Aug 2026 23:29:29 +0200 Subject: [PATCH 4/6] use element type size --- clang/lib/CodeGen/Targets/Sparc.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp b/clang/lib/CodeGen/Targets/Sparc.cpp index 2ea5c1a4ea2d5..f7c7a15e4f966 100644 --- a/clang/lib/CodeGen/Targets/Sparc.cpp +++ b/clang/lib/CodeGen/Targets/Sparc.cpp @@ -47,12 +47,12 @@ llvm::Type *SparcV8ABIInfo::getComplexIntCoerceType(QualType Ty) const { return nullptr; // The default path already does the right thing for `long long _Complex`. - uint64_t Size = getContext().getTypeSize(Ty); - if (Size > 64) + uint64_t ElementTypeSize = getContext().getTypeSize(CT->getElementType()); + if (ElementTypeSize > 32) return nullptr; // Coerce to an integer to get the correct scalar-like behavior. - return llvm::IntegerType::get(getVMContext(), Size); + return llvm::IntegerType::get(getVMContext(), 2 * ElementTypeSize); } ABIArgInfo SparcV8ABIInfo::classifyReturnType(QualType Ty) const { @@ -317,12 +317,17 @@ ABIArgInfo SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit, // When being GCC-compatible, cast a complex integer to an integer type // of the right size to get the correct scalar-like behavior. - if (IsComplexGnuABI) - if (const auto *CT = Ty->getAs<ComplexType>(); - CT && Size < 64 && CT->getElementType()->isIntegerType()) { - RegOffset += 1; - return ABIArgInfo::getDirect(llvm::IntegerType::get(VMContext, Size)); + if (IsComplexGnuABI) { + const auto *CT = Ty->getAs<ComplexType>(); + if (CT && CT->getElementType()->isIntegerType()) { + uint64_t ElementTypeSize = Context.getTypeSize(CT->getElementType()); + if (ElementTypeSize < 32) { + RegOffset += 1; + return ABIArgInfo::getDirect( + llvm::IntegerType::get(VMContext, 2 * ElementTypeSize)); + } } + } // Other non-aggregates go in registers. if (!isAggregateTypeForABI(Ty)) { >From 27c742a9a3b0c75fff444755601b382fb73adf4a Mon Sep 17 00:00:00 2001 From: Folkert de Vries <[email protected]> Date: Sat, 1 Aug 2026 23:25:04 +0200 Subject: [PATCH 5/6] `getComplexIntCoerceType` -> `classifyComplexType` --- clang/lib/CodeGen/Targets/Sparc.cpp | 66 ++++++++++++++--------------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp b/clang/lib/CodeGen/Targets/Sparc.cpp index f7c7a15e4f966..32a71e4811c7d 100644 --- a/clang/lib/CodeGen/Targets/Sparc.cpp +++ b/clang/lib/CodeGen/Targets/Sparc.cpp @@ -31,47 +31,46 @@ class SparcV8ABIInfo : public DefaultABIInfo { /// Whether how `_Complex` values are passed and returned is GCC-compatible. bool IsComplexGnuABI; - llvm::Type *getComplexIntCoerceType(QualType Ty) const; + ABIArgInfo classifyComplexType(const ComplexType *Ty, bool IsRet) const; ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType Ty) const; void computeInfo(CGFunctionInfo &FI) const override; }; } // end anonymous namespace -llvm::Type *SparcV8ABIInfo::getComplexIntCoerceType(QualType Ty) const { - if (!IsComplexGnuABI) - return nullptr; +ABIArgInfo SparcV8ABIInfo::classifyComplexType(const ComplexType *CT, + bool IsRet) const { + QualType ElementTy = CT->getElementType(); + + if (IsComplexGnuABI && ElementTy->isIntegerType()) { + // The default path already does the right thing for `long long _Complex`. + uint64_t ElementTypeSize = getContext().getTypeSize(ElementTy); + if (ElementTypeSize <= 32) { + // Coerce to an integer to get the correct scalar-like behavior. + return ABIArgInfo::getDirect( + llvm::IntegerType::get(getVMContext(), 2 * ElementTypeSize)); + } + } - const auto *CT = Ty->getAs<ComplexType>(); - if (!CT || !CT->getElementType()->isIntegerType()) - return nullptr; + // Any other complex value is passed indirectly, but returned in registers. + if (!IsRet) + return getNaturalAlignIndirect(QualType(CT, 0), + getDataLayout().getAllocaAddrSpace()); - // The default path already does the right thing for `long long _Complex`. - uint64_t ElementTypeSize = getContext().getTypeSize(CT->getElementType()); - if (ElementTypeSize > 32) - return nullptr; + // long double _Complex is special, it is marked as inreg. + const auto *BT = ElementTy->getAs<BuiltinType>(); + if (BT && BT->getKind() == BuiltinType::LongDouble) + return ABIArgInfo::getDirectInReg(); - // Coerce to an integer to get the correct scalar-like behavior. - return llvm::IntegerType::get(getVMContext(), 2 * ElementTypeSize); + return ABIArgInfo::getDirect(); } ABIArgInfo SparcV8ABIInfo::classifyReturnType(QualType Ty) const { - const auto *CT = Ty->getAs<ComplexType>(); - const auto *BT = Ty->getAs<BuiltinType>(); - if (CT) - BT = CT->getElementType()->getAs<BuiltinType>(); - bool IsLongDouble = BT && BT->getKind() == BuiltinType::LongDouble; - - // long double _Complex is special in that it should be marked as inreg. - if (CT) { - if (IsLongDouble) - return ABIArgInfo::getDirectInReg(); - if (llvm::Type *CoerceTy = getComplexIntCoerceType(Ty)) - return ABIArgInfo::getDirect(CoerceTy); - return ABIArgInfo::getDirect(); - } + if (const auto *CT = Ty->getAs<ComplexType>()) + return classifyComplexType(CT, /*IsRet=*/true); - if (IsLongDouble) + if (const auto *BT = Ty->getAs<BuiltinType>(); + BT && BT->getKind() == BuiltinType::LongDouble) return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(), /*ByVal=*/false); @@ -79,13 +78,12 @@ ABIArgInfo SparcV8ABIInfo::classifyReturnType(QualType Ty) const { } ABIArgInfo SparcV8ABIInfo::classifyArgumentType(QualType Ty) const { - if (const auto *BT = Ty->getAs<BuiltinType>(); - BT && BT->getKind() == BuiltinType::LongDouble) - return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace()); + if (const auto *CT = Ty->getAs<ComplexType>()) + return classifyComplexType(CT, /*IsRet=*/false); - // Complex integers go in registers. - if (llvm::Type *CoerceTy = getComplexIntCoerceType(Ty)) - return ABIArgInfo::getDirect(CoerceTy); + const auto *BT = Ty->getAs<BuiltinType>(); + if (BT && BT->getKind() == BuiltinType::LongDouble) + return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace()); return DefaultABIInfo::classifyArgumentType(Ty); } >From dbfddf2daa7d48d175ef879238c37a9a74e7e6d6 Mon Sep 17 00:00:00 2001 From: Folkert de Vries <[email protected]> Date: Sun, 2 Aug 2026 13:43:22 +0200 Subject: [PATCH 6/6] expand comment with how non-small-integer complex types are handled --- clang/lib/CodeGen/Targets/Sparc.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp b/clang/lib/CodeGen/Targets/Sparc.cpp index 32a71e4811c7d..81bcd939caef0 100644 --- a/clang/lib/CodeGen/Targets/Sparc.cpp +++ b/clang/lib/CodeGen/Targets/Sparc.cpp @@ -313,8 +313,10 @@ ABIArgInfo SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit, return ABIArgInfo::getExtend(Ty); } - // When being GCC-compatible, cast a complex integer to an integer type - // of the right size to get the correct scalar-like behavior. + // When being GCC-compatible, cast a complex char, short and int to an integer + // type of the right size to get the correct scalar-like behavior. Other + // comple types fall through and are treated like any other struct, e.g. + // `{ i64, i64 }` or `{ double, double }`. if (IsComplexGnuABI) { const auto *CT = Ty->getAs<ComplexType>(); if (CT && CT->getElementType()->isIntegerType()) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
