Index: lib/Target/SystemZ/SystemZFrameLowering.cpp =================================================================== --- lib/Target/SystemZ/SystemZFrameLowering.cpp +++ lib/Target/SystemZ/SystemZFrameLowering.cpp @@ -68,7 +68,8 @@ TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); MachineFrameInfo *MFFrame = MF.getFrameInfo(); - const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); + const TargetSubtargetInfo &STI = MF.getSubtarget(); + const TargetRegisterInfo *TRI = STI.getRegisterInfo(); bool HasFP = hasFP(MF); SystemZMachineFunctionInfo *MFI = MF.getInfo(); bool IsVarArg = MF.getFunction()->isVarArg(); @@ -88,7 +89,8 @@ // If the function calls other functions, record that the return // address register will be clobbered. - if (MFFrame->hasCalls()) + const SystemZSubtarget &ZSTI = static_cast(STI); + if (MFFrame->hasCalls() || ZSTI.hasBackChain()) SavedRegs.set(SystemZ::R14D); // If we are saving GPRs other than the stack pointer, we might as well @@ -351,7 +353,17 @@ } } + const TargetSubtargetInfo &STI = MF.getSubtarget(); + const SystemZSubtarget &ZSTI = static_cast(STI); uint64_t StackSize = getAllocatedStackSize(MF); + + // If back chains are used, copy the old stack pointer to R14. + if (ZSTI.hasBackChain()) { + assert(StackSize && "Must allocate stack frame to svae back chain"); + BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::LGR), SystemZ::R14D) + .addReg(SystemZ::R15D); + } + if (StackSize) { // Allocate StackSize bytes. int64_t Delta = -int64_t(StackSize); @@ -384,6 +396,17 @@ I->addLiveIn(SystemZ::R11D); } + // Now store the old stack pointer to the back chain slot, if used. + if (ZSTI.hasBackChain()) { + const TargetRegisterInfo *TRI = STI.getRegisterInfo(); + const TargetInstrInfo *TII = STI.getInstrInfo(); + int BackChainIdx = MFFrame->CreateFixedObject(8, + -(SystemZMC::CallFrameSize + StackSize), false); + // int BackChainIdx = ZFI->getFramePointerSaveIndex(); + TII->storeRegToStackSlot(MBB, MBBI, SystemZ::R14D, true, BackChainIdx, + &SystemZ::GR64BitRegClass, TRI); + } + // Skip over the FPR saves. SmallVector CFIIndexes; for (auto &Save : CSI) { @@ -489,14 +512,17 @@ uint64_t SystemZFrameLowering:: getAllocatedStackSize(const MachineFunction &MF) const { const MachineFrameInfo *MFFrame = MF.getFrameInfo(); + const TargetSubtargetInfo &STI = MF.getSubtarget(); + const SystemZSubtarget &ZSTI = static_cast(STI); // Start with the size of the local variables and spill slots. uint64_t StackSize = MFFrame->getStackSize(); // We need to allocate the ABI-defined 160-byte base area whenever // we allocate stack space for our own use and whenever we call another - // function. - if (StackSize || MFFrame->hasVarSizedObjects() || MFFrame->hasCalls()) + // function, or if back chain support has been requested. + if (StackSize || MFFrame->hasVarSizedObjects() || MFFrame->hasCalls() || + ZSTI.hasBackChain()) StackSize += SystemZMC::CallFrameSize; return StackSize; Index: lib/Target/SystemZ/SystemZISelLowering.h =================================================================== --- lib/Target/SystemZ/SystemZISelLowering.h +++ lib/Target/SystemZ/SystemZISelLowering.h @@ -467,6 +467,8 @@ 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; Index: lib/Target/SystemZ/SystemZISelLowering.cpp =================================================================== --- lib/Target/SystemZ/SystemZISelLowering.cpp +++ lib/Target/SystemZ/SystemZISelLowering.cpp @@ -2676,6 +2676,83 @@ 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 && !Subtarget.hasBackChain()) { + report_fatal_error("Cannot traverse call stack without -mattr=backchain."); + } + + while (Depth--) + BackChain = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), + BackChain, MachinePointerInfo(), + false, false, false, 0); + + 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()); + + if (Depth > 0) { + const SystemZFrameLowering *TFI = Subtarget.getFrameLowering(); + SDValue FrameAddr = lowerFRAMEADDR(Op, DAG); + SDValue Offset = DAG.getConstant(TFI->getRegSpillOffset(SystemZ::R14D), + DL, PtrVT); + return DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), + DAG.getNode(ISD::ADD, DL, PtrVT, FrameAddr, Offset), + MachinePointerInfo(), false, false, false, 0); + } + + if (Subtarget.hasBackChain()) { + // If the return address frame index has not been allocated yet, do so. + SystemZMachineFunctionInfo *FI = MF.getInfo(); + int RetAddrIdx = FI->getReturnAddrSaveIndex(); + if (!RetAddrIdx) { + const SystemZFrameLowering *TFI = Subtarget.getFrameLowering(); + int R14Offset = + TFI->getRegSpillOffset(SystemZ::R14D) - SystemZMC::CallFrameSize; + RetAddrIdx = MFI->CreateFixedObject(8, R14Offset, false); + FI->setReturnAddrSaveIndex(RetAddrIdx); + } + SDValue RetAddrSlot = DAG.getFrameIndex(RetAddrIdx, PtrVT); + return DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), RetAddrSlot, + MachinePointerInfo(), false, false, false, 0); + } else { + // 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 +4424,10 @@ 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: Index: lib/Target/SystemZ/SystemZMachineFunctionInfo.h =================================================================== --- lib/Target/SystemZ/SystemZMachineFunctionInfo.h +++ lib/Target/SystemZ/SystemZMachineFunctionInfo.h @@ -22,14 +22,17 @@ unsigned VarArgsFirstFPR; unsigned VarArgsFrameIndex; unsigned RegSaveFrameIndex; + int FramePointerSaveIndex; + int ReturnAddrSaveIndex; 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), ReturnAddrSaveIndex(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 +62,14 @@ 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 the frame index of where the return address is stored. + int getReturnAddrSaveIndex() const { return ReturnAddrSaveIndex; } + void setReturnAddrSaveIndex(int Idx) { ReturnAddrSaveIndex = Idx; } + // Get and set whether the function directly manipulates the stack pointer, // e.g. through STACKSAVE or STACKRESTORE. bool getManipulatesSP() const { return ManipulatesSP; } Index: lib/Target/SystemZ/SystemZProcessors.td =================================================================== --- lib/Target/SystemZ/SystemZProcessors.td +++ lib/Target/SystemZ/SystemZProcessors.td @@ -76,6 +76,11 @@ >; def FeatureNoVector : SystemZMissingFeature<"Vector">; +def FeatureBackChain : SystemZFeature< + "backchain", "BackChain", + "Enable the saving of back chains in call frames" +>; + def : Processor<"generic", NoItineraries, []>; def : Processor<"z10", NoItineraries, []>; def : Processor<"z196", NoItineraries, Index: lib/Target/SystemZ/SystemZSubtarget.h =================================================================== --- lib/Target/SystemZ/SystemZSubtarget.h +++ lib/Target/SystemZ/SystemZSubtarget.h @@ -45,6 +45,7 @@ bool HasTransactionalExecution; bool HasProcessorAssist; bool HasVector; + bool HasBackChain; private: Triple TargetTriple; @@ -59,7 +60,7 @@ SystemZSubtarget(const Triple &TT, const std::string &CPU, const std::string &FS, const TargetMachine &TM); - const TargetFrameLowering *getFrameLowering() const override { + const SystemZFrameLowering *getFrameLowering() const override { return &FrameLowering; } const SystemZInstrInfo *getInstrInfo() const override { return &InstrInfo; } @@ -114,6 +115,9 @@ // Return true if the target has the vector facility. bool hasVector() const { return HasVector; } + // Return true if the back chain needs to be saved. + bool hasBackChain() const { return HasBackChain; } + // Return true if GV can be accessed using LARL for reloc model RM // and code model CM. bool isPC32DBLSymbol(const GlobalValue *GV, Reloc::Model RM, Index: lib/Target/SystemZ/SystemZSubtarget.cpp =================================================================== --- lib/Target/SystemZ/SystemZSubtarget.cpp +++ lib/Target/SystemZ/SystemZSubtarget.cpp @@ -40,7 +40,7 @@ HasPopulationCount(false), HasFastSerialization(false), HasInterlockedAccess1(false), HasMiscellaneousExtensions(false), HasTransactionalExecution(false), HasProcessorAssist(false), - HasVector(false), TargetTriple(TT), + HasVector(false), HasBackChain(false), TargetTriple(TT), InstrInfo(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM, *this), TSInfo(), FrameLowering() {} Index: test/CodeGen/SystemZ/frameaddr-01.ll =================================================================== --- /dev/null +++ test/CodeGen/SystemZ/frameaddr-01.ll @@ -0,0 +1,14 @@ +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s + +; Return the current function's frame address by taking 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 +} + +declare i8* @llvm.frameaddress(i32) nounwind readnone Index: test/CodeGen/SystemZ/frameaddr-02.ll =================================================================== --- /dev/null +++ test/CodeGen/SystemZ/frameaddr-02.ll @@ -0,0 +1,34 @@ +; RUN: llc < %s -mtriple=s390x-linux-gnu -mattr=backchain | FileCheck %s + +; With back chain support, the frame address is always preserved at 0(%r15). +define i8* @fp2b() nounwind { +entry: +; CHECK-LABEL: fp2b: +; CHECK: stmg %r14, %r15, 112(%r15) +; CHECK: lgr %r14, %r15 +; CHECK: aghi %r15, -160 +; CHECK: stg %r14, 0(%r15) +; CHECK: lg %r1, 160(%r15) +; CHECK: lg %r2, 0(%r1) +; CHECK: lmg %r14, %r15, 272(%r15) +; CHECK: br %r14 + %0 = tail call i8* @llvm.frameaddress(i32 2) + ret i8* %0 +} + +define i8* @fp1bfp() nounwind "no-frame-pointer-elim"="true" { +entry: +; CHECK-LABEL: fp1bfp: +; CHECK: stmg %r11, %r15, 88(%r15) +; CHECK: lgr %r14, %r15 +; CHECK: aghi %r15, -160 +; CHECK: lgr %r11, %r15 +; CHECK: stg %r14, 0(%r11) +; CHECK: lg %r2, 160(%r11) +; CHECK: lmg %r11, %r15, 248(%r11) +; CHECK: br %r14 + %0 = tail call i8* @llvm.frameaddress(i32 1) + ret i8* %0 +} + +declare i8* @llvm.frameaddress(i32) nounwind readnone Index: test/CodeGen/SystemZ/ret-addr-01.ll =================================================================== --- /dev/null +++ test/CodeGen/SystemZ/ret-addr-01.ll @@ -0,0 +1,16 @@ +; Test support for the llvm.returnaddress intrinsic. +; +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s + +; Without back chain support, just return the current function's +; return address from 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 Index: test/CodeGen/SystemZ/ret-addr-02.ll =================================================================== --- /dev/null +++ test/CodeGen/SystemZ/ret-addr-02.ll @@ -0,0 +1,52 @@ +; Test support for the llvm.returnaddress intrinsic. +; +; RUN: llc < %s -mtriple=s390x-linux-gnu -mattr=backchain | FileCheck %s + +; With back chain support, the return address is always preserved. +define i8* @rt0() norecurse nounwind readnone { +entry: +; CHECK-LABEL: rt0: +; CHECK: stmg %r14, %r15, 112(%r15) +; CHECK: lgr %r14, %r15 +; CHECK: aghi %r15, -160 +; CHECK: stg %r14, 0(%r15) +; CHECK: lg %r2, 272(%r15) +; CHECK: lmg %r14, %r15, 272(%r15) +; CHECK: br %r14 + %0 = tail call i8* @llvm.returnaddress(i32 0) + ret i8* %0 +} + +define i8* @rt2b() nounwind readnone { +entry: +; CHECK-LABEL: rt2b: +; CHECK: stmg %r14, %r15, 112(%r15) +; CHECK: lgr %r14, %r15 +; CHECK: aghi %r15, -160 +; CHECK: stg %r14, 0(%r15) +; CHECK: lg %r1, 160(%r15) +; CHECK: lg %r1, 0(%r1) +; CHECK: lg %r2, 112(%r1) +; CHECK: lmg %r14, %r15, 272(%r15) +; CHECK: br %r14 + %0 = tail call i8* @llvm.returnaddress(i32 2) + ret i8* %0 +} + +define i8* @rt1bfp() nounwind "no-frame-pointer-elim"="true" readnone { +entry: +; CHECK-LABEL: rt1bfp: +; CHECK: stmg %r11, %r15, 88(%r15) +; CHECK: lgr %r14, %r15 +; CHECK: aghi %r15, -160 +; CHECK: lgr %r11, %r15 +; CHECK: stg %r14, 0(%r11) +; CHECK: lg %r1, 160(%r11) +; CHECK: lg %r2, 112(%r1) +; CHECK: lmg %r11, %r15, 248(%r11) +; CHECK: br %r14 + %0 = tail call i8* @llvm.returnaddress(i32 1) + ret i8* %0 +} + +declare i8* @llvm.returnaddress(i32) nounwind readnone