https://github.com/Luminyx1 created 
https://github.com/llvm/llvm-project/pull/175145

This patch extends the `preserve_all` calling convention to PowerPC targets. 
Replaces #174320

>From 46343d8b637d3d82e6316c9e9248ce7610b9399e Mon Sep 17 00:00:00 2001
From: Luminyx <[email protected]>
Date: Fri, 9 Jan 2026 04:26:53 -0500
Subject: [PATCH] [clang][llvm][PPC] PreserveAll attribute

---
 clang/include/clang/Basic/AttrDocs.td       |  7 +-
 clang/lib/Basic/Targets/PPC.h               | 11 +++
 llvm/lib/Target/PowerPC/PPCCallingConv.td   | 84 +++++++++++++++++++++
 llvm/lib/Target/PowerPC/PPCISelLowering.cpp |  7 ++
 llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp | 81 ++++++++++++++++++++
 5 files changed, 188 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Basic/AttrDocs.td 
b/clang/include/clang/Basic/AttrDocs.td
index 812b48058d189..7e4bb5eaf2f39 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -6584,7 +6584,7 @@ in the future.
 def PreserveAllDocs : Documentation {
   let Category = DocCatCallingConvs;
   let Content = [{
-On X86-64 and AArch64 targets, this attribute changes the calling convention of
+On X86-64, AArch64, and PowerPC targets, this attribute changes the calling 
convention of
 a function. The ``preserve_all`` calling convention attempts to make the code
 in the caller even less intrusive than the ``preserve_most`` calling 
convention.
 This calling convention also behaves identical to the ``C`` calling convention
@@ -6599,10 +6599,13 @@ returned in callee-saved registers.
   R11. R11 can be used as a scratch register. Furthermore it also preserves
   all floating-point registers (XMMs/YMMs).
 
-- On AArch64 the callee preserve all general purpose registers, except X0-X8 
and
+- On AArch64 the callee preserves all general purpose registers, except X0-X8 
and
   X16-X18. Furthermore it also preserves lower 128 bits of V8-V31 SIMD - 
floating
   point registers.
 
+- On PowerPC the callee preserves all general purpose registers, except R1 and 
R2.
+  Furthermore it also preserves all floating-point and vector registers.
+
 The idea behind this convention is to support calls to runtime functions
 that don't need to call out to any other functions.
 
diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h
index 664c9e15d8d18..d49f23b3fa68d 100644
--- a/clang/lib/Basic/Targets/PPC.h
+++ b/clang/lib/Basic/Targets/PPC.h
@@ -428,6 +428,16 @@ class LLVM_LIBRARY_VISIBILITY PPC32TargetInfo : public 
PPCTargetInfo {
   std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
     return std::make_pair(32, 32);
   }
+
+  CallingConvCheckResult checkCallingConvention(CallingConv CC) const override 
{
+    switch (CC) {
+    default:
+      return CCCR_Warning;
+    case CC_PreserveAll:
+    case CC_C:
+      return CCCR_OK;
+    }
+  }
 };
 
 // Note: ABI differences may eventually require us to have a separate
@@ -490,6 +500,7 @@ class LLVM_LIBRARY_VISIBILITY PPC64TargetInfo : public 
PPCTargetInfo {
   CallingConvCheckResult checkCallingConvention(CallingConv CC) const override 
{
     switch (CC) {
     case CC_Swift:
+    case CC_PreserveAll:
       return CCCR_OK;
     case CC_SwiftAsync:
       return CCCR_Error;
diff --git a/llvm/lib/Target/PowerPC/PPCCallingConv.td 
b/llvm/lib/Target/PowerPC/PPCCallingConv.td
index 5d4fe06ebdddd..b564b30a94bbe 100644
--- a/llvm/lib/Target/PowerPC/PPCCallingConv.td
+++ b/llvm/lib/Target/PowerPC/PPCCallingConv.td
@@ -343,6 +343,90 @@ def CSR_PPC64_R2_Altivec : CalleeSavedRegs<(add 
CSR_PPC64_Altivec, X2)>;
 
 def CSR_NoRegs : CalleeSavedRegs<(add)>;
 
+def CSR_PPC32_PreserveMost : CalleeSavedRegs<(add R0, (sequence "R%u", 3, 31),
+                                 (sequence "CR%u", 0, 7))>;
+
+def CSR_PPC32_PreserveMost_NonVoid
+    : CalleeSavedRegs<(sub CSR_PPC32_PreserveMost, R3)>;
+
+def CSR_PPC32_PreserveAll
+    : CalleeSavedRegs<(add CSR_PPC32_PreserveMost, (sequence "F%u", 0, 31))>;
+
+def CSR_PPC32_PreserveAll_Unknown
+    : CalleeSavedRegs<(sub CSR_PPC32_PreserveAll, R3, R4, F1)>;
+
+def CSR_PPC32_PreserveAll_NonVoid
+    : CalleeSavedRegs<(sub CSR_PPC32_PreserveAll, R3)>;
+
+def CSR_PPC32_PreserveAll_NonVoid_64
+    : CalleeSavedRegs<(sub CSR_PPC32_PreserveAll_NonVoid, R4)>;
+
+def CSR_PPC32_PreserveAll_NonVoid_Float
+    : CalleeSavedRegs<(sub CSR_PPC32_PreserveAll, F1)>;
+
+def CSR_PPC32_PreserveAll_Altivec
+    : CalleeSavedRegs<(add CSR_PPC32_PreserveAll, (sequence "V%u", 0, 31))>;
+
+def CSR_PPC32_PreserveAll_Altivec_Unknown
+    : CalleeSavedRegs<(sub CSR_PPC32_PreserveAll_Altivec, R3, R4, F1, V2)>;
+
+def CSR_PPC32_PreserveAll_Altivec_NonVoid
+    : CalleeSavedRegs<(sub CSR_PPC32_PreserveAll_Altivec, R3)>;
+
+def CSR_PPC32_PreserveAll_Altivec_NonVoid_64
+    : CalleeSavedRegs<(sub CSR_PPC32_PreserveAll_Altivec_NonVoid, R4)>;
+
+def CSR_PPC32_PreserveAll_Altivec_NonVoid_Vec
+    : CalleeSavedRegs<(sub CSR_PPC32_PreserveAll_Altivec, V2)>;
+
+def CSR_PPC32_PreserveAll_Altivec_NonVoid_Float
+    : CalleeSavedRegs<(sub CSR_PPC32_PreserveAll_Altivec, F1)>;
+
+def CSR_PPC32_PreserveAll_SPE
+    : CalleeSavedRegs<(add CSR_PPC32_PreserveMost, (sequence "S%u", 3, 31))>;
+
+def CSR_PPC32_PreserveAll_SPE_NonVoid
+    : CalleeSavedRegs<(sub CSR_PPC32_PreserveAll_SPE, R3, S3)>;
+
+def CSR_PPC64_PreserveMost : CalleeSavedRegs<(add X0, (sequence "X%u", 3, 31),
+                                 (sequence "CR%u", 0, 7))>;
+
+def CSR_PPC64_PreserveMost_NonVoid
+    : CalleeSavedRegs<(sub CSR_PPC64_PreserveMost, X3)>;
+
+def CSR_PPC64_PreserveAll
+    : CalleeSavedRegs<(add CSR_PPC64_PreserveMost, (sequence "F%u", 0, 31))>;
+
+def CSR_PPC64_PreserveAll_Unknown
+    : CalleeSavedRegs<(sub CSR_PPC64_PreserveAll, X3, X4, F1)>;
+
+def CSR_PPC64_PreserveAll_NonVoid
+    : CalleeSavedRegs<(sub CSR_PPC64_PreserveAll, X3)>;
+
+def CSR_PPC64_PreserveAll_NonVoid_Float
+    : CalleeSavedRegs<(sub CSR_PPC64_PreserveAll, F1)>;
+
+def CSR_PPC64_PreserveAll_NonVoid_128
+    : CalleeSavedRegs<(sub CSR_PPC64_PreserveAll_NonVoid, X4)>;
+
+def CSR_PPC64_PreserveAll_Altivec
+    : CalleeSavedRegs<(add CSR_PPC64_PreserveAll, (sequence "V%u", 0, 31))>;
+
+def CSR_PPC64_PreserveAll_Altivec_NonVoid
+    : CalleeSavedRegs<(sub CSR_PPC64_PreserveAll_Altivec, X3)>;
+
+def CSR_PPC64_PreserveAll_Altivec_Unknown
+    : CalleeSavedRegs<(sub CSR_PPC64_PreserveAll_Altivec, X3, X4, F1, V2)>;
+
+def CSR_PPC64_PreserveAll_Altivec_NonVoid_Float
+    : CalleeSavedRegs<(sub CSR_PPC64_PreserveAll_Altivec, F1)>;
+
+def CSR_PPC64_PreserveAll_Altivec_NonVoid_Vec
+    : CalleeSavedRegs<(sub CSR_PPC64_PreserveAll_Altivec, V2)>;
+
+def CSR_PPC64_PreserveAll_Altivec_NonVoid_128
+    : CalleeSavedRegs<(sub CSR_PPC64_PreserveAll_Altivec_NonVoid, X4)>;
+
 // coldcc calling convection marks most registers as non-volatile.
 // Do not include r1 since the stack pointer is never considered a CSR.
 // Do not include r2, since it is the TOC register and is added depending
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp 
b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index ef211bf8c8982..2b68774e73937 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -7804,11 +7804,18 @@ PPCTargetLowering::LowerReturn(SDValue Chain, 
CallingConv::ID CallConv,
   SDValue Glue;
   SmallVector<SDValue, 4> RetOps(1, Chain);
 
+  MachineFunction &MF = DAG.getMachineFunction();
+  bool ShouldDisableCalleeSavedRegister =
+      MF.getFunction().hasFnAttribute("preserve_all");
+
   // Copy the result values into the output registers.
   for (unsigned i = 0, RealResIdx = 0; i != RVLocs.size(); ++i, ++RealResIdx) {
     CCValAssign &VA = RVLocs[i];
     assert(VA.isRegLoc() && "Can only return in registers!");
 
+    if (ShouldDisableCalleeSavedRegister)
+      MF.getRegInfo().disableCalleeSavedRegister(VA.getLocReg());
+
     SDValue Arg = OutVals[RealResIdx];
 
     switch (VA.getLocInfo()) {
diff --git a/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp 
b/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp
index b3a7c829958ec..2712eb6b1f7cb 100644
--- a/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp
+++ b/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp
@@ -199,6 +199,76 @@ PPCRegisterInfo::getCalleeSavedRegs(const MachineFunction 
*MF) const {
     return CSR_64_AllRegs_SaveList;
   }
 
+  const Type *const ReturnTy = MF->getFunction().getReturnType();
+
+  // Preserve registers for PreserveAll attribute
+  // We need to skip r3 (return register) if the function isn't void
+  // however for floats it's f1 instead
+  // We also need to skip r4 if the return value is 64-bit on PPC32
+  // or 128-bit on PPC64
+  bool RetVec = ReturnTy->isVectorTy();
+  bool RetFloat = ReturnTy->isFloatingPointTy();
+  bool RetInt = ReturnTy->isIntOrPtrTy();
+  TypeSize RetIntSize = ReturnTy->getPrimitiveSizeInBits();
+  bool RetVoid = ReturnTy->isVoidTy();
+
+  if (MF->getFunction().getCallingConv() == CallingConv::PreserveAll) {
+    if (Subtarget.hasSPE() || Subtarget.pairedVectorMemops() ||
+        Subtarget.isAIXABI())
+      report_fatal_error("PreserveAll unimplemented on this target.");
+
+    if (TM.isPPC64()) {
+      if (RetVoid) {
+        if (Subtarget.hasAltivec())
+          return CSR_PPC64_PreserveAll_Altivec_SaveList;
+        return CSR_PPC64_PreserveAll_SaveList;
+      }
+      if (RetVec) {
+        if (Subtarget.hasAltivec())
+          return CSR_PPC64_PreserveAll_Altivec_NonVoid_Vec_SaveList;
+        report_fatal_error("Returning vector without vector extension");
+      }
+      if (RetFloat) {
+        if (Subtarget.hasAltivec())
+          return CSR_PPC64_PreserveAll_Altivec_NonVoid_Float_SaveList;
+        return CSR_PPC64_PreserveAll_NonVoid_Float_SaveList;
+      }
+      if (RetInt) {
+        if (Subtarget.hasAltivec())
+          return RetIntSize == 128
+                     ? CSR_PPC64_PreserveAll_Altivec_NonVoid_128_SaveList
+                     : CSR_PPC64_PreserveAll_Altivec_NonVoid_SaveList;
+        return RetIntSize == 128 ? CSR_PPC64_PreserveAll_NonVoid_128_SaveList
+                                 : CSR_PPC64_PreserveAll_NonVoid_SaveList;
+      }
+      report_fatal_error("Unhandled return type");
+    }
+    // PPC32:
+    if (RetVoid) {
+      if (Subtarget.hasAltivec())
+        return CSR_PPC32_PreserveAll_Altivec_SaveList;
+      return CSR_PPC32_PreserveAll_SaveList;
+    }
+    if (RetVec) {
+      if (Subtarget.hasAltivec())
+        return CSR_PPC32_PreserveAll_Altivec_NonVoid_Vec_SaveList;
+      report_fatal_error("Returning vector without vector extension");
+    }
+    if (RetFloat) {
+      if (Subtarget.hasAltivec())
+        return CSR_PPC32_PreserveAll_Altivec_NonVoid_Float_SaveList;
+      return CSR_PPC32_PreserveAll_NonVoid_Float_SaveList;
+    }
+    if (RetInt) {
+      if (Subtarget.hasAltivec())
+        return RetIntSize == 64
+                   ? CSR_PPC32_PreserveAll_Altivec_NonVoid_64_SaveList
+                   : CSR_PPC32_PreserveAll_Altivec_NonVoid_SaveList;
+      return RetIntSize == 64 ? CSR_PPC32_PreserveAll_NonVoid_64_SaveList
+                              : CSR_PPC32_PreserveAll_NonVoid_SaveList;
+    }
+  }
+
   // On PPC64, we might need to save r2 (but only if it is not reserved).
   // We do not need to treat R2 as callee-saved when using PC-Relative calls
   // because any direct uses of R2 will cause it to be reserved. If the 
function
@@ -291,6 +361,17 @@ PPCRegisterInfo::getCallPreservedMask(const 
MachineFunction &MF,
     return CSR_64_AllRegs_RegMask;
   }
 
+  if (CC == CallingConv::PreserveAll) {
+    if (TM.isPPC64()) {
+      if (Subtarget.hasAltivec())
+        return CSR_PPC64_PreserveAll_Altivec_Unknown_RegMask;
+      return CSR_PPC64_PreserveAll_Unknown_RegMask;
+    }
+    if (Subtarget.hasAltivec())
+      return CSR_PPC32_PreserveAll_Altivec_Unknown_RegMask;
+    return CSR_PPC32_PreserveAll_Unknown_RegMask;
+  }
+
   if (Subtarget.isAIXABI()) {
     if (Subtarget.pairedVectorMemops()) {
       if (!TM.getAIXExtendedAltivecABI())

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to