diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index a670185c378d..654f66a79667 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -2676,6 +2676,57 @@ SDValue SystemZTargetLowering::lowerConstantPool(ConstantPoolSDNode *CP, return DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Result); } +SDValue SystemZTargetLowering::lowerFRAMEADDR(SDValue Op, + SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MFI->setFrameAddressIsTaken(true); + + SDLoc DL(Op); + unsigned Depth = cast(Op.getOperand(0))->getZExtValue(); + EVT PtrVT = getPointerTy(DAG.getDataLayout()); + + // If the back chain frame index has not been allocated yet, do so. + SystemZMachineFunctionInfo *FI = MF.getInfo(); + int BackChainIdx = FI->getFramePointerSaveIndex(); + if (!BackChainIdx) { + // By definition, the frame address is the address of the back chain. + BackChainIdx = MFI->CreateFixedObject(8, -SystemZMC::CallFrameSize, false); + FI->setFramePointerSaveIndex(BackChainIdx); + } + SDValue BackChain = DAG.getFrameIndex(BackChainIdx, PtrVT); + + // FIXME The frontend should detect this case. + if (Depth > 0) { + report_fatal_error("Unsupported stack frame traversal count"); + } + + return BackChain; +} + +SDValue SystemZTargetLowering::lowerRETURNADDR(SDValue Op, + SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MFI->setReturnAddressIsTaken(true); + + if (verifyReturnAddressArgumentIsConstant(Op, DAG)) + return SDValue(); + + SDLoc DL(Op); + unsigned Depth = cast(Op.getOperand(0))->getZExtValue(); + EVT PtrVT = getPointerTy(DAG.getDataLayout()); + + // FIXME The frontend should detect this case. + if (Depth > 0) { + report_fatal_error("Unsupported stack frame traversal count"); + } + + // Return R14D, which has the return address. Mark it an implicit live-in. + unsigned LinkReg = MF.addLiveIn(SystemZ::R14D, &SystemZ::GR64BitRegClass); + return DAG.getCopyFromReg(DAG.getEntryNode(), DL, LinkReg, PtrVT); +} + SDValue SystemZTargetLowering::lowerBITCAST(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); @@ -4347,6 +4398,10 @@ SDValue SystemZTargetLowering::lowerShift(SDValue Op, SelectionDAG &DAG, SDValue SystemZTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { + case ISD::FRAMEADDR: + return lowerFRAMEADDR(Op, DAG); + case ISD::RETURNADDR: + return lowerRETURNADDR(Op, DAG); case ISD::BR_CC: return lowerBR_CC(Op, DAG); case ISD::SELECT_CC: diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h index 391636e5467f..af8c67d78493 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h @@ -467,6 +467,8 @@ private: SelectionDAG &DAG) const; SDValue lowerJumpTable(JumpTableSDNode *JT, SelectionDAG &DAG) const; SDValue lowerConstantPool(ConstantPoolSDNode *CP, SelectionDAG &DAG) const; + SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; SDValue lowerVASTART(SDValue Op, SelectionDAG &DAG) const; SDValue lowerVACOPY(SDValue Op, SelectionDAG &DAG) const; SDValue lowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/SystemZ/SystemZMachineFunctionInfo.h b/llvm/lib/Target/SystemZ/SystemZMachineFunctionInfo.h index f4a517bd54df..4f64f4c65f1d 100644 --- a/llvm/lib/Target/SystemZ/SystemZMachineFunctionInfo.h +++ b/llvm/lib/Target/SystemZ/SystemZMachineFunctionInfo.h @@ -22,14 +22,15 @@ class SystemZMachineFunctionInfo : public MachineFunctionInfo { unsigned VarArgsFirstFPR; unsigned VarArgsFrameIndex; unsigned RegSaveFrameIndex; + int FramePointerSaveIndex; bool ManipulatesSP; unsigned NumLocalDynamics; public: explicit SystemZMachineFunctionInfo(MachineFunction &MF) : LowSavedGPR(0), HighSavedGPR(0), VarArgsFirstGPR(0), VarArgsFirstFPR(0), - VarArgsFrameIndex(0), RegSaveFrameIndex(0), ManipulatesSP(false), - NumLocalDynamics(0) {} + VarArgsFrameIndex(0), RegSaveFrameIndex(0), FramePointerSaveIndex(0), + ManipulatesSP(false), NumLocalDynamics(0) {} // Get and set the first call-saved GPR that should be saved and restored // by this function. This is 0 if no GPRs need to be saved or restored. @@ -59,6 +60,10 @@ public: unsigned getRegSaveFrameIndex() const { return RegSaveFrameIndex; } void setRegSaveFrameIndex(unsigned FI) { RegSaveFrameIndex = FI; } + // Get and set the frame index of where the old frame pointer is stored. + int getFramePointerSaveIndex() const { return FramePointerSaveIndex; } + void setFramePointerSaveIndex(int Idx) { FramePointerSaveIndex = Idx; } + // Get and set whether the function directly manipulates the stack pointer, // e.g. through STACKSAVE or STACKRESTORE. bool getManipulatesSP() const { return ManipulatesSP; } diff --git a/llvm/test/CodeGen/SystemZ/frameaddr-01.ll b/llvm/test/CodeGen/SystemZ/frameaddr-01.ll new file mode 100644 index 000000000000..4dfdf308e8a6 --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/frameaddr-01.ll @@ -0,0 +1,28 @@ +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s + +; The current function's frame address is the address of +; the optional back chain slot. +define i8* @fp0() nounwind { +entry: +; CHECK-LABEL: fp0: +; CHECK: la %r2, 0(%r15) +; CHECK: br %r14 + %0 = tail call i8* @llvm.frameaddress(i32 0) + ret i8* %0 +} + +; Check that the frame address is correct in a presence +; of a stack frame. +define i8* @fp0f() nounwind { +entry: +; CHECK-LABEL: fp0f: +; CHECK: aghi %r15, -168 +; CHECK: la %r2, 168(%r15) +; CHECK: aghi %r15, 168 +; CHECK: br %r14 + %0 = alloca i64, align 8 + %1 = tail call i8* @llvm.frameaddress(i32 0) + ret i8* %1 +} + +declare i8* @llvm.frameaddress(i32) nounwind readnone diff --git a/llvm/test/CodeGen/SystemZ/ret-addr-01.ll b/llvm/test/CodeGen/SystemZ/ret-addr-01.ll new file mode 100644 index 000000000000..9c3b246af578 --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/ret-addr-01.ll @@ -0,0 +1,15 @@ +; Test support for the llvm.returnaddress intrinsic. +; +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s + +; The current function's return address is in the link register. +define i8* @rt0() norecurse nounwind readnone { +entry: +; CHECK-LABEL: rt0: +; CHECK: lgr %r2, %r14 +; CHECK: br %r14 + %0 = tail call i8* @llvm.returnaddress(i32 0) + ret i8* %0 +} + +declare i8* @llvm.returnaddress(i32) nounwind readnone