https://github.com/w2yehia created https://github.com/llvm/llvm-project/pull/153049
None >From ed0bc14a65e718aaead6eb9397dad9b289e72c91 Mon Sep 17 00:00:00 2001 From: Wael Yehia <wye...@ca.ibm.com> Date: Mon, 11 Aug 2025 15:56:25 +0000 Subject: [PATCH 1/3] Create and implement lowering of two intrinsics: int.ppc.get.function.descriptor int.ppc.get.function.entry --- llvm/include/llvm/IR/IntrinsicsPowerPC.td | 10 ++++++++ llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 8 +++++-- llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp | 4 ++++ llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 26 +++++++++++++++++++++ 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/llvm/include/llvm/IR/IntrinsicsPowerPC.td b/llvm/include/llvm/IR/IntrinsicsPowerPC.td index 7dd9ff7f08b8b..75b64fba6e3ca 100644 --- a/llvm/include/llvm/IR/IntrinsicsPowerPC.td +++ b/llvm/include/llvm/IR/IntrinsicsPowerPC.td @@ -2090,3 +2090,13 @@ let TargetPrefix = "ppc" in { Intrinsic<[], [llvm_i64_ty, llvm_i64_ty, llvm_ptr_ty], [IntrArgMemOnly, IntrWriteMem, NoCapture<ArgIndex<2>>]>; } + + +//===----------------------------------------------------------------------===// +// XCOFF Intrinsics +let TargetPrefix = "ppc" in { + def int_ppc_get_function_entry : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_ptr_ty], [IntrNoMem]>; + def int_ppc_get_function_descriptor : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_ptr_ty], [IntrNoMem]>; +} diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp index 2ab2c147be0ec..957b2b3e7555d 100644 --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -763,6 +763,8 @@ static MCSymbol *getMCSymbolForTOCPseudoMO(const MachineOperand &MO, return AP.GetJTISymbol(MO.getIndex()); case MachineOperand::MO_BlockAddress: return AP.GetBlockAddressSymbol(MO.getBlockAddress()); + case MachineOperand::MO_MCSymbol: + return MO.getMCSymbol(); default: llvm_unreachable("Unexpected operand type to get symbol."); } @@ -792,6 +794,8 @@ getTOCEntryTypeForMO(const MachineOperand &MO) { return PPCAsmPrinter::TOCType_JumpTable; case MachineOperand::MO_BlockAddress: return PPCAsmPrinter::TOCType_BlockAddress; + case MachineOperand::MO_MCSymbol: + return PPCAsmPrinter::TOCType_GlobalExternal; // TODO default: llvm_unreachable("Unexpected operand type to get TOC type."); } @@ -1043,7 +1047,7 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) { TmpInst.setOpcode(PPC::LWZ); const MachineOperand &MO = MI->getOperand(1); - assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && + assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress() || MO.isMCSymbol()) && "Invalid operand for LWZtoc."); // Map the operand to its corresponding MCSymbol. @@ -1127,7 +1131,7 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) { TmpInst.setOpcode(PPC::LD); const MachineOperand &MO = MI->getOperand(1); - assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && + assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress() || MO.isMCSymbol()) && "Invalid operand!"); // Map the operand to its corresponding MCSymbol. diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp index 415164fc9e2cb..921cb72a83030 100644 --- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -6158,6 +6158,10 @@ void PPCDAGToDAGISel::Select(SDNode *N) { replaceWith(PPC::ADDItoc8, N, MVT::i64); return; } + if (N->getOperand(0).getOpcode() == ISD::MCSymbol) { + replaceWith(PPC::LDtoc, N, MVT::i64); + return; + } // Break if it doesn't have toc data attribute. Proceed with common // SelectCode. break; diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index 74ae8502dccea..bbdd573f4a81b 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -11167,6 +11167,32 @@ SDValue PPCTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SDLoc dl(Op); switch (IntrinsicID) { + case Intrinsic::ppc_get_function_descriptor: + return Op.getOperand(1); + case Intrinsic::ppc_get_function_entry: { + SDValue Op1 = Op.getOperand(1); + if (auto *G = dyn_cast<GlobalAddressSDNode>(Op1)) { + const GlobalValue *GV = G->getGlobal(); + assert(isFunctionGlobalAddress(GV)); + assert(Subtarget.isAIXABI()); + assert(!isa<GlobalIFunc>(GV) && "IFunc is not supported on AIX."); + const TargetMachine &TM = Subtarget.getTargetMachine(); + const TargetLoweringObjectFile *TLOF = TM.getObjFileLowering(); + MCSymbolXCOFF *S = + cast<MCSymbolXCOFF>(TLOF->getFunctionEntryPointSymbol(GV, TM)); + + MVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout()); + SDValue EntryPointSym = DAG.getMCSymbol(S, PtrVT); + return getTOCEntry(DAG, dl, EntryPointSym); + } + assert (Op1.getOpcode() == ISD::CopyFromReg); + SDLoc dl(Op); + EVT PtrVT = getPointerTy(DAG.getDataLayout()); + SDValue Result = DAG.getLoad( + PtrVT, dl, DAG.getEntryNode(), Op1, MachinePointerInfo(), DAG.getDataLayout().getPointerABIAlignment(0), + MachineMemOperand::MODereferenceable); + return Result; + } case Intrinsic::thread_pointer: // Reads the thread pointer register, used for __builtin_thread_pointer. if (Subtarget.isPPC64()) >From e402550f411947bfcf3afc2dae0b3462e5b6c90c Mon Sep 17 00:00:00 2001 From: Wael Yehia <wye...@ca.ibm.com> Date: Tue, 5 Aug 2025 18:01:19 +0000 Subject: [PATCH 2/3] accept ifunc attribute on AIX --- clang/include/clang/Basic/TargetInfo.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index ce4677e540226..ffeab27b67911 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1545,6 +1545,8 @@ class TargetInfo : public TransferrableTargetInfo, return true; if (getTriple().getArch() == llvm::Triple::ArchType::avr) return true; + if (getTriple().isOSAIX()) + return true; return getTriple().isOSBinFormatELF() && ((getTriple().isOSLinux() && !getTriple().isMusl()) || getTriple().isOSFreeBSD()); >From a6c86372d870e737351b26a3e616912ff3c62d3f Mon Sep 17 00:00:00 2001 From: Wael Yehia <wye...@ca.ibm.com> Date: Mon, 11 Aug 2025 16:01:25 +0000 Subject: [PATCH 3/3] initial LowerIFuncsOnAIX impl --- .../llvm/Transforms/Utils/ModuleUtils.h | 7 ++ llvm/lib/Target/PowerPC/PPCTargetMachine.cpp | 11 +++ llvm/lib/Target/PowerPC/PPCTargetMachine.h | 2 + llvm/lib/Transforms/Utils/LowerIFunc.cpp | 7 +- llvm/lib/Transforms/Utils/ModuleUtils.cpp | 81 +++++++++++++++++++ 5 files changed, 107 insertions(+), 1 deletion(-) diff --git a/llvm/include/llvm/Transforms/Utils/ModuleUtils.h b/llvm/include/llvm/Transforms/Utils/ModuleUtils.h index 4036c4e947c75..6be7ac80dd428 100644 --- a/llvm/include/llvm/Transforms/Utils/ModuleUtils.h +++ b/llvm/include/llvm/Transforms/Utils/ModuleUtils.h @@ -159,6 +159,13 @@ LLVM_ABI bool lowerGlobalIFuncUsersAsGlobalCtor(Module &M, ArrayRef<GlobalIFunc *> IFuncsToLower = {}); +/// AIX specific lowering of ifuncs where we convert an ifunc to a regular +/// function with the following implementation: +/// Check if the function's descriptor still points to itself (true on first +/// entry), if so then call the resolver function and atomically store the +/// resulting function pointer into the descriptor. Make an indirect call +/// through the function pointer in the descriptor. +LLVM_ABI void lowerIFuncsOnAIX(Module &M); } // End llvm namespace #endif // LLVM_TRANSFORMS_UTILS_MODULEUTILS_H diff --git a/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp b/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp index b5c6ac111dff0..d8e840912bc37 100644 --- a/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp +++ b/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp @@ -36,6 +36,7 @@ #include "llvm/InitializePasses.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Pass.h" +#include "llvm/Passes/PassBuilder.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" @@ -43,6 +44,7 @@ #include "llvm/Target/TargetOptions.h" #include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Utils/LowerIFunc.h" #include <cassert> #include <memory> #include <optional> @@ -452,6 +454,15 @@ class PPCPassConfig : public TargetPassConfig { } // end anonymous namespace +void PPCTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) { + if (getTargetTriple().isOSAIX()) + PB.registerOptimizerLastEPCallback( + [](ModulePassManager &PM, OptimizationLevel Level, ThinOrFullLTOPhase Phase) { + if (Phase == ThinOrFullLTOPhase::None) + PM.addPass(LowerIFuncPass()); + }); +} + TargetPassConfig *PPCTargetMachine::createPassConfig(PassManagerBase &PM) { return new PPCPassConfig(*this, PM); } diff --git a/llvm/lib/Target/PowerPC/PPCTargetMachine.h b/llvm/lib/Target/PowerPC/PPCTargetMachine.h index cb02b446fadb3..608750f7a3f2b 100644 --- a/llvm/lib/Target/PowerPC/PPCTargetMachine.h +++ b/llvm/lib/Target/PowerPC/PPCTargetMachine.h @@ -54,6 +54,8 @@ class PPCTargetMachine final : public CodeGenTargetMachineImpl { // Pass Pipeline Configuration TargetPassConfig *createPassConfig(PassManagerBase &PM) override; + void registerPassBuilderCallbacks(PassBuilder &PB) override; + TargetTransformInfo getTargetTransformInfo(const Function &F) const override; TargetLoweringObjectFile *getObjFileLowering() const override { diff --git a/llvm/lib/Transforms/Utils/LowerIFunc.cpp b/llvm/lib/Transforms/Utils/LowerIFunc.cpp index 18ae0bbe2e731..991890aa56b83 100644 --- a/llvm/lib/Transforms/Utils/LowerIFunc.cpp +++ b/llvm/lib/Transforms/Utils/LowerIFunc.cpp @@ -13,6 +13,7 @@ #include "llvm/Transforms/Utils/LowerIFunc.h" #include "llvm/IR/Module.h" #include "llvm/Pass.h" +#include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/Utils/ModuleUtils.h" using namespace llvm; @@ -22,6 +23,10 @@ PreservedAnalyses LowerIFuncPass::run(Module &M, ModuleAnalysisManager &AM) { if (M.ifunc_empty()) return PreservedAnalyses::all(); - lowerGlobalIFuncUsersAsGlobalCtor(M, {}); + Triple TargetTriple(M.getTargetTriple()); + if (TargetTriple.isOSAIX()) + lowerIFuncsOnAIX(M); + else + lowerGlobalIFuncUsersAsGlobalCtor(M, {}); return PreservedAnalyses::none(); } diff --git a/llvm/lib/Transforms/Utils/ModuleUtils.cpp b/llvm/lib/Transforms/Utils/ModuleUtils.cpp index 596849ecab742..67da3e66cf16a 100644 --- a/llvm/lib/Transforms/Utils/ModuleUtils.cpp +++ b/llvm/lib/Transforms/Utils/ModuleUtils.cpp @@ -16,6 +16,8 @@ #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IntrinsicsPowerPC.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Module.h" #include "llvm/Support/Casting.h" @@ -397,6 +399,85 @@ void llvm::embedBufferInModule(Module &M, MemoryBufferRef Buf, appendToCompilerUsed(M, GV); } +void llvm::lowerIFuncsOnAIX(Module &M) { + for (GlobalIFunc &IFunc : make_early_inc_range(M.ifuncs())) { + + // Let IFunc be: + // @foo = ifunc rt-type (type1, type2), ptr @resolver + assert(isa<llvm::FunctionType>(IFunc.getValueType())); + FunctionType *FTy = cast<llvm::FunctionType>(IFunc.getValueType()); + + // Create the regular (non-ifunc) function: + // define rt-type @foo(type1 %0, type2 %1) + Function *F = Function::Create(FTy, IFunc.getLinkage(), IFunc.getAddressSpace(), IFunc.getName(), &M); + LLVMContext &Ctx = F->getContext(); + + // entry: + BasicBlock *CurBlock = BasicBlock::Create(Ctx, "entry", F); + IRBuilder<> Builder(CurBlock); + + PointerType *PtrTy = Builder.getPtrTy(); + // %DescPtr = call ptr @ppc_get_function_descriptor(ptr noundef @foo) + auto *DescPtr = Builder.CreateIntrinsic(/*RetTy*/ PtrTy, Intrinsic::ppc_get_function_descriptor, {F}, {}, "desc.ptr"); + + // %DesctAddr = getelementptr inbounds %struct.Desc_t, ptr %DescPtr, i32 0, i32 0 + StructType *DescriptorType = StructType::get(PtrTy, PtrTy, PtrTy); + auto *DesctAddr = Builder.CreateStructGEP(DescriptorType, DescPtr, 0, "desc_t.addr"); + + // %AddrInDesc = load ptr, ptr %DesctAddr, align 4 + auto *AddrInDesc = Builder.CreateAlignedLoad(PtrTy, DesctAddr, DesctAddr->getPointerAlignment(M.getDataLayout()), "addr.in.desc"); + + // %OriginalAddr = call ptr @ppc_get_function_entry(ptr noundef @foo) #3 + auto *OriginalAddr = Builder.CreateIntrinsic(/*RetTy*/ PtrTy, Intrinsic::ppc_get_function_entry, {F}, {}, "original.addr"); + + // %cmp = icmp eq ptr %AddrInDesc, %OriginalAddr + auto *CMP = Builder.CreateICmpEQ(AddrInDesc, OriginalAddr); + + // br i1 %cmp, label %resolver, label %end + CurBlock = BasicBlock::Create(Ctx, "resolver", F); + BasicBlock *FinalBlock = BasicBlock::Create(Ctx, "end", F); + Builder.CreateCondBr(CMP, CurBlock, FinalBlock); + + // Emit the 'then' (resolver) code: + Builder.SetInsertPoint(CurBlock); + + // resolver: + // %ResolvedFunc = call ptr @resolver() + // %ResolvedAddr = call ptr @ppc_get_function_entry(ptr %ResolvedFunc) + // %4 = ptrtoint ptr %ResolvedAddr to i32 + // store atomic i32 %4, ptr %desc_t.addr release, align 4 + Function *ResolverFunc = IFunc.getResolverFunction(); + auto *ResolvedFunc = Builder.CreateCall(ResolverFunc, ArrayRef<Value *>(), "resolved.func"); + auto *ResolvedAddr = Builder.CreateIntrinsic(/*RetTy*/ PtrTy, Intrinsic::ppc_get_function_entry, {ResolvedFunc}, {}, "resolved.addr"); + auto *PtrToInt = Builder.CreatePtrToInt(ResolvedAddr, Builder.getIntPtrTy(M.getDataLayout())); + // TODO fix alignment + Builder.CreateAlignedStore(PtrToInt, DesctAddr, MaybeAlign())->setAtomic(AtomicOrdering::Release); + + // br label %if.end + Builder.CreateBr(FinalBlock); + + // Emit the continuation block for code after the if. + Builder.SetInsertPoint(FinalBlock); + + // %res = musttail call i32 %DescPtr(i32 noundef %a) #3 + SmallVector<Value *, 10> Args(make_pointer_range(F->args())); + CallInst *Result = Builder.CreateCall(F->getFunctionType(), DescPtr, Args, "res"); + //Result->setTailCallKind(CallInst::TCK_MustTail); + + // ret i32 %res + if (F->getReturnType()->isVoidTy()) + Builder.CreateRetVoid(); + else + Builder.CreateRet(Result); + + // replace all uses of the ifunc with the newly created function + IFunc.replaceAllUsesWith(F); + + std::string name = IFunc.getName().str(); + IFunc.eraseFromParent(); + F->setName(name); + } +} bool llvm::lowerGlobalIFuncUsersAsGlobalCtor( Module &M, ArrayRef<GlobalIFunc *> FilteredIFuncsToLower) { SmallVector<GlobalIFunc *, 32> AllIFuncs; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits