Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AIX] Add -msave-reg-params to save arguments to stack #97524

Merged
merged 1 commit into from
Jul 24, 2024

Conversation

ecnelises
Copy link
Member

@ecnelises ecnelises commented Jul 3, 2024

In PowerPC ABI, a few initial arguments are passed through registers,
but their places in parameter save area are reserved, arguments passed
by memory goes after the reserved location.

For debugging purpose, we may want to save copy of the pass-by-reg
arguments into correct places on stack. The new option achieves by
adding new function level attribute and make argument lowering part
aware of it.

@llvmbot llvmbot added clang Clang issues not falling into any other category backend:PowerPC clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen labels Jul 3, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Jul 3, 2024

@llvm/pr-subscribers-backend-powerpc
@llvm/pr-subscribers-clang-driver
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-codegen

Author: Qiu Chaofan (ecnelises)

Changes

In PowerPC ABI, a few initial arguments are passed through registers, but their places in parameter save area are reserved, arguments passed by memory goes after the reserved location.

For debugging purpose, we may want to save copy of the pass-by-reg arguments into correct places on stack. The new option achieves by adding new function level attribute and make argument lowering part aware of it.


Patch is 34.74 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/97524.diff

9 Files Affected:

  • (modified) clang/include/clang/Basic/CodeGenOptions.def (+3)
  • (modified) clang/include/clang/Driver/Options.td (+4)
  • (modified) clang/lib/CodeGen/CGCall.cpp (+3)
  • (modified) clang/lib/Driver/ToolChains/AIX.cpp (+3)
  • (added) clang/test/CodeGen/PowerPC/save-reg-params.c (+12)
  • (modified) llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp (+12-8)
  • (modified) llvm/lib/Target/PowerPC/PPCISelLowering.cpp (+24)
  • (modified) llvm/lib/Target/PowerPC/PPCMachineFunctionInfo.h (+6)
  • (added) llvm/test/CodeGen/PowerPC/save-reg-params.ll (+817)
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index e3f6da4a84f69..fcf15aa9c400a 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -425,6 +425,9 @@ CODEGENOPT(ForceAAPCSBitfieldLoad, 1, 0)
 /// Assume that by-value parameters do not alias any other values.
 CODEGENOPT(PassByValueIsNoAlias, 1, 0)
 
+/// Whether to store register parameters to stack.
+CODEGENOPT(SaveRegParams, 1, 0)
+
 /// Whether to not follow the AAPCS that enforces volatile bit-field access width to be
 /// according to the field declaring type width.
 CODEGENOPT(AAPCSBitfieldWidth, 1, 1)
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 1c2b8cfeef6ce..4135f0db60450 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -5040,6 +5040,10 @@ def mspe : Flag<["-"], "mspe">, Group<m_ppc_Features_Group>;
 def mno_spe : Flag<["-"], "mno-spe">, Group<m_ppc_Features_Group>;
 def mefpu2 : Flag<["-"], "mefpu2">, Group<m_ppc_Features_Group>;
 } // let Flags = [TargetSpecific]
+def msave_reg_params : Flag<["-"], "msave-reg-params">, Group<m_Group>,
+  Visibility<[ClangOption, CC1Option]>,
+  HelpText<"Save arguments passed by registers to stack">,
+  MarshallingInfoFlag<CodeGenOpts<"SaveRegParams">>;
 def mabi_EQ_quadword_atomics : Flag<["-"], "mabi=quadword-atomics">,
   Group<m_Group>, Visibility<[ClangOption, CC1Option]>,
   HelpText<"Enable quadword atomics ABI on AIX (AIX PPC64 only). Uses lqarx/stqcx. instructions.">,
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 2b301130ef7b7..8269755cdbf89 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -1931,6 +1931,9 @@ static void getTrivialDefaultFunctionAttributes(
     if (CodeGenOpts.NullPointerIsValid)
       FuncAttrs.addAttribute(llvm::Attribute::NullPointerIsValid);
 
+    if (CodeGenOpts.SaveRegParams)
+      FuncAttrs.addAttribute("save-reg-params");
+
     if (LangOpts.getDefaultExceptionMode() == LangOptions::FPE_Ignore)
       FuncAttrs.addAttribute("no-trapping-math", "true");
 
diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp
index b04502a57a9f7..c2de7328c25c5 100644
--- a/clang/lib/Driver/ToolChains/AIX.cpp
+++ b/clang/lib/Driver/ToolChains/AIX.cpp
@@ -548,6 +548,9 @@ void AIX::addClangTargetOptions(
                   options::OPT_mtocdata))
     addTocDataOptions(Args, CC1Args, getDriver());
 
+  if (Args.hasArg(options::OPT_msave_reg_params))
+    CC1Args.push_back("-msave-reg-params");
+
   if (Args.hasFlag(options::OPT_fxl_pragma_pack,
                    options::OPT_fno_xl_pragma_pack, true))
     CC1Args.push_back("-fxl-pragma-pack");
diff --git a/clang/test/CodeGen/PowerPC/save-reg-params.c b/clang/test/CodeGen/PowerPC/save-reg-params.c
new file mode 100644
index 0000000000000..6599310afa41a
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/save-reg-params.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -emit-llvm -o - %s -msave-reg-params | FileCheck -check-prefix=SAVE %s
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix -emit-llvm -o - %s -msave-reg-params | FileCheck -check-prefix=SAVE %s
+// RUN: %clang_cc1 -triple powerpc-ibm-aix -emit-llvm -o - %s -msave-reg-params | FileCheck -check-prefix=SAVE %s
+// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=NOSAVE %s
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix -emit-llvm -o - %s | FileCheck -check-prefix=NOSAVE %s
+// RUN: %clang_cc1 -triple powerpc-ibm-aix -emit-llvm -o - %s | FileCheck -check-prefix=NOSAVE %s
+
+void bar(int);
+void foo(int x) { bar(x); }
+
+// SAVE: attributes #{{[0-9]+}} = { {{.+}} "save-reg-params" {{.+}} }
+// NOSAVE-NOT: "save-reg-params"···
\ No newline at end of file
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index d74143b487880..085a67e919421 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -2496,15 +2496,19 @@ void PPCAIXAsmPrinter::emitTracebackTable() {
 
   uint32_t GPRSaved = 0;
 
-  // X13 is reserved under 64-bit environment.
-  unsigned GPRBegin = Subtarget->isPPC64() ? PPC::X14 : PPC::R13;
-  unsigned GPREnd = Subtarget->isPPC64() ? PPC::X31 : PPC::R31;
-
-  for (unsigned Reg = GPRBegin; Reg <= GPREnd; ++Reg) {
-    if (MRI.isPhysRegModified(Reg)) {
-      GPRSaved = GPREnd - Reg + 1;
-      break;
+  if (FI->getForceGPRSaveCount() < 0) {
+    // X13 is reserved under 64-bit environment.
+    unsigned GPRBegin = Subtarget->isPPC64() ? PPC::X14 : PPC::R13;
+    unsigned GPREnd = Subtarget->isPPC64() ? PPC::X31 : PPC::R31;
+
+    for (unsigned Reg = GPRBegin; Reg <= GPREnd; ++Reg) {
+      if (MRI.isPhysRegModified(Reg)) {
+        GPRSaved = GPREnd - Reg + 1;
+        break;
+      }
     }
+  } else {
+    GPRSaved = FI->getForceGPRSaveCount();
   }
 
   SecondHalfOfMandatoryField |= (GPRSaved << TracebackTable::GPRSavedShift) &
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 4d4008ac0ba70..189d75defd849 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -7224,6 +7224,8 @@ SDValue PPCTargetLowering::LowerFormalArguments_AIX(
   // Reserve space for the linkage area on the stack.
   const unsigned LinkageSize = Subtarget.getFrameLowering()->getLinkageSize();
   CCInfo.AllocateStack(LinkageSize, Align(PtrByteSize));
+  uint64_t SaveStackPos = CCInfo.getStackSize();
+  bool SaveParams = MF.getFunction().hasFnAttribute("save-reg-params");
   CCInfo.AnalyzeFormalArguments(Ins, CC_AIX);
 
   SmallVector<SDValue, 8> MemOps;
@@ -7242,6 +7244,23 @@ SDValue PPCTargetLowering::LowerFormalArguments_AIX(
     if (VA.isMemLoc() && VA.needsCustom() && ValVT.isFloatingPoint())
       continue;
 
+    if (SaveParams && VA.isRegLoc()) {
+      const TargetRegisterClass *RegClass = getRegClassForSVT(
+          LocVT.SimpleTy, IsPPC64, Subtarget.hasP8Vector(), Subtarget.hasVSX());
+      // On PPC64, we need to use std instead of stw for GPR.
+      MVT SaveVT = RegClass == &PPC::G8RCRegClass ? MVT::i64 : LocVT;
+      const Register VReg = MF.addLiveIn(VA.getLocReg(), RegClass);
+      SDValue Parm = DAG.getRegister(VReg, SaveVT);
+      int FI = MFI.CreateFixedObject(SaveVT.getStoreSize(), SaveStackPos, true);
+      SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
+      unsigned Alignment = IsPPC64 ? 8 : 4;
+      SDValue StoreReg = DAG.getStore(Chain, dl, Parm, FIN,
+                                      MachinePointerInfo(), Align(Alignment));
+      SaveStackPos = alignTo(SaveStackPos + SaveVT.getStoreSize(), Alignment);
+      MemOps.push_back(StoreReg);
+      Chain = StoreReg;
+    }
+
     auto HandleMemLoc = [&]() {
       const unsigned LocSize = LocVT.getStoreSize();
       const unsigned ValSize = ValVT.getStoreSize();
@@ -7454,6 +7473,11 @@ SDValue PPCTargetLowering::LowerFormalArguments_AIX(
   FuncInfo->setMinReservedArea(CallerReservedArea);
 
   if (isVarArg) {
+    // Maximum number of saved GPR in traceback table is 8, for varargs,
+    // assuming eight GPRs matches XL behavior.
+    if (SaveParams)
+      FuncInfo->setForceGPRSaveCount(8);
+
     FuncInfo->setVarArgsFrameIndex(
         MFI.CreateFixedObject(PtrByteSize, CCInfo.getStackSize(), true));
     SDValue FIN = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), PtrVT);
diff --git a/llvm/lib/Target/PowerPC/PPCMachineFunctionInfo.h b/llvm/lib/Target/PowerPC/PPCMachineFunctionInfo.h
index b7d14da05ee24..a9e7d63237c7b 100644
--- a/llvm/lib/Target/PowerPC/PPCMachineFunctionInfo.h
+++ b/llvm/lib/Target/PowerPC/PPCMachineFunctionInfo.h
@@ -150,6 +150,9 @@ class PPCFunctionInfo : public MachineFunctionInfo {
   /// to use SExt/ZExt flags in later optimization.
   std::vector<std::pair<Register, ISD::ArgFlagsTy>> LiveInAttrs;
 
+  /// Set a fixed number of saved GPRs, negative if it's non-fixed.
+  int ForceGPRSaveCount = -1;
+
   /// Flags for aix-shared-lib-tls-model-opt, will be lazily initialized for
   /// each function.
   bool AIXFuncUseTLSIEForLD = false;
@@ -163,6 +166,9 @@ class PPCFunctionInfo : public MachineFunctionInfo {
         const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB)
       const override;
 
+  int getForceGPRSaveCount() const { return ForceGPRSaveCount; }
+  void setForceGPRSaveCount(int Num) { ForceGPRSaveCount = Num; }
+
   int getFramePointerSaveIndex() const { return FramePointerSaveIndex; }
   void setFramePointerSaveIndex(int Idx) { FramePointerSaveIndex = Idx; }
 
diff --git a/llvm/test/CodeGen/PowerPC/save-reg-params.ll b/llvm/test/CodeGen/PowerPC/save-reg-params.ll
new file mode 100644
index 0000000000000..3ed1e2820c2a1
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/save-reg-params.ll
@@ -0,0 +1,817 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4
+; RUN: llc -verify-machineinstrs -mtriple=powerpc-ibm-aix -mcpu=pwr7 < %s | FileCheck %s -check-prefix=32BIT
+; RUN: llc -verify-machineinstrs -mtriple=powerpc64-ibm-aix -mcpu=pwr7 < %s | FileCheck %s -check-prefix=64BIT
+
+define void @i64_join(i64 %a, i64 %b, i64 %c, i64 %d, i64 %e, i64 %f, i64 %g, i64 %h, i64 %i, i64 %j) #0 {
+; 32BIT-LABEL: i64_join:
+; 32BIT:       # %bb.0: # %entry
+; 32BIT-NEXT:    mflr 0
+; 32BIT-NEXT:    stwu 1, -64(1)
+; 32BIT-NEXT:    stw 0, 72(1)
+; 32BIT-NEXT:    stw 10, 116(1)
+; 32BIT-NEXT:    stw 9, 112(1)
+; 32BIT-NEXT:    stw 8, 108(1)
+; 32BIT-NEXT:    stw 7, 104(1)
+; 32BIT-NEXT:    stw 6, 100(1)
+; 32BIT-NEXT:    stw 5, 96(1)
+; 32BIT-NEXT:    stw 4, 92(1)
+; 32BIT-NEXT:    stw 3, 88(1)
+; 32BIT-NEXT:    bl .foo[PR]
+; 32BIT-NEXT:    nop
+; 32BIT-NEXT:    addi 1, 1, 64
+; 32BIT-NEXT:    lwz 0, 8(1)
+; 32BIT-NEXT:    mtlr 0
+; 32BIT-NEXT:    blr
+;
+; 64BIT-LABEL: i64_join:
+; 64BIT:       # %bb.0: # %entry
+; 64BIT-NEXT:    mflr 0
+; 64BIT-NEXT:    stdu 1, -112(1)
+; 64BIT-NEXT:    std 0, 128(1)
+; 64BIT-NEXT:    std 10, 216(1)
+; 64BIT-NEXT:    std 9, 208(1)
+; 64BIT-NEXT:    std 8, 200(1)
+; 64BIT-NEXT:    std 7, 192(1)
+; 64BIT-NEXT:    std 6, 184(1)
+; 64BIT-NEXT:    std 5, 176(1)
+; 64BIT-NEXT:    std 4, 168(1)
+; 64BIT-NEXT:    std 3, 160(1)
+; 64BIT-NEXT:    bl .foo[PR]
+; 64BIT-NEXT:    nop
+; 64BIT-NEXT:    addi 1, 1, 112
+; 64BIT-NEXT:    ld 0, 16(1)
+; 64BIT-NEXT:    mtlr 0
+; 64BIT-NEXT:    blr
+entry:
+  %add = add nsw i64 %b, %a
+  %add1 = add nsw i64 %add, %c
+  %add2 = add nsw i64 %add1, %d
+  %add3 = add nsw i64 %add2, %e
+  %add4 = add nsw i64 %add3, %f
+  %add5 = add nsw i64 %add4, %g
+  %add6 = add nsw i64 %add5, %h
+  %add7 = add nsw i64 %add6, %i
+  %add8 = add nsw i64 %add7, %j
+  tail call void @foo()
+  ret void
+}
+
+define void @i64_join_missing(i64 %a, i64 %b, i64 %c, i64 %d, i64 %e, i64 %f, i64 %g, i64 %h, i64 %i, i64 %j) #0 {
+; 32BIT-LABEL: i64_join_missing:
+; 32BIT:       # %bb.0: # %entry
+; 32BIT-NEXT:    mflr 0
+; 32BIT-NEXT:    stwu 1, -64(1)
+; 32BIT-NEXT:    stw 0, 72(1)
+; 32BIT-NEXT:    stw 10, 116(1)
+; 32BIT-NEXT:    stw 9, 112(1)
+; 32BIT-NEXT:    stw 8, 108(1)
+; 32BIT-NEXT:    stw 7, 104(1)
+; 32BIT-NEXT:    stw 6, 100(1)
+; 32BIT-NEXT:    stw 5, 96(1)
+; 32BIT-NEXT:    stw 4, 92(1)
+; 32BIT-NEXT:    stw 3, 88(1)
+; 32BIT-NEXT:    bl .foo[PR]
+; 32BIT-NEXT:    nop
+; 32BIT-NEXT:    addi 1, 1, 64
+; 32BIT-NEXT:    lwz 0, 8(1)
+; 32BIT-NEXT:    mtlr 0
+; 32BIT-NEXT:    blr
+;
+; 64BIT-LABEL: i64_join_missing:
+; 64BIT:       # %bb.0: # %entry
+; 64BIT-NEXT:    mflr 0
+; 64BIT-NEXT:    stdu 1, -112(1)
+; 64BIT-NEXT:    std 0, 128(1)
+; 64BIT-NEXT:    std 10, 216(1)
+; 64BIT-NEXT:    std 9, 208(1)
+; 64BIT-NEXT:    std 8, 200(1)
+; 64BIT-NEXT:    std 7, 192(1)
+; 64BIT-NEXT:    std 6, 184(1)
+; 64BIT-NEXT:    std 5, 176(1)
+; 64BIT-NEXT:    std 4, 168(1)
+; 64BIT-NEXT:    std 3, 160(1)
+; 64BIT-NEXT:    bl .foo[PR]
+; 64BIT-NEXT:    nop
+; 64BIT-NEXT:    addi 1, 1, 112
+; 64BIT-NEXT:    ld 0, 16(1)
+; 64BIT-NEXT:    mtlr 0
+; 64BIT-NEXT:    blr
+entry:
+  %add1 = mul nsw i64 %a, 3
+  %add2 = add nsw i64 %add1, %d
+  %add3 = add nsw i64 %add2, %e
+  %add4 = add nsw i64 %add3, %f
+  %add5 = add nsw i64 %add4, %g
+  %add6 = add nsw i64 %add5, %h
+  %add7 = add nsw i64 %add6, %i
+  %add8 = add nsw i64 %add7, %j
+  tail call void @foo()
+  ret void
+}
+
+define void @i32_join(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e, i32 signext %f, i32 signext %g, i32 signext %h, i32 signext %i, i32 signext %j) #0 {
+; 32BIT-LABEL: i32_join:
+; 32BIT:       # %bb.0: # %entry
+; 32BIT-NEXT:    mflr 0
+; 32BIT-NEXT:    stwu 1, -64(1)
+; 32BIT-NEXT:    stw 0, 72(1)
+; 32BIT-NEXT:    stw 10, 116(1)
+; 32BIT-NEXT:    stw 9, 112(1)
+; 32BIT-NEXT:    stw 8, 108(1)
+; 32BIT-NEXT:    stw 7, 104(1)
+; 32BIT-NEXT:    stw 6, 100(1)
+; 32BIT-NEXT:    stw 5, 96(1)
+; 32BIT-NEXT:    stw 4, 92(1)
+; 32BIT-NEXT:    stw 3, 88(1)
+; 32BIT-NEXT:    bl .foo[PR]
+; 32BIT-NEXT:    nop
+; 32BIT-NEXT:    addi 1, 1, 64
+; 32BIT-NEXT:    lwz 0, 8(1)
+; 32BIT-NEXT:    mtlr 0
+; 32BIT-NEXT:    blr
+;
+; 64BIT-LABEL: i32_join:
+; 64BIT:       # %bb.0: # %entry
+; 64BIT-NEXT:    mflr 0
+; 64BIT-NEXT:    stdu 1, -112(1)
+; 64BIT-NEXT:    std 0, 128(1)
+; 64BIT-NEXT:    std 10, 216(1)
+; 64BIT-NEXT:    std 9, 208(1)
+; 64BIT-NEXT:    std 8, 200(1)
+; 64BIT-NEXT:    std 7, 192(1)
+; 64BIT-NEXT:    std 6, 184(1)
+; 64BIT-NEXT:    std 5, 176(1)
+; 64BIT-NEXT:    std 4, 168(1)
+; 64BIT-NEXT:    std 3, 160(1)
+; 64BIT-NEXT:    bl .foo[PR]
+; 64BIT-NEXT:    nop
+; 64BIT-NEXT:    addi 1, 1, 112
+; 64BIT-NEXT:    ld 0, 16(1)
+; 64BIT-NEXT:    mtlr 0
+; 64BIT-NEXT:    blr
+entry:
+  %add = add nsw i32 %b, %a
+  %add1 = add nsw i32 %add, %c
+  %add2 = add nsw i32 %add1, %d
+  %add3 = add nsw i32 %add2, %e
+  %add4 = add nsw i32 %add3, %f
+  %add5 = add nsw i32 %add4, %g
+  %add6 = add nsw i32 %add5, %h
+  %add7 = add nsw i32 %add6, %i
+  %add8 = add nsw i32 %add7, %j
+  tail call void @foo()
+  ret void
+}
+
+define void @i32_join_missing(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e, i32 signext %f, i32 signext %g, i32 signext %h, i32 signext %i, i32 signext %j) #0 {
+; 32BIT-LABEL: i32_join_missing:
+; 32BIT:       # %bb.0: # %entry
+; 32BIT-NEXT:    mflr 0
+; 32BIT-NEXT:    stwu 1, -64(1)
+; 32BIT-NEXT:    stw 0, 72(1)
+; 32BIT-NEXT:    stw 10, 116(1)
+; 32BIT-NEXT:    stw 9, 112(1)
+; 32BIT-NEXT:    stw 8, 108(1)
+; 32BIT-NEXT:    stw 7, 104(1)
+; 32BIT-NEXT:    stw 6, 100(1)
+; 32BIT-NEXT:    stw 5, 96(1)
+; 32BIT-NEXT:    stw 4, 92(1)
+; 32BIT-NEXT:    stw 3, 88(1)
+; 32BIT-NEXT:    bl .foo[PR]
+; 32BIT-NEXT:    nop
+; 32BIT-NEXT:    addi 1, 1, 64
+; 32BIT-NEXT:    lwz 0, 8(1)
+; 32BIT-NEXT:    mtlr 0
+; 32BIT-NEXT:    blr
+;
+; 64BIT-LABEL: i32_join_missing:
+; 64BIT:       # %bb.0: # %entry
+; 64BIT-NEXT:    mflr 0
+; 64BIT-NEXT:    stdu 1, -112(1)
+; 64BIT-NEXT:    std 0, 128(1)
+; 64BIT-NEXT:    std 10, 216(1)
+; 64BIT-NEXT:    std 9, 208(1)
+; 64BIT-NEXT:    std 8, 200(1)
+; 64BIT-NEXT:    std 7, 192(1)
+; 64BIT-NEXT:    std 6, 184(1)
+; 64BIT-NEXT:    std 5, 176(1)
+; 64BIT-NEXT:    std 4, 168(1)
+; 64BIT-NEXT:    std 3, 160(1)
+; 64BIT-NEXT:    bl .foo[PR]
+; 64BIT-NEXT:    nop
+; 64BIT-NEXT:    addi 1, 1, 112
+; 64BIT-NEXT:    ld 0, 16(1)
+; 64BIT-NEXT:    mtlr 0
+; 64BIT-NEXT:    blr
+entry:
+  %add1 = mul nsw i32 %a, 3
+  %add2 = add nsw i32 %add1, %d
+  %add3 = add nsw i32 %add2, %e
+  %add4 = add nsw i32 %add3, %f
+  %add5 = add nsw i32 %add4, %g
+  %add6 = add nsw i32 %add5, %h
+  %add7 = add nsw i32 %add6, %i
+  %add8 = add nsw i32 %add7, %j
+  tail call void @foo()
+  ret void
+}
+
+define void @f32_join(float %a, float %b, float %c, float %d, float %e, float %f, float %g, float %h, float %i, float %j) #0 {
+; 32BIT-LABEL: f32_join:
+; 32BIT:       # %bb.0: # %entry
+; 32BIT-NEXT:    mflr 0
+; 32BIT-NEXT:    stwu 1, -64(1)
+; 32BIT-NEXT:    stw 0, 72(1)
+; 32BIT-NEXT:    stfs 10, 124(1)
+; 32BIT-NEXT:    stfs 9, 120(1)
+; 32BIT-NEXT:    stfs 8, 116(1)
+; 32BIT-NEXT:    stfs 7, 112(1)
+; 32BIT-NEXT:    stfs 6, 108(1)
+; 32BIT-NEXT:    stfs 5, 104(1)
+; 32BIT-NEXT:    stfs 4, 100(1)
+; 32BIT-NEXT:    stfs 3, 96(1)
+; 32BIT-NEXT:    stfs 2, 92(1)
+; 32BIT-NEXT:    stfs 1, 88(1)
+; 32BIT-NEXT:    bl .foo[PR]
+; 32BIT-NEXT:    nop
+; 32BIT-NEXT:    addi 1, 1, 64
+; 32BIT-NEXT:    lwz 0, 8(1)
+; 32BIT-NEXT:    mtlr 0
+; 32BIT-NEXT:    blr
+;
+; 64BIT-LABEL: f32_join:
+; 64BIT:       # %bb.0: # %entry
+; 64BIT-NEXT:    mflr 0
+; 64BIT-NEXT:    stdu 1, -112(1)
+; 64BIT-NEXT:    std 0, 128(1)
+; 64BIT-NEXT:    stfs 10, 232(1)
+; 64BIT-NEXT:    stfs 9, 224(1)
+; 64BIT-NEXT:    stfs 8, 216(1)
+; 64BIT-NEXT:    stfs 7, 208(1)
+; 64BIT-NEXT:    stfs 6, 200(1)
+; 64BIT-NEXT:    stfs 5, 192(1)
+; 64BIT-NEXT:    stfs 4, 184(1)
+; 64BIT-NEXT:    stfs 3, 176(1)
+; 64BIT-NEXT:    stfs 2, 168(1)
+; 64BIT-NEXT:    stfs 1, 160(1)
+; 64BIT-NEXT:    bl .foo[PR]
+; 64BIT-NEXT:    nop
+; 64BIT-NEXT:    addi 1, 1, 112
+; 64BIT-NEXT:    ld 0, 16(1)
+; 64BIT-NEXT:    mtlr 0
+; 64BIT-NEXT:    blr
+entry:
+  %add = fadd float %a, %b
+  %add1 = fadd float %add, %c
+  %add2 = fadd float %add1, %d
+  %add3 = fadd float %add2, %e
+  %add4 = fadd float %add3, %f
+  %add5 = fadd float %add4, %g
+  %add6 = fadd float %add5, %h
+  %add7 = fadd float %add6, %i
+  %add8 = fadd float %add7, %j
+  tail call void @foo()
+  ret void
+}
+
+define void @f32_join_missing(float %a, float %b, float %c, float %d, float %e, float %f, float %g, float %h, float %i, float %j) #0 {
+; 32BIT-LABEL: f32_join_missing:
+; 32BIT:       # %bb.0: # %entry
+; 32BIT-NEXT:    mflr 0
+; 32BIT-NEXT:    stwu 1, -64(1)
+; 32BIT-NEXT:    stw 0, 72(1)
+; 32BIT-NEXT:    stfs 10, 124(1)
+; 32BIT-NEXT:    stfs 9, 120(1)
+; 32BIT-NEXT:    stfs 8, 116(1)
+; 32BIT-NEXT:    stfs 7, 112(1)
+; 32BIT-NEXT:    stfs 6, 108(1)
+; 32BIT-NEXT:    stfs 5, 104(1)
+; 32BIT-NEXT:    stfs 4, 100(1)
+; 32BIT-NEXT:    stfs 3, 96(1)
+; 32BIT-NEXT:    stfs 2, 92(1)
+; 32BIT-NEXT:    stfs 1, 88(1)
+; 32BIT-NEXT:    bl .foo[PR]
+; 32BIT-NEXT:    nop
+; 32BIT-NEXT:    addi 1, 1, 64
+; 32BIT-NEXT:    lwz 0, 8(1)
+; 32BIT-NEXT:    mtlr 0
+; 32BIT-NEXT:    blr
+;
+; 64BIT-LABEL: f32_join_missing:
+; 64BIT:       # %bb.0: # %entry
+; 64BIT-NEXT:    mflr 0
+; 64BIT-NEXT:    stdu 1, -112(1)
+; 64BIT-NEXT:    std 0, 128(1)
+; 64BIT-NEXT:    stfs 10, 232(1)
+; 64BIT-NEXT:    stfs 9, 224(1)
+; 64BIT-NEXT:    stfs 8, 216(1)
+; 64BIT-NEXT:    stfs 7, 208(1)
+; 64BIT-NEXT:    stfs 6, 200(1)
+; 64BIT-NEXT:    stfs 5, 192(1)
+; 64BIT-NEXT:    stfs 4, 184(1)
+; 64BIT-NEXT:    stfs 3, 176(1)
+; 64BIT-NEXT:    stfs 2, 168(1)
+; 64BIT-NEXT:    stfs 1, 160(1)
+; 64BIT-NEXT:    bl .foo[PR]
+; 64BIT-NEXT:    nop
+; 64BIT-NEXT:    addi 1, 1, 112
+; 64BIT-NEXT:    ld 0, 16(1)
+; 64BIT-NEXT:    mtlr 0
+; 64BIT-NEXT:    blr
+entry:
+  %add = fadd float %a, %a
+  %add1 = fadd float %add, %a
+  %add2 = fadd float %add1, %d
+  %add3 = fadd float %add2, %e
+  %add4 = fadd float %add3, %f
+  %add5 = fadd float %add4, %g
+  %add6 = fadd float %add5, %h
+  %add7 = fadd float %add6, %i
+  %add8 = fadd float %add7, %j
+  tail call void @foo()
+  ret void
+}
+
+define void @f64_join(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, double %j) #0 {
+; 32BIT-LABEL: f64_join:
+; 32BIT:       # %bb.0: # %entry
+; 32BIT-NEXT:    mflr 0
+; 32BIT-NEXT:    stwu 1, -64(1)
+; 32BIT-NEXT:    stw 0, 72(1)
+; 32BIT-NEXT:    stfd 10, 160(1)
+; 32BIT-NEXT:    stfd 9, 152(1)
+; 32BIT-NEXT:    stfd 8, 144(1)
+; 32BIT-NEXT:    stfd 7, 136(1)
+; 32BIT-NEXT:    stfd 6, 128(1)
+; 32BIT-NEXT:    stfd 5, 120(1)
+; 32BIT-NEXT:    stfd 4, 112(1)
+; 32BIT-NEXT:    stfd 3, 104(1)
+; 32BIT-NEXT:    stfd 2, 96(1)
+; 32BIT-NEXT:    stfd 1, 88(1)
+; 32BIT-NEXT:    bl .foo[PR]
+; 32BIT-NEXT:    nop
+; 32BIT-NEXT:    addi 1, 1, 64
+; 32BIT-NEXT:    lwz 0, 8(1)
+; 32BIT-NEXT:    mtlr 0
+; 32BIT-NEXT:    blr
+;
+; 64BIT-LABEL: f64_join:
+; 64BIT:       # %bb.0: # %entry
+; 64BIT-NEXT:    mflr 0
+; 64BIT-NEXT:    stdu 1, -112(1)
+; 64BIT-NEXT:    std 0, 128(1)
+; 64BIT-NEXT:    stfd 10, 232(1)
+; 64BIT-NEXT:    stfd 9, 224(1)
+; 64BIT-NEXT:    stfd 8, 216(1)
+; 64BIT-NEXT:    stfd 7, 208(1)
+; 64BIT-NEXT:    stfd 6, 200(1)
+; 64BIT-NEXT:    stfd 5, 192(1)
+; 64BIT-NEXT:    st...
[truncated]

@ecnelises ecnelises marked this pull request as draft July 5, 2024 09:19
@efriedma-quic
Copy link
Collaborator

Why do we want a module flag, and not a function attribute? Module flags are generally problematic during LTO, so we try to avoid them if they aren't truly necessary.

@ecnelises
Copy link
Member Author

Thanks for pointing LTO stuff out. Do you mean the module flags might be messed up when merging in LTO? I thought a file level codegen option can be mapped to a module level flag.

@efriedma-quic
Copy link
Collaborator

The question is, if LTO merges two bitcode modules together with different settings for the flag, how do you want the backend to behave? Usually you want it to just continue to apply to the same functions it would have without LTO; the only way to represent that is a function attribute.

In PowerPC ABI, a few initial arguments are passed through registers,
but their places in parameter save area are reserved, arguments passed
by memory goes after the reserved location.

For debugging purpose, we may want to save copy of the pass-by-reg
arguments into correct places on stack. The new option achieves by
adding new function level attribute and make argument lowering part
aware of it.
@ecnelises ecnelises marked this pull request as ready for review July 15, 2024 08:57
Copy link
Collaborator

@chenzheng1030 chenzheng1030 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks for adding this support.

@ecnelises ecnelises merged commit 20957d2 into llvm:main Jul 24, 2024
9 checks passed
@ecnelises ecnelises deleted the ppc_saveregs branch July 24, 2024 12:58
yuxuanchen1997 pushed a commit that referenced this pull request Jul 25, 2024
Summary:
In PowerPC ABI, a few initial arguments are passed through registers,
but their places in parameter save area are reserved, arguments passed
by memory goes after the reserved location.

For debugging purpose, we may want to save copy of the pass-by-reg
arguments into correct places on stack. The new option achieves by
adding new function level attribute and make argument lowering part
aware of it.

Test Plan: 

Reviewers: 

Subscribers: 

Tasks: 

Tags: 


Differential Revision: https://phabricator.intern.facebook.com/D60250560
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:PowerPC clang:codegen clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants