From d5c328d9a71d9780f95022b516d8912c6a624115 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Wed, 5 Feb 2025 15:08:58 +0530 Subject: [PATCH] [clang][PowerPC] Add flag to enable compatibility with GNU for complex arguments (#77732) Fixes : https://github.com/llvm/llvm-project/issues/56023 https://godbolt.org/z/1bsW1sKMs newFlag : -fcomplex-ppc-gnu-abi GNU uses GPRs for complex parameters and return values storing for PowerPC-32bit, which can be enabled which above flag. Intent of this patch is to make clang compatible with GNU libraries of complex. Following up with this patch : https://reviews.llvm.org/D146942 --- clang/docs/ReleaseNotes.rst | 5 + clang/include/clang/Basic/CodeGenOptions.def | 2 + clang/include/clang/Basic/CodeGenOptions.h | 6 + clang/include/clang/Driver/Options.td | 4 + clang/lib/CodeGen/Targets/PPC.cpp | 85 +++- clang/lib/Driver/ToolChains/Clang.cpp | 11 + clang/lib/Frontend/CompilerInvocation.cpp | 6 + .../CodeGen/PowerPC/ppc32-complex-gnu-abi.c | 403 ++++++++++++++++++ .../ppc32-complex-soft-float-gnu-abi.c | 98 +++++ .../test/Driver/ppc32-fcomplex-ppc-gnu-abi.c | 12 + 10 files changed, 627 insertions(+), 5 deletions(-) create mode 100644 clang/test/CodeGen/PowerPC/ppc32-complex-gnu-abi.c create mode 100644 clang/test/CodeGen/PowerPC/ppc32-complex-soft-float-gnu-abi.c create mode 100644 clang/test/Driver/ppc32-fcomplex-ppc-gnu-abi.c diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 18ecf1efa13a164..930e79f245c1492 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -100,6 +100,11 @@ Non-comprehensive list of changes in this release New Compiler Flags ------------------ +* ``-fcomplex-ppc-gnu-abi`` follow ABI ATR-PASS-COMPLEX-IN-GPRS for ppc32 and pass + complex parameters on GPRs instead of stack. + For more info check `Power Architectureâ„¢ 32-bit ABI Supplement 1.0 - Embedded + `_ + Deprecated Compiler Flags ------------------------- diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 386652d2efa9e14..03e3e9e4beffb57 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -239,6 +239,8 @@ VALUE_CODEGENOPT(MCDCMaxTVs, 32, 0x7FFFFFFE) ///< MC/DC Maximum test vectors. /// If -fpcc-struct-return or -freg-struct-return is specified. ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, SRCK_Default) + /// If -fcomplex-ppc-gnu-abi is specified on ppc32. +ENUM_CODEGENOPT(ComplexInRegABI, ComplexArgumentConventionKind, 2, CMPLX_OnStack) CODEGENOPT(RelaxAll , 1, 0) ///< Relax all machine code instructions. CODEGENOPT(RelaxedAliasing , 1, 0) ///< Set when -fno-strict-aliasing is enabled. diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index c531c656f42b7ec..3340098fc5f56ea 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -80,6 +80,12 @@ class CodeGenOptions : public CodeGenOptionsBase { SRCK_InRegs // Small structs in registers (-freg-struct-return). }; + enum ComplexArgumentConventionKind { + CMPLX_OnStack, + CMPLX_InGPR, // If -fcomplex-ppc-gnu-abi is specified on ppc32 + CMPLX_InFPR + }; + enum ProfileInstrKind { ProfileNone, // Profile instrumentation is turned off. ProfileClangInstr, // Clang instrumentation to generate execution counts diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index c0749c418b7bcec..eb221e5b8aa17e9 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2640,6 +2640,10 @@ def ffp_contract : Joined<["-"], "ffp-contract=">, Group, HelpText<"Form fused FP ops (e.g. FMAs)">, Values<"fast,on,off,fast-honor-pragmas">; +def fcomplex_ppc_gnu_abi : Flag<["-"], "fcomplex-ppc-gnu-abi">, Group, Visibility<[ClangOption, CC1Option]>, + DocBrief<"Follow the GNU ABI, pass Complex values in GPRs instead of the stack for PowerPC-32">, + HelpText<"Pass Complex values in GPR instead of stack for PowerPC-32">; + defm strict_float_cast_overflow : BoolFOption<"strict-float-cast-overflow", CodeGenOpts<"StrictFloatCastOverflow">, DefaultTrue, NegFlag> 5; + } + return ABIArgInfo::getDirect(llvm::ArrayType::get(ElemTy, RegsNeeded)); +} + +ABIArgInfo PPC32_SVR4_ABIInfo::classifyArgumentType(QualType Ty, + int &ArgGPRsLeft) const { + Ty = useFirstFieldIfTransparentUnion(Ty); + bool IsComplex = Ty->isAnyComplexType(); + + if ((getCodeGenOpts().getComplexInRegABI() != CodeGenOptions::CMPLX_InGPR) || + !ArgGPRsLeft || (!IsComplex && Ty->isFloatingType() && !IsSoftFloatABI)) + return DefaultABIInfo::classifyArgumentType(Ty); + + assert(ArgGPRsLeft >= 0 && "Arg GPR must be large or equal than zero"); + ASTContext &Context = getContext(); + uint64_t TypeSize = Context.getTypeSize(Ty); + + // For complex type or any other primitive types. + if (IsComplex || !isAggregateTypeForABI(Ty)) { + // If gr is even set gr = gr + 1 for TypeSize=64. + if (TypeSize == 64 && ArgGPRsLeft % 2 == 1) + --ArgGPRsLeft; + + if (TypeSize <= GPRBits * ArgGPRsLeft) { + ArgGPRsLeft -= TypeSize / GPRBits; + if (IsComplex) + return handleComplex(TypeSize); + } + } else + --ArgGPRsLeft; // Records with non-trivial destructors/copy-constructors + // should not be passed by value. + + return DefaultABIInfo::classifyArgumentType(Ty); +} + ABIArgInfo PPC32_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const { - uint64_t Size; + + uint64_t Size = getContext().getTypeSize(RetTy); // -msvr4-struct-return puts small aggregates in GPR3 and GPR4. - if (isAggregateTypeForABI(RetTy) && IsRetSmallStructInRegABI && - (Size = getContext().getTypeSize(RetTy)) <= 64) { + if (isAggregateTypeForABI(RetTy) && IsRetSmallStructInRegABI && Size <= 64) { // System V ABI (1995), page 3-22, specified: // > A structure or union whose size is less than or equal to 8 bytes // > shall be returned in r3 and r4, as if it were first stored in the @@ -419,6 +488,10 @@ ABIArgInfo PPC32_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const { } } + if ((getCodeGenOpts().getComplexInRegABI() == CodeGenOptions::CMPLX_InGPR) && + RetTy->isAnyComplexType()) + return handleComplex(Size); + return DefaultABIInfo::classifyReturnType(RetTy); } @@ -429,10 +502,12 @@ RValue PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList, if (getTarget().getTriple().isOSDarwin()) { auto TI = getContext().getTypeInfoInChars(Ty); TI.Align = getParamTypeAlignment(Ty); + int ArgGPRs = ArgGPRsNum; CharUnits SlotSize = CharUnits::fromQuantity(4); return emitVoidPtrVAArg(CGF, VAList, Ty, - classifyArgumentType(Ty).isIndirect(), TI, SlotSize, + classifyArgumentType(Ty, ArgGPRs).isIndirect(), TI, + SlotSize, /*AllowHigherAlign=*/true, Slot); } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 9b5132c5625faa0..b068470ab0c8292 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5865,6 +5865,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + if (Arg *A = Args.getLastArg(options::OPT_fcomplex_ppc_gnu_abi)) { + if (!TC.getTriple().isPPC32() || !TC.getTriple().isOSBinFormatELF()) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << RawTriple.str(); + } else { + CmdArgs.push_back("-fcomplex-ppc-gnu-abi"); + } + } else if (TC.getTriple().isPPC32() && TC.getTriple().isGNUEnvironment() && + TC.getTriple().isOSBinFormatELF()) + CmdArgs.push_back("-fcomplex-ppc-gnu-abi"); + if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) { if (Triple.getArch() == llvm::Triple::m68k) CmdArgs.push_back("-fdefault-calling-conv=rtdcall"); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 95d3eac71058b37..20f40fbca0d834d 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1786,6 +1786,9 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts, GenerateArg(Consumer, Opt); } + if (T.isPPC32() && Opts.ComplexInRegABI == CodeGenOptions::CMPLX_InGPR) + GenerateArg(Consumer, OPT_fcomplex_ppc_gnu_abi); + if (Opts.EnableAIXExtendedAltivecABI) GenerateArg(Consumer, OPT_mabi_EQ_vec_extabi); @@ -2184,6 +2187,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, } } + if (Args.getLastArg(OPT_fcomplex_ppc_gnu_abi)) + Opts.setComplexInRegABI(CodeGenOptions::CMPLX_InGPR); + if (Arg *A = Args.getLastArg(OPT_mxcoff_roptr)) { if (!T.isOSAIX()) Diags.Report(diag::err_drv_unsupported_opt_for_target) diff --git a/clang/test/CodeGen/PowerPC/ppc32-complex-gnu-abi.c b/clang/test/CodeGen/PowerPC/ppc32-complex-gnu-abi.c new file mode 100644 index 000000000000000..506c1acd1a3b087 --- /dev/null +++ b/clang/test/CodeGen/PowerPC/ppc32-complex-gnu-abi.c @@ -0,0 +1,403 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 + +// RUN: %clang_cc1 -triple powerpc-unknown-linux-unknown \ +// RUN: -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-DEF +// RUN: %clang_cc1 -triple powerpc-unknown-linux-unknown -fcomplex-ppc-gnu-abi \ +// RUN: -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-GNU + +// CHECK-DEF-LABEL: define dso_local void @_cfloat +// CHECK-DEF-SAME: (ptr dead_on_unwind noalias writable sret({ float, float }) align 4 [[AGG_RESULT:%.*]], ptr noundef byval({ float, float }) align 4 [[X:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-DEF-NEXT: entry: +// CHECK-DEF-NEXT: [[X_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[X]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[X_REAL:%.*]] = load float, ptr [[X_REALP]], align 4 +// CHECK-DEF-NEXT: [[X_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[X]], i32 0, i32 1 +// CHECK-DEF-NEXT: [[X_IMAG:%.*]] = load float, ptr [[X_IMAGP]], align 4 +// CHECK-DEF-NEXT: [[AGG_RESULT_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[AGG_RESULT]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[AGG_RESULT]], i32 0, i32 1 +// CHECK-DEF-NEXT: store float [[X_REAL]], ptr [[AGG_RESULT_REALP]], align 4 +// CHECK-DEF-NEXT: store float [[X_IMAG]], ptr [[AGG_RESULT_IMAGP]], align 4 +// CHECK-DEF-NEXT: [[AGG_RESULT_REALP1:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[AGG_RESULT]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[AGG_RESULT_REAL:%.*]] = load float, ptr [[AGG_RESULT_REALP1]], align 4 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP2:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[AGG_RESULT]], i32 0, i32 1 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAG:%.*]] = load float, ptr [[AGG_RESULT_IMAGP2]], align 4 +// CHECK-DEF-NEXT: [[AGG_RESULT_REALP3:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[AGG_RESULT]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP4:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[AGG_RESULT]], i32 0, i32 1 +// CHECK-DEF-NEXT: store float [[AGG_RESULT_REAL]], ptr [[AGG_RESULT_REALP3]], align 4 +// CHECK-DEF-NEXT: store float [[AGG_RESULT_IMAG]], ptr [[AGG_RESULT_IMAGP4]], align 4 +// CHECK-DEF-NEXT: ret void +// +// CHECK-GNU-LABEL: define dso_local [1 x i64] @_cfloat +// CHECK-GNU-SAME: ([1 x i64] noundef [[X_COERCE:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-GNU-NEXT: entry: +// CHECK-GNU-NEXT: [[RETVAL:%.*]] = alloca { float, float }, align 4 +// CHECK-GNU-NEXT: [[X:%.*]] = alloca { float, float }, align 4 +// CHECK-GNU-NEXT: store [1 x i64] [[X_COERCE]], ptr [[X]], align 4 +// CHECK-GNU-NEXT: [[X_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[X]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[X_REAL:%.*]] = load float, ptr [[X_REALP]], align 4 +// CHECK-GNU-NEXT: [[X_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[X]], i32 0, i32 1 +// CHECK-GNU-NEXT: [[X_IMAG:%.*]] = load float, ptr [[X_IMAGP]], align 4 +// CHECK-GNU-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[RETVAL]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[RETVAL]], i32 0, i32 1 +// CHECK-GNU-NEXT: store float [[X_REAL]], ptr [[RETVAL_REALP]], align 4 +// CHECK-GNU-NEXT: store float [[X_IMAG]], ptr [[RETVAL_IMAGP]], align 4 +// CHECK-GNU-NEXT: [[TMP0:%.*]] = load [1 x i64], ptr [[RETVAL]], align 4 +// CHECK-GNU-NEXT: ret [1 x i64] [[TMP0]] +// +_Complex float _cfloat(_Complex float x) { + return x; +} + + +// CHECK-DEF-LABEL: define dso_local void @_cdouble +// CHECK-DEF-SAME: (ptr dead_on_unwind noalias writable sret({ double, double }) align 8 [[AGG_RESULT:%.*]], ptr noundef byval({ double, double }) align 8 [[X:%.*]]) #[[ATTR0]] { +// CHECK-DEF-NEXT: entry: +// CHECK-DEF-NEXT: [[X_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[X]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[X_REAL:%.*]] = load double, ptr [[X_REALP]], align 8 +// CHECK-DEF-NEXT: [[X_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[X]], i32 0, i32 1 +// CHECK-DEF-NEXT: [[X_IMAG:%.*]] = load double, ptr [[X_IMAGP]], align 8 +// CHECK-DEF-NEXT: [[AGG_RESULT_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 1 +// CHECK-DEF-NEXT: store double [[X_REAL]], ptr [[AGG_RESULT_REALP]], align 8 +// CHECK-DEF-NEXT: store double [[X_IMAG]], ptr [[AGG_RESULT_IMAGP]], align 8 +// CHECK-DEF-NEXT: [[AGG_RESULT_REALP1:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[AGG_RESULT_REAL:%.*]] = load double, ptr [[AGG_RESULT_REALP1]], align 8 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP2:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 1 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAG:%.*]] = load double, ptr [[AGG_RESULT_IMAGP2]], align 8 +// CHECK-DEF-NEXT: [[AGG_RESULT_REALP3:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP4:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 1 +// CHECK-DEF-NEXT: store double [[AGG_RESULT_REAL]], ptr [[AGG_RESULT_REALP3]], align 8 +// CHECK-DEF-NEXT: store double [[AGG_RESULT_IMAG]], ptr [[AGG_RESULT_IMAGP4]], align 8 +// CHECK-DEF-NEXT: ret void +// +// CHECK-GNU-LABEL: define dso_local [4 x i32] @_cdouble +// CHECK-GNU-SAME: ([4 x i32] noundef [[X_COERCE:%.*]]) #[[ATTR0]] { +// CHECK-GNU-NEXT: entry: +// CHECK-GNU-NEXT: [[RETVAL:%.*]] = alloca { double, double }, align 8 +// CHECK-GNU-NEXT: [[X:%.*]] = alloca { double, double }, align 8 +// CHECK-GNU-NEXT: store [4 x i32] [[X_COERCE]], ptr [[X]], align 8 +// CHECK-GNU-NEXT: [[X_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[X]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[X_REAL:%.*]] = load double, ptr [[X_REALP]], align 8 +// CHECK-GNU-NEXT: [[X_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[X]], i32 0, i32 1 +// CHECK-GNU-NEXT: [[X_IMAG:%.*]] = load double, ptr [[X_IMAGP]], align 8 +// CHECK-GNU-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 1 +// CHECK-GNU-NEXT: store double [[X_REAL]], ptr [[RETVAL_REALP]], align 8 +// CHECK-GNU-NEXT: store double [[X_IMAG]], ptr [[RETVAL_IMAGP]], align 8 +// CHECK-GNU-NEXT: [[TMP0:%.*]] = load [4 x i32], ptr [[RETVAL]], align 8 +// CHECK-GNU-NEXT: ret [4 x i32] [[TMP0]] +// +_Complex double _cdouble(_Complex double x) { + return x; +} + + + +// CHECK-DEF-LABEL: define dso_local void @_cldouble +// CHECK-DEF-SAME: (ptr dead_on_unwind noalias writable sret({ ppc_fp128, ppc_fp128 }) align 16 [[AGG_RESULT:%.*]], ptr noundef byval({ ppc_fp128, ppc_fp128 }) align 16 [[X:%.*]]) #[[ATTR0]] { +// CHECK-DEF-NEXT: entry: +// CHECK-DEF-NEXT: [[X_REALP:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[X]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[X_REAL:%.*]] = load ppc_fp128, ptr [[X_REALP]], align 16 +// CHECK-DEF-NEXT: [[X_IMAGP:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[X]], i32 0, i32 1 +// CHECK-DEF-NEXT: [[X_IMAG:%.*]] = load ppc_fp128, ptr [[X_IMAGP]], align 16 +// CHECK-DEF-NEXT: [[AGG_RESULT_REALP:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[AGG_RESULT]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[AGG_RESULT]], i32 0, i32 1 +// CHECK-DEF-NEXT: store ppc_fp128 [[X_REAL]], ptr [[AGG_RESULT_REALP]], align 16 +// CHECK-DEF-NEXT: store ppc_fp128 [[X_IMAG]], ptr [[AGG_RESULT_IMAGP]], align 16 +// CHECK-DEF-NEXT: [[AGG_RESULT_REALP1:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[AGG_RESULT]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[AGG_RESULT_REAL:%.*]] = load ppc_fp128, ptr [[AGG_RESULT_REALP1]], align 16 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP2:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[AGG_RESULT]], i32 0, i32 1 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAG:%.*]] = load ppc_fp128, ptr [[AGG_RESULT_IMAGP2]], align 16 +// CHECK-DEF-NEXT: [[AGG_RESULT_REALP3:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[AGG_RESULT]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP4:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[AGG_RESULT]], i32 0, i32 1 +// CHECK-DEF-NEXT: store ppc_fp128 [[AGG_RESULT_REAL]], ptr [[AGG_RESULT_REALP3]], align 16 +// CHECK-DEF-NEXT: store ppc_fp128 [[AGG_RESULT_IMAG]], ptr [[AGG_RESULT_IMAGP4]], align 16 +// CHECK-DEF-NEXT: ret void +// +// CHECK-GNU-LABEL: define dso_local [8 x i32] @_cldouble +// CHECK-GNU-SAME: ([8 x i32] noundef [[X_COERCE:%.*]]) #[[ATTR0]] { +// CHECK-GNU-NEXT: entry: +// CHECK-GNU-NEXT: [[RETVAL:%.*]] = alloca { ppc_fp128, ppc_fp128 }, align 16 +// CHECK-GNU-NEXT: [[X:%.*]] = alloca { ppc_fp128, ppc_fp128 }, align 16 +// CHECK-GNU-NEXT: store [8 x i32] [[X_COERCE]], ptr [[X]], align 16 +// CHECK-GNU-NEXT: [[X_REALP:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[X]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[X_REAL:%.*]] = load ppc_fp128, ptr [[X_REALP]], align 16 +// CHECK-GNU-NEXT: [[X_IMAGP:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[X]], i32 0, i32 1 +// CHECK-GNU-NEXT: [[X_IMAG:%.*]] = load ppc_fp128, ptr [[X_IMAGP]], align 16 +// CHECK-GNU-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[RETVAL]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[RETVAL]], i32 0, i32 1 +// CHECK-GNU-NEXT: store ppc_fp128 [[X_REAL]], ptr [[RETVAL_REALP]], align 16 +// CHECK-GNU-NEXT: store ppc_fp128 [[X_IMAG]], ptr [[RETVAL_IMAGP]], align 16 +// CHECK-GNU-NEXT: [[TMP0:%.*]] = load [8 x i32], ptr [[RETVAL]], align 16 +// CHECK-GNU-NEXT: ret [8 x i32] [[TMP0]] +// +_Complex long double _cldouble(_Complex long double x) { + return x; +} + + + +// CHECK-DEF-LABEL: define dso_local void @testComplexDouble +// CHECK-DEF-SAME: (ptr dead_on_unwind noalias writable sret({ double, double }) align 8 [[AGG_RESULT:%.*]], i32 noundef [[W:%.*]], ptr noundef byval({ float, float }) align 4 [[X:%.*]], ptr noundef byval({ double, double }) align 8 [[Z:%.*]]) #[[ATTR0]] { +// CHECK-DEF-NEXT: entry: +// CHECK-DEF-NEXT: [[W_ADDR:%.*]] = alloca i32, align 4 +// CHECK-DEF-NEXT: [[TMP:%.*]] = alloca { double, double }, align 8 +// CHECK-DEF-NEXT: [[BYVAL_TEMP:%.*]] = alloca { double, double }, align 8 +// CHECK-DEF-NEXT: store i32 [[W]], ptr [[W_ADDR]], align 4 +// CHECK-DEF-NEXT: [[Z_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[Z]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[Z_REAL:%.*]] = load double, ptr [[Z_REALP]], align 8 +// CHECK-DEF-NEXT: [[Z_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[Z]], i32 0, i32 1 +// CHECK-DEF-NEXT: [[Z_IMAG:%.*]] = load double, ptr [[Z_IMAGP]], align 8 +// CHECK-DEF-NEXT: [[BYVAL_TEMP_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[BYVAL_TEMP]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[BYVAL_TEMP_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[BYVAL_TEMP]], i32 0, i32 1 +// CHECK-DEF-NEXT: store double [[Z_REAL]], ptr [[BYVAL_TEMP_REALP]], align 8 +// CHECK-DEF-NEXT: store double [[Z_IMAG]], ptr [[BYVAL_TEMP_IMAGP]], align 8 +// CHECK-DEF-NEXT: call void @_cdouble(ptr dead_on_unwind writable sret({ double, double }) align 8 [[TMP]], ptr noundef byval({ double, double }) align 8 [[BYVAL_TEMP]]) +// CHECK-DEF-NEXT: [[TMP_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[TMP]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[TMP_REAL:%.*]] = load double, ptr [[TMP_REALP]], align 8 +// CHECK-DEF-NEXT: [[TMP_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[TMP]], i32 0, i32 1 +// CHECK-DEF-NEXT: [[TMP_IMAG:%.*]] = load double, ptr [[TMP_IMAGP]], align 8 +// CHECK-DEF-NEXT: [[AGG_RESULT_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 1 +// CHECK-DEF-NEXT: store double [[TMP_REAL]], ptr [[AGG_RESULT_REALP]], align 8 +// CHECK-DEF-NEXT: store double [[TMP_IMAG]], ptr [[AGG_RESULT_IMAGP]], align 8 +// CHECK-DEF-NEXT: [[AGG_RESULT_REALP1:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[AGG_RESULT_REAL:%.*]] = load double, ptr [[AGG_RESULT_REALP1]], align 8 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP2:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 1 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAG:%.*]] = load double, ptr [[AGG_RESULT_IMAGP2]], align 8 +// CHECK-DEF-NEXT: [[AGG_RESULT_REALP3:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP4:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 1 +// CHECK-DEF-NEXT: store double [[AGG_RESULT_REAL]], ptr [[AGG_RESULT_REALP3]], align 8 +// CHECK-DEF-NEXT: store double [[AGG_RESULT_IMAG]], ptr [[AGG_RESULT_IMAGP4]], align 8 +// CHECK-DEF-NEXT: ret void +// +// CHECK-GNU-LABEL: define dso_local [4 x i32] @testComplexDouble +// CHECK-GNU-SAME: (i32 noundef [[W:%.*]], [1 x i64] noundef [[X_COERCE:%.*]], [4 x i32] noundef [[Z_COERCE:%.*]]) #[[ATTR0]] { +// CHECK-GNU-NEXT: entry: +// CHECK-GNU-NEXT: [[RETVAL:%.*]] = alloca { double, double }, align 8 +// CHECK-GNU-NEXT: [[X:%.*]] = alloca { float, float }, align 4 +// CHECK-GNU-NEXT: [[Z:%.*]] = alloca { double, double }, align 8 +// CHECK-GNU-NEXT: [[W_ADDR:%.*]] = alloca i32, align 4 +// CHECK-GNU-NEXT: [[COERCE:%.*]] = alloca { double, double }, align 8 +// CHECK-GNU-NEXT: [[COERCE1:%.*]] = alloca { double, double }, align 8 +// CHECK-GNU-NEXT: store [1 x i64] [[X_COERCE]], ptr [[X]], align 4 +// CHECK-GNU-NEXT: store [4 x i32] [[Z_COERCE]], ptr [[Z]], align 8 +// CHECK-GNU-NEXT: store i32 [[W]], ptr [[W_ADDR]], align 4 +// CHECK-GNU-NEXT: [[Z_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[Z]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[Z_REAL:%.*]] = load double, ptr [[Z_REALP]], align 8 +// CHECK-GNU-NEXT: [[Z_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[Z]], i32 0, i32 1 +// CHECK-GNU-NEXT: [[Z_IMAG:%.*]] = load double, ptr [[Z_IMAGP]], align 8 +// CHECK-GNU-NEXT: [[COERCE_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE]], i32 0, i32 1 +// CHECK-GNU-NEXT: store double [[Z_REAL]], ptr [[COERCE_REALP]], align 8 +// CHECK-GNU-NEXT: store double [[Z_IMAG]], ptr [[COERCE_IMAGP]], align 8 +// CHECK-GNU-NEXT: [[TMP0:%.*]] = load [4 x i32], ptr [[COERCE]], align 8 +// CHECK-GNU-NEXT: [[CALL:%.*]] = call [4 x i32] @_cdouble([4 x i32] noundef [[TMP0]]) +// CHECK-GNU-NEXT: store [4 x i32] [[CALL]], ptr [[COERCE1]], align 8 +// CHECK-GNU-NEXT: [[COERCE1_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE1]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[COERCE1_REAL:%.*]] = load double, ptr [[COERCE1_REALP]], align 8 +// CHECK-GNU-NEXT: [[COERCE1_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE1]], i32 0, i32 1 +// CHECK-GNU-NEXT: [[COERCE1_IMAG:%.*]] = load double, ptr [[COERCE1_IMAGP]], align 8 +// CHECK-GNU-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 1 +// CHECK-GNU-NEXT: store double [[COERCE1_REAL]], ptr [[RETVAL_REALP]], align 8 +// CHECK-GNU-NEXT: store double [[COERCE1_IMAG]], ptr [[RETVAL_IMAGP]], align 8 +// CHECK-GNU-NEXT: [[TMP1:%.*]] = load [4 x i32], ptr [[RETVAL]], align 8 +// CHECK-GNU-NEXT: ret [4 x i32] [[TMP1]] +// +_Complex double testComplexDouble(int w, _Complex float x, _Complex double z) +{ + return _cdouble(z); +} + + + +// CHECK-DEF-LABEL: define dso_local void @checkComplexDoubleOnStack +// CHECK-DEF-SAME: (ptr dead_on_unwind noalias writable sret({ double, double }) align 8 [[AGG_RESULT:%.*]], i32 noundef [[X1:%.*]], ptr noundef byval({ float, float }) align 4 [[CF:%.*]], i32 noundef [[X2:%.*]], ptr noundef byval({ double, double }) align 8 [[CD:%.*]]) #[[ATTR0]] { +// CHECK-DEF-NEXT: entry: +// CHECK-DEF-NEXT: [[X1_ADDR:%.*]] = alloca i32, align 4 +// CHECK-DEF-NEXT: [[X2_ADDR:%.*]] = alloca i32, align 4 +// CHECK-DEF-NEXT: [[TMP:%.*]] = alloca { double, double }, align 8 +// CHECK-DEF-NEXT: [[BYVAL_TEMP:%.*]] = alloca { float, float }, align 4 +// CHECK-DEF-NEXT: [[BYVAL_TEMP1:%.*]] = alloca { double, double }, align 8 +// CHECK-DEF-NEXT: store i32 [[X1]], ptr [[X1_ADDR]], align 4 +// CHECK-DEF-NEXT: store i32 [[X2]], ptr [[X2_ADDR]], align 4 +// CHECK-DEF-NEXT: [[TMP0:%.*]] = load i32, ptr [[X2_ADDR]], align 4 +// CHECK-DEF-NEXT: [[CF_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[CF]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[CF_REAL:%.*]] = load float, ptr [[CF_REALP]], align 4 +// CHECK-DEF-NEXT: [[CF_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[CF]], i32 0, i32 1 +// CHECK-DEF-NEXT: [[CF_IMAG:%.*]] = load float, ptr [[CF_IMAGP]], align 4 +// CHECK-DEF-NEXT: [[CD_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[CD]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[CD_REAL:%.*]] = load double, ptr [[CD_REALP]], align 8 +// CHECK-DEF-NEXT: [[CD_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[CD]], i32 0, i32 1 +// CHECK-DEF-NEXT: [[CD_IMAG:%.*]] = load double, ptr [[CD_IMAGP]], align 8 +// CHECK-DEF-NEXT: [[BYVAL_TEMP_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[BYVAL_TEMP]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[BYVAL_TEMP_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[BYVAL_TEMP]], i32 0, i32 1 +// CHECK-DEF-NEXT: store float [[CF_REAL]], ptr [[BYVAL_TEMP_REALP]], align 4 +// CHECK-DEF-NEXT: store float [[CF_IMAG]], ptr [[BYVAL_TEMP_IMAGP]], align 4 +// CHECK-DEF-NEXT: [[BYVAL_TEMP1_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[BYVAL_TEMP1]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[BYVAL_TEMP1_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[BYVAL_TEMP1]], i32 0, i32 1 +// CHECK-DEF-NEXT: store double [[CD_REAL]], ptr [[BYVAL_TEMP1_REALP]], align 8 +// CHECK-DEF-NEXT: store double [[CD_IMAG]], ptr [[BYVAL_TEMP1_IMAGP]], align 8 +// CHECK-DEF-NEXT: call void @testComplexDouble(ptr dead_on_unwind writable sret({ double, double }) align 8 [[TMP]], i32 noundef [[TMP0]], ptr noundef byval({ float, float }) align 4 [[BYVAL_TEMP]], ptr noundef byval({ double, double }) align 8 [[BYVAL_TEMP1]]) +// CHECK-DEF-NEXT: [[TMP_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[TMP]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[TMP_REAL:%.*]] = load double, ptr [[TMP_REALP]], align 8 +// CHECK-DEF-NEXT: [[TMP_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[TMP]], i32 0, i32 1 +// CHECK-DEF-NEXT: [[TMP_IMAG:%.*]] = load double, ptr [[TMP_IMAGP]], align 8 +// CHECK-DEF-NEXT: [[AGG_RESULT_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 1 +// CHECK-DEF-NEXT: store double [[TMP_REAL]], ptr [[AGG_RESULT_REALP]], align 8 +// CHECK-DEF-NEXT: store double [[TMP_IMAG]], ptr [[AGG_RESULT_IMAGP]], align 8 +// CHECK-DEF-NEXT: [[AGG_RESULT_REALP2:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[AGG_RESULT_REAL:%.*]] = load double, ptr [[AGG_RESULT_REALP2]], align 8 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP3:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 1 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAG:%.*]] = load double, ptr [[AGG_RESULT_IMAGP3]], align 8 +// CHECK-DEF-NEXT: [[AGG_RESULT_REALP4:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP5:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 1 +// CHECK-DEF-NEXT: store double [[AGG_RESULT_REAL]], ptr [[AGG_RESULT_REALP4]], align 8 +// CHECK-DEF-NEXT: store double [[AGG_RESULT_IMAG]], ptr [[AGG_RESULT_IMAGP5]], align 8 +// CHECK-DEF-NEXT: ret void +// +// CHECK-GNU-LABEL: define dso_local [4 x i32] @checkComplexDoubleOnStack +// CHECK-GNU-SAME: (i32 noundef [[X1:%.*]], [1 x i64] noundef [[CF_COERCE:%.*]], i32 noundef [[X2:%.*]], ptr noundef byval({ double, double }) align 8 [[CD:%.*]]) #[[ATTR0]] { +// CHECK-GNU-NEXT: entry: +// CHECK-GNU-NEXT: [[RETVAL:%.*]] = alloca { double, double }, align 8 +// CHECK-GNU-NEXT: [[CF:%.*]] = alloca { float, float }, align 4 +// CHECK-GNU-NEXT: [[X1_ADDR:%.*]] = alloca i32, align 4 +// CHECK-GNU-NEXT: [[X2_ADDR:%.*]] = alloca i32, align 4 +// CHECK-GNU-NEXT: [[COERCE:%.*]] = alloca { float, float }, align 4 +// CHECK-GNU-NEXT: [[COERCE1:%.*]] = alloca { double, double }, align 8 +// CHECK-GNU-NEXT: [[COERCE2:%.*]] = alloca { double, double }, align 8 +// CHECK-GNU-NEXT: store [1 x i64] [[CF_COERCE]], ptr [[CF]], align 4 +// CHECK-GNU-NEXT: store i32 [[X1]], ptr [[X1_ADDR]], align 4 +// CHECK-GNU-NEXT: store i32 [[X2]], ptr [[X2_ADDR]], align 4 +// CHECK-GNU-NEXT: [[TMP0:%.*]] = load i32, ptr [[X2_ADDR]], align 4 +// CHECK-GNU-NEXT: [[CF_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[CF]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[CF_REAL:%.*]] = load float, ptr [[CF_REALP]], align 4 +// CHECK-GNU-NEXT: [[CF_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[CF]], i32 0, i32 1 +// CHECK-GNU-NEXT: [[CF_IMAG:%.*]] = load float, ptr [[CF_IMAGP]], align 4 +// CHECK-GNU-NEXT: [[CD_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[CD]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[CD_REAL:%.*]] = load double, ptr [[CD_REALP]], align 8 +// CHECK-GNU-NEXT: [[CD_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[CD]], i32 0, i32 1 +// CHECK-GNU-NEXT: [[CD_IMAG:%.*]] = load double, ptr [[CD_IMAGP]], align 8 +// CHECK-GNU-NEXT: [[COERCE_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[COERCE]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[COERCE]], i32 0, i32 1 +// CHECK-GNU-NEXT: store float [[CF_REAL]], ptr [[COERCE_REALP]], align 4 +// CHECK-GNU-NEXT: store float [[CF_IMAG]], ptr [[COERCE_IMAGP]], align 4 +// CHECK-GNU-NEXT: [[TMP1:%.*]] = load [1 x i64], ptr [[COERCE]], align 4 +// CHECK-GNU-NEXT: [[COERCE1_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE1]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[COERCE1_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE1]], i32 0, i32 1 +// CHECK-GNU-NEXT: store double [[CD_REAL]], ptr [[COERCE1_REALP]], align 8 +// CHECK-GNU-NEXT: store double [[CD_IMAG]], ptr [[COERCE1_IMAGP]], align 8 +// CHECK-GNU-NEXT: [[TMP2:%.*]] = load [4 x i32], ptr [[COERCE1]], align 8 +// CHECK-GNU-NEXT: [[CALL:%.*]] = call [4 x i32] @testComplexDouble(i32 noundef [[TMP0]], [1 x i64] noundef [[TMP1]], [4 x i32] noundef [[TMP2]]) +// CHECK-GNU-NEXT: store [4 x i32] [[CALL]], ptr [[COERCE2]], align 8 +// CHECK-GNU-NEXT: [[COERCE2_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE2]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[COERCE2_REAL:%.*]] = load double, ptr [[COERCE2_REALP]], align 8 +// CHECK-GNU-NEXT: [[COERCE2_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE2]], i32 0, i32 1 +// CHECK-GNU-NEXT: [[COERCE2_IMAG:%.*]] = load double, ptr [[COERCE2_IMAGP]], align 8 +// CHECK-GNU-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 1 +// CHECK-GNU-NEXT: store double [[COERCE2_REAL]], ptr [[RETVAL_REALP]], align 8 +// CHECK-GNU-NEXT: store double [[COERCE2_IMAG]], ptr [[RETVAL_IMAGP]], align 8 +// CHECK-GNU-NEXT: [[TMP3:%.*]] = load [4 x i32], ptr [[RETVAL]], align 8 +// CHECK-GNU-NEXT: ret [4 x i32] [[TMP3]] +// +_Complex double checkComplexDoubleOnStack(int x1, _Complex float cf, int x2, _Complex double cd) +{ + return testComplexDouble(x2, cf, cd); +} + + + +// CHECK-DEF-LABEL: define dso_local void @checkComplexFloatOnStack +// CHECK-DEF-SAME: (ptr dead_on_unwind noalias writable sret({ double, double }) align 8 [[AGG_RESULT:%.*]], ptr noundef byval({ double, double }) align 8 [[_CD1:%.*]], ptr noundef byval({ float, float }) align 4 [[_CF1:%.*]], i32 noundef [[Y:%.*]], ptr noundef byval({ float, float }) align 4 [[_CF2:%.*]]) #[[ATTR0]] { +// CHECK-DEF-NEXT: entry: +// CHECK-DEF-NEXT: [[Y_ADDR:%.*]] = alloca i32, align 4 +// CHECK-DEF-NEXT: [[TMP:%.*]] = alloca { double, double }, align 8 +// CHECK-DEF-NEXT: [[BYVAL_TEMP:%.*]] = alloca { float, float }, align 4 +// CHECK-DEF-NEXT: [[BYVAL_TEMP1:%.*]] = alloca { double, double }, align 8 +// CHECK-DEF-NEXT: store i32 [[Y]], ptr [[Y_ADDR]], align 4 +// CHECK-DEF-NEXT: [[TMP0:%.*]] = load i32, ptr [[Y_ADDR]], align 4 +// CHECK-DEF-NEXT: [[_CF2_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[_CF2]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[_CF2_REAL:%.*]] = load float, ptr [[_CF2_REALP]], align 4 +// CHECK-DEF-NEXT: [[_CF2_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[_CF2]], i32 0, i32 1 +// CHECK-DEF-NEXT: [[_CF2_IMAG:%.*]] = load float, ptr [[_CF2_IMAGP]], align 4 +// CHECK-DEF-NEXT: [[_CD1_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[_CD1]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[_CD1_REAL:%.*]] = load double, ptr [[_CD1_REALP]], align 8 +// CHECK-DEF-NEXT: [[_CD1_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[_CD1]], i32 0, i32 1 +// CHECK-DEF-NEXT: [[_CD1_IMAG:%.*]] = load double, ptr [[_CD1_IMAGP]], align 8 +// CHECK-DEF-NEXT: [[BYVAL_TEMP_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[BYVAL_TEMP]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[BYVAL_TEMP_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[BYVAL_TEMP]], i32 0, i32 1 +// CHECK-DEF-NEXT: store float [[_CF2_REAL]], ptr [[BYVAL_TEMP_REALP]], align 4 +// CHECK-DEF-NEXT: store float [[_CF2_IMAG]], ptr [[BYVAL_TEMP_IMAGP]], align 4 +// CHECK-DEF-NEXT: [[BYVAL_TEMP1_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[BYVAL_TEMP1]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[BYVAL_TEMP1_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[BYVAL_TEMP1]], i32 0, i32 1 +// CHECK-DEF-NEXT: store double [[_CD1_REAL]], ptr [[BYVAL_TEMP1_REALP]], align 8 +// CHECK-DEF-NEXT: store double [[_CD1_IMAG]], ptr [[BYVAL_TEMP1_IMAGP]], align 8 +// CHECK-DEF-NEXT: call void @checkComplexDoubleOnStack(ptr dead_on_unwind writable sret({ double, double }) align 8 [[TMP]], i32 noundef [[TMP0]], ptr noundef byval({ float, float }) align 4 [[BYVAL_TEMP]], i32 noundef 0, ptr noundef byval({ double, double }) align 8 [[BYVAL_TEMP1]]) +// CHECK-DEF-NEXT: [[TMP_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[TMP]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[TMP_REAL:%.*]] = load double, ptr [[TMP_REALP]], align 8 +// CHECK-DEF-NEXT: [[TMP_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[TMP]], i32 0, i32 1 +// CHECK-DEF-NEXT: [[TMP_IMAG:%.*]] = load double, ptr [[TMP_IMAGP]], align 8 +// CHECK-DEF-NEXT: [[AGG_RESULT_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 1 +// CHECK-DEF-NEXT: store double [[TMP_REAL]], ptr [[AGG_RESULT_REALP]], align 8 +// CHECK-DEF-NEXT: store double [[TMP_IMAG]], ptr [[AGG_RESULT_IMAGP]], align 8 +// CHECK-DEF-NEXT: [[AGG_RESULT_REALP2:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[AGG_RESULT_REAL:%.*]] = load double, ptr [[AGG_RESULT_REALP2]], align 8 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP3:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 1 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAG:%.*]] = load double, ptr [[AGG_RESULT_IMAGP3]], align 8 +// CHECK-DEF-NEXT: [[AGG_RESULT_REALP4:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 0 +// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP5:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[AGG_RESULT]], i32 0, i32 1 +// CHECK-DEF-NEXT: store double [[AGG_RESULT_REAL]], ptr [[AGG_RESULT_REALP4]], align 8 +// CHECK-DEF-NEXT: store double [[AGG_RESULT_IMAG]], ptr [[AGG_RESULT_IMAGP5]], align 8 +// CHECK-DEF-NEXT: ret void +// +// CHECK-GNU-LABEL: define dso_local [4 x i32] @checkComplexFloatOnStack +// CHECK-GNU-SAME: ([4 x i32] noundef [[_CD1_COERCE:%.*]], [1 x i64] noundef [[_CF1_COERCE:%.*]], i32 noundef [[Y:%.*]], ptr noundef byval({ float, float }) align 4 [[_CF2:%.*]]) #[[ATTR0]] { +// CHECK-GNU-NEXT: entry: +// CHECK-GNU-NEXT: [[RETVAL:%.*]] = alloca { double, double }, align 8 +// CHECK-GNU-NEXT: [[_CD1:%.*]] = alloca { double, double }, align 8 +// CHECK-GNU-NEXT: [[_CF1:%.*]] = alloca { float, float }, align 4 +// CHECK-GNU-NEXT: [[Y_ADDR:%.*]] = alloca i32, align 4 +// CHECK-GNU-NEXT: [[COERCE:%.*]] = alloca { float, float }, align 4 +// CHECK-GNU-NEXT: [[BYVAL_TEMP:%.*]] = alloca { double, double }, align 8 +// CHECK-GNU-NEXT: [[COERCE1:%.*]] = alloca { double, double }, align 8 +// CHECK-GNU-NEXT: store [4 x i32] [[_CD1_COERCE]], ptr [[_CD1]], align 8 +// CHECK-GNU-NEXT: store [1 x i64] [[_CF1_COERCE]], ptr [[_CF1]], align 4 +// CHECK-GNU-NEXT: store i32 [[Y]], ptr [[Y_ADDR]], align 4 +// CHECK-GNU-NEXT: [[TMP0:%.*]] = load i32, ptr [[Y_ADDR]], align 4 +// CHECK-GNU-NEXT: [[_CF2_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[_CF2]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[_CF2_REAL:%.*]] = load float, ptr [[_CF2_REALP]], align 4 +// CHECK-GNU-NEXT: [[_CF2_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[_CF2]], i32 0, i32 1 +// CHECK-GNU-NEXT: [[_CF2_IMAG:%.*]] = load float, ptr [[_CF2_IMAGP]], align 4 +// CHECK-GNU-NEXT: [[_CD1_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[_CD1]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[_CD1_REAL:%.*]] = load double, ptr [[_CD1_REALP]], align 8 +// CHECK-GNU-NEXT: [[_CD1_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[_CD1]], i32 0, i32 1 +// CHECK-GNU-NEXT: [[_CD1_IMAG:%.*]] = load double, ptr [[_CD1_IMAGP]], align 8 +// CHECK-GNU-NEXT: [[COERCE_REALP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[COERCE]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[COERCE]], i32 0, i32 1 +// CHECK-GNU-NEXT: store float [[_CF2_REAL]], ptr [[COERCE_REALP]], align 4 +// CHECK-GNU-NEXT: store float [[_CF2_IMAG]], ptr [[COERCE_IMAGP]], align 4 +// CHECK-GNU-NEXT: [[TMP1:%.*]] = load [1 x i64], ptr [[COERCE]], align 4 +// CHECK-GNU-NEXT: [[BYVAL_TEMP_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[BYVAL_TEMP]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[BYVAL_TEMP_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[BYVAL_TEMP]], i32 0, i32 1 +// CHECK-GNU-NEXT: store double [[_CD1_REAL]], ptr [[BYVAL_TEMP_REALP]], align 8 +// CHECK-GNU-NEXT: store double [[_CD1_IMAG]], ptr [[BYVAL_TEMP_IMAGP]], align 8 +// CHECK-GNU-NEXT: [[CALL:%.*]] = call [4 x i32] @checkComplexDoubleOnStack(i32 noundef [[TMP0]], [1 x i64] noundef [[TMP1]], i32 noundef 0, ptr noundef byval({ double, double }) align 8 [[BYVAL_TEMP]]) +// CHECK-GNU-NEXT: store [4 x i32] [[CALL]], ptr [[COERCE1]], align 8 +// CHECK-GNU-NEXT: [[COERCE1_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE1]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[COERCE1_REAL:%.*]] = load double, ptr [[COERCE1_REALP]], align 8 +// CHECK-GNU-NEXT: [[COERCE1_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE1]], i32 0, i32 1 +// CHECK-GNU-NEXT: [[COERCE1_IMAG:%.*]] = load double, ptr [[COERCE1_IMAGP]], align 8 +// CHECK-GNU-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 0 +// CHECK-GNU-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 1 +// CHECK-GNU-NEXT: store double [[COERCE1_REAL]], ptr [[RETVAL_REALP]], align 8 +// CHECK-GNU-NEXT: store double [[COERCE1_IMAG]], ptr [[RETVAL_IMAGP]], align 8 +// CHECK-GNU-NEXT: [[TMP2:%.*]] = load [4 x i32], ptr [[RETVAL]], align 8 +// CHECK-GNU-NEXT: ret [4 x i32] [[TMP2]] +// +_Complex double checkComplexFloatOnStack(_Complex double _cd1, _Complex float _cf1, int y, _Complex float _cf2) +{ + return checkComplexDoubleOnStack(y, _cf2, 0, _cd1); +} diff --git a/clang/test/CodeGen/PowerPC/ppc32-complex-soft-float-gnu-abi.c b/clang/test/CodeGen/PowerPC/ppc32-complex-soft-float-gnu-abi.c new file mode 100644 index 000000000000000..423bcf4bb0f7b0c --- /dev/null +++ b/clang/test/CodeGen/PowerPC/ppc32-complex-soft-float-gnu-abi.c @@ -0,0 +1,98 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 + +// RUN: %clang_cc1 -triple powerpc-unknown-linux-unknown -fcomplex-ppc-gnu-abi \ +// RUN: -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-GNU-DEF +// RUN: %clang_cc1 -msoft-float -mfloat-abi soft -triple powerpc-unknown-linux-unknown -fcomplex-ppc-gnu-abi \ +// RUN: -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-GNU-SOFT-FLOAT + + +// CHECK-GNU-DEF-LABEL: define dso_local [8 x i32] @_cldouble +// CHECK-GNU-DEF-SAME: (float noundef [[F:%.*]], [8 x i32] noundef [[X_COERCE:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-GNU-DEF-NEXT: entry: +// CHECK-GNU-DEF-NEXT: [[RETVAL:%.*]] = alloca { ppc_fp128, ppc_fp128 }, align 16 +// CHECK-GNU-DEF-NEXT: [[X:%.*]] = alloca { ppc_fp128, ppc_fp128 }, align 16 +// CHECK-GNU-DEF-NEXT: [[F_ADDR:%.*]] = alloca float, align 4 +// CHECK-GNU-DEF-NEXT: store [8 x i32] [[X_COERCE]], ptr [[X]], align 16 +// CHECK-GNU-DEF-NEXT: store float [[F]], ptr [[F_ADDR]], align 4 +// CHECK-GNU-DEF-NEXT: [[X_REALP:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[X]], i32 0, i32 0 +// CHECK-GNU-DEF-NEXT: [[X_REAL:%.*]] = load ppc_fp128, ptr [[X_REALP]], align 16 +// CHECK-GNU-DEF-NEXT: [[X_IMAGP:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[X]], i32 0, i32 1 +// CHECK-GNU-DEF-NEXT: [[X_IMAG:%.*]] = load ppc_fp128, ptr [[X_IMAGP]], align 16 +// CHECK-GNU-DEF-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[RETVAL]], i32 0, i32 0 +// CHECK-GNU-DEF-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[RETVAL]], i32 0, i32 1 +// CHECK-GNU-DEF-NEXT: store ppc_fp128 [[X_REAL]], ptr [[RETVAL_REALP]], align 16 +// CHECK-GNU-DEF-NEXT: store ppc_fp128 [[X_IMAG]], ptr [[RETVAL_IMAGP]], align 16 +// CHECK-GNU-DEF-NEXT: [[TMP0:%.*]] = load [8 x i32], ptr [[RETVAL]], align 16 +// CHECK-GNU-DEF-NEXT: ret [8 x i32] [[TMP0]] +// +// CHECK-GNU-SOFT-FLOAT-LABEL: define dso_local [8 x i32] @_cldouble +// CHECK-GNU-SOFT-FLOAT-SAME: (float noundef [[F:%.*]], ptr noundef byval({ ppc_fp128, ppc_fp128 }) align 16 [[X:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-GNU-SOFT-FLOAT-NEXT: entry: +// CHECK-GNU-SOFT-FLOAT-NEXT: [[RETVAL:%.*]] = alloca { ppc_fp128, ppc_fp128 }, align 16 +// CHECK-GNU-SOFT-FLOAT-NEXT: [[F_ADDR:%.*]] = alloca float, align 4 +// CHECK-GNU-SOFT-FLOAT-NEXT: store float [[F]], ptr [[F_ADDR]], align 4 +// CHECK-GNU-SOFT-FLOAT-NEXT: [[X_REALP:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[X]], i32 0, i32 0 +// CHECK-GNU-SOFT-FLOAT-NEXT: [[X_REAL:%.*]] = load ppc_fp128, ptr [[X_REALP]], align 16 +// CHECK-GNU-SOFT-FLOAT-NEXT: [[X_IMAGP:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[X]], i32 0, i32 1 +// CHECK-GNU-SOFT-FLOAT-NEXT: [[X_IMAG:%.*]] = load ppc_fp128, ptr [[X_IMAGP]], align 16 +// CHECK-GNU-SOFT-FLOAT-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[RETVAL]], i32 0, i32 0 +// CHECK-GNU-SOFT-FLOAT-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { ppc_fp128, ppc_fp128 }, ptr [[RETVAL]], i32 0, i32 1 +// CHECK-GNU-SOFT-FLOAT-NEXT: store ppc_fp128 [[X_REAL]], ptr [[RETVAL_REALP]], align 16 +// CHECK-GNU-SOFT-FLOAT-NEXT: store ppc_fp128 [[X_IMAG]], ptr [[RETVAL_IMAGP]], align 16 +// CHECK-GNU-SOFT-FLOAT-NEXT: [[TMP0:%.*]] = load [8 x i32], ptr [[RETVAL]], align 16 +// CHECK-GNU-SOFT-FLOAT-NEXT: ret [8 x i32] [[TMP0]] +// +_Complex long double _cldouble(float f, _Complex long double x) { + return x; +} + + + +// CHECK-GNU-DEF-LABEL: define dso_local [4 x i32] @testComplexDouble +// CHECK-GNU-DEF-SAME: (float noundef [[W:%.*]], [1 x i64] noundef [[X_COERCE:%.*]], float noundef [[Y:%.*]], [4 x i32] noundef [[Z_COERCE:%.*]]) #[[ATTR0]] { +// CHECK-GNU-DEF-NEXT: entry: +// CHECK-GNU-DEF-NEXT: [[RETVAL:%.*]] = alloca { double, double }, align 8 +// CHECK-GNU-DEF-NEXT: [[X:%.*]] = alloca { float, float }, align 4 +// CHECK-GNU-DEF-NEXT: [[Z:%.*]] = alloca { double, double }, align 8 +// CHECK-GNU-DEF-NEXT: [[W_ADDR:%.*]] = alloca float, align 4 +// CHECK-GNU-DEF-NEXT: [[Y_ADDR:%.*]] = alloca float, align 4 +// CHECK-GNU-DEF-NEXT: store [1 x i64] [[X_COERCE]], ptr [[X]], align 4 +// CHECK-GNU-DEF-NEXT: store [4 x i32] [[Z_COERCE]], ptr [[Z]], align 8 +// CHECK-GNU-DEF-NEXT: store float [[W]], ptr [[W_ADDR]], align 4 +// CHECK-GNU-DEF-NEXT: store float [[Y]], ptr [[Y_ADDR]], align 4 +// CHECK-GNU-DEF-NEXT: [[Z_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[Z]], i32 0, i32 0 +// CHECK-GNU-DEF-NEXT: [[Z_REAL:%.*]] = load double, ptr [[Z_REALP]], align 8 +// CHECK-GNU-DEF-NEXT: [[Z_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[Z]], i32 0, i32 1 +// CHECK-GNU-DEF-NEXT: [[Z_IMAG:%.*]] = load double, ptr [[Z_IMAGP]], align 8 +// CHECK-GNU-DEF-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 0 +// CHECK-GNU-DEF-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 1 +// CHECK-GNU-DEF-NEXT: store double [[Z_REAL]], ptr [[RETVAL_REALP]], align 8 +// CHECK-GNU-DEF-NEXT: store double [[Z_IMAG]], ptr [[RETVAL_IMAGP]], align 8 +// CHECK-GNU-DEF-NEXT: [[TMP0:%.*]] = load [4 x i32], ptr [[RETVAL]], align 8 +// CHECK-GNU-DEF-NEXT: ret [4 x i32] [[TMP0]] +// +// CHECK-GNU-SOFT-FLOAT-LABEL: define dso_local [4 x i32] @testComplexDouble +// CHECK-GNU-SOFT-FLOAT-SAME: (float noundef [[W:%.*]], [1 x i64] noundef [[X_COERCE:%.*]], float noundef [[Y:%.*]], ptr noundef byval({ double, double }) align 8 [[Z:%.*]]) #[[ATTR0]] { +// CHECK-GNU-SOFT-FLOAT-NEXT: entry: +// CHECK-GNU-SOFT-FLOAT-NEXT: [[RETVAL:%.*]] = alloca { double, double }, align 8 +// CHECK-GNU-SOFT-FLOAT-NEXT: [[X:%.*]] = alloca { float, float }, align 4 +// CHECK-GNU-SOFT-FLOAT-NEXT: [[W_ADDR:%.*]] = alloca float, align 4 +// CHECK-GNU-SOFT-FLOAT-NEXT: [[Y_ADDR:%.*]] = alloca float, align 4 +// CHECK-GNU-SOFT-FLOAT-NEXT: store [1 x i64] [[X_COERCE]], ptr [[X]], align 4 +// CHECK-GNU-SOFT-FLOAT-NEXT: store float [[W]], ptr [[W_ADDR]], align 4 +// CHECK-GNU-SOFT-FLOAT-NEXT: store float [[Y]], ptr [[Y_ADDR]], align 4 +// CHECK-GNU-SOFT-FLOAT-NEXT: [[Z_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[Z]], i32 0, i32 0 +// CHECK-GNU-SOFT-FLOAT-NEXT: [[Z_REAL:%.*]] = load double, ptr [[Z_REALP]], align 8 +// CHECK-GNU-SOFT-FLOAT-NEXT: [[Z_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[Z]], i32 0, i32 1 +// CHECK-GNU-SOFT-FLOAT-NEXT: [[Z_IMAG:%.*]] = load double, ptr [[Z_IMAGP]], align 8 +// CHECK-GNU-SOFT-FLOAT-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 0 +// CHECK-GNU-SOFT-FLOAT-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[RETVAL]], i32 0, i32 1 +// CHECK-GNU-SOFT-FLOAT-NEXT: store double [[Z_REAL]], ptr [[RETVAL_REALP]], align 8 +// CHECK-GNU-SOFT-FLOAT-NEXT: store double [[Z_IMAG]], ptr [[RETVAL_IMAGP]], align 8 +// CHECK-GNU-SOFT-FLOAT-NEXT: [[TMP0:%.*]] = load [4 x i32], ptr [[RETVAL]], align 8 +// CHECK-GNU-SOFT-FLOAT-NEXT: ret [4 x i32] [[TMP0]] +// +_Complex double testComplexDouble(float w, _Complex float x, float y, _Complex double z) +{ + return z; +} diff --git a/clang/test/Driver/ppc32-fcomplex-ppc-gnu-abi.c b/clang/test/Driver/ppc32-fcomplex-ppc-gnu-abi.c new file mode 100644 index 000000000000000..4fe5f1b74b5f9f5 --- /dev/null +++ b/clang/test/Driver/ppc32-fcomplex-ppc-gnu-abi.c @@ -0,0 +1,12 @@ +// RUN: %clang -### -S --target=ppc32 -fcomplex-ppc-gnu-abi %s 2>&1 + +// RUN: %clang -target ppc32-unknown-unknown-gnu -### -S %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-GNU +// CHECK-GNU: "-fcomplex-ppc-gnu-abi" + +// RUN: not %clang -### --target=ppc64 -fcomplex-ppc-gnu-abi %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK-ERROR + +// RUN: not %clang -### --target=ppc32-unknown-unknown-coff -fcomplex-ppc-gnu-abi %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK-ERROR + +// CHECK-ERROR: error: unsupported option '-fcomplex-ppc-gnu-abi' for target