diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h @@ -553,6 +553,12 @@ SDValue LowerCall(CallLoweringInfo &CLI, SmallVectorImpl &InVals) const override; + std::pair + makeExternalCall(SDValue Chain, SelectionDAG &DAG, const char *CalleeName, + EVT RetVT, ArrayRef Ops, CallingConv::ID CallConv, + bool IsSigned, SDLoc DL, bool DoesNotReturn, + bool IsReturnValueUsed) const; + bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, bool isVarArg, const SmallVectorImpl &Outs, @@ -624,6 +630,8 @@ SDValue lowerVASTART(SDValue Op, SelectionDAG &DAG) const; SDValue lowerVACOPY(SDValue Op, SelectionDAG &DAG) const; SDValue lowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerDYNAMIC_STACKALLOC_ELF(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerDYNAMIC_STACKALLOC_XPLINK(SDValue Op, SelectionDAG &DAG) const; SDValue lowerGET_DYNAMIC_AREA_OFFSET(SDValue Op, SelectionDAG &DAG) const; SDValue lowerSMUL_LOHI(SDValue Op, SelectionDAG &DAG) const; SDValue lowerUMUL_LOHI(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -1833,6 +1833,40 @@ return Chain; } +// Generate a call taking the given operands as arguments and returning a +// result of type RetVT. +std::pair SystemZTargetLowering::makeExternalCall( + SDValue Chain, SelectionDAG &DAG, const char *CalleeName, EVT RetVT, + ArrayRef Ops, CallingConv::ID CallConv, bool IsSigned, SDLoc DL, + bool DoesNotReturn, bool IsReturnValueUsed) const { + TargetLowering::ArgListTy Args; + Args.reserve(Ops.size()); + + TargetLowering::ArgListEntry Entry; + for (SDValue Op : Ops) { + Entry.Node = Op; + Entry.Ty = Entry.Node.getValueType().getTypeForEVT(*DAG.getContext()); + Entry.IsSExt = shouldSignExtendTypeInLibCall(Op.getValueType(), IsSigned); + Entry.IsZExt = !shouldSignExtendTypeInLibCall(Op.getValueType(), IsSigned); + Args.push_back(Entry); + } + + SDValue Callee = + DAG.getExternalSymbol(CalleeName, getPointerTy(DAG.getDataLayout())); + + Type *RetTy = RetVT.getTypeForEVT(*DAG.getContext()); + TargetLowering::CallLoweringInfo CLI(DAG); + bool SignExtend = shouldSignExtendTypeInLibCall(RetVT, IsSigned); + CLI.setDebugLoc(DL) + .setChain(Chain) + .setCallee(CallConv, RetTy, Callee, std::move(Args)) + .setNoReturn(DoesNotReturn) + .setDiscardResult(!IsReturnValueUsed) + .setSExtResult(SignExtend) + .setZExtResult(!SignExtend); + return LowerCallTo(CLI); +} + bool SystemZTargetLowering:: CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, bool isVarArg, @@ -3520,8 +3554,82 @@ MachinePointerInfo(SrcSV)); } -SDValue SystemZTargetLowering:: -lowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const { +SDValue +SystemZTargetLowering::lowerDYNAMIC_STACKALLOC(SDValue Op, + SelectionDAG &DAG) const { + if (Subtarget.isTargetXPLINK64()) + return lowerDYNAMIC_STACKALLOC_XPLINK(Op, DAG); + else + return lowerDYNAMIC_STACKALLOC_ELF(Op, DAG); +} + +SDValue +SystemZTargetLowering::lowerDYNAMIC_STACKALLOC_XPLINK(SDValue Op, + SelectionDAG &DAG) const { + const TargetFrameLowering *TFI = Subtarget.getFrameLowering(); + MachineFunction &MF = DAG.getMachineFunction(); + bool RealignOpt = !MF.getFunction().hasFnAttribute("no-realign-stack"); + SDValue Chain = Op.getOperand(0); + SDValue Size = Op.getOperand(1); + SDValue Align = Op.getOperand(2); + SDLoc DL(Op); + + // If user has set the no alignment function attribute, ignore + // alloca alignments. + uint64_t AlignVal = + (RealignOpt ? dyn_cast(Align)->getZExtValue() : 0); + + uint64_t StackAlign = TFI->getStackAlignment(); + uint64_t RequiredAlign = std::max(AlignVal, StackAlign); + uint64_t ExtraAlignSpace = RequiredAlign - StackAlign; + + SDValue NeededSpace = Size; + + // Add extra space for alignment if needed. + EVT PtrVT = getPointerTy(MF.getDataLayout()); + if (ExtraAlignSpace) + NeededSpace = DAG.getNode(ISD::ADD, DL, PtrVT, NeededSpace, + DAG.getConstant(ExtraAlignSpace, DL, PtrVT)); + + bool IsSigned = false; + bool DoesNotReturn = false; + bool IsReturnValueUsed = false; + EVT VT = Op.getValueType(); + SDValue AllocaCall = + makeExternalCall(Chain, DAG, "@@ALCAXP", VT, makeArrayRef(NeededSpace), + CallingConv::C, IsSigned, DL, DoesNotReturn, + IsReturnValueUsed) + .first; + + // Perform a CopyFromReg from %GPR4 (stack pointer register). Chain and Glue + // to end of call in order to ensure it isn't broken up from the call + // sequence. + auto &Regs = Subtarget.getSpecialRegisters(); + Register SPReg = Regs.getStackPointerRegister(); + Chain = AllocaCall.getValue(1); + SDValue Glue = AllocaCall.getValue(2); + SDValue NewSPRegNode = DAG.getCopyFromReg(Chain, DL, SPReg, PtrVT, Glue); + Chain = NewSPRegNode.getValue(1); + + MVT PtrMVT = getPointerMemTy(MF.getDataLayout()); + SDValue ArgAdjust = DAG.getNode(SystemZISD::ADJDYNALLOC, DL, PtrMVT); + SDValue Result = DAG.getNode(ISD::ADD, DL, PtrMVT, NewSPRegNode, ArgAdjust); + + // Dynamically realign if needed. + if (ExtraAlignSpace) { + Result = DAG.getNode(ISD::ADD, DL, PtrVT, Result, + DAG.getConstant(ExtraAlignSpace, DL, PtrVT)); + Result = DAG.getNode(ISD::AND, DL, PtrVT, Result, + DAG.getConstant(~(RequiredAlign - 1), DL, PtrVT)); + } + + SDValue Ops[2] = {Result, Chain}; + return DAG.getMergeValues(Ops, DL); +} + +SDValue +SystemZTargetLowering::lowerDYNAMIC_STACKALLOC_ELF(SDValue Op, + SelectionDAG &DAG) const { const TargetFrameLowering *TFI = Subtarget.getFrameLowering(); MachineFunction &MF = DAG.getMachineFunction(); bool RealignOpt = !MF.getFunction().hasFnAttribute("no-realign-stack"); diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp --- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp +++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp @@ -119,9 +119,11 @@ MachineFunction &MF = *MBB->getParent(); MachineFrameInfo &MFFrame = MF.getFrameInfo(); MachineOperand &OffsetMO = MI->getOperand(2); + SystemZCallingConventionRegisters *Regs = STI.getSpecialRegisters(); uint64_t Offset = (MFFrame.getMaxCallFrameSize() + - SystemZMC::ELFCallFrameSize + + Regs->getCallFrameSize() + + Regs->getStackPointerBias() + OffsetMO.getImm()); unsigned NewOpcode = getOpcodeForOffset(SystemZ::LA, Offset); assert(NewOpcode && "No support for huge argument lists yet"); diff --git a/llvm/test/CodeGen/SystemZ/zos-prologue-epilog.ll b/llvm/test/CodeGen/SystemZ/zos-prologue-epilog.ll --- a/llvm/test/CodeGen/SystemZ/zos-prologue-epilog.ll +++ b/llvm/test/CodeGen/SystemZ/zos-prologue-epilog.ll @@ -280,10 +280,14 @@ } ; Requires the saving of r4 due to variable sized -; object in stack frame. (Eg: VLA) -; CHECK64: stmg 4, 8, 1856(4) +; object in stack frame. (Eg: VLA) Sets up frame pointer in r8 +; CHECK64: stmg 4, 9, 1856(4) ; CHECK64: aghi 4, -192 -; CHECK64: lmg 4, 8, 2048(4) +; CHECK64: lgr 8, 4 +; TODO Will change to basr with ADA introduction. +; CHECK64: brasl 7, @@ALCAXP +; CHECK64-NEXT: bcr 0, 3 +; CHECK64: lmg 4, 9, 2048(4) define i64 @func4(i64 %n) { %vla = alloca i64, i64 %n, align 8 %call = call i64 @fun2(i64 %n, i64* nonnull %vla, i64* nonnull %vla) @@ -294,8 +298,12 @@ ; to force use of agfi before stmg. ; CHECK64: lgr 0, 4 ; CHECK64: agfi 4, -1040192 -; CHECK64: stmg 4, 8, 2048(4) -; CHECK64: lmg 4, 8, 2048(4) +; CHECK64: stmg 4, 9, 2048(4) +; CHECK64: lgr 8, 4 +; TODO Will change to basr with ADA introduction. +; CHECK64: brasl 7, @@ALCAXP +; CHECK64-NEXT: bcr 0, 3 +;; CHECK64: lmg 4, 9, 2048(4) define i64 @func5(i64 %n) { %vla = alloca i64, i64 %n, align 8 %arr = alloca [130000 x i64], align 8