diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index 459525ed4ee9a..aec06d74f5399 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -3926,9 +3926,6 @@ SDValue PPCTargetLowering::LowerVACOPY(SDValue Op, SelectionDAG &DAG) const { SDValue PPCTargetLowering::LowerADJUST_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const { - if (Subtarget.isAIXABI()) - report_fatal_error("ADJUST_TRAMPOLINE operation is not supported on AIX."); - return Op.getOperand(0); } @@ -3985,9 +3982,6 @@ SDValue PPCTargetLowering::LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const { SDValue PPCTargetLowering::LowerINIT_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const { - if (Subtarget.isAIXABI()) - report_fatal_error("INIT_TRAMPOLINE operation is not supported on AIX."); - SDValue Chain = Op.getOperand(0); SDValue Trmp = Op.getOperand(1); // trampoline SDValue FPtr = Op.getOperand(2); // nested function @@ -3995,6 +3989,65 @@ SDValue PPCTargetLowering::LowerINIT_TRAMPOLINE(SDValue Op, SDLoc dl(Op); EVT PtrVT = getPointerTy(DAG.getDataLayout()); + + if (Subtarget.isAIXABI()) { + // On AIX we create a trampoline descriptor by combining the + // entry point and TOC from the global descriptor (FPtr) with the + // nest argument as the environment pointer. + uint64_t PointerSize = Subtarget.isPPC64() ? 8 : 4; + MaybeAlign PointerAlign(PointerSize); + auto MMOFlags = Subtarget.hasInvariantFunctionDescriptors() + ? (MachineMemOperand::MODereferenceable | + MachineMemOperand::MOInvariant) + : MachineMemOperand::MONone; + + uint64_t TOCPointerOffset = 1 * PointerSize; + uint64_t EnvPointerOffset = 2 * PointerSize; + SDValue SDTOCPtrOffset = DAG.getConstant(TOCPointerOffset, dl, PtrVT); + SDValue SDEnvPtrOffset = DAG.getConstant(EnvPointerOffset, dl, PtrVT); + + const Value *TrampolineAddr = + cast(Op.getOperand(4))->getValue(); + const Function *Func = + cast(cast(Op.getOperand(5))->getValue()); + + SDValue OutChains[3]; + + // Copy the entry point address from the global descriptor to the + // trampoline buffer. + SDValue LoadEntryPoint = + DAG.getLoad(PtrVT, dl, Chain, FPtr, MachinePointerInfo(Func, 0), + PointerAlign, MMOFlags); + SDValue EPLoadChain = LoadEntryPoint.getValue(1); + OutChains[0] = DAG.getStore(EPLoadChain, dl, LoadEntryPoint, Trmp, + MachinePointerInfo(TrampolineAddr, 0)); + + // Copy the TOC pointer from the global descriptor to the trampoline + // buffer. + SDValue TOCFromDescriptorPtr = + DAG.getNode(ISD::ADD, dl, PtrVT, FPtr, SDTOCPtrOffset); + SDValue TOCReg = DAG.getLoad(PtrVT, dl, Chain, TOCFromDescriptorPtr, + MachinePointerInfo(Func, TOCPointerOffset), + PointerAlign, MMOFlags); + SDValue TrampolineTOCPointer = + DAG.getNode(ISD::ADD, dl, PtrVT, Trmp, SDTOCPtrOffset); + SDValue TOCLoadChain = TOCReg.getValue(1); + OutChains[1] = + DAG.getStore(TOCLoadChain, dl, TOCReg, TrampolineTOCPointer, + MachinePointerInfo(TrampolineAddr, TOCPointerOffset)); + + // Store the nest argument into the environment pointer in the trampoline + // buffer. + SDValue EnvPointer = DAG.getNode(ISD::ADD, dl, PtrVT, Trmp, SDEnvPtrOffset); + OutChains[2] = + DAG.getStore(Chain, dl, Nest, EnvPointer, + MachinePointerInfo(TrampolineAddr, EnvPointerOffset)); + + SDValue TokenFactor = + DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains); + return TokenFactor; + } + bool isPPC64 = (PtrVT == MVT::i64); Type *IntPtrTy = DAG.getDataLayout().getIntPtrType(*DAG.getContext()); @@ -6866,9 +6919,6 @@ static bool CC_AIX(unsigned ValNo, MVT ValVT, MVT LocVT, if (ValVT == MVT::f128) report_fatal_error("f128 is unimplemented on AIX."); - if (ArgFlags.isNest()) - report_fatal_error("Nest arguments are unimplemented."); - static const MCPhysReg GPR_32[] = {// 32-bit registers. PPC::R3, PPC::R4, PPC::R5, PPC::R6, PPC::R7, PPC::R8, PPC::R9, PPC::R10}; @@ -6883,6 +6933,14 @@ static bool CC_AIX(unsigned ValNo, MVT ValVT, MVT LocVT, const ArrayRef GPRs = IsPPC64 ? GPR_64 : GPR_32; + if (ArgFlags.isNest()) { + MCRegister EnvReg = State.AllocateReg(IsPPC64 ? PPC::X11 : PPC::R11); + if (!EnvReg) + report_fatal_error("More then one nest argument."); + State.addLoc(CCValAssign::getReg(ValNo, ValVT, EnvReg, RegVT, LocInfo)); + return false; + } + if (ArgFlags.isByVal()) { const Align ByValAlign(ArgFlags.getNonZeroByValAlign()); if (ByValAlign > StackAlign) diff --git a/llvm/test/CodeGen/PowerPC/aix-nest-param.ll b/llvm/test/CodeGen/PowerPC/aix-nest-param.ll index 1863eaf999f14..bfc7fbb374f1b 100644 --- a/llvm/test/CodeGen/PowerPC/aix-nest-param.ll +++ b/llvm/test/CodeGen/PowerPC/aix-nest-param.ll @@ -1,5 +1,5 @@ -; RUN: not --crash llc -mtriple powerpc-ibm-aix-xcoff < %s 2>&1 | FileCheck %s -; RUN: not --crash llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 | FileCheck %s +; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s 2>&1 | FileCheck %s +; RUN: llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 | FileCheck %s define ptr @nest_receiver(ptr nest %arg) nounwind { ret ptr %arg @@ -9,5 +9,10 @@ define ptr @nest_caller(ptr %arg) nounwind { %result = call ptr @nest_receiver(ptr nest %arg) ret ptr %result } +; CHECK-LABEL: .nest_receiver: +; CHECK: mr 3, 11 +; CHECK: blr -; CHECK: LLVM ERROR: Nest arguments are unimplemented. +; CHECK-LABEL: .nest_caller: +; CHECK: mr 11, 3 +; CHECK: bl .nest_receiver diff --git a/llvm/test/CodeGen/PowerPC/aix-trampoline.ll b/llvm/test/CodeGen/PowerPC/aix-trampoline.ll index b71f6b54587c5..19df220178e3b 100644 --- a/llvm/test/CodeGen/PowerPC/aix-trampoline.ll +++ b/llvm/test/CodeGen/PowerPC/aix-trampoline.ll @@ -1,7 +1,7 @@ -; RUN: not --crash llc -mtriple powerpc-ibm-aix-xcoff < %s 2>&1 | FileCheck %s -; RUN: not --crash llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 | FileCheck %s - -; CHECK: LLVM ERROR: INIT_TRAMPOLINE operation is not supported on AIX. +; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s 2>&1 | \ +; RUN: FileCheck %s --check-prefix=32BIT +; RUN: llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 -mattr=-altivec | \ +; RUN: FileCheck %s --check-prefix=64BIT define void @create_trampoline(ptr %buffer, ptr %nval) nounwind { entry: @@ -12,3 +12,17 @@ entry: declare i32 @nested(i32); declare void @llvm.init.trampoline(ptr, ptr, ptr) nounwind + +; 32BIT: stw 4, 8(3) +; 32BIT: lwz [[FuncDesc:[0-9]+]], L..C0(2) +; 32BIT-DAG: lwz [[SCRATCH1:[0-9]+]], 0([[FuncDesc]]) +; 32BIT-DAG: lwz [[SCRATCH2:[0-9]+]], 4([[FuncDesc]]) +; 32BIT-DAG: stw [[SCRATCH1]], 0(3) +; 32BIT-DAG: stw [[SCRATCH2]], 4(3) + +; 64BIT: std 4, 16(3) +; 64BIT-DAG: ld [[FuncDesc:[0-9]+]], L..C0(2) +; 64BIT-DAG: ld [[SCRATCH1:[0-9]+]], 0([[FuncDesc]]) +; 64BIT-DAG: ld [[SCRATCH2:[0-9]+]], 8([[FuncDesc]]) +; 64BIT-DAG: std [[SCRATCH1]], 0(3) +; 64BIT-DAG: std [[SCRATCH2]], 8(3)