[clang] [clang][PowerPC] Add flag to enable compatibility with GNU for complex arguments (PR #77732)

Kishan Parmar via cfe-commits cfe-commits at lists.llvm.org
Tue Jan 16 21:03:32 PST 2024


https://github.com/Long5hot updated https://github.com/llvm/llvm-project/pull/77732

>From ec05087b89af829247879c2e860f9d93f548c7a1 Mon Sep 17 00:00:00 2001
From: Kishan Parmar <kparmar2101 at gmail.com>
Date: Wed, 17 Jan 2024 10:29:34 +0530
Subject: [PATCH] [clang][PowerPC] Add flag to enable compatibility with GNU
 for complex arguments

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.
---
 clang/include/clang/Basic/CodeGenOptions.def  |   2 +
 clang/include/clang/Basic/CodeGenOptions.h    |   7 +
 clang/include/clang/Driver/Options.td         |   4 +
 clang/lib/CodeGen/CodeGenModule.cpp           |   6 +-
 clang/lib/CodeGen/TargetInfo.h                |   3 +-
 clang/lib/CodeGen/Targets/PPC.cpp             | 110 +++++++++++++--
 clang/lib/Driver/ToolChains/Clang.cpp         |   9 ++
 clang/lib/Frontend/CompilerInvocation.cpp     |   8 ++
 .../CodeGen/PowerPC/ppc32-complex-gnu-abi.c   | 132 ++++++++++++++++++
 9 files changed, 266 insertions(+), 15 deletions(-)
 create mode 100644 clang/test/CodeGen/PowerPC/ppc32-complex-gnu-abi.c

diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 2c4fb6745bc172f..beeefae15c63f82 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -213,6 +213,8 @@ CODEGENOPT(MCDCCoverage , 1, 0) ///< Enable MC/DC code coverage criteria.
 
   /// If -fpcc-struct-return or -freg-struct-return is specified.
 ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, SRCK_Default)
+  /// If -fcomplex-ppc-gnu-abi for ppc32
+ENUM_CODEGENOPT(ComplexInRegABI, ComplexArgumentConventionKind, 2, CMPLX_Default)
 
 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 6952b48e898a819..8abca0e3dda3343 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -78,6 +78,13 @@ class CodeGenOptions : public CodeGenOptionsBase {
     SRCK_InRegs    // Small structs in registers (-freg-struct-return).
   };
 
+  enum ComplexArgumentConventionKind {
+    CMPLX_Default,
+    CMPLX_OnStack,
+    CMPLX_OnGPR, // if ppc32 -fcomplex-ppc-gnu-abi
+    CMPLX_OnFPR
+  };
+
   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 a4a988c71ec412c..10166757b1352ed 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2540,6 +2540,10 @@ def ffp_contract : Joined<["-"], "ffp-contract=">, Group<f_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<f_Group>, Visibility<[ClangOption, CC1Option]>,
+  DocBrief<"Follow the GNU ABI, store Complex values in GPR instead of stack for PowerPC-32">,
+  HelpText<"Store Complex values in GPR instead of stack for PowerPC-32">;
+
 defm strict_float_cast_overflow : BoolFOption<"strict-float-cast-overflow",
   CodeGenOpts<"StrictFloatCastOverflow">, DefaultTrue,
   NegFlag<SetFalse, [], [ClangOption, CC1Option],
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 482c2108a988a16..ae4c6cb37ef1906 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -184,11 +184,13 @@ createTargetCodeGenInfo(CodeGenModule &CGM) {
 
     bool IsSoftFloat =
         CodeGenOpts.FloatABI == "soft" || Target.hasFeature("spe");
-    return createPPC32TargetCodeGenInfo(CGM, IsSoftFloat);
+    unsigned RLen = Target.getPointerWidth(LangAS::Default);
+    return createPPC32TargetCodeGenInfo(CGM, IsSoftFloat, RLen);
   }
   case llvm::Triple::ppcle: {
     bool IsSoftFloat = CodeGenOpts.FloatABI == "soft";
-    return createPPC32TargetCodeGenInfo(CGM, IsSoftFloat);
+    unsigned RLen = Target.getPointerWidth(LangAS::Default);
+    return createPPC32TargetCodeGenInfo(CGM, IsSoftFloat, RLen);
   }
   case llvm::Triple::ppc64:
     if (Triple.isOSAIX())
diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h
index 7682f197041c748..5616141bc0f0c09 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -486,7 +486,8 @@ std::unique_ptr<TargetCodeGenInfo>
 createAIXTargetCodeGenInfo(CodeGenModule &CGM, bool Is64Bit);
 
 std::unique_ptr<TargetCodeGenInfo>
-createPPC32TargetCodeGenInfo(CodeGenModule &CGM, bool SoftFloatABI);
+createPPC32TargetCodeGenInfo(CodeGenModule &CGM, bool SoftFloatABI,
+                             unsigned RLen);
 
 std::unique_ptr<TargetCodeGenInfo>
 createPPC64TargetCodeGenInfo(CodeGenModule &CGM);
diff --git a/clang/lib/CodeGen/Targets/PPC.cpp b/clang/lib/CodeGen/Targets/PPC.cpp
index 40dddde508c1772..f514f2e25a48f92 100644
--- a/clang/lib/CodeGen/Targets/PPC.cpp
+++ b/clang/lib/CodeGen/Targets/PPC.cpp
@@ -271,22 +271,33 @@ namespace {
 class PPC32_SVR4_ABIInfo : public DefaultABIInfo {
   bool IsSoftFloatABI;
   bool IsRetSmallStructInRegABI;
+  bool isComplexInRegABI;
+  // Size of GPR in bits
+  unsigned RLen;
+  static const int NumArgGPRs = 8;
 
   CharUnits getParamTypeAlignment(QualType Ty) const;
+  ABIArgInfo handleComplex(QualType Ty, uint64_t &TypeSize) const;
 
 public:
   PPC32_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, bool SoftFloatABI,
-                     bool RetSmallStructInRegABI)
+                     bool RetSmallStructInRegABI, unsigned RLen,
+                     bool ComplexInRegABI)
       : DefaultABIInfo(CGT), IsSoftFloatABI(SoftFloatABI),
-        IsRetSmallStructInRegABI(RetSmallStructInRegABI) {}
+        IsRetSmallStructInRegABI(RetSmallStructInRegABI),
+        isComplexInRegABI(ComplexInRegABI), RLen(RLen) {}
 
   ABIArgInfo classifyReturnType(QualType RetTy) const;
+  ABIArgInfo classifyArgumentType(QualType Ty, int &ArgGPRsLeft) const;
 
   void computeInfo(CGFunctionInfo &FI) const override {
+
+    int ArgGPRsLeft = NumArgGPRs;
+
     if (!getCXXABI().classifyReturnType(FI))
       FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
     for (auto &I : FI.arguments())
-      I.info = classifyArgumentType(I.type);
+      I.info = classifyArgumentType(I.type, ArgGPRsLeft);
   }
 
   Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
@@ -296,9 +307,11 @@ class PPC32_SVR4_ABIInfo : public DefaultABIInfo {
 class PPC32TargetCodeGenInfo : public TargetCodeGenInfo {
 public:
   PPC32TargetCodeGenInfo(CodeGenTypes &CGT, bool SoftFloatABI,
-                         bool RetSmallStructInRegABI)
+                         bool RetSmallStructInRegABI, unsigned RLen,
+                         bool ComplexInRegABI)
       : TargetCodeGenInfo(std::make_unique<PPC32_SVR4_ABIInfo>(
-            CGT, SoftFloatABI, RetSmallStructInRegABI)) {}
+            CGT, SoftFloatABI, RetSmallStructInRegABI, RLen, ComplexInRegABI)) {
+  }
 
   static bool isStructReturnInRegABI(const llvm::Triple &Triple,
                                      const CodeGenOptions &Opts);
@@ -337,12 +350,77 @@ CharUnits PPC32_SVR4_ABIInfo::getParamTypeAlignment(QualType Ty) const {
   return CharUnits::fromQuantity(4);
 }
 
+ABIArgInfo PPC32_SVR4_ABIInfo::handleComplex(QualType Ty,
+                                             uint64_t &TypeSize) const {
+
+  assert(Ty->isAnyComplexType());
+  llvm::Type *ElemTy;
+  unsigned SizeRegs;
+
+  if (TypeSize == 64) {
+    ElemTy = llvm::Type::getInt64Ty(getVMContext());
+    SizeRegs = 1;
+  } else {
+    ElemTy = llvm::Type::getInt32Ty(getVMContext());
+    SizeRegs = (TypeSize + 31) / 32;
+  }
+  return ABIArgInfo::getDirect(llvm::ArrayType::get(ElemTy, SizeRegs));
+}
+
+ABIArgInfo PPC32_SVR4_ABIInfo::classifyArgumentType(QualType Ty,
+                                                    int &ArgGPRsLeft) const {
+
+  assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow");
+  Ty = useFirstFieldIfTransparentUnion(Ty);
+
+  ASTContext &Context = getContext();
+
+  uint64_t TypeSize = Context.getTypeSize(Ty);
+
+  if (isComplexInRegABI && Ty->isAnyComplexType() &&
+      TypeSize <= RLen * ArgGPRsLeft) {
+    ArgGPRsLeft -= TypeSize / RLen;
+    return handleComplex(Ty, TypeSize);
+  }
+
+  if (isAggregateTypeForABI(Ty)) {
+    if (ArgGPRsLeft)
+      ArgGPRsLeft -= 1;
+    // Records with non-trivial destructors/copy-constructors should not be
+    // passed by value.
+    if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
+      return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
+    }
+    return getNaturalAlignIndirect(Ty);
+  }
+
+  if (!Ty->isFloatingType()) {
+    if (TypeSize > RLen && TypeSize <= 2 * RLen)
+      ArgGPRsLeft -= 2;
+    else
+      ArgGPRsLeft--;
+  }
+
+  // Treat an enum type as its underlying type.
+  if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+    Ty = EnumTy->getDecl()->getIntegerType();
+
+  if (const auto *EIT = Ty->getAs<BitIntType>())
+    if (EIT->getNumBits() >
+        Context.getTypeSize(Context.getTargetInfo().hasInt128Type()
+                                ? Context.Int128Ty
+                                : Context.LongLongTy))
+      return getNaturalAlignIndirect(Ty);
+
+  return (isPromotableIntegerTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty)
+                                            : ABIArgInfo::getDirect());
+}
+
 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
@@ -361,6 +439,9 @@ ABIArgInfo PPC32_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const {
       return ABIArgInfo::getDirect(CoerceTy);
     }
   }
+  if (isComplexInRegABI && RetTy->isAnyComplexType()) {
+    return handleComplex(RetTy, Size);
+  }
 
   return DefaultABIInfo::classifyReturnType(RetTy);
 }
@@ -372,11 +453,12 @@ Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList,
   if (getTarget().getTriple().isOSDarwin()) {
     auto TI = getContext().getTypeInfoInChars(Ty);
     TI.Align = getParamTypeAlignment(Ty);
+    int ArgGPRs = NumArgGPRs;
 
     CharUnits SlotSize = CharUnits::fromQuantity(4);
     return emitVoidPtrVAArg(CGF, VAList, Ty,
-                            classifyArgumentType(Ty).isIndirect(), TI, SlotSize,
-                            /*AllowHigherAlign=*/true);
+                            classifyArgumentType(Ty, ArgGPRs).isIndirect(), TI,
+                            SlotSize, /*AllowHigherAlign=*/true);
   }
 
   const unsigned OverflowLimit = 8;
@@ -974,11 +1056,15 @@ CodeGen::createAIXTargetCodeGenInfo(CodeGenModule &CGM, bool Is64Bit) {
 }
 
 std::unique_ptr<TargetCodeGenInfo>
-CodeGen::createPPC32TargetCodeGenInfo(CodeGenModule &CGM, bool SoftFloatABI) {
+CodeGen::createPPC32TargetCodeGenInfo(CodeGenModule &CGM, bool SoftFloatABI,
+                                      unsigned RLen) {
   bool RetSmallStructInRegABI = PPC32TargetCodeGenInfo::isStructReturnInRegABI(
       CGM.getTriple(), CGM.getCodeGenOpts());
+  bool isComplexInRegABI = (CGM.getCodeGenOpts().getComplexInRegABI() ==
+                            CodeGenOptions::CMPLX_OnGPR);
   return std::make_unique<PPC32TargetCodeGenInfo>(CGM.getTypes(), SoftFloatABI,
-                                                  RetSmallStructInRegABI);
+                                                  RetSmallStructInRegABI, RLen,
+                                                  isComplexInRegABI);
 }
 
 std::unique_ptr<TargetCodeGenInfo>
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 997ec2d491d02c8..09b4dc8aac6eb78 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5470,6 +5470,15 @@ 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");
+    }
+  }
+
   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 11f3f2c2d6425cc..5c1f7da805db87e 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1640,6 +1640,10 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
     GenerateArg(Consumer, Opt);
   }
 
+  if (T.isPPC32() && Opts.ComplexInRegABI == CodeGenOptions::CMPLX_OnGPR) {
+    GenerateArg(Consumer, OPT_fcomplex_ppc_gnu_abi);
+  }
+
   if (Opts.EnableAIXExtendedAltivecABI)
     GenerateArg(Consumer, OPT_mabi_EQ_vec_extabi);
 
@@ -2034,6 +2038,10 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
     }
   }
 
+  if (Args.getLastArg(OPT_fcomplex_ppc_gnu_abi)) {
+    Opts.setComplexInRegABI(CodeGenOptions::CMPLX_OnGPR);
+  }
+
   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..b0df1dc836ba816
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/ppc32-complex-gnu-abi.c
@@ -0,0 +1,132 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2
+
+// RUN: %clang_cc1 -triple powerpc-unknown-linux-gnu -target-cpu pwr8 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-DEF
+// RUN: %clang_cc1 -triple powerpc-unknown-linux-gnu -target-cpu pwr8 -fcomplex-ppc-gnu-abi \
+// RUN:   -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-GNU
+
+// CHECK-DEF-LABEL: define dso_local void @foo1
+// CHECK-DEF-SAME: (ptr noalias 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 { 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 { 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 { float, float }, ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-DEF-NEXT:    [[AGG_RESULT_IMAGP:%.*]] = getelementptr inbounds { 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 { 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 { 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 { float, float }, ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-DEF-NEXT:    [[AGG_RESULT_IMAGP4:%.*]] = getelementptr inbounds { 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] @foo1
+// 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 { 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 { 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 { float, float }, ptr [[RETVAL]], i32 0, i32 0
+// CHECK-GNU-NEXT:    [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { 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 foo1(_Complex float x) {
+  return x;
+}
+
+// CHECK-DEF-LABEL: define dso_local void @foo2
+// CHECK-DEF-SAME: (ptr noalias 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 { 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 { 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 { double, double }, ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-DEF-NEXT:    [[AGG_RESULT_IMAGP:%.*]] = getelementptr inbounds { 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 { 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 { 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 { double, double }, ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-DEF-NEXT:    [[AGG_RESULT_IMAGP4:%.*]] = getelementptr inbounds { 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] @foo2
+// 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 { 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 { 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 { double, double }, ptr [[RETVAL]], i32 0, i32 0
+// CHECK-GNU-NEXT:    [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { 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 foo2(_Complex double x) {
+  return x;
+}
+
+// CHECK-DEF-LABEL: define dso_local void @foo3
+// CHECK-DEF-SAME: (ptr noalias 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 { 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 { 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 { ppc_fp128, ppc_fp128 }, ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-DEF-NEXT:    [[AGG_RESULT_IMAGP:%.*]] = getelementptr inbounds { 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 { 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 { 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 { ppc_fp128, ppc_fp128 }, ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-DEF-NEXT:    [[AGG_RESULT_IMAGP4:%.*]] = getelementptr inbounds { 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] @foo3
+// 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 { 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 { 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 { ppc_fp128, ppc_fp128 }, ptr [[RETVAL]], i32 0, i32 0
+// CHECK-GNU-NEXT:    [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { 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 foo3(_Complex long double x) {
+  return x;
+}



More information about the cfe-commits mailing list