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
