10b57cec5SDimitry Andric //===-- SystemZFrameLowering.cpp - Frame lowering for SystemZ -------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "SystemZFrameLowering.h" 100b57cec5SDimitry Andric #include "SystemZCallingConv.h" 110b57cec5SDimitry Andric #include "SystemZInstrBuilder.h" 120b57cec5SDimitry Andric #include "SystemZInstrInfo.h" 130b57cec5SDimitry Andric #include "SystemZMachineFunctionInfo.h" 140b57cec5SDimitry Andric #include "SystemZRegisterInfo.h" 150b57cec5SDimitry Andric #include "SystemZSubtarget.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h" 190b57cec5SDimitry Andric #include "llvm/IR/Function.h" 205ffd83dbSDimitry Andric #include "llvm/Target/TargetMachine.h" 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric using namespace llvm; 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric namespace { 25480093f4SDimitry Andric // The ABI-defined register save slots, relative to the CFA (i.e. 26fe6060f1SDimitry Andric // incoming stack pointer + SystemZMC::ELFCallFrameSize). 27349cc55cSDimitry Andric static const TargetFrameLowering::SpillSlot ELFSpillOffsetTable[] = { 280b57cec5SDimitry Andric { SystemZ::R2D, 0x10 }, 290b57cec5SDimitry Andric { SystemZ::R3D, 0x18 }, 300b57cec5SDimitry Andric { SystemZ::R4D, 0x20 }, 310b57cec5SDimitry Andric { SystemZ::R5D, 0x28 }, 320b57cec5SDimitry Andric { SystemZ::R6D, 0x30 }, 330b57cec5SDimitry Andric { SystemZ::R7D, 0x38 }, 340b57cec5SDimitry Andric { SystemZ::R8D, 0x40 }, 350b57cec5SDimitry Andric { SystemZ::R9D, 0x48 }, 360b57cec5SDimitry Andric { SystemZ::R10D, 0x50 }, 370b57cec5SDimitry Andric { SystemZ::R11D, 0x58 }, 380b57cec5SDimitry Andric { SystemZ::R12D, 0x60 }, 390b57cec5SDimitry Andric { SystemZ::R13D, 0x68 }, 400b57cec5SDimitry Andric { SystemZ::R14D, 0x70 }, 410b57cec5SDimitry Andric { SystemZ::R15D, 0x78 }, 420b57cec5SDimitry Andric { SystemZ::F0D, 0x80 }, 430b57cec5SDimitry Andric { SystemZ::F2D, 0x88 }, 440b57cec5SDimitry Andric { SystemZ::F4D, 0x90 }, 450b57cec5SDimitry Andric { SystemZ::F6D, 0x98 } 460b57cec5SDimitry Andric }; 47349cc55cSDimitry Andric 48349cc55cSDimitry Andric static const TargetFrameLowering::SpillSlot XPLINKSpillOffsetTable[] = { 49349cc55cSDimitry Andric {SystemZ::R4D, 0x00}, {SystemZ::R5D, 0x08}, {SystemZ::R6D, 0x10}, 50349cc55cSDimitry Andric {SystemZ::R7D, 0x18}, {SystemZ::R8D, 0x20}, {SystemZ::R9D, 0x28}, 51349cc55cSDimitry Andric {SystemZ::R10D, 0x30}, {SystemZ::R11D, 0x38}, {SystemZ::R12D, 0x40}, 52349cc55cSDimitry Andric {SystemZ::R13D, 0x48}, {SystemZ::R14D, 0x50}, {SystemZ::R15D, 0x58}}; 530b57cec5SDimitry Andric } // end anonymous namespace 540b57cec5SDimitry Andric 55349cc55cSDimitry Andric SystemZFrameLowering::SystemZFrameLowering(StackDirection D, Align StackAl, 56349cc55cSDimitry Andric int LAO, Align TransAl, 57349cc55cSDimitry Andric bool StackReal) 58349cc55cSDimitry Andric : TargetFrameLowering(D, StackAl, LAO, TransAl, StackReal) {} 59480093f4SDimitry Andric 60349cc55cSDimitry Andric std::unique_ptr<SystemZFrameLowering> 61349cc55cSDimitry Andric SystemZFrameLowering::create(const SystemZSubtarget &STI) { 62349cc55cSDimitry Andric if (STI.isTargetXPLINK64()) 63349cc55cSDimitry Andric return std::make_unique<SystemZXPLINKFrameLowering>(); 64349cc55cSDimitry Andric return std::make_unique<SystemZELFFrameLowering>(); 650b57cec5SDimitry Andric } 660b57cec5SDimitry Andric 67349cc55cSDimitry Andric MachineBasicBlock::iterator SystemZFrameLowering::eliminateCallFramePseudoInstr( 68349cc55cSDimitry Andric MachineFunction &MF, MachineBasicBlock &MBB, 69349cc55cSDimitry Andric MachineBasicBlock::iterator MI) const { 70349cc55cSDimitry Andric switch (MI->getOpcode()) { 71349cc55cSDimitry Andric case SystemZ::ADJCALLSTACKDOWN: 72349cc55cSDimitry Andric case SystemZ::ADJCALLSTACKUP: 73349cc55cSDimitry Andric assert(hasReservedCallFrame(MF) && 74349cc55cSDimitry Andric "ADJSTACKDOWN and ADJSTACKUP should be no-ops"); 75349cc55cSDimitry Andric return MBB.erase(MI); 76349cc55cSDimitry Andric break; 77349cc55cSDimitry Andric 78349cc55cSDimitry Andric default: 79349cc55cSDimitry Andric llvm_unreachable("Unexpected call frame instruction"); 80349cc55cSDimitry Andric } 81349cc55cSDimitry Andric } 82349cc55cSDimitry Andric 83349cc55cSDimitry Andric bool SystemZFrameLowering::hasReservedCallFrame( 84349cc55cSDimitry Andric const MachineFunction &MF) const { 85349cc55cSDimitry Andric // The ELF ABI requires us to allocate 160 bytes of stack space for the 86349cc55cSDimitry Andric // callee, with any outgoing stack arguments being placed above that. It 87349cc55cSDimitry Andric // seems better to make that area a permanent feature of the frame even if 88349cc55cSDimitry Andric // we're using a frame pointer. Similarly, 64-bit XPLINK requires 96 bytes 89349cc55cSDimitry Andric // of stack space for the register save area. 90349cc55cSDimitry Andric return true; 91349cc55cSDimitry Andric } 92349cc55cSDimitry Andric 93349cc55cSDimitry Andric bool SystemZELFFrameLowering::assignCalleeSavedSpillSlots( 94349cc55cSDimitry Andric MachineFunction &MF, const TargetRegisterInfo *TRI, 95480093f4SDimitry Andric std::vector<CalleeSavedInfo> &CSI) const { 96480093f4SDimitry Andric SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); 97480093f4SDimitry Andric MachineFrameInfo &MFFrame = MF.getFrameInfo(); 98480093f4SDimitry Andric bool IsVarArg = MF.getFunction().isVarArg(); 99480093f4SDimitry Andric if (CSI.empty()) 100480093f4SDimitry Andric return true; // Early exit if no callee saved registers are modified! 101480093f4SDimitry Andric 102480093f4SDimitry Andric unsigned LowGPR = 0; 103480093f4SDimitry Andric unsigned HighGPR = SystemZ::R15D; 104fe6060f1SDimitry Andric int StartSPOffset = SystemZMC::ELFCallFrameSize; 105480093f4SDimitry Andric for (auto &CS : CSI) { 106480093f4SDimitry Andric unsigned Reg = CS.getReg(); 1075ffd83dbSDimitry Andric int Offset = getRegSpillOffset(MF, Reg); 108480093f4SDimitry Andric if (Offset) { 109480093f4SDimitry Andric if (SystemZ::GR64BitRegClass.contains(Reg) && StartSPOffset > Offset) { 110480093f4SDimitry Andric LowGPR = Reg; 111480093f4SDimitry Andric StartSPOffset = Offset; 112480093f4SDimitry Andric } 113fe6060f1SDimitry Andric Offset -= SystemZMC::ELFCallFrameSize; 114480093f4SDimitry Andric int FrameIdx = MFFrame.CreateFixedSpillStackObject(8, Offset); 115480093f4SDimitry Andric CS.setFrameIdx(FrameIdx); 116480093f4SDimitry Andric } else 117480093f4SDimitry Andric CS.setFrameIdx(INT32_MAX); 118480093f4SDimitry Andric } 119480093f4SDimitry Andric 120480093f4SDimitry Andric // Save the range of call-saved registers, for use by the 121480093f4SDimitry Andric // prologue/epilogue inserters. 122480093f4SDimitry Andric ZFI->setRestoreGPRRegs(LowGPR, HighGPR, StartSPOffset); 123480093f4SDimitry Andric if (IsVarArg) { 124480093f4SDimitry Andric // Also save the GPR varargs, if any. R6D is call-saved, so would 125480093f4SDimitry Andric // already be included, but we also need to handle the call-clobbered 126480093f4SDimitry Andric // argument registers. 127480093f4SDimitry Andric unsigned FirstGPR = ZFI->getVarArgsFirstGPR(); 128fe6060f1SDimitry Andric if (FirstGPR < SystemZ::ELFNumArgGPRs) { 129fe6060f1SDimitry Andric unsigned Reg = SystemZ::ELFArgGPRs[FirstGPR]; 1305ffd83dbSDimitry Andric int Offset = getRegSpillOffset(MF, Reg); 131480093f4SDimitry Andric if (StartSPOffset > Offset) { 132480093f4SDimitry Andric LowGPR = Reg; StartSPOffset = Offset; 133480093f4SDimitry Andric } 134480093f4SDimitry Andric } 135480093f4SDimitry Andric } 136480093f4SDimitry Andric ZFI->setSpillGPRRegs(LowGPR, HighGPR, StartSPOffset); 137480093f4SDimitry Andric 138480093f4SDimitry Andric // Create fixed stack objects for the remaining registers. 139fe6060f1SDimitry Andric int CurrOffset = -SystemZMC::ELFCallFrameSize; 1405ffd83dbSDimitry Andric if (usePackedStack(MF)) 1415ffd83dbSDimitry Andric CurrOffset += StartSPOffset; 1425ffd83dbSDimitry Andric 143480093f4SDimitry Andric for (auto &CS : CSI) { 144480093f4SDimitry Andric if (CS.getFrameIdx() != INT32_MAX) 145480093f4SDimitry Andric continue; 146480093f4SDimitry Andric unsigned Reg = CS.getReg(); 147480093f4SDimitry Andric const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); 148480093f4SDimitry Andric unsigned Size = TRI->getSpillSize(*RC); 149480093f4SDimitry Andric CurrOffset -= Size; 150480093f4SDimitry Andric assert(CurrOffset % 8 == 0 && 151480093f4SDimitry Andric "8-byte alignment required for for all register save slots"); 152480093f4SDimitry Andric int FrameIdx = MFFrame.CreateFixedSpillStackObject(Size, CurrOffset); 153480093f4SDimitry Andric CS.setFrameIdx(FrameIdx); 154480093f4SDimitry Andric } 155480093f4SDimitry Andric 156480093f4SDimitry Andric return true; 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 159349cc55cSDimitry Andric void SystemZELFFrameLowering::determineCalleeSaves(MachineFunction &MF, 1600b57cec5SDimitry Andric BitVector &SavedRegs, 1610b57cec5SDimitry Andric RegScavenger *RS) const { 1620b57cec5SDimitry Andric TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric MachineFrameInfo &MFFrame = MF.getFrameInfo(); 1650b57cec5SDimitry Andric const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); 1660b57cec5SDimitry Andric bool HasFP = hasFP(MF); 1670b57cec5SDimitry Andric SystemZMachineFunctionInfo *MFI = MF.getInfo<SystemZMachineFunctionInfo>(); 1680b57cec5SDimitry Andric bool IsVarArg = MF.getFunction().isVarArg(); 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric // va_start stores incoming FPR varargs in the normal way, but delegates 1710b57cec5SDimitry Andric // the saving of incoming GPR varargs to spillCalleeSavedRegisters(). 1720b57cec5SDimitry Andric // Record these pending uses, which typically include the call-saved 1730b57cec5SDimitry Andric // argument register R6D. 1740b57cec5SDimitry Andric if (IsVarArg) 175fe6060f1SDimitry Andric for (unsigned I = MFI->getVarArgsFirstGPR(); I < SystemZ::ELFNumArgGPRs; ++I) 176fe6060f1SDimitry Andric SavedRegs.set(SystemZ::ELFArgGPRs[I]); 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric // If there are any landing pads, entering them will modify r6/r7. 1790b57cec5SDimitry Andric if (!MF.getLandingPads().empty()) { 1800b57cec5SDimitry Andric SavedRegs.set(SystemZ::R6D); 1810b57cec5SDimitry Andric SavedRegs.set(SystemZ::R7D); 1820b57cec5SDimitry Andric } 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric // If the function requires a frame pointer, record that the hard 1850b57cec5SDimitry Andric // frame pointer will be clobbered. 1860b57cec5SDimitry Andric if (HasFP) 1870b57cec5SDimitry Andric SavedRegs.set(SystemZ::R11D); 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric // If the function calls other functions, record that the return 1900b57cec5SDimitry Andric // address register will be clobbered. 1910b57cec5SDimitry Andric if (MFFrame.hasCalls()) 1920b57cec5SDimitry Andric SavedRegs.set(SystemZ::R14D); 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric // If we are saving GPRs other than the stack pointer, we might as well 1950b57cec5SDimitry Andric // save and restore the stack pointer at the same time, via STMG and LMG. 1960b57cec5SDimitry Andric // This allows the deallocation to be done by the LMG, rather than needing 1970b57cec5SDimitry Andric // a separate %r15 addition. 1980b57cec5SDimitry Andric const MCPhysReg *CSRegs = TRI->getCalleeSavedRegs(&MF); 1990b57cec5SDimitry Andric for (unsigned I = 0; CSRegs[I]; ++I) { 2000b57cec5SDimitry Andric unsigned Reg = CSRegs[I]; 2010b57cec5SDimitry Andric if (SystemZ::GR64BitRegClass.contains(Reg) && SavedRegs.test(Reg)) { 2020b57cec5SDimitry Andric SavedRegs.set(SystemZ::R15D); 2030b57cec5SDimitry Andric break; 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric } 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric 208349cc55cSDimitry Andric SystemZELFFrameLowering::SystemZELFFrameLowering() 209349cc55cSDimitry Andric : SystemZFrameLowering(TargetFrameLowering::StackGrowsDown, Align(8), 0, 210349cc55cSDimitry Andric Align(8), /* StackRealignable */ false), 211349cc55cSDimitry Andric RegSpillOffsets(0) { 212349cc55cSDimitry Andric 213349cc55cSDimitry Andric // Due to the SystemZ ABI, the DWARF CFA (Canonical Frame Address) is not 214349cc55cSDimitry Andric // equal to the incoming stack pointer, but to incoming stack pointer plus 215349cc55cSDimitry Andric // 160. Instead of using a Local Area Offset, the Register save area will 216349cc55cSDimitry Andric // be occupied by fixed frame objects, and all offsets are actually 217349cc55cSDimitry Andric // relative to CFA. 218349cc55cSDimitry Andric 219349cc55cSDimitry Andric // Create a mapping from register number to save slot offset. 220349cc55cSDimitry Andric // These offsets are relative to the start of the register save area. 221349cc55cSDimitry Andric RegSpillOffsets.grow(SystemZ::NUM_TARGET_REGS); 222349cc55cSDimitry Andric for (unsigned I = 0, E = array_lengthof(ELFSpillOffsetTable); I != E; ++I) 223349cc55cSDimitry Andric RegSpillOffsets[ELFSpillOffsetTable[I].Reg] = ELFSpillOffsetTable[I].Offset; 224349cc55cSDimitry Andric } 225349cc55cSDimitry Andric 2260b57cec5SDimitry Andric // Add GPR64 to the save instruction being built by MIB, which is in basic 2270b57cec5SDimitry Andric // block MBB. IsImplicit says whether this is an explicit operand to the 2280b57cec5SDimitry Andric // instruction, or an implicit one that comes between the explicit start 2290b57cec5SDimitry Andric // and end registers. 2300b57cec5SDimitry Andric static void addSavedGPR(MachineBasicBlock &MBB, MachineInstrBuilder &MIB, 2310b57cec5SDimitry Andric unsigned GPR64, bool IsImplicit) { 2320b57cec5SDimitry Andric const TargetRegisterInfo *RI = 2330b57cec5SDimitry Andric MBB.getParent()->getSubtarget().getRegisterInfo(); 2348bcb0991SDimitry Andric Register GPR32 = RI->getSubReg(GPR64, SystemZ::subreg_l32); 2350b57cec5SDimitry Andric bool IsLive = MBB.isLiveIn(GPR64) || MBB.isLiveIn(GPR32); 2360b57cec5SDimitry Andric if (!IsLive || !IsImplicit) { 2370b57cec5SDimitry Andric MIB.addReg(GPR64, getImplRegState(IsImplicit) | getKillRegState(!IsLive)); 2380b57cec5SDimitry Andric if (!IsLive) 2390b57cec5SDimitry Andric MBB.addLiveIn(GPR64); 2400b57cec5SDimitry Andric } 2410b57cec5SDimitry Andric } 2420b57cec5SDimitry Andric 243349cc55cSDimitry Andric bool SystemZELFFrameLowering::spillCalleeSavedRegisters( 2445ffd83dbSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 2455ffd83dbSDimitry Andric ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 2460b57cec5SDimitry Andric if (CSI.empty()) 2470b57cec5SDimitry Andric return false; 2480b57cec5SDimitry Andric 2490b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent(); 2500b57cec5SDimitry Andric const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); 2510b57cec5SDimitry Andric SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); 2520b57cec5SDimitry Andric bool IsVarArg = MF.getFunction().isVarArg(); 2530b57cec5SDimitry Andric DebugLoc DL; 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric // Save GPRs 256480093f4SDimitry Andric SystemZ::GPRRegs SpillGPRs = ZFI->getSpillGPRRegs(); 257480093f4SDimitry Andric if (SpillGPRs.LowGPR) { 258480093f4SDimitry Andric assert(SpillGPRs.LowGPR != SpillGPRs.HighGPR && 259480093f4SDimitry Andric "Should be saving %r15 and something else"); 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric // Build an STMG instruction. 2620b57cec5SDimitry Andric MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(SystemZ::STMG)); 2630b57cec5SDimitry Andric 2640b57cec5SDimitry Andric // Add the explicit register operands. 265480093f4SDimitry Andric addSavedGPR(MBB, MIB, SpillGPRs.LowGPR, false); 266480093f4SDimitry Andric addSavedGPR(MBB, MIB, SpillGPRs.HighGPR, false); 2670b57cec5SDimitry Andric 2680b57cec5SDimitry Andric // Add the address. 269480093f4SDimitry Andric MIB.addReg(SystemZ::R15D).addImm(SpillGPRs.GPROffset); 2700b57cec5SDimitry Andric 2710b57cec5SDimitry Andric // Make sure all call-saved GPRs are included as operands and are 2720b57cec5SDimitry Andric // marked as live on entry. 273*4824e7fdSDimitry Andric for (const CalleeSavedInfo &I : CSI) { 274*4824e7fdSDimitry Andric unsigned Reg = I.getReg(); 2750b57cec5SDimitry Andric if (SystemZ::GR64BitRegClass.contains(Reg)) 2760b57cec5SDimitry Andric addSavedGPR(MBB, MIB, Reg, true); 2770b57cec5SDimitry Andric } 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric // ...likewise GPR varargs. 2800b57cec5SDimitry Andric if (IsVarArg) 281fe6060f1SDimitry Andric for (unsigned I = ZFI->getVarArgsFirstGPR(); I < SystemZ::ELFNumArgGPRs; ++I) 282fe6060f1SDimitry Andric addSavedGPR(MBB, MIB, SystemZ::ELFArgGPRs[I], true); 2830b57cec5SDimitry Andric } 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric // Save FPRs/VRs in the normal TargetInstrInfo way. 286*4824e7fdSDimitry Andric for (const CalleeSavedInfo &I : CSI) { 287*4824e7fdSDimitry Andric unsigned Reg = I.getReg(); 2880b57cec5SDimitry Andric if (SystemZ::FP64BitRegClass.contains(Reg)) { 2890b57cec5SDimitry Andric MBB.addLiveIn(Reg); 290*4824e7fdSDimitry Andric TII->storeRegToStackSlot(MBB, MBBI, Reg, true, I.getFrameIdx(), 2910b57cec5SDimitry Andric &SystemZ::FP64BitRegClass, TRI); 2920b57cec5SDimitry Andric } 2930b57cec5SDimitry Andric if (SystemZ::VR128BitRegClass.contains(Reg)) { 2940b57cec5SDimitry Andric MBB.addLiveIn(Reg); 295*4824e7fdSDimitry Andric TII->storeRegToStackSlot(MBB, MBBI, Reg, true, I.getFrameIdx(), 2960b57cec5SDimitry Andric &SystemZ::VR128BitRegClass, TRI); 2970b57cec5SDimitry Andric } 2980b57cec5SDimitry Andric } 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric return true; 3010b57cec5SDimitry Andric } 3020b57cec5SDimitry Andric 303349cc55cSDimitry Andric bool SystemZELFFrameLowering::restoreCalleeSavedRegisters( 3045ffd83dbSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 3055ffd83dbSDimitry Andric MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 3060b57cec5SDimitry Andric if (CSI.empty()) 3070b57cec5SDimitry Andric return false; 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent(); 3100b57cec5SDimitry Andric const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); 3110b57cec5SDimitry Andric SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); 3120b57cec5SDimitry Andric bool HasFP = hasFP(MF); 3130b57cec5SDimitry Andric DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric // Restore FPRs/VRs in the normal TargetInstrInfo way. 316*4824e7fdSDimitry Andric for (const CalleeSavedInfo &I : CSI) { 317*4824e7fdSDimitry Andric unsigned Reg = I.getReg(); 3180b57cec5SDimitry Andric if (SystemZ::FP64BitRegClass.contains(Reg)) 319*4824e7fdSDimitry Andric TII->loadRegFromStackSlot(MBB, MBBI, Reg, I.getFrameIdx(), 3200b57cec5SDimitry Andric &SystemZ::FP64BitRegClass, TRI); 3210b57cec5SDimitry Andric if (SystemZ::VR128BitRegClass.contains(Reg)) 322*4824e7fdSDimitry Andric TII->loadRegFromStackSlot(MBB, MBBI, Reg, I.getFrameIdx(), 3230b57cec5SDimitry Andric &SystemZ::VR128BitRegClass, TRI); 3240b57cec5SDimitry Andric } 3250b57cec5SDimitry Andric 3260b57cec5SDimitry Andric // Restore call-saved GPRs (but not call-clobbered varargs, which at 3270b57cec5SDimitry Andric // this point might hold return values). 328480093f4SDimitry Andric SystemZ::GPRRegs RestoreGPRs = ZFI->getRestoreGPRRegs(); 329480093f4SDimitry Andric if (RestoreGPRs.LowGPR) { 3300b57cec5SDimitry Andric // If we saved any of %r2-%r5 as varargs, we should also be saving 3310b57cec5SDimitry Andric // and restoring %r6. If we're saving %r6 or above, we should be 3320b57cec5SDimitry Andric // restoring it too. 333480093f4SDimitry Andric assert(RestoreGPRs.LowGPR != RestoreGPRs.HighGPR && 334480093f4SDimitry Andric "Should be loading %r15 and something else"); 3350b57cec5SDimitry Andric 3360b57cec5SDimitry Andric // Build an LMG instruction. 3370b57cec5SDimitry Andric MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(SystemZ::LMG)); 3380b57cec5SDimitry Andric 3390b57cec5SDimitry Andric // Add the explicit register operands. 340480093f4SDimitry Andric MIB.addReg(RestoreGPRs.LowGPR, RegState::Define); 341480093f4SDimitry Andric MIB.addReg(RestoreGPRs.HighGPR, RegState::Define); 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric // Add the address. 3440b57cec5SDimitry Andric MIB.addReg(HasFP ? SystemZ::R11D : SystemZ::R15D); 345480093f4SDimitry Andric MIB.addImm(RestoreGPRs.GPROffset); 3460b57cec5SDimitry Andric 3470b57cec5SDimitry Andric // Do a second scan adding regs as being defined by instruction 348*4824e7fdSDimitry Andric for (const CalleeSavedInfo &I : CSI) { 349*4824e7fdSDimitry Andric unsigned Reg = I.getReg(); 350480093f4SDimitry Andric if (Reg != RestoreGPRs.LowGPR && Reg != RestoreGPRs.HighGPR && 3510b57cec5SDimitry Andric SystemZ::GR64BitRegClass.contains(Reg)) 3520b57cec5SDimitry Andric MIB.addReg(Reg, RegState::ImplicitDefine); 3530b57cec5SDimitry Andric } 3540b57cec5SDimitry Andric } 3550b57cec5SDimitry Andric 3560b57cec5SDimitry Andric return true; 3570b57cec5SDimitry Andric } 3580b57cec5SDimitry Andric 359349cc55cSDimitry Andric void SystemZELFFrameLowering::processFunctionBeforeFrameFinalized( 360349cc55cSDimitry Andric MachineFunction &MF, RegScavenger *RS) const { 3610b57cec5SDimitry Andric MachineFrameInfo &MFFrame = MF.getFrameInfo(); 362e8d8bef9SDimitry Andric SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); 363e8d8bef9SDimitry Andric MachineRegisterInfo *MRI = &MF.getRegInfo(); 3645ffd83dbSDimitry Andric bool BackChain = MF.getFunction().hasFnAttribute("backchain"); 365480093f4SDimitry Andric 3665ffd83dbSDimitry Andric if (!usePackedStack(MF) || BackChain) 3675ffd83dbSDimitry Andric // Create the incoming register save area. 368480093f4SDimitry Andric getOrCreateFramePointerSaveIndex(MF); 369480093f4SDimitry Andric 3700b57cec5SDimitry Andric // Get the size of our stack frame to be allocated ... 3710b57cec5SDimitry Andric uint64_t StackSize = (MFFrame.estimateStackSize(MF) + 372fe6060f1SDimitry Andric SystemZMC::ELFCallFrameSize); 3730b57cec5SDimitry Andric // ... and the maximum offset we may need to reach into the 3740b57cec5SDimitry Andric // caller's frame to access the save area or stack arguments. 375480093f4SDimitry Andric int64_t MaxArgOffset = 0; 3760b57cec5SDimitry Andric for (int I = MFFrame.getObjectIndexBegin(); I != 0; ++I) 3770b57cec5SDimitry Andric if (MFFrame.getObjectOffset(I) >= 0) { 378480093f4SDimitry Andric int64_t ArgOffset = MFFrame.getObjectOffset(I) + 3790b57cec5SDimitry Andric MFFrame.getObjectSize(I); 3800b57cec5SDimitry Andric MaxArgOffset = std::max(MaxArgOffset, ArgOffset); 3810b57cec5SDimitry Andric } 3820b57cec5SDimitry Andric 3830b57cec5SDimitry Andric uint64_t MaxReach = StackSize + MaxArgOffset; 3840b57cec5SDimitry Andric if (!isUInt<12>(MaxReach)) { 3850b57cec5SDimitry Andric // We may need register scavenging slots if some parts of the frame 3860b57cec5SDimitry Andric // are outside the reach of an unsigned 12-bit displacement. 3870b57cec5SDimitry Andric // Create 2 for the case where both addresses in an MVC are 3880b57cec5SDimitry Andric // out of range. 3895ffd83dbSDimitry Andric RS->addScavengingFrameIndex(MFFrame.CreateStackObject(8, Align(8), false)); 3905ffd83dbSDimitry Andric RS->addScavengingFrameIndex(MFFrame.CreateStackObject(8, Align(8), false)); 3910b57cec5SDimitry Andric } 392e8d8bef9SDimitry Andric 393e8d8bef9SDimitry Andric // If R6 is used as an argument register it is still callee saved. If it in 394e8d8bef9SDimitry Andric // this case is not clobbered (and restored) it should never be marked as 395e8d8bef9SDimitry Andric // killed. 396e8d8bef9SDimitry Andric if (MF.front().isLiveIn(SystemZ::R6D) && 397e8d8bef9SDimitry Andric ZFI->getRestoreGPRRegs().LowGPR != SystemZ::R6D) 398e8d8bef9SDimitry Andric for (auto &MO : MRI->use_nodbg_operands(SystemZ::R6D)) 399e8d8bef9SDimitry Andric MO.setIsKill(false); 4000b57cec5SDimitry Andric } 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric // Emit instructions before MBBI (in MBB) to add NumBytes to Reg. 4030b57cec5SDimitry Andric static void emitIncrement(MachineBasicBlock &MBB, 4045ffd83dbSDimitry Andric MachineBasicBlock::iterator &MBBI, const DebugLoc &DL, 4055ffd83dbSDimitry Andric Register Reg, int64_t NumBytes, 4060b57cec5SDimitry Andric const TargetInstrInfo *TII) { 4070b57cec5SDimitry Andric while (NumBytes) { 4080b57cec5SDimitry Andric unsigned Opcode; 4090b57cec5SDimitry Andric int64_t ThisVal = NumBytes; 4100b57cec5SDimitry Andric if (isInt<16>(NumBytes)) 4110b57cec5SDimitry Andric Opcode = SystemZ::AGHI; 4120b57cec5SDimitry Andric else { 4130b57cec5SDimitry Andric Opcode = SystemZ::AGFI; 4140b57cec5SDimitry Andric // Make sure we maintain 8-byte stack alignment. 4150b57cec5SDimitry Andric int64_t MinVal = -uint64_t(1) << 31; 4160b57cec5SDimitry Andric int64_t MaxVal = (int64_t(1) << 31) - 8; 4170b57cec5SDimitry Andric if (ThisVal < MinVal) 4180b57cec5SDimitry Andric ThisVal = MinVal; 4190b57cec5SDimitry Andric else if (ThisVal > MaxVal) 4200b57cec5SDimitry Andric ThisVal = MaxVal; 4210b57cec5SDimitry Andric } 4220b57cec5SDimitry Andric MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII->get(Opcode), Reg) 4230b57cec5SDimitry Andric .addReg(Reg).addImm(ThisVal); 4240b57cec5SDimitry Andric // The CC implicit def is dead. 4250b57cec5SDimitry Andric MI->getOperand(3).setIsDead(); 4260b57cec5SDimitry Andric NumBytes -= ThisVal; 4270b57cec5SDimitry Andric } 4280b57cec5SDimitry Andric } 4290b57cec5SDimitry Andric 4305ffd83dbSDimitry Andric // Add CFI for the new CFA offset. 4315ffd83dbSDimitry Andric static void buildCFAOffs(MachineBasicBlock &MBB, 4325ffd83dbSDimitry Andric MachineBasicBlock::iterator MBBI, 4335ffd83dbSDimitry Andric const DebugLoc &DL, int Offset, 4345ffd83dbSDimitry Andric const SystemZInstrInfo *ZII) { 4355ffd83dbSDimitry Andric unsigned CFIIndex = MBB.getParent()->addFrameInst( 4365ffd83dbSDimitry Andric MCCFIInstruction::cfiDefCfaOffset(nullptr, -Offset)); 4375ffd83dbSDimitry Andric BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION)) 4385ffd83dbSDimitry Andric .addCFIIndex(CFIIndex); 4395ffd83dbSDimitry Andric } 4405ffd83dbSDimitry Andric 4415ffd83dbSDimitry Andric // Add CFI for the new frame location. 4425ffd83dbSDimitry Andric static void buildDefCFAReg(MachineBasicBlock &MBB, 4435ffd83dbSDimitry Andric MachineBasicBlock::iterator MBBI, 4445ffd83dbSDimitry Andric const DebugLoc &DL, unsigned Reg, 4455ffd83dbSDimitry Andric const SystemZInstrInfo *ZII) { 4465ffd83dbSDimitry Andric MachineFunction &MF = *MBB.getParent(); 4475ffd83dbSDimitry Andric MachineModuleInfo &MMI = MF.getMMI(); 4485ffd83dbSDimitry Andric const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); 4495ffd83dbSDimitry Andric unsigned RegNum = MRI->getDwarfRegNum(Reg, true); 4505ffd83dbSDimitry Andric unsigned CFIIndex = MF.addFrameInst( 4515ffd83dbSDimitry Andric MCCFIInstruction::createDefCfaRegister(nullptr, RegNum)); 4525ffd83dbSDimitry Andric BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION)) 4535ffd83dbSDimitry Andric .addCFIIndex(CFIIndex); 4545ffd83dbSDimitry Andric } 4555ffd83dbSDimitry Andric 456349cc55cSDimitry Andric void SystemZELFFrameLowering::emitPrologue(MachineFunction &MF, 4570b57cec5SDimitry Andric MachineBasicBlock &MBB) const { 4580b57cec5SDimitry Andric assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported"); 4595ffd83dbSDimitry Andric const SystemZSubtarget &STI = MF.getSubtarget<SystemZSubtarget>(); 4605ffd83dbSDimitry Andric const SystemZTargetLowering &TLI = *STI.getTargetLowering(); 4610b57cec5SDimitry Andric MachineFrameInfo &MFFrame = MF.getFrameInfo(); 4625ffd83dbSDimitry Andric auto *ZII = static_cast<const SystemZInstrInfo *>(STI.getInstrInfo()); 4630b57cec5SDimitry Andric SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); 4640b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.begin(); 4650b57cec5SDimitry Andric MachineModuleInfo &MMI = MF.getMMI(); 4660b57cec5SDimitry Andric const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); 4670b57cec5SDimitry Andric const std::vector<CalleeSavedInfo> &CSI = MFFrame.getCalleeSavedInfo(); 4680b57cec5SDimitry Andric bool HasFP = hasFP(MF); 4690b57cec5SDimitry Andric 470480093f4SDimitry Andric // In GHC calling convention C stack space, including the ABI-defined 471480093f4SDimitry Andric // 160-byte base area, is (de)allocated by GHC itself. This stack space may 472480093f4SDimitry Andric // be used by LLVM as spill slots for the tail recursive GHC functions. Thus 473480093f4SDimitry Andric // do not allocate stack space here, too. 474480093f4SDimitry Andric if (MF.getFunction().getCallingConv() == CallingConv::GHC) { 475480093f4SDimitry Andric if (MFFrame.getStackSize() > 2048 * sizeof(long)) { 476480093f4SDimitry Andric report_fatal_error( 477480093f4SDimitry Andric "Pre allocated stack space for GHC function is too small"); 478480093f4SDimitry Andric } 479480093f4SDimitry Andric if (HasFP) { 480480093f4SDimitry Andric report_fatal_error( 481480093f4SDimitry Andric "In GHC calling convention a frame pointer is not supported"); 482480093f4SDimitry Andric } 483fe6060f1SDimitry Andric MFFrame.setStackSize(MFFrame.getStackSize() + SystemZMC::ELFCallFrameSize); 484480093f4SDimitry Andric return; 485480093f4SDimitry Andric } 486480093f4SDimitry Andric 4870b57cec5SDimitry Andric // Debug location must be unknown since the first debug location is used 4880b57cec5SDimitry Andric // to determine the end of the prologue. 4890b57cec5SDimitry Andric DebugLoc DL; 4900b57cec5SDimitry Andric 4910b57cec5SDimitry Andric // The current offset of the stack pointer from the CFA. 492fe6060f1SDimitry Andric int64_t SPOffsetFromCFA = -SystemZMC::ELFCFAOffsetFromInitialSP; 4930b57cec5SDimitry Andric 494480093f4SDimitry Andric if (ZFI->getSpillGPRRegs().LowGPR) { 4950b57cec5SDimitry Andric // Skip over the GPR saves. 4960b57cec5SDimitry Andric if (MBBI != MBB.end() && MBBI->getOpcode() == SystemZ::STMG) 4970b57cec5SDimitry Andric ++MBBI; 4980b57cec5SDimitry Andric else 4990b57cec5SDimitry Andric llvm_unreachable("Couldn't skip over GPR saves"); 5000b57cec5SDimitry Andric 5010b57cec5SDimitry Andric // Add CFI for the GPR saves. 5020b57cec5SDimitry Andric for (auto &Save : CSI) { 5030b57cec5SDimitry Andric unsigned Reg = Save.getReg(); 5040b57cec5SDimitry Andric if (SystemZ::GR64BitRegClass.contains(Reg)) { 505480093f4SDimitry Andric int FI = Save.getFrameIdx(); 506480093f4SDimitry Andric int64_t Offset = MFFrame.getObjectOffset(FI); 5070b57cec5SDimitry Andric unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( 5080b57cec5SDimitry Andric nullptr, MRI->getDwarfRegNum(Reg, true), Offset)); 5090b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION)) 5100b57cec5SDimitry Andric .addCFIIndex(CFIIndex); 5110b57cec5SDimitry Andric } 5120b57cec5SDimitry Andric } 5130b57cec5SDimitry Andric } 5140b57cec5SDimitry Andric 5150b57cec5SDimitry Andric uint64_t StackSize = MFFrame.getStackSize(); 5160b57cec5SDimitry Andric // We need to allocate the ABI-defined 160-byte base area whenever 5170b57cec5SDimitry Andric // we allocate stack space for our own use and whenever we call another 5180b57cec5SDimitry Andric // function. 519480093f4SDimitry Andric bool HasStackObject = false; 520480093f4SDimitry Andric for (unsigned i = 0, e = MFFrame.getObjectIndexEnd(); i != e; ++i) 521480093f4SDimitry Andric if (!MFFrame.isDeadObjectIndex(i)) { 522480093f4SDimitry Andric HasStackObject = true; 523480093f4SDimitry Andric break; 5240b57cec5SDimitry Andric } 525480093f4SDimitry Andric if (HasStackObject || MFFrame.hasCalls()) 526fe6060f1SDimitry Andric StackSize += SystemZMC::ELFCallFrameSize; 527480093f4SDimitry Andric // Don't allocate the incoming reg save area. 528fe6060f1SDimitry Andric StackSize = StackSize > SystemZMC::ELFCallFrameSize 529fe6060f1SDimitry Andric ? StackSize - SystemZMC::ELFCallFrameSize 530480093f4SDimitry Andric : 0; 531480093f4SDimitry Andric MFFrame.setStackSize(StackSize); 5320b57cec5SDimitry Andric 5330b57cec5SDimitry Andric if (StackSize) { 5340b57cec5SDimitry Andric // Allocate StackSize bytes. 5350b57cec5SDimitry Andric int64_t Delta = -int64_t(StackSize); 5365ffd83dbSDimitry Andric const unsigned ProbeSize = TLI.getStackProbeSize(MF); 5375ffd83dbSDimitry Andric bool FreeProbe = (ZFI->getSpillGPRRegs().GPROffset && 5385ffd83dbSDimitry Andric (ZFI->getSpillGPRRegs().GPROffset + StackSize) < ProbeSize); 5395ffd83dbSDimitry Andric if (!FreeProbe && 5405ffd83dbSDimitry Andric MF.getSubtarget().getTargetLowering()->hasInlineStackProbe(MF)) { 5415ffd83dbSDimitry Andric // Stack probing may involve looping, but splitting the prologue block 5425ffd83dbSDimitry Andric // is not possible at this point since it would invalidate the 5435ffd83dbSDimitry Andric // SaveBlocks / RestoreBlocks sets of PEI in the single block function 5445ffd83dbSDimitry Andric // case. Build a pseudo to be handled later by inlineStackProbe(). 5455ffd83dbSDimitry Andric BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::PROBED_STACKALLOC)) 5465ffd83dbSDimitry Andric .addImm(StackSize); 5475ffd83dbSDimitry Andric } 5485ffd83dbSDimitry Andric else { 549e8d8bef9SDimitry Andric bool StoreBackchain = MF.getFunction().hasFnAttribute("backchain"); 550e8d8bef9SDimitry Andric // If we need backchain, save current stack pointer. R1 is free at 551e8d8bef9SDimitry Andric // this point. 552e8d8bef9SDimitry Andric if (StoreBackchain) 553e8d8bef9SDimitry Andric BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::LGR)) 554e8d8bef9SDimitry Andric .addReg(SystemZ::R1D, RegState::Define).addReg(SystemZ::R15D); 5550b57cec5SDimitry Andric emitIncrement(MBB, MBBI, DL, SystemZ::R15D, Delta, ZII); 5565ffd83dbSDimitry Andric buildCFAOffs(MBB, MBBI, DL, SPOffsetFromCFA + Delta, ZII); 557e8d8bef9SDimitry Andric if (StoreBackchain) 5580b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::STG)) 5595ffd83dbSDimitry Andric .addReg(SystemZ::R1D, RegState::Kill).addReg(SystemZ::R15D) 560e8d8bef9SDimitry Andric .addImm(getBackchainOffset(MF)).addReg(0); 5615ffd83dbSDimitry Andric } 562e8d8bef9SDimitry Andric SPOffsetFromCFA += Delta; 5630b57cec5SDimitry Andric } 5640b57cec5SDimitry Andric 5650b57cec5SDimitry Andric if (HasFP) { 5660b57cec5SDimitry Andric // Copy the base of the frame to R11. 5670b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::LGR), SystemZ::R11D) 5680b57cec5SDimitry Andric .addReg(SystemZ::R15D); 5690b57cec5SDimitry Andric 5700b57cec5SDimitry Andric // Add CFI for the new frame location. 5715ffd83dbSDimitry Andric buildDefCFAReg(MBB, MBBI, DL, SystemZ::R11D, ZII); 5720b57cec5SDimitry Andric 5730b57cec5SDimitry Andric // Mark the FramePtr as live at the beginning of every block except 5740b57cec5SDimitry Andric // the entry block. (We'll have marked R11 as live on entry when 5750b57cec5SDimitry Andric // saving the GPRs.) 576349cc55cSDimitry Andric for (MachineBasicBlock &MBBJ : llvm::drop_begin(MF)) 577349cc55cSDimitry Andric MBBJ.addLiveIn(SystemZ::R11D); 5780b57cec5SDimitry Andric } 5790b57cec5SDimitry Andric 5800b57cec5SDimitry Andric // Skip over the FPR/VR saves. 5810b57cec5SDimitry Andric SmallVector<unsigned, 8> CFIIndexes; 5820b57cec5SDimitry Andric for (auto &Save : CSI) { 5830b57cec5SDimitry Andric unsigned Reg = Save.getReg(); 5840b57cec5SDimitry Andric if (SystemZ::FP64BitRegClass.contains(Reg)) { 5850b57cec5SDimitry Andric if (MBBI != MBB.end() && 5860b57cec5SDimitry Andric (MBBI->getOpcode() == SystemZ::STD || 5870b57cec5SDimitry Andric MBBI->getOpcode() == SystemZ::STDY)) 5880b57cec5SDimitry Andric ++MBBI; 5890b57cec5SDimitry Andric else 5900b57cec5SDimitry Andric llvm_unreachable("Couldn't skip over FPR save"); 5910b57cec5SDimitry Andric } else if (SystemZ::VR128BitRegClass.contains(Reg)) { 5920b57cec5SDimitry Andric if (MBBI != MBB.end() && 5930b57cec5SDimitry Andric MBBI->getOpcode() == SystemZ::VST) 5940b57cec5SDimitry Andric ++MBBI; 5950b57cec5SDimitry Andric else 5960b57cec5SDimitry Andric llvm_unreachable("Couldn't skip over VR save"); 5970b57cec5SDimitry Andric } else 5980b57cec5SDimitry Andric continue; 5990b57cec5SDimitry Andric 6000b57cec5SDimitry Andric // Add CFI for the this save. 6010b57cec5SDimitry Andric unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true); 6025ffd83dbSDimitry Andric Register IgnoredFrameReg; 6030b57cec5SDimitry Andric int64_t Offset = 604e8d8bef9SDimitry Andric getFrameIndexReference(MF, Save.getFrameIdx(), IgnoredFrameReg) 605e8d8bef9SDimitry Andric .getFixed(); 6060b57cec5SDimitry Andric 6070b57cec5SDimitry Andric unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( 6080b57cec5SDimitry Andric nullptr, DwarfReg, SPOffsetFromCFA + Offset)); 6090b57cec5SDimitry Andric CFIIndexes.push_back(CFIIndex); 6100b57cec5SDimitry Andric } 6110b57cec5SDimitry Andric // Complete the CFI for the FPR/VR saves, modelling them as taking effect 6120b57cec5SDimitry Andric // after the last save. 6130b57cec5SDimitry Andric for (auto CFIIndex : CFIIndexes) { 6140b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION)) 6150b57cec5SDimitry Andric .addCFIIndex(CFIIndex); 6160b57cec5SDimitry Andric } 6170b57cec5SDimitry Andric } 6180b57cec5SDimitry Andric 619349cc55cSDimitry Andric void SystemZELFFrameLowering::emitEpilogue(MachineFunction &MF, 6200b57cec5SDimitry Andric MachineBasicBlock &MBB) const { 6210b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); 6220b57cec5SDimitry Andric auto *ZII = 6230b57cec5SDimitry Andric static_cast<const SystemZInstrInfo *>(MF.getSubtarget().getInstrInfo()); 6240b57cec5SDimitry Andric SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); 6250b57cec5SDimitry Andric MachineFrameInfo &MFFrame = MF.getFrameInfo(); 6260b57cec5SDimitry Andric 627349cc55cSDimitry Andric // See SystemZELFFrameLowering::emitPrologue 628480093f4SDimitry Andric if (MF.getFunction().getCallingConv() == CallingConv::GHC) 629480093f4SDimitry Andric return; 630480093f4SDimitry Andric 6310b57cec5SDimitry Andric // Skip the return instruction. 6320b57cec5SDimitry Andric assert(MBBI->isReturn() && "Can only insert epilogue into returning blocks"); 6330b57cec5SDimitry Andric 6340b57cec5SDimitry Andric uint64_t StackSize = MFFrame.getStackSize(); 635480093f4SDimitry Andric if (ZFI->getRestoreGPRRegs().LowGPR) { 6360b57cec5SDimitry Andric --MBBI; 6370b57cec5SDimitry Andric unsigned Opcode = MBBI->getOpcode(); 6380b57cec5SDimitry Andric if (Opcode != SystemZ::LMG) 6390b57cec5SDimitry Andric llvm_unreachable("Expected to see callee-save register restore code"); 6400b57cec5SDimitry Andric 6410b57cec5SDimitry Andric unsigned AddrOpNo = 2; 6420b57cec5SDimitry Andric DebugLoc DL = MBBI->getDebugLoc(); 6430b57cec5SDimitry Andric uint64_t Offset = StackSize + MBBI->getOperand(AddrOpNo + 1).getImm(); 6440b57cec5SDimitry Andric unsigned NewOpcode = ZII->getOpcodeForOffset(Opcode, Offset); 6450b57cec5SDimitry Andric 6460b57cec5SDimitry Andric // If the offset is too large, use the largest stack-aligned offset 6470b57cec5SDimitry Andric // and add the rest to the base register (the stack or frame pointer). 6480b57cec5SDimitry Andric if (!NewOpcode) { 6490b57cec5SDimitry Andric uint64_t NumBytes = Offset - 0x7fff8; 6500b57cec5SDimitry Andric emitIncrement(MBB, MBBI, DL, MBBI->getOperand(AddrOpNo).getReg(), 6510b57cec5SDimitry Andric NumBytes, ZII); 6520b57cec5SDimitry Andric Offset -= NumBytes; 6530b57cec5SDimitry Andric NewOpcode = ZII->getOpcodeForOffset(Opcode, Offset); 6540b57cec5SDimitry Andric assert(NewOpcode && "No restore instruction available"); 6550b57cec5SDimitry Andric } 6560b57cec5SDimitry Andric 6570b57cec5SDimitry Andric MBBI->setDesc(ZII->get(NewOpcode)); 6580b57cec5SDimitry Andric MBBI->getOperand(AddrOpNo + 1).ChangeToImmediate(Offset); 6590b57cec5SDimitry Andric } else if (StackSize) { 6600b57cec5SDimitry Andric DebugLoc DL = MBBI->getDebugLoc(); 6610b57cec5SDimitry Andric emitIncrement(MBB, MBBI, DL, SystemZ::R15D, StackSize, ZII); 6620b57cec5SDimitry Andric } 6630b57cec5SDimitry Andric } 6640b57cec5SDimitry Andric 665349cc55cSDimitry Andric void SystemZELFFrameLowering::inlineStackProbe( 666349cc55cSDimitry Andric MachineFunction &MF, MachineBasicBlock &PrologMBB) const { 6675ffd83dbSDimitry Andric auto *ZII = 6685ffd83dbSDimitry Andric static_cast<const SystemZInstrInfo *>(MF.getSubtarget().getInstrInfo()); 6695ffd83dbSDimitry Andric const SystemZSubtarget &STI = MF.getSubtarget<SystemZSubtarget>(); 6705ffd83dbSDimitry Andric const SystemZTargetLowering &TLI = *STI.getTargetLowering(); 6715ffd83dbSDimitry Andric 6725ffd83dbSDimitry Andric MachineInstr *StackAllocMI = nullptr; 6735ffd83dbSDimitry Andric for (MachineInstr &MI : PrologMBB) 6745ffd83dbSDimitry Andric if (MI.getOpcode() == SystemZ::PROBED_STACKALLOC) { 6755ffd83dbSDimitry Andric StackAllocMI = &MI; 6765ffd83dbSDimitry Andric break; 6775ffd83dbSDimitry Andric } 6785ffd83dbSDimitry Andric if (StackAllocMI == nullptr) 6795ffd83dbSDimitry Andric return; 6805ffd83dbSDimitry Andric uint64_t StackSize = StackAllocMI->getOperand(0).getImm(); 6815ffd83dbSDimitry Andric const unsigned ProbeSize = TLI.getStackProbeSize(MF); 6825ffd83dbSDimitry Andric uint64_t NumFullBlocks = StackSize / ProbeSize; 6835ffd83dbSDimitry Andric uint64_t Residual = StackSize % ProbeSize; 684fe6060f1SDimitry Andric int64_t SPOffsetFromCFA = -SystemZMC::ELFCFAOffsetFromInitialSP; 6855ffd83dbSDimitry Andric MachineBasicBlock *MBB = &PrologMBB; 6865ffd83dbSDimitry Andric MachineBasicBlock::iterator MBBI = StackAllocMI; 6875ffd83dbSDimitry Andric const DebugLoc DL = StackAllocMI->getDebugLoc(); 6885ffd83dbSDimitry Andric 6895ffd83dbSDimitry Andric // Allocate a block of Size bytes on the stack and probe it. 6905ffd83dbSDimitry Andric auto allocateAndProbe = [&](MachineBasicBlock &InsMBB, 6915ffd83dbSDimitry Andric MachineBasicBlock::iterator InsPt, unsigned Size, 6925ffd83dbSDimitry Andric bool EmitCFI) -> void { 6935ffd83dbSDimitry Andric emitIncrement(InsMBB, InsPt, DL, SystemZ::R15D, -int64_t(Size), ZII); 6945ffd83dbSDimitry Andric if (EmitCFI) { 6955ffd83dbSDimitry Andric SPOffsetFromCFA -= Size; 6965ffd83dbSDimitry Andric buildCFAOffs(InsMBB, InsPt, DL, SPOffsetFromCFA, ZII); 6975ffd83dbSDimitry Andric } 6985ffd83dbSDimitry Andric // Probe by means of a volatile compare. 6995ffd83dbSDimitry Andric MachineMemOperand *MMO = MF.getMachineMemOperand(MachinePointerInfo(), 7005ffd83dbSDimitry Andric MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad, 8, Align(1)); 7015ffd83dbSDimitry Andric BuildMI(InsMBB, InsPt, DL, ZII->get(SystemZ::CG)) 7025ffd83dbSDimitry Andric .addReg(SystemZ::R0D, RegState::Undef) 7035ffd83dbSDimitry Andric .addReg(SystemZ::R15D).addImm(Size - 8).addReg(0) 7045ffd83dbSDimitry Andric .addMemOperand(MMO); 7055ffd83dbSDimitry Andric }; 7065ffd83dbSDimitry Andric 707e8d8bef9SDimitry Andric bool StoreBackchain = MF.getFunction().hasFnAttribute("backchain"); 708e8d8bef9SDimitry Andric if (StoreBackchain) 709e8d8bef9SDimitry Andric BuildMI(*MBB, MBBI, DL, ZII->get(SystemZ::LGR)) 710e8d8bef9SDimitry Andric .addReg(SystemZ::R1D, RegState::Define).addReg(SystemZ::R15D); 711e8d8bef9SDimitry Andric 712e8d8bef9SDimitry Andric MachineBasicBlock *DoneMBB = nullptr; 713e8d8bef9SDimitry Andric MachineBasicBlock *LoopMBB = nullptr; 7145ffd83dbSDimitry Andric if (NumFullBlocks < 3) { 7155ffd83dbSDimitry Andric // Emit unrolled probe statements. 7165ffd83dbSDimitry Andric for (unsigned int i = 0; i < NumFullBlocks; i++) 7175ffd83dbSDimitry Andric allocateAndProbe(*MBB, MBBI, ProbeSize, true/*EmitCFI*/); 7185ffd83dbSDimitry Andric } else { 7195ffd83dbSDimitry Andric // Emit a loop probing the pages. 7205ffd83dbSDimitry Andric uint64_t LoopAlloc = ProbeSize * NumFullBlocks; 7215ffd83dbSDimitry Andric SPOffsetFromCFA -= LoopAlloc; 7225ffd83dbSDimitry Andric 723e8d8bef9SDimitry Andric // Use R0D to hold the exit value. 724e8d8bef9SDimitry Andric BuildMI(*MBB, MBBI, DL, ZII->get(SystemZ::LGR), SystemZ::R0D) 7255ffd83dbSDimitry Andric .addReg(SystemZ::R15D); 726e8d8bef9SDimitry Andric buildDefCFAReg(*MBB, MBBI, DL, SystemZ::R0D, ZII); 727e8d8bef9SDimitry Andric emitIncrement(*MBB, MBBI, DL, SystemZ::R0D, -int64_t(LoopAlloc), ZII); 728fe6060f1SDimitry Andric buildCFAOffs(*MBB, MBBI, DL, -int64_t(SystemZMC::ELFCallFrameSize + LoopAlloc), 7295ffd83dbSDimitry Andric ZII); 7305ffd83dbSDimitry Andric 731e8d8bef9SDimitry Andric DoneMBB = SystemZ::splitBlockBefore(MBBI, MBB); 732e8d8bef9SDimitry Andric LoopMBB = SystemZ::emitBlockAfter(MBB); 7335ffd83dbSDimitry Andric MBB->addSuccessor(LoopMBB); 7345ffd83dbSDimitry Andric LoopMBB->addSuccessor(LoopMBB); 7355ffd83dbSDimitry Andric LoopMBB->addSuccessor(DoneMBB); 7365ffd83dbSDimitry Andric 7375ffd83dbSDimitry Andric MBB = LoopMBB; 7385ffd83dbSDimitry Andric allocateAndProbe(*MBB, MBB->end(), ProbeSize, false/*EmitCFI*/); 7395ffd83dbSDimitry Andric BuildMI(*MBB, MBB->end(), DL, ZII->get(SystemZ::CLGR)) 740e8d8bef9SDimitry Andric .addReg(SystemZ::R15D).addReg(SystemZ::R0D); 7415ffd83dbSDimitry Andric BuildMI(*MBB, MBB->end(), DL, ZII->get(SystemZ::BRC)) 7425ffd83dbSDimitry Andric .addImm(SystemZ::CCMASK_ICMP).addImm(SystemZ::CCMASK_CMP_GT).addMBB(MBB); 7435ffd83dbSDimitry Andric 7445ffd83dbSDimitry Andric MBB = DoneMBB; 7455ffd83dbSDimitry Andric MBBI = DoneMBB->begin(); 7465ffd83dbSDimitry Andric buildDefCFAReg(*MBB, MBBI, DL, SystemZ::R15D, ZII); 7475ffd83dbSDimitry Andric } 7485ffd83dbSDimitry Andric 7495ffd83dbSDimitry Andric if (Residual) 7505ffd83dbSDimitry Andric allocateAndProbe(*MBB, MBBI, Residual, true/*EmitCFI*/); 7515ffd83dbSDimitry Andric 752e8d8bef9SDimitry Andric if (StoreBackchain) 753e8d8bef9SDimitry Andric BuildMI(*MBB, MBBI, DL, ZII->get(SystemZ::STG)) 754e8d8bef9SDimitry Andric .addReg(SystemZ::R1D, RegState::Kill).addReg(SystemZ::R15D) 755e8d8bef9SDimitry Andric .addImm(getBackchainOffset(MF)).addReg(0); 756e8d8bef9SDimitry Andric 7575ffd83dbSDimitry Andric StackAllocMI->eraseFromParent(); 758e8d8bef9SDimitry Andric if (DoneMBB != nullptr) { 759e8d8bef9SDimitry Andric // Compute the live-in lists for the new blocks. 760e8d8bef9SDimitry Andric recomputeLiveIns(*DoneMBB); 761e8d8bef9SDimitry Andric recomputeLiveIns(*LoopMBB); 762e8d8bef9SDimitry Andric } 7635ffd83dbSDimitry Andric } 7645ffd83dbSDimitry Andric 765349cc55cSDimitry Andric bool SystemZELFFrameLowering::hasFP(const MachineFunction &MF) const { 7660b57cec5SDimitry Andric return (MF.getTarget().Options.DisableFramePointerElim(MF) || 7670b57cec5SDimitry Andric MF.getFrameInfo().hasVarSizedObjects() || 7680b57cec5SDimitry Andric MF.getInfo<SystemZMachineFunctionInfo>()->getManipulatesSP()); 7690b57cec5SDimitry Andric } 7700b57cec5SDimitry Andric 771349cc55cSDimitry Andric StackOffset SystemZELFFrameLowering::getFrameIndexReference( 772349cc55cSDimitry Andric const MachineFunction &MF, int FI, Register &FrameReg) const { 773fe6060f1SDimitry Andric // Our incoming SP is actually SystemZMC::ELFCallFrameSize below the CFA, so 774480093f4SDimitry Andric // add that difference here. 775e8d8bef9SDimitry Andric StackOffset Offset = 776480093f4SDimitry Andric TargetFrameLowering::getFrameIndexReference(MF, FI, FrameReg); 777fe6060f1SDimitry Andric return Offset + StackOffset::getFixed(SystemZMC::ELFCallFrameSize); 778480093f4SDimitry Andric } 779480093f4SDimitry Andric 780349cc55cSDimitry Andric unsigned SystemZELFFrameLowering::getRegSpillOffset(MachineFunction &MF, 7815ffd83dbSDimitry Andric Register Reg) const { 7825ffd83dbSDimitry Andric bool IsVarArg = MF.getFunction().isVarArg(); 7835ffd83dbSDimitry Andric bool BackChain = MF.getFunction().hasFnAttribute("backchain"); 7845ffd83dbSDimitry Andric bool SoftFloat = MF.getSubtarget<SystemZSubtarget>().hasSoftFloat(); 7855ffd83dbSDimitry Andric unsigned Offset = RegSpillOffsets[Reg]; 7865ffd83dbSDimitry Andric if (usePackedStack(MF) && !(IsVarArg && !SoftFloat)) { 7875ffd83dbSDimitry Andric if (SystemZ::GR64BitRegClass.contains(Reg)) 7885ffd83dbSDimitry Andric // Put all GPRs at the top of the Register save area with packed 7895ffd83dbSDimitry Andric // stack. Make room for the backchain if needed. 7905ffd83dbSDimitry Andric Offset += BackChain ? 24 : 32; 7915ffd83dbSDimitry Andric else 7925ffd83dbSDimitry Andric Offset = 0; 7935ffd83dbSDimitry Andric } 7945ffd83dbSDimitry Andric return Offset; 7955ffd83dbSDimitry Andric } 7965ffd83dbSDimitry Andric 797349cc55cSDimitry Andric int SystemZELFFrameLowering::getOrCreateFramePointerSaveIndex( 798349cc55cSDimitry Andric MachineFunction &MF) const { 799480093f4SDimitry Andric SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); 800480093f4SDimitry Andric int FI = ZFI->getFramePointerSaveIndex(); 801480093f4SDimitry Andric if (!FI) { 802480093f4SDimitry Andric MachineFrameInfo &MFFrame = MF.getFrameInfo(); 803fe6060f1SDimitry Andric int Offset = getBackchainOffset(MF) - SystemZMC::ELFCallFrameSize; 8045ffd83dbSDimitry Andric FI = MFFrame.CreateFixedObject(8, Offset, false); 805480093f4SDimitry Andric ZFI->setFramePointerSaveIndex(FI); 806480093f4SDimitry Andric } 807480093f4SDimitry Andric return FI; 808480093f4SDimitry Andric } 8095ffd83dbSDimitry Andric 810349cc55cSDimitry Andric bool SystemZELFFrameLowering::usePackedStack(MachineFunction &MF) const { 8115ffd83dbSDimitry Andric bool HasPackedStackAttr = MF.getFunction().hasFnAttribute("packed-stack"); 8125ffd83dbSDimitry Andric bool BackChain = MF.getFunction().hasFnAttribute("backchain"); 8135ffd83dbSDimitry Andric bool SoftFloat = MF.getSubtarget<SystemZSubtarget>().hasSoftFloat(); 8145ffd83dbSDimitry Andric if (HasPackedStackAttr && BackChain && !SoftFloat) 8155ffd83dbSDimitry Andric report_fatal_error("packed-stack + backchain + hard-float is unsupported."); 8165ffd83dbSDimitry Andric bool CallConv = MF.getFunction().getCallingConv() != CallingConv::GHC; 8175ffd83dbSDimitry Andric return HasPackedStackAttr && CallConv; 8185ffd83dbSDimitry Andric } 819349cc55cSDimitry Andric 820349cc55cSDimitry Andric SystemZXPLINKFrameLowering::SystemZXPLINKFrameLowering() 821349cc55cSDimitry Andric : SystemZFrameLowering(TargetFrameLowering::StackGrowsUp, Align(32), 128, 822349cc55cSDimitry Andric Align(32), /* StackRealignable */ false), 823349cc55cSDimitry Andric RegSpillOffsets(-1) { 824349cc55cSDimitry Andric 825349cc55cSDimitry Andric // Create a mapping from register number to save slot offset. 826349cc55cSDimitry Andric // These offsets are relative to the start of the local are area. 827349cc55cSDimitry Andric RegSpillOffsets.grow(SystemZ::NUM_TARGET_REGS); 828349cc55cSDimitry Andric for (unsigned I = 0, E = array_lengthof(XPLINKSpillOffsetTable); I != E; ++I) 829349cc55cSDimitry Andric RegSpillOffsets[XPLINKSpillOffsetTable[I].Reg] = 830349cc55cSDimitry Andric XPLINKSpillOffsetTable[I].Offset; 831349cc55cSDimitry Andric } 832349cc55cSDimitry Andric 833349cc55cSDimitry Andric bool SystemZXPLINKFrameLowering::assignCalleeSavedSpillSlots( 834349cc55cSDimitry Andric MachineFunction &MF, const TargetRegisterInfo *TRI, 835349cc55cSDimitry Andric std::vector<CalleeSavedInfo> &CSI) const { 836349cc55cSDimitry Andric MachineFrameInfo &MFFrame = MF.getFrameInfo(); 837349cc55cSDimitry Andric SystemZMachineFunctionInfo *MFI = MF.getInfo<SystemZMachineFunctionInfo>(); 838349cc55cSDimitry Andric const SystemZSubtarget &Subtarget = MF.getSubtarget<SystemZSubtarget>(); 839349cc55cSDimitry Andric auto &Regs = Subtarget.getSpecialRegisters<SystemZXPLINK64Registers>(); 840349cc55cSDimitry Andric 841349cc55cSDimitry Andric // Scan the call-saved GPRs and find the bounds of the register spill area. 842349cc55cSDimitry Andric unsigned LowGPR = 0; 843349cc55cSDimitry Andric int LowOffset = INT32_MAX; 844349cc55cSDimitry Andric unsigned HighGPR = LowGPR; 845349cc55cSDimitry Andric int HighOffset = -1; 846349cc55cSDimitry Andric 847349cc55cSDimitry Andric unsigned RegSP = Regs.getStackPointerRegister(); 848349cc55cSDimitry Andric auto &GRRegClass = SystemZ::GR64BitRegClass; 849349cc55cSDimitry Andric const unsigned RegSize = 8; 850349cc55cSDimitry Andric 851349cc55cSDimitry Andric auto ProcessCSI = [&](std::vector<CalleeSavedInfo> &CSIList) { 852349cc55cSDimitry Andric for (auto &CS : CSIList) { 853349cc55cSDimitry Andric unsigned Reg = CS.getReg(); 854349cc55cSDimitry Andric int Offset = RegSpillOffsets[Reg]; 855349cc55cSDimitry Andric if (Offset >= 0) { 856349cc55cSDimitry Andric if (GRRegClass.contains(Reg)) { 857349cc55cSDimitry Andric if (LowOffset > Offset) { 858349cc55cSDimitry Andric LowOffset = Offset; 859349cc55cSDimitry Andric LowGPR = Reg; 860349cc55cSDimitry Andric } 861349cc55cSDimitry Andric 862349cc55cSDimitry Andric if (Offset > HighOffset) { 863349cc55cSDimitry Andric HighOffset = Offset; 864349cc55cSDimitry Andric HighGPR = Reg; 865349cc55cSDimitry Andric } 866349cc55cSDimitry Andric } 867349cc55cSDimitry Andric int FrameIdx = MFFrame.CreateFixedSpillStackObject(RegSize, Offset); 868349cc55cSDimitry Andric CS.setFrameIdx(FrameIdx); 869349cc55cSDimitry Andric } else 870349cc55cSDimitry Andric CS.setFrameIdx(INT32_MAX); 871349cc55cSDimitry Andric } 872349cc55cSDimitry Andric }; 873349cc55cSDimitry Andric 874349cc55cSDimitry Andric std::vector<CalleeSavedInfo> Spills; 875349cc55cSDimitry Andric 876349cc55cSDimitry Andric // For non-leaf functions: 877349cc55cSDimitry Andric // - the address of callee (entry point) register R6 must be saved 878349cc55cSDimitry Andric Spills.push_back(CalleeSavedInfo(Regs.getAddressOfCalleeRegister())); 879349cc55cSDimitry Andric 880349cc55cSDimitry Andric // If the function needs a frame pointer, or if the backchain pointer should 881349cc55cSDimitry Andric // be stored, then save the stack pointer register R4. 882349cc55cSDimitry Andric if (hasFP(MF) || MF.getFunction().hasFnAttribute("backchain")) 883349cc55cSDimitry Andric Spills.push_back(CalleeSavedInfo(RegSP)); 884349cc55cSDimitry Andric 885349cc55cSDimitry Andric // Save the range of call-saved registers, for use by the 886349cc55cSDimitry Andric // prologue/epilogue inserters. 887349cc55cSDimitry Andric ProcessCSI(CSI); 888349cc55cSDimitry Andric MFI->setRestoreGPRRegs(LowGPR, HighGPR, LowOffset); 889349cc55cSDimitry Andric 890349cc55cSDimitry Andric // Save the range of call-saved registers, for use by the epilogue inserter. 891349cc55cSDimitry Andric ProcessCSI(Spills); 892349cc55cSDimitry Andric MFI->setSpillGPRRegs(LowGPR, HighGPR, LowOffset); 893349cc55cSDimitry Andric 894349cc55cSDimitry Andric // Create spill slots for the remaining registers. 895349cc55cSDimitry Andric for (auto &CS : CSI) { 896349cc55cSDimitry Andric if (CS.getFrameIdx() != INT32_MAX) 897349cc55cSDimitry Andric continue; 898349cc55cSDimitry Andric unsigned Reg = CS.getReg(); 899349cc55cSDimitry Andric const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); 900349cc55cSDimitry Andric Align Alignment = TRI->getSpillAlign(*RC); 901349cc55cSDimitry Andric unsigned Size = TRI->getSpillSize(*RC); 902349cc55cSDimitry Andric Alignment = std::min(Alignment, getStackAlign()); 903349cc55cSDimitry Andric int FrameIdx = MFFrame.CreateStackObject(Size, Alignment, true); 904349cc55cSDimitry Andric CS.setFrameIdx(FrameIdx); 905349cc55cSDimitry Andric } 906349cc55cSDimitry Andric 907349cc55cSDimitry Andric return true; 908349cc55cSDimitry Andric } 909349cc55cSDimitry Andric 910349cc55cSDimitry Andric void SystemZXPLINKFrameLowering::determineCalleeSaves(MachineFunction &MF, 911349cc55cSDimitry Andric BitVector &SavedRegs, 912349cc55cSDimitry Andric RegScavenger *RS) const { 913349cc55cSDimitry Andric TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); 914349cc55cSDimitry Andric 915349cc55cSDimitry Andric bool HasFP = hasFP(MF); 916349cc55cSDimitry Andric const SystemZSubtarget &Subtarget = MF.getSubtarget<SystemZSubtarget>(); 917349cc55cSDimitry Andric auto &Regs = Subtarget.getSpecialRegisters<SystemZXPLINK64Registers>(); 918349cc55cSDimitry Andric 919349cc55cSDimitry Andric // If the function requires a frame pointer, record that the hard 920349cc55cSDimitry Andric // frame pointer will be clobbered. 921349cc55cSDimitry Andric if (HasFP) 922349cc55cSDimitry Andric SavedRegs.set(Regs.getFramePointerRegister()); 923349cc55cSDimitry Andric 924349cc55cSDimitry Andric // If the function is not an XPLeaf function, we need to save the 925349cc55cSDimitry Andric // return address register. We also always use that register for 926349cc55cSDimitry Andric // the return instruction, so it needs to be restored in the 927349cc55cSDimitry Andric // epilogue even though that register is considered to be volatile. 928349cc55cSDimitry Andric // #TODO: Implement leaf detection. 929349cc55cSDimitry Andric SavedRegs.set(Regs.getReturnFunctionAddressRegister()); 930349cc55cSDimitry Andric } 931349cc55cSDimitry Andric 932349cc55cSDimitry Andric bool SystemZXPLINKFrameLowering::spillCalleeSavedRegisters( 933349cc55cSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 934349cc55cSDimitry Andric ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 935349cc55cSDimitry Andric if (CSI.empty()) 936349cc55cSDimitry Andric return true; 937349cc55cSDimitry Andric 938349cc55cSDimitry Andric MachineFunction &MF = *MBB.getParent(); 939349cc55cSDimitry Andric SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); 940349cc55cSDimitry Andric const SystemZSubtarget &Subtarget = MF.getSubtarget<SystemZSubtarget>(); 941349cc55cSDimitry Andric const TargetInstrInfo *TII = Subtarget.getInstrInfo(); 942349cc55cSDimitry Andric auto &Regs = Subtarget.getSpecialRegisters<SystemZXPLINK64Registers>(); 943349cc55cSDimitry Andric SystemZ::GPRRegs SpillGPRs = ZFI->getSpillGPRRegs(); 944349cc55cSDimitry Andric DebugLoc DL; 945349cc55cSDimitry Andric 946349cc55cSDimitry Andric // Save GPRs 947349cc55cSDimitry Andric if (SpillGPRs.LowGPR) { 948349cc55cSDimitry Andric assert(SpillGPRs.LowGPR != SpillGPRs.HighGPR && 949349cc55cSDimitry Andric "Should be saving multiple registers"); 950349cc55cSDimitry Andric 951349cc55cSDimitry Andric // Build an STM/STMG instruction. 952349cc55cSDimitry Andric MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(SystemZ::STMG)); 953349cc55cSDimitry Andric 954349cc55cSDimitry Andric // Add the explicit register operands. 955349cc55cSDimitry Andric addSavedGPR(MBB, MIB, SpillGPRs.LowGPR, false); 956349cc55cSDimitry Andric addSavedGPR(MBB, MIB, SpillGPRs.HighGPR, false); 957349cc55cSDimitry Andric 958349cc55cSDimitry Andric // Add the address r4 959349cc55cSDimitry Andric MIB.addReg(Regs.getStackPointerRegister()); 960349cc55cSDimitry Andric 961349cc55cSDimitry Andric // Add the partial offset 962349cc55cSDimitry Andric // We cannot add the actual offset as, at the stack is not finalized 963349cc55cSDimitry Andric MIB.addImm(SpillGPRs.GPROffset); 964349cc55cSDimitry Andric 965349cc55cSDimitry Andric // Make sure all call-saved GPRs are included as operands and are 966349cc55cSDimitry Andric // marked as live on entry. 967349cc55cSDimitry Andric auto &GRRegClass = SystemZ::GR64BitRegClass; 968*4824e7fdSDimitry Andric for (const CalleeSavedInfo &I : CSI) { 969*4824e7fdSDimitry Andric unsigned Reg = I.getReg(); 970349cc55cSDimitry Andric if (GRRegClass.contains(Reg)) 971349cc55cSDimitry Andric addSavedGPR(MBB, MIB, Reg, true); 972349cc55cSDimitry Andric } 973349cc55cSDimitry Andric } 974349cc55cSDimitry Andric 975349cc55cSDimitry Andric // Spill FPRs to the stack in the normal TargetInstrInfo way 976*4824e7fdSDimitry Andric for (const CalleeSavedInfo &I : CSI) { 977*4824e7fdSDimitry Andric unsigned Reg = I.getReg(); 978349cc55cSDimitry Andric if (SystemZ::FP64BitRegClass.contains(Reg)) { 979349cc55cSDimitry Andric MBB.addLiveIn(Reg); 980*4824e7fdSDimitry Andric TII->storeRegToStackSlot(MBB, MBBI, Reg, true, I.getFrameIdx(), 981349cc55cSDimitry Andric &SystemZ::FP64BitRegClass, TRI); 982349cc55cSDimitry Andric } 983349cc55cSDimitry Andric if (SystemZ::VR128BitRegClass.contains(Reg)) { 984349cc55cSDimitry Andric MBB.addLiveIn(Reg); 985*4824e7fdSDimitry Andric TII->storeRegToStackSlot(MBB, MBBI, Reg, true, I.getFrameIdx(), 986349cc55cSDimitry Andric &SystemZ::VR128BitRegClass, TRI); 987349cc55cSDimitry Andric } 988349cc55cSDimitry Andric } 989349cc55cSDimitry Andric 990349cc55cSDimitry Andric return true; 991349cc55cSDimitry Andric } 992349cc55cSDimitry Andric 993349cc55cSDimitry Andric void SystemZXPLINKFrameLowering::emitPrologue(MachineFunction &MF, 994349cc55cSDimitry Andric MachineBasicBlock &MBB) const {} 995349cc55cSDimitry Andric 996349cc55cSDimitry Andric void SystemZXPLINKFrameLowering::emitEpilogue(MachineFunction &MF, 997349cc55cSDimitry Andric MachineBasicBlock &MBB) const {} 998349cc55cSDimitry Andric 999349cc55cSDimitry Andric bool SystemZXPLINKFrameLowering::hasFP(const MachineFunction &MF) const { 1000349cc55cSDimitry Andric return false; 1001349cc55cSDimitry Andric } 1002