This revision was automatically updated to reflect the committed changes.
Closed by commit rG4ca2cad947d0: [PowerPC] Add clang -msvr4-struct-return for 
32-bit ELF (authored by jhibbits).

Changed prior to commit:
  https://reviews.llvm.org/D73290?vs=239982&id=259143#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D73290/new/

https://reviews.llvm.org/D73290

Files:
  clang/docs/ClangCommandLineReference.rst
  clang/include/clang/Driver/Options.td
  clang/lib/CodeGen/TargetInfo.cpp
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/test/CodeGen/ppc32-struct-return.c
  clang/test/Driver/ppc-unsupported.c

Index: clang/test/Driver/ppc-unsupported.c
===================================================================
--- /dev/null
+++ clang/test/Driver/ppc-unsupported.c
@@ -0,0 +1,10 @@
+// REQUIRES: powerpc-registered-target
+// RUN: not %clang -target powerpc64-unknown-freebsd -maix-struct-return \
+// RUN:   -c %s 2>&1 | FileCheck %s
+// RUN: not %clang -target powerpc64-unknown-freebsd -msvr4-struct-return \
+// RUN:   -c %s 2>&1 | FileCheck %s
+// RUN: not %clang -target powerpc64le-unknown-linux -maix-struct-return \
+// RUN:   -c %s 2>&1 | FileCheck %s
+// RUN: not %clang -target powerpc64le-unknown-linux -msvr4-struct-return \
+// RUN:   -c %s 2>&1 | FileCheck %s
+// CHECK: unsupported option
Index: clang/test/CodeGen/ppc32-struct-return.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/ppc32-struct-return.c
@@ -0,0 +1,88 @@
+// REQUIRES: powerpc-registered-target
+// RUN: %clang_cc1 -triple powerpc-unknown-freebsd \
+// RUN:   -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-SVR4
+// RUN: %clang_cc1 -triple powerpc-unknown-linux \
+// RUN:   -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-AIX
+// RUN: %clang_cc1 -triple powerpc-unknown-linux -maix-struct-return \
+// RUN:   -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-AIX
+// RUN: %clang_cc1 -triple powerpc-unknown-linux -msvr4-struct-return \
+// RUN:   -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-SVR4
+// RUN: %clang_cc1 -triple powerpc-unknown-netbsd \
+// RUN:   -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-SVR4
+// RUN: %clang_cc1 -triple powerpc-unknown-openbsd \
+// RUN:   -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-SVR4
+// RUN: %clang_cc1 -triple powerpc-unknown-openbsd -maix-struct-return \
+// RUN:   -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-AIX
+// RUN: %clang_cc1 -triple powerpc-unknown-openbsd -msvr4-struct-return \
+// RUN:   -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-SVR4
+
+typedef struct {
+} Zero;
+typedef struct {
+  char c;
+} One;
+typedef struct {
+  short s;
+} Two;
+typedef struct {
+  char c[3];
+} Three;
+typedef struct {
+  float f;
+} Four; // svr4 to return i32, not float
+typedef struct {
+  char c[5];
+} Five;
+typedef struct {
+  short s[3];
+} Six;
+typedef struct {
+  char c[7];
+} Seven;
+typedef struct {
+  int i;
+  char c;
+} Eight; // padded for alignment
+typedef struct {
+  char c[9];
+} Nine;
+
+// CHECK-AIX-LABEL: define void @ret0(%struct.Zero* noalias sret {{[^,]*}})
+// CHECK-SVR4-LABEL: define void @ret0()
+Zero ret0(void) { return (Zero){}; }
+
+// CHECK-AIX-LABEL: define void @ret1(%struct.One* noalias sret {{[^,]*}})
+// CHECK-SVR4-LABEL: define i8 @ret1()
+One ret1(void) { return (One){'a'}; }
+
+// CHECK-AIX-LABEL: define void @ret2(%struct.Two* noalias sret {{[^,]*}})
+// CHECK-SVR4-LABEL: define i16 @ret2()
+Two ret2(void) { return (Two){123}; }
+
+// CHECK-AIX-LABEL: define void @ret3(%struct.Three* noalias sret {{[^,]*}})
+// CHECK-SVR4-LABEL: define i24 @ret3()
+Three ret3(void) { return (Three){"abc"}; }
+
+// CHECK-AIX-LABEL: define void @ret4(%struct.Four* noalias sret {{[^,]*}})
+// CHECK-SVR4-LABEL: define i32 @ret4()
+Four ret4(void) { return (Four){0.4}; }
+
+// CHECK-AIX-LABEL: define void @ret5(%struct.Five* noalias sret {{[^,]*}})
+// CHECK-SVR4-LABEL: define i40 @ret5()
+Five ret5(void) { return (Five){"abcde"}; }
+
+// CHECK-AIX-LABEL: define void @ret6(%struct.Six* noalias sret {{[^,]*}})
+// CHECK-SVR4-LABEL: define i48 @ret6()
+Six ret6(void) { return (Six){12, 34, 56}; }
+
+// CHECK-AIX-LABEL: define void @ret7(%struct.Seven* noalias sret {{[^,]*}})
+// CHECK-SVR4-LABEL: define i56 @ret7()
+Seven ret7(void) { return (Seven){"abcdefg"}; }
+
+// CHECK-AIX-LABEL: define void @ret8(%struct.Eight* noalias sret {{[^,]*}})
+// CHECK-SVR4-LABEL: define i64 @ret8()
+Eight ret8(void) { return (Eight){123, 'a'}; }
+
+// CHECK-AIX-LABEL: define void @ret9(%struct.Nine* noalias sret {{[^,]*}})
+// CHECK-SVR4-LABEL: define void @ret9(%struct.Nine* noalias sret {{[^,]*}})
+Nine ret9(void) { return (Nine){"abcdefghi"}; }
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -1297,11 +1297,18 @@
       Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
   }
 
-  if (Arg *A = Args.getLastArg(OPT_fpcc_struct_return, OPT_freg_struct_return)) {
-    if (A->getOption().matches(OPT_fpcc_struct_return)) {
+  // X86_32 has -fppc-struct-return and -freg-struct-return.
+  // PPC32 has -maix-struct-return and -msvr4-struct-return.
+  if (Arg *A =
+          Args.getLastArg(OPT_fpcc_struct_return, OPT_freg_struct_return,
+                          OPT_maix_struct_return, OPT_msvr4_struct_return)) {
+    const Option &O = A->getOption();
+    if (O.matches(OPT_fpcc_struct_return) ||
+        O.matches(OPT_maix_struct_return)) {
       Opts.setStructReturnConvention(CodeGenOptions::SRCK_OnStack);
     } else {
-      assert(A->getOption().matches(OPT_freg_struct_return));
+      assert(O.matches(OPT_freg_struct_return) ||
+             O.matches(OPT_msvr4_struct_return));
       Opts.setStructReturnConvention(CodeGenOptions::SRCK_InRegs);
     }
   }
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -4535,6 +4535,19 @@
     CmdArgs.push_back(A->getValue());
   }
 
+  if (Arg *A = Args.getLastArg(options::OPT_maix_struct_return,
+                               options::OPT_msvr4_struct_return)) {
+    if (TC.getArch() != llvm::Triple::ppc) {
+      D.Diag(diag::err_drv_unsupported_opt_for_target)
+          << A->getSpelling() << RawTriple.str();
+    } else if (A->getOption().matches(options::OPT_maix_struct_return)) {
+      CmdArgs.push_back("-maix-struct-return");
+    } else {
+      assert(A->getOption().matches(options::OPT_msvr4_struct_return));
+      CmdArgs.push_back("-msvr4-struct-return");
+    }
+  }
+
   if (Arg *A = Args.getLastArg(options::OPT_fpcc_struct_return,
                                options::OPT_freg_struct_return)) {
     if (TC.getArch() != llvm::Triple::x86) {
Index: clang/lib/CodeGen/TargetInfo.cpp
===================================================================
--- clang/lib/CodeGen/TargetInfo.cpp
+++ clang/lib/CodeGen/TargetInfo.cpp
@@ -4177,12 +4177,24 @@
 /// PPC32_SVR4_ABIInfo - The 32-bit PowerPC ELF (SVR4) ABI information.
 class PPC32_SVR4_ABIInfo : public DefaultABIInfo {
   bool IsSoftFloatABI;
+  bool IsRetSmallStructInRegABI;
 
   CharUnits getParamTypeAlignment(QualType Ty) const;
 
 public:
-  PPC32_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, bool SoftFloatABI)
-      : DefaultABIInfo(CGT), IsSoftFloatABI(SoftFloatABI) {}
+  PPC32_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, bool SoftFloatABI,
+                     bool RetSmallStructInRegABI)
+      : DefaultABIInfo(CGT), IsSoftFloatABI(SoftFloatABI),
+        IsRetSmallStructInRegABI(RetSmallStructInRegABI) {}
+
+  ABIArgInfo classifyReturnType(QualType RetTy) const;
+
+  void computeInfo(CGFunctionInfo &FI) const override {
+    if (!getCXXABI().classifyReturnType(FI))
+      FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+    for (auto &I : FI.arguments())
+      I.info = classifyArgumentType(I.type);
+  }
 
   Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
                     QualType Ty) const override;
@@ -4190,8 +4202,13 @@
 
 class PPC32TargetCodeGenInfo : public TargetCodeGenInfo {
 public:
-  PPC32TargetCodeGenInfo(CodeGenTypes &CGT, bool SoftFloatABI)
-      : TargetCodeGenInfo(new PPC32_SVR4_ABIInfo(CGT, SoftFloatABI)) {}
+  PPC32TargetCodeGenInfo(CodeGenTypes &CGT, bool SoftFloatABI,
+                         bool RetSmallStructInRegABI)
+      : TargetCodeGenInfo(new PPC32_SVR4_ABIInfo(CGT, SoftFloatABI,
+                                                 RetSmallStructInRegABI)) {}
+
+  static bool isStructReturnInRegABI(const llvm::Triple &Triple,
+                                     const CodeGenOptions &Opts);
 
   int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
     // This is recovered from gcc output.
@@ -4227,6 +4244,34 @@
   return CharUnits::fromQuantity(4);
 }
 
+ABIArgInfo PPC32_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const {
+  uint64_t Size;
+
+  // -msvr4-struct-return puts small aggregates in GPR3 and GPR4.
+  if (isAggregateTypeForABI(RetTy) && IsRetSmallStructInRegABI &&
+      (Size = getContext().getTypeSize(RetTy)) <= 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
+    // > 8-byte aligned memory area and then the low addressed word were
+    // > loaded into r3 and the high-addressed word into r4.  Bits beyond
+    // > the last member of the structure or union are not defined.
+    //
+    // GCC for big-endian PPC32 inserts the pad before the first member,
+    // not "beyond the last member" of the struct.  To stay compatible
+    // with GCC, we coerce the struct to an integer of the same size.
+    // LLVM will extend it and return i32 in r3, or i64 in r3:r4.
+    if (Size == 0)
+      return ABIArgInfo::getIgnore();
+    else {
+      llvm::Type *CoerceTy = llvm::Type::getIntNTy(getVMContext(), Size);
+      return ABIArgInfo::getDirect(CoerceTy);
+    }
+  }
+
+  return DefaultABIInfo::classifyReturnType(RetTy);
+}
+
 // TODO: this implementation is now likely redundant with
 // DefaultABIInfo::EmitVAArg.
 Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList,
@@ -4382,6 +4427,25 @@
   return Result;
 }
 
+bool PPC32TargetCodeGenInfo::isStructReturnInRegABI(
+    const llvm::Triple &Triple, const CodeGenOptions &Opts) {
+  assert(Triple.getArch() == llvm::Triple::ppc);
+
+  switch (Opts.getStructReturnConvention()) {
+  case CodeGenOptions::SRCK_Default:
+    break;
+  case CodeGenOptions::SRCK_OnStack: // -maix-struct-return
+    return false;
+  case CodeGenOptions::SRCK_InRegs: // -msvr4-struct-return
+    return true;
+  }
+
+  if (Triple.isOSBinFormatELF() && !Triple.isOSLinux())
+    return true;
+
+  return false;
+}
+
 bool
 PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
                                                 llvm::Value *Address) const {
@@ -10264,10 +10328,14 @@
     return SetCGInfo(new ARMTargetCodeGenInfo(Types, Kind));
   }
 
-  case llvm::Triple::ppc:
+  case llvm::Triple::ppc: {
+    bool IsSoftFloat =
+        CodeGenOpts.FloatABI == "soft" || getTarget().hasFeature("spe");
+    bool RetSmallStructInRegABI =
+        PPC32TargetCodeGenInfo::isStructReturnInRegABI(Triple, CodeGenOpts);
     return SetCGInfo(
-        new PPC32TargetCodeGenInfo(Types, CodeGenOpts.FloatABI == "soft" ||
-                                   getTarget().hasFeature("spe")));
+        new PPC32TargetCodeGenInfo(Types, IsSoftFloat, RetSmallStructInRegABI));
+  }
   case llvm::Triple::ppc64:
     if (Triple.isOSBinFormatELF()) {
       PPC64_SVR4_ABIInfo::ABIKind Kind = PPC64_SVR4_ABIInfo::ELFv1;
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -2510,6 +2510,12 @@
     Group<m_ppc_Features_Group>;
 def mno_longcall : Flag<["-"], "mno-longcall">,
     Group<m_ppc_Features_Group>;
+def maix_struct_return : Flag<["-"], "maix-struct-return">,
+  Group<m_Group>, Flags<[CC1Option]>,
+  HelpText<"Return all structs in memory (PPC32 only)">;
+def msvr4_struct_return : Flag<["-"], "msvr4-struct-return">,
+  Group<m_Group>, Flags<[CC1Option]>,
+  HelpText<"Return small structs in registers (PPC32 only)">;
 
 def mvx : Flag<["-"], "mvx">, Group<m_Group>;
 def mno_vx : Flag<["-"], "mno-vx">, Group<m_Group>;
Index: clang/docs/ClangCommandLineReference.rst
===================================================================
--- clang/docs/ClangCommandLineReference.rst
+++ clang/docs/ClangCommandLineReference.rst
@@ -2973,6 +2973,11 @@
 
 PowerPC
 -------
+.. option:: -maix-struct-return
+
+Override the default ABI for 32-bit targets to return all structs in memory,
+as in the Power 32-bit ABI for Linux (2011), and on AIX and Darwin.
+
 .. option:: -maltivec, -mno-altivec
 
 .. option:: -mcmpb, -mno-cmpb
@@ -3009,6 +3014,11 @@
 
 .. option:: -mspe, -mno-spe
 
+.. option:: -msvr4-struct-return
+
+Override the default ABI for 32-bit targets to return small structs in
+registers, as in the System V ABI (1995).
+
 .. option:: -mvsx, -mno-vsx
 
 WebAssembly
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to