15f613dfdSUlrich Weigand //===-- SystemZFrameLowering.cpp - Frame lowering for SystemZ -------------===// 25f613dfdSUlrich Weigand // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65f613dfdSUlrich Weigand // 75f613dfdSUlrich Weigand //===----------------------------------------------------------------------===// 85f613dfdSUlrich Weigand 95f613dfdSUlrich Weigand #include "SystemZFrameLowering.h" 105f613dfdSUlrich Weigand #include "SystemZCallingConv.h" 115f613dfdSUlrich Weigand #include "SystemZInstrBuilder.h" 12f1bd22dfSEric Christopher #include "SystemZInstrInfo.h" 135f613dfdSUlrich Weigand #include "SystemZMachineFunctionInfo.h" 14f1bd22dfSEric Christopher #include "SystemZRegisterInfo.h" 15d913448bSEric Christopher #include "SystemZSubtarget.h" 165f613dfdSUlrich Weigand #include "llvm/CodeGen/MachineModuleInfo.h" 175f613dfdSUlrich Weigand #include "llvm/CodeGen/MachineRegisterInfo.h" 185dd52f8cSRichard Sandiford #include "llvm/CodeGen/RegisterScavenging.h" 195f613dfdSUlrich Weigand #include "llvm/IR/Function.h" 20fe0006c8SSimon Pilgrim #include "llvm/Target/TargetMachine.h" 215f613dfdSUlrich Weigand 225f613dfdSUlrich Weigand using namespace llvm; 235f613dfdSUlrich Weigand 24db39b4a2SRichard Sandiford namespace { 25a7d3f693SJonas Paulsson // The ABI-defined register save slots, relative to the CFA (i.e. 26a7d3f693SJonas Paulsson // incoming stack pointer + SystemZMC::CallFrameSize). 27db39b4a2SRichard Sandiford static const TargetFrameLowering::SpillSlot SpillOffsetTable[] = { 2861f5ba5cSJonas Paulsson { SystemZ::R2D, 0x10 }, 2961f5ba5cSJonas Paulsson { SystemZ::R3D, 0x18 }, 3061f5ba5cSJonas Paulsson { SystemZ::R4D, 0x20 }, 3161f5ba5cSJonas Paulsson { SystemZ::R5D, 0x28 }, 3261f5ba5cSJonas Paulsson { SystemZ::R6D, 0x30 }, 3361f5ba5cSJonas Paulsson { SystemZ::R7D, 0x38 }, 3461f5ba5cSJonas Paulsson { SystemZ::R8D, 0x40 }, 3561f5ba5cSJonas Paulsson { SystemZ::R9D, 0x48 }, 3661f5ba5cSJonas Paulsson { SystemZ::R10D, 0x50 }, 3761f5ba5cSJonas Paulsson { SystemZ::R11D, 0x58 }, 3861f5ba5cSJonas Paulsson { SystemZ::R12D, 0x60 }, 3961f5ba5cSJonas Paulsson { SystemZ::R13D, 0x68 }, 4061f5ba5cSJonas Paulsson { SystemZ::R14D, 0x70 }, 4161f5ba5cSJonas Paulsson { SystemZ::R15D, 0x78 }, 4261f5ba5cSJonas Paulsson { SystemZ::F0D, 0x80 }, 4361f5ba5cSJonas Paulsson { SystemZ::F2D, 0x88 }, 4461f5ba5cSJonas Paulsson { SystemZ::F4D, 0x90 }, 4561f5ba5cSJonas Paulsson { SystemZ::F6D, 0x98 } 465f613dfdSUlrich Weigand }; 47c231269fSRichard Sandiford } // end anonymous namespace 485f613dfdSUlrich Weigand 49f1bd22dfSEric Christopher SystemZFrameLowering::SystemZFrameLowering() 50882c43d7SGuillaume Chatelet : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(8), 5161f5ba5cSJonas Paulsson 0, Align(8), false /* StackRealignable */), 5261f5ba5cSJonas Paulsson RegSpillOffsets(0) { 53a7d3f693SJonas Paulsson // Due to the SystemZ ABI, the DWARF CFA (Canonical Frame Address) is not 54a7d3f693SJonas Paulsson // equal to the incoming stack pointer, but to incoming stack pointer plus 5561f5ba5cSJonas Paulsson // 160. Instead of using a Local Area Offset, the Register save area will 5661f5ba5cSJonas Paulsson // be occupied by fixed frame objects, and all offsets are actually 5761f5ba5cSJonas Paulsson // relative to CFA. 58a7d3f693SJonas Paulsson 595f613dfdSUlrich Weigand // Create a mapping from register number to save slot offset. 60a7d3f693SJonas Paulsson // These offsets are relative to the start of the register save area. 615f613dfdSUlrich Weigand RegSpillOffsets.grow(SystemZ::NUM_TARGET_REGS); 625f613dfdSUlrich Weigand for (unsigned I = 0, E = array_lengthof(SpillOffsetTable); I != E; ++I) 6361f5ba5cSJonas Paulsson RegSpillOffsets[SpillOffsetTable[I].Reg] = SpillOffsetTable[I].Offset; 64db39b4a2SRichard Sandiford } 65db39b4a2SRichard Sandiford 6661f5ba5cSJonas Paulsson bool SystemZFrameLowering:: 6761f5ba5cSJonas Paulsson assignCalleeSavedSpillSlots(MachineFunction &MF, 6861f5ba5cSJonas Paulsson const TargetRegisterInfo *TRI, 6961f5ba5cSJonas Paulsson std::vector<CalleeSavedInfo> &CSI) const { 7061f5ba5cSJonas Paulsson SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); 7161f5ba5cSJonas Paulsson MachineFrameInfo &MFFrame = MF.getFrameInfo(); 7261f5ba5cSJonas Paulsson bool IsVarArg = MF.getFunction().isVarArg(); 7361f5ba5cSJonas Paulsson if (CSI.empty()) 7461f5ba5cSJonas Paulsson return true; // Early exit if no callee saved registers are modified! 7561f5ba5cSJonas Paulsson 7661f5ba5cSJonas Paulsson unsigned LowGPR = 0; 7761f5ba5cSJonas Paulsson unsigned HighGPR = SystemZ::R15D; 7861f5ba5cSJonas Paulsson int StartSPOffset = SystemZMC::CallFrameSize; 7961f5ba5cSJonas Paulsson for (auto &CS : CSI) { 8061f5ba5cSJonas Paulsson unsigned Reg = CS.getReg(); 8182879c29SJonas Paulsson int Offset = getRegSpillOffset(MF, Reg); 8261f5ba5cSJonas Paulsson if (Offset) { 8361f5ba5cSJonas Paulsson if (SystemZ::GR64BitRegClass.contains(Reg) && StartSPOffset > Offset) { 8461f5ba5cSJonas Paulsson LowGPR = Reg; 8561f5ba5cSJonas Paulsson StartSPOffset = Offset; 8661f5ba5cSJonas Paulsson } 8761f5ba5cSJonas Paulsson Offset -= SystemZMC::CallFrameSize; 8861f5ba5cSJonas Paulsson int FrameIdx = MFFrame.CreateFixedSpillStackObject(8, Offset); 8961f5ba5cSJonas Paulsson CS.setFrameIdx(FrameIdx); 9061f5ba5cSJonas Paulsson } else 9161f5ba5cSJonas Paulsson CS.setFrameIdx(INT32_MAX); 9261f5ba5cSJonas Paulsson } 9361f5ba5cSJonas Paulsson 9461f5ba5cSJonas Paulsson // Save the range of call-saved registers, for use by the 9561f5ba5cSJonas Paulsson // prologue/epilogue inserters. 9661f5ba5cSJonas Paulsson ZFI->setRestoreGPRRegs(LowGPR, HighGPR, StartSPOffset); 9761f5ba5cSJonas Paulsson if (IsVarArg) { 9861f5ba5cSJonas Paulsson // Also save the GPR varargs, if any. R6D is call-saved, so would 9961f5ba5cSJonas Paulsson // already be included, but we also need to handle the call-clobbered 10061f5ba5cSJonas Paulsson // argument registers. 10161f5ba5cSJonas Paulsson unsigned FirstGPR = ZFI->getVarArgsFirstGPR(); 10261f5ba5cSJonas Paulsson if (FirstGPR < SystemZ::NumArgGPRs) { 10361f5ba5cSJonas Paulsson unsigned Reg = SystemZ::ArgGPRs[FirstGPR]; 10482879c29SJonas Paulsson int Offset = getRegSpillOffset(MF, Reg); 10561f5ba5cSJonas Paulsson if (StartSPOffset > Offset) { 10661f5ba5cSJonas Paulsson LowGPR = Reg; StartSPOffset = Offset; 10761f5ba5cSJonas Paulsson } 10861f5ba5cSJonas Paulsson } 10961f5ba5cSJonas Paulsson } 11061f5ba5cSJonas Paulsson ZFI->setSpillGPRRegs(LowGPR, HighGPR, StartSPOffset); 11161f5ba5cSJonas Paulsson 11261f5ba5cSJonas Paulsson // Create fixed stack objects for the remaining registers. 11382879c29SJonas Paulsson int CurrOffset = -SystemZMC::CallFrameSize; 11482879c29SJonas Paulsson if (usePackedStack(MF)) 11582879c29SJonas Paulsson CurrOffset += StartSPOffset; 11682879c29SJonas Paulsson 11761f5ba5cSJonas Paulsson for (auto &CS : CSI) { 11861f5ba5cSJonas Paulsson if (CS.getFrameIdx() != INT32_MAX) 11961f5ba5cSJonas Paulsson continue; 12061f5ba5cSJonas Paulsson unsigned Reg = CS.getReg(); 12161f5ba5cSJonas Paulsson const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); 12261f5ba5cSJonas Paulsson unsigned Size = TRI->getSpillSize(*RC); 12361f5ba5cSJonas Paulsson CurrOffset -= Size; 12461f5ba5cSJonas Paulsson assert(CurrOffset % 8 == 0 && 12561f5ba5cSJonas Paulsson "8-byte alignment required for for all register save slots"); 12661f5ba5cSJonas Paulsson int FrameIdx = MFFrame.CreateFixedSpillStackObject(Size, CurrOffset); 12761f5ba5cSJonas Paulsson CS.setFrameIdx(FrameIdx); 12861f5ba5cSJonas Paulsson } 12961f5ba5cSJonas Paulsson 13061f5ba5cSJonas Paulsson return true; 1315f613dfdSUlrich Weigand } 1325f613dfdSUlrich Weigand 13302564865SMatthias Braun void SystemZFrameLowering::determineCalleeSaves(MachineFunction &MF, 13402564865SMatthias Braun BitVector &SavedRegs, 1355f613dfdSUlrich Weigand RegScavenger *RS) const { 13602564865SMatthias Braun TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); 13702564865SMatthias Braun 138941a705bSMatthias Braun MachineFrameInfo &MFFrame = MF.getFrameInfo(); 139fc6de428SEric Christopher const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); 1405f613dfdSUlrich Weigand bool HasFP = hasFP(MF); 1415f613dfdSUlrich Weigand SystemZMachineFunctionInfo *MFI = MF.getInfo<SystemZMachineFunctionInfo>(); 142f1caa283SMatthias Braun bool IsVarArg = MF.getFunction().isVarArg(); 1435f613dfdSUlrich Weigand 1445f613dfdSUlrich Weigand // va_start stores incoming FPR varargs in the normal way, but delegates 1455f613dfdSUlrich Weigand // the saving of incoming GPR varargs to spillCalleeSavedRegisters(). 1465f613dfdSUlrich Weigand // Record these pending uses, which typically include the call-saved 1475f613dfdSUlrich Weigand // argument register R6D. 1485f613dfdSUlrich Weigand if (IsVarArg) 1495f613dfdSUlrich Weigand for (unsigned I = MFI->getVarArgsFirstGPR(); I < SystemZ::NumArgGPRs; ++I) 15002564865SMatthias Braun SavedRegs.set(SystemZ::ArgGPRs[I]); 1515f613dfdSUlrich Weigand 152234e5a80SMarcin Koscielnicki // If there are any landing pads, entering them will modify r6/r7. 153d0ee66c2SMatthias Braun if (!MF.getLandingPads().empty()) { 154234e5a80SMarcin Koscielnicki SavedRegs.set(SystemZ::R6D); 155234e5a80SMarcin Koscielnicki SavedRegs.set(SystemZ::R7D); 156234e5a80SMarcin Koscielnicki } 157234e5a80SMarcin Koscielnicki 1585f613dfdSUlrich Weigand // If the function requires a frame pointer, record that the hard 1595f613dfdSUlrich Weigand // frame pointer will be clobbered. 1605f613dfdSUlrich Weigand if (HasFP) 16102564865SMatthias Braun SavedRegs.set(SystemZ::R11D); 1625f613dfdSUlrich Weigand 1635f613dfdSUlrich Weigand // If the function calls other functions, record that the return 1645f613dfdSUlrich Weigand // address register will be clobbered. 165941a705bSMatthias Braun if (MFFrame.hasCalls()) 16602564865SMatthias Braun SavedRegs.set(SystemZ::R14D); 1675f613dfdSUlrich Weigand 1685f613dfdSUlrich Weigand // If we are saving GPRs other than the stack pointer, we might as well 1695f613dfdSUlrich Weigand // save and restore the stack pointer at the same time, via STMG and LMG. 1705f613dfdSUlrich Weigand // This allows the deallocation to be done by the LMG, rather than needing 1715f613dfdSUlrich Weigand // a separate %r15 addition. 172840beec2SCraig Topper const MCPhysReg *CSRegs = TRI->getCalleeSavedRegs(&MF); 1735f613dfdSUlrich Weigand for (unsigned I = 0; CSRegs[I]; ++I) { 1745f613dfdSUlrich Weigand unsigned Reg = CSRegs[I]; 17502564865SMatthias Braun if (SystemZ::GR64BitRegClass.contains(Reg) && SavedRegs.test(Reg)) { 17602564865SMatthias Braun SavedRegs.set(SystemZ::R15D); 1775f613dfdSUlrich Weigand break; 1785f613dfdSUlrich Weigand } 1795f613dfdSUlrich Weigand } 1805f613dfdSUlrich Weigand } 1815f613dfdSUlrich Weigand 1825f613dfdSUlrich Weigand // Add GPR64 to the save instruction being built by MIB, which is in basic 1835f613dfdSUlrich Weigand // block MBB. IsImplicit says whether this is an explicit operand to the 1845f613dfdSUlrich Weigand // instruction, or an implicit one that comes between the explicit start 1855f613dfdSUlrich Weigand // and end registers. 1865f613dfdSUlrich Weigand static void addSavedGPR(MachineBasicBlock &MBB, MachineInstrBuilder &MIB, 1875f613dfdSUlrich Weigand unsigned GPR64, bool IsImplicit) { 188d913448bSEric Christopher const TargetRegisterInfo *RI = 189fc6de428SEric Christopher MBB.getParent()->getSubtarget().getRegisterInfo(); 1900c476111SDaniel Sanders Register GPR32 = RI->getSubReg(GPR64, SystemZ::subreg_l32); 1915f613dfdSUlrich Weigand bool IsLive = MBB.isLiveIn(GPR64) || MBB.isLiveIn(GPR32); 1925f613dfdSUlrich Weigand if (!IsLive || !IsImplicit) { 1935f613dfdSUlrich Weigand MIB.addReg(GPR64, getImplRegState(IsImplicit) | getKillRegState(!IsLive)); 1945f613dfdSUlrich Weigand if (!IsLive) 1955f613dfdSUlrich Weigand MBB.addLiveIn(GPR64); 1965f613dfdSUlrich Weigand } 1975f613dfdSUlrich Weigand } 1985f613dfdSUlrich Weigand 199e4230a9fSBenjamin Kramer bool SystemZFrameLowering::spillCalleeSavedRegisters( 200e4230a9fSBenjamin Kramer MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 201e4230a9fSBenjamin Kramer ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 2025f613dfdSUlrich Weigand if (CSI.empty()) 2035f613dfdSUlrich Weigand return false; 2045f613dfdSUlrich Weigand 2055f613dfdSUlrich Weigand MachineFunction &MF = *MBB.getParent(); 206fc6de428SEric Christopher const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); 2075f613dfdSUlrich Weigand SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); 208f1caa283SMatthias Braun bool IsVarArg = MF.getFunction().isVarArg(); 209057c5a6bSOleg Ranevskyy DebugLoc DL; 2105f613dfdSUlrich Weigand 2115f613dfdSUlrich Weigand // Save GPRs 21261f5ba5cSJonas Paulsson SystemZ::GPRRegs SpillGPRs = ZFI->getSpillGPRRegs(); 21361f5ba5cSJonas Paulsson if (SpillGPRs.LowGPR) { 21461f5ba5cSJonas Paulsson assert(SpillGPRs.LowGPR != SpillGPRs.HighGPR && 21561f5ba5cSJonas Paulsson "Should be saving %r15 and something else"); 2165f613dfdSUlrich Weigand 2175f613dfdSUlrich Weigand // Build an STMG instruction. 2185f613dfdSUlrich Weigand MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(SystemZ::STMG)); 2195f613dfdSUlrich Weigand 2205f613dfdSUlrich Weigand // Add the explicit register operands. 22161f5ba5cSJonas Paulsson addSavedGPR(MBB, MIB, SpillGPRs.LowGPR, false); 22261f5ba5cSJonas Paulsson addSavedGPR(MBB, MIB, SpillGPRs.HighGPR, false); 2235f613dfdSUlrich Weigand 2245f613dfdSUlrich Weigand // Add the address. 22561f5ba5cSJonas Paulsson MIB.addReg(SystemZ::R15D).addImm(SpillGPRs.GPROffset); 2265f613dfdSUlrich Weigand 2275f613dfdSUlrich Weigand // Make sure all call-saved GPRs are included as operands and are 2285f613dfdSUlrich Weigand // marked as live on entry. 2295f613dfdSUlrich Weigand for (unsigned I = 0, E = CSI.size(); I != E; ++I) { 2305f613dfdSUlrich Weigand unsigned Reg = CSI[I].getReg(); 2315f613dfdSUlrich Weigand if (SystemZ::GR64BitRegClass.contains(Reg)) 232f1bd22dfSEric Christopher addSavedGPR(MBB, MIB, Reg, true); 2335f613dfdSUlrich Weigand } 2345f613dfdSUlrich Weigand 2355f613dfdSUlrich Weigand // ...likewise GPR varargs. 2365f613dfdSUlrich Weigand if (IsVarArg) 2375f613dfdSUlrich Weigand for (unsigned I = ZFI->getVarArgsFirstGPR(); I < SystemZ::NumArgGPRs; ++I) 238f1bd22dfSEric Christopher addSavedGPR(MBB, MIB, SystemZ::ArgGPRs[I], true); 2395f613dfdSUlrich Weigand } 2405f613dfdSUlrich Weigand 2418b19be46SUlrich Weigand // Save FPRs/VRs in the normal TargetInstrInfo way. 2425f613dfdSUlrich Weigand for (unsigned I = 0, E = CSI.size(); I != E; ++I) { 2435f613dfdSUlrich Weigand unsigned Reg = CSI[I].getReg(); 2445f613dfdSUlrich Weigand if (SystemZ::FP64BitRegClass.contains(Reg)) { 2455f613dfdSUlrich Weigand MBB.addLiveIn(Reg); 2465f613dfdSUlrich Weigand TII->storeRegToStackSlot(MBB, MBBI, Reg, true, CSI[I].getFrameIdx(), 2475f613dfdSUlrich Weigand &SystemZ::FP64BitRegClass, TRI); 2485f613dfdSUlrich Weigand } 2498b19be46SUlrich Weigand if (SystemZ::VR128BitRegClass.contains(Reg)) { 2508b19be46SUlrich Weigand MBB.addLiveIn(Reg); 2518b19be46SUlrich Weigand TII->storeRegToStackSlot(MBB, MBBI, Reg, true, CSI[I].getFrameIdx(), 2528b19be46SUlrich Weigand &SystemZ::VR128BitRegClass, TRI); 2538b19be46SUlrich Weigand } 2545f613dfdSUlrich Weigand } 2555f613dfdSUlrich Weigand 2565f613dfdSUlrich Weigand return true; 2575f613dfdSUlrich Weigand } 2585f613dfdSUlrich Weigand 259186dd631SBenjamin Kramer bool SystemZFrameLowering::restoreCalleeSavedRegisters( 260186dd631SBenjamin Kramer MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 261186dd631SBenjamin Kramer MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 2625f613dfdSUlrich Weigand if (CSI.empty()) 2635f613dfdSUlrich Weigand return false; 2645f613dfdSUlrich Weigand 2655f613dfdSUlrich Weigand MachineFunction &MF = *MBB.getParent(); 266fc6de428SEric Christopher const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); 2675f613dfdSUlrich Weigand SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); 2685f613dfdSUlrich Weigand bool HasFP = hasFP(MF); 2695f613dfdSUlrich Weigand DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); 2705f613dfdSUlrich Weigand 2718b19be46SUlrich Weigand // Restore FPRs/VRs in the normal TargetInstrInfo way. 2725f613dfdSUlrich Weigand for (unsigned I = 0, E = CSI.size(); I != E; ++I) { 2735f613dfdSUlrich Weigand unsigned Reg = CSI[I].getReg(); 2745f613dfdSUlrich Weigand if (SystemZ::FP64BitRegClass.contains(Reg)) 2755f613dfdSUlrich Weigand TII->loadRegFromStackSlot(MBB, MBBI, Reg, CSI[I].getFrameIdx(), 2765f613dfdSUlrich Weigand &SystemZ::FP64BitRegClass, TRI); 2778b19be46SUlrich Weigand if (SystemZ::VR128BitRegClass.contains(Reg)) 2788b19be46SUlrich Weigand TII->loadRegFromStackSlot(MBB, MBBI, Reg, CSI[I].getFrameIdx(), 2798b19be46SUlrich Weigand &SystemZ::VR128BitRegClass, TRI); 2805f613dfdSUlrich Weigand } 2815f613dfdSUlrich Weigand 2825f613dfdSUlrich Weigand // Restore call-saved GPRs (but not call-clobbered varargs, which at 2835f613dfdSUlrich Weigand // this point might hold return values). 28461f5ba5cSJonas Paulsson SystemZ::GPRRegs RestoreGPRs = ZFI->getRestoreGPRRegs(); 28561f5ba5cSJonas Paulsson if (RestoreGPRs.LowGPR) { 2865f613dfdSUlrich Weigand // If we saved any of %r2-%r5 as varargs, we should also be saving 2875f613dfdSUlrich Weigand // and restoring %r6. If we're saving %r6 or above, we should be 2885f613dfdSUlrich Weigand // restoring it too. 28961f5ba5cSJonas Paulsson assert(RestoreGPRs.LowGPR != RestoreGPRs.HighGPR && 29061f5ba5cSJonas Paulsson "Should be loading %r15 and something else"); 2915f613dfdSUlrich Weigand 2925f613dfdSUlrich Weigand // Build an LMG instruction. 2935f613dfdSUlrich Weigand MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(SystemZ::LMG)); 2945f613dfdSUlrich Weigand 2955f613dfdSUlrich Weigand // Add the explicit register operands. 29661f5ba5cSJonas Paulsson MIB.addReg(RestoreGPRs.LowGPR, RegState::Define); 29761f5ba5cSJonas Paulsson MIB.addReg(RestoreGPRs.HighGPR, RegState::Define); 2985f613dfdSUlrich Weigand 2995f613dfdSUlrich Weigand // Add the address. 3005f613dfdSUlrich Weigand MIB.addReg(HasFP ? SystemZ::R11D : SystemZ::R15D); 30161f5ba5cSJonas Paulsson MIB.addImm(RestoreGPRs.GPROffset); 3025f613dfdSUlrich Weigand 3035f613dfdSUlrich Weigand // Do a second scan adding regs as being defined by instruction 3045f613dfdSUlrich Weigand for (unsigned I = 0, E = CSI.size(); I != E; ++I) { 3055f613dfdSUlrich Weigand unsigned Reg = CSI[I].getReg(); 30661f5ba5cSJonas Paulsson if (Reg != RestoreGPRs.LowGPR && Reg != RestoreGPRs.HighGPR && 307f0344826SJonas Paulsson SystemZ::GR64BitRegClass.contains(Reg)) 3085f613dfdSUlrich Weigand MIB.addReg(Reg, RegState::ImplicitDefine); 3095f613dfdSUlrich Weigand } 3105f613dfdSUlrich Weigand } 3115f613dfdSUlrich Weigand 3125f613dfdSUlrich Weigand return true; 3135f613dfdSUlrich Weigand } 3145f613dfdSUlrich Weigand 3155dd52f8cSRichard Sandiford void SystemZFrameLowering:: 3165dd52f8cSRichard Sandiford processFunctionBeforeFrameFinalized(MachineFunction &MF, 3175dd52f8cSRichard Sandiford RegScavenger *RS) const { 318941a705bSMatthias Braun MachineFrameInfo &MFFrame = MF.getFrameInfo(); 31923762575SJonas Paulsson bool BackChain = MF.getFunction().hasFnAttribute("backchain"); 32061f5ba5cSJonas Paulsson 32123762575SJonas Paulsson if (!usePackedStack(MF) || BackChain) 32223762575SJonas Paulsson // Create the incoming register save area. 32361f5ba5cSJonas Paulsson getOrCreateFramePointerSaveIndex(MF); 32461f5ba5cSJonas Paulsson 325af98b748SUlrich Weigand // Get the size of our stack frame to be allocated ... 326af98b748SUlrich Weigand uint64_t StackSize = (MFFrame.estimateStackSize(MF) + 327af98b748SUlrich Weigand SystemZMC::CallFrameSize); 328af98b748SUlrich Weigand // ... and the maximum offset we may need to reach into the 329af98b748SUlrich Weigand // caller's frame to access the save area or stack arguments. 33061f5ba5cSJonas Paulsson int64_t MaxArgOffset = 0; 331af98b748SUlrich Weigand for (int I = MFFrame.getObjectIndexBegin(); I != 0; ++I) 332af98b748SUlrich Weigand if (MFFrame.getObjectOffset(I) >= 0) { 33361f5ba5cSJonas Paulsson int64_t ArgOffset = MFFrame.getObjectOffset(I) + 334af98b748SUlrich Weigand MFFrame.getObjectSize(I); 335af98b748SUlrich Weigand MaxArgOffset = std::max(MaxArgOffset, ArgOffset); 336af98b748SUlrich Weigand } 337af98b748SUlrich Weigand 338af98b748SUlrich Weigand uint64_t MaxReach = StackSize + MaxArgOffset; 33923943229SRichard Sandiford if (!isUInt<12>(MaxReach)) { 34023943229SRichard Sandiford // We may need register scavenging slots if some parts of the frame 3415dd52f8cSRichard Sandiford // are outside the reach of an unsigned 12-bit displacement. 34223943229SRichard Sandiford // Create 2 for the case where both addresses in an MVC are 34323943229SRichard Sandiford // out of range. 344*28de229bSGuillaume Chatelet RS->addScavengingFrameIndex(MFFrame.CreateStackObject(8, Align(8), false)); 345*28de229bSGuillaume Chatelet RS->addScavengingFrameIndex(MFFrame.CreateStackObject(8, Align(8), false)); 34623943229SRichard Sandiford } 3475dd52f8cSRichard Sandiford } 3485dd52f8cSRichard Sandiford 3495f613dfdSUlrich Weigand // Emit instructions before MBBI (in MBB) to add NumBytes to Reg. 3505f613dfdSUlrich Weigand static void emitIncrement(MachineBasicBlock &MBB, 3512481f26aSMatt Arsenault MachineBasicBlock::iterator &MBBI, const DebugLoc &DL, 3522481f26aSMatt Arsenault Register Reg, int64_t NumBytes, 3535f613dfdSUlrich Weigand const TargetInstrInfo *TII) { 3545f613dfdSUlrich Weigand while (NumBytes) { 3555f613dfdSUlrich Weigand unsigned Opcode; 3565f613dfdSUlrich Weigand int64_t ThisVal = NumBytes; 3575f613dfdSUlrich Weigand if (isInt<16>(NumBytes)) 3585f613dfdSUlrich Weigand Opcode = SystemZ::AGHI; 3595f613dfdSUlrich Weigand else { 3605f613dfdSUlrich Weigand Opcode = SystemZ::AGFI; 3615f613dfdSUlrich Weigand // Make sure we maintain 8-byte stack alignment. 362fffd56ecSAlexey Samsonov int64_t MinVal = -uint64_t(1) << 31; 3635f613dfdSUlrich Weigand int64_t MaxVal = (int64_t(1) << 31) - 8; 3645f613dfdSUlrich Weigand if (ThisVal < MinVal) 3655f613dfdSUlrich Weigand ThisVal = MinVal; 3665f613dfdSUlrich Weigand else if (ThisVal > MaxVal) 3675f613dfdSUlrich Weigand ThisVal = MaxVal; 3685f613dfdSUlrich Weigand } 3695f613dfdSUlrich Weigand MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII->get(Opcode), Reg) 3705f613dfdSUlrich Weigand .addReg(Reg).addImm(ThisVal); 37114a44495SRichard Sandiford // The CC implicit def is dead. 3725f613dfdSUlrich Weigand MI->getOperand(3).setIsDead(); 3735f613dfdSUlrich Weigand NumBytes -= ThisVal; 3745f613dfdSUlrich Weigand } 3755f613dfdSUlrich Weigand } 3765f613dfdSUlrich Weigand 377515bfc66SJonas Paulsson // Add CFI for the new CFA offset. 378515bfc66SJonas Paulsson static void buildCFAOffs(MachineBasicBlock &MBB, 379515bfc66SJonas Paulsson MachineBasicBlock::iterator MBBI, 380515bfc66SJonas Paulsson const DebugLoc &DL, int Offset, 381515bfc66SJonas Paulsson const SystemZInstrInfo *ZII) { 382515bfc66SJonas Paulsson unsigned CFIIndex = MBB.getParent()->addFrameInst( 383515bfc66SJonas Paulsson MCCFIInstruction::cfiDefCfaOffset(nullptr, -Offset)); 384515bfc66SJonas Paulsson BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION)) 385515bfc66SJonas Paulsson .addCFIIndex(CFIIndex); 386515bfc66SJonas Paulsson } 387515bfc66SJonas Paulsson 388515bfc66SJonas Paulsson // Add CFI for the new frame location. 389515bfc66SJonas Paulsson static void buildDefCFAReg(MachineBasicBlock &MBB, 390515bfc66SJonas Paulsson MachineBasicBlock::iterator MBBI, 391515bfc66SJonas Paulsson const DebugLoc &DL, unsigned Reg, 392515bfc66SJonas Paulsson const SystemZInstrInfo *ZII) { 393515bfc66SJonas Paulsson MachineFunction &MF = *MBB.getParent(); 394515bfc66SJonas Paulsson MachineModuleInfo &MMI = MF.getMMI(); 395515bfc66SJonas Paulsson const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); 396515bfc66SJonas Paulsson unsigned RegNum = MRI->getDwarfRegNum(Reg, true); 397515bfc66SJonas Paulsson unsigned CFIIndex = MF.addFrameInst( 398515bfc66SJonas Paulsson MCCFIInstruction::createDefCfaRegister(nullptr, RegNum)); 399515bfc66SJonas Paulsson BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION)) 400515bfc66SJonas Paulsson .addCFIIndex(CFIIndex); 401515bfc66SJonas Paulsson } 402515bfc66SJonas Paulsson 40361b305edSQuentin Colombet void SystemZFrameLowering::emitPrologue(MachineFunction &MF, 40461b305edSQuentin Colombet MachineBasicBlock &MBB) const { 40561b305edSQuentin Colombet assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported"); 406515bfc66SJonas Paulsson const SystemZSubtarget &STI = MF.getSubtarget<SystemZSubtarget>(); 407515bfc66SJonas Paulsson const SystemZTargetLowering &TLI = *STI.getTargetLowering(); 408941a705bSMatthias Braun MachineFrameInfo &MFFrame = MF.getFrameInfo(); 409515bfc66SJonas Paulsson auto *ZII = static_cast<const SystemZInstrInfo *>(STI.getInstrInfo()); 4105f613dfdSUlrich Weigand SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); 4115f613dfdSUlrich Weigand MachineBasicBlock::iterator MBBI = MBB.begin(); 4125f613dfdSUlrich Weigand MachineModuleInfo &MMI = MF.getMMI(); 413bc07a890SBill Wendling const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); 414941a705bSMatthias Braun const std::vector<CalleeSavedInfo> &CSI = MFFrame.getCalleeSavedInfo(); 4155f613dfdSUlrich Weigand bool HasFP = hasFP(MF); 416057c5a6bSOleg Ranevskyy 41722f94291SUlrich Weigand // In GHC calling convention C stack space, including the ABI-defined 41822f94291SUlrich Weigand // 160-byte base area, is (de)allocated by GHC itself. This stack space may 41922f94291SUlrich Weigand // be used by LLVM as spill slots for the tail recursive GHC functions. Thus 42022f94291SUlrich Weigand // do not allocate stack space here, too. 42122f94291SUlrich Weigand if (MF.getFunction().getCallingConv() == CallingConv::GHC) { 42222f94291SUlrich Weigand if (MFFrame.getStackSize() > 2048 * sizeof(long)) { 42322f94291SUlrich Weigand report_fatal_error( 42422f94291SUlrich Weigand "Pre allocated stack space for GHC function is too small"); 42522f94291SUlrich Weigand } 42622f94291SUlrich Weigand if (HasFP) { 42722f94291SUlrich Weigand report_fatal_error( 42822f94291SUlrich Weigand "In GHC calling convention a frame pointer is not supported"); 42922f94291SUlrich Weigand } 43022f94291SUlrich Weigand MFFrame.setStackSize(MFFrame.getStackSize() + SystemZMC::CallFrameSize); 43122f94291SUlrich Weigand return; 43222f94291SUlrich Weigand } 43322f94291SUlrich Weigand 434057c5a6bSOleg Ranevskyy // Debug location must be unknown since the first debug location is used 435057c5a6bSOleg Ranevskyy // to determine the end of the prologue. 436057c5a6bSOleg Ranevskyy DebugLoc DL; 4375f613dfdSUlrich Weigand 4385f613dfdSUlrich Weigand // The current offset of the stack pointer from the CFA. 4395f613dfdSUlrich Weigand int64_t SPOffsetFromCFA = -SystemZMC::CFAOffsetFromInitialSP; 4405f613dfdSUlrich Weigand 44161f5ba5cSJonas Paulsson if (ZFI->getSpillGPRRegs().LowGPR) { 4425f613dfdSUlrich Weigand // Skip over the GPR saves. 4435f613dfdSUlrich Weigand if (MBBI != MBB.end() && MBBI->getOpcode() == SystemZ::STMG) 4445f613dfdSUlrich Weigand ++MBBI; 4455f613dfdSUlrich Weigand else 4465f613dfdSUlrich Weigand llvm_unreachable("Couldn't skip over GPR saves"); 4475f613dfdSUlrich Weigand 4485f613dfdSUlrich Weigand // Add CFI for the GPR saves. 44928c111ecSRichard Sandiford for (auto &Save : CSI) { 45028c111ecSRichard Sandiford unsigned Reg = Save.getReg(); 4515f613dfdSUlrich Weigand if (SystemZ::GR64BitRegClass.contains(Reg)) { 45261f5ba5cSJonas Paulsson int FI = Save.getFrameIdx(); 45361f5ba5cSJonas Paulsson int64_t Offset = MFFrame.getObjectOffset(FI); 454f23ef437SMatthias Braun unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( 455b1f25f1bSRafael Espindola nullptr, MRI->getDwarfRegNum(Reg, true), Offset)); 456b1f25f1bSRafael Espindola BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION)) 457b1f25f1bSRafael Espindola .addCFIIndex(CFIIndex); 4585f613dfdSUlrich Weigand } 4595f613dfdSUlrich Weigand } 4605f613dfdSUlrich Weigand } 4615f613dfdSUlrich Weigand 46232063888SUlrich Weigand uint64_t StackSize = MFFrame.getStackSize(); 46332063888SUlrich Weigand // We need to allocate the ABI-defined 160-byte base area whenever 46432063888SUlrich Weigand // we allocate stack space for our own use and whenever we call another 46532063888SUlrich Weigand // function. 46661f5ba5cSJonas Paulsson bool HasStackObject = false; 46761f5ba5cSJonas Paulsson for (unsigned i = 0, e = MFFrame.getObjectIndexEnd(); i != e; ++i) 46861f5ba5cSJonas Paulsson if (!MFFrame.isDeadObjectIndex(i)) { 46961f5ba5cSJonas Paulsson HasStackObject = true; 47061f5ba5cSJonas Paulsson break; 47132063888SUlrich Weigand } 47261f5ba5cSJonas Paulsson if (HasStackObject || MFFrame.hasCalls()) 47361f5ba5cSJonas Paulsson StackSize += SystemZMC::CallFrameSize; 47461f5ba5cSJonas Paulsson // Don't allocate the incoming reg save area. 47561f5ba5cSJonas Paulsson StackSize = StackSize > SystemZMC::CallFrameSize 47661f5ba5cSJonas Paulsson ? StackSize - SystemZMC::CallFrameSize 47761f5ba5cSJonas Paulsson : 0; 47861f5ba5cSJonas Paulsson MFFrame.setStackSize(StackSize); 47932063888SUlrich Weigand 4805f613dfdSUlrich Weigand if (StackSize) { 481ad1482c6SMarcin Koscielnicki // Determine if we want to store a backchain. 482f1caa283SMatthias Braun bool StoreBackchain = MF.getFunction().hasFnAttribute("backchain"); 483ad1482c6SMarcin Koscielnicki 484ad1482c6SMarcin Koscielnicki // If we need backchain, save current stack pointer. R1 is free at this 485ad1482c6SMarcin Koscielnicki // point. 486ad1482c6SMarcin Koscielnicki if (StoreBackchain) 487ad1482c6SMarcin Koscielnicki BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::LGR)) 488ad1482c6SMarcin Koscielnicki .addReg(SystemZ::R1D, RegState::Define).addReg(SystemZ::R15D); 489ad1482c6SMarcin Koscielnicki 4905f613dfdSUlrich Weigand // Allocate StackSize bytes. 4915f613dfdSUlrich Weigand int64_t Delta = -int64_t(StackSize); 492515bfc66SJonas Paulsson const unsigned ProbeSize = TLI.getStackProbeSize(MF); 493515bfc66SJonas Paulsson bool FreeProbe = (ZFI->getSpillGPRRegs().GPROffset && 494515bfc66SJonas Paulsson (ZFI->getSpillGPRRegs().GPROffset + StackSize) < ProbeSize); 495515bfc66SJonas Paulsson if (!FreeProbe && 496515bfc66SJonas Paulsson MF.getSubtarget().getTargetLowering()->hasInlineStackProbe(MF)) { 497515bfc66SJonas Paulsson // Stack probing may involve looping, but splitting the prologue block 498515bfc66SJonas Paulsson // is not possible at this point since it would invalidate the 499515bfc66SJonas Paulsson // SaveBlocks / RestoreBlocks sets of PEI in the single block function 500515bfc66SJonas Paulsson // case. Build a pseudo to be handled later by inlineStackProbe(). 501515bfc66SJonas Paulsson BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::PROBED_STACKALLOC)) 502515bfc66SJonas Paulsson .addImm(StackSize); 503515bfc66SJonas Paulsson } 504515bfc66SJonas Paulsson else { 5055f613dfdSUlrich Weigand emitIncrement(MBB, MBBI, DL, SystemZ::R15D, Delta, ZII); 506515bfc66SJonas Paulsson buildCFAOffs(MBB, MBBI, DL, SPOffsetFromCFA + Delta, ZII); 507515bfc66SJonas Paulsson } 5085f613dfdSUlrich Weigand SPOffsetFromCFA += Delta; 509ad1482c6SMarcin Koscielnicki 51082879c29SJonas Paulsson if (StoreBackchain) { 51182879c29SJonas Paulsson // The back chain is stored topmost with packed-stack. 51282879c29SJonas Paulsson int Offset = usePackedStack(MF) ? SystemZMC::CallFrameSize - 8 : 0; 513ad1482c6SMarcin Koscielnicki BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::STG)) 51482879c29SJonas Paulsson .addReg(SystemZ::R1D, RegState::Kill).addReg(SystemZ::R15D) 51582879c29SJonas Paulsson .addImm(Offset).addReg(0); 51682879c29SJonas Paulsson } 5175f613dfdSUlrich Weigand } 5185f613dfdSUlrich Weigand 5195f613dfdSUlrich Weigand if (HasFP) { 5205f613dfdSUlrich Weigand // Copy the base of the frame to R11. 5215f613dfdSUlrich Weigand BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::LGR), SystemZ::R11D) 5225f613dfdSUlrich Weigand .addReg(SystemZ::R15D); 5235f613dfdSUlrich Weigand 5245f613dfdSUlrich Weigand // Add CFI for the new frame location. 525515bfc66SJonas Paulsson buildDefCFAReg(MBB, MBBI, DL, SystemZ::R11D, ZII); 5265f613dfdSUlrich Weigand 5275f613dfdSUlrich Weigand // Mark the FramePtr as live at the beginning of every block except 5285f613dfdSUlrich Weigand // the entry block. (We'll have marked R11 as live on entry when 5295f613dfdSUlrich Weigand // saving the GPRs.) 53028c111ecSRichard Sandiford for (auto I = std::next(MF.begin()), E = MF.end(); I != E; ++I) 5315f613dfdSUlrich Weigand I->addLiveIn(SystemZ::R11D); 5325f613dfdSUlrich Weigand } 5335f613dfdSUlrich Weigand 5348b19be46SUlrich Weigand // Skip over the FPR/VR saves. 535b1f25f1bSRafael Espindola SmallVector<unsigned, 8> CFIIndexes; 53628c111ecSRichard Sandiford for (auto &Save : CSI) { 53728c111ecSRichard Sandiford unsigned Reg = Save.getReg(); 5385f613dfdSUlrich Weigand if (SystemZ::FP64BitRegClass.contains(Reg)) { 5395f613dfdSUlrich Weigand if (MBBI != MBB.end() && 5405f613dfdSUlrich Weigand (MBBI->getOpcode() == SystemZ::STD || 5415f613dfdSUlrich Weigand MBBI->getOpcode() == SystemZ::STDY)) 5425f613dfdSUlrich Weigand ++MBBI; 5435f613dfdSUlrich Weigand else 5445f613dfdSUlrich Weigand llvm_unreachable("Couldn't skip over FPR save"); 5458b19be46SUlrich Weigand } else if (SystemZ::VR128BitRegClass.contains(Reg)) { 5468b19be46SUlrich Weigand if (MBBI != MBB.end() && 5478b19be46SUlrich Weigand MBBI->getOpcode() == SystemZ::VST) 5488b19be46SUlrich Weigand ++MBBI; 5498b19be46SUlrich Weigand else 5508b19be46SUlrich Weigand llvm_unreachable("Couldn't skip over VR save"); 5518b19be46SUlrich Weigand } else 5528b19be46SUlrich Weigand continue; 5535f613dfdSUlrich Weigand 5545f613dfdSUlrich Weigand // Add CFI for the this save. 55528c111ecSRichard Sandiford unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true); 5562481f26aSMatt Arsenault Register IgnoredFrameReg; 5575567bafeSJames Y Knight int64_t Offset = 5585567bafeSJames Y Knight getFrameIndexReference(MF, Save.getFrameIdx(), IgnoredFrameReg); 5595567bafeSJames Y Knight 560f23ef437SMatthias Braun unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( 561b1f25f1bSRafael Espindola nullptr, DwarfReg, SPOffsetFromCFA + Offset)); 562b1f25f1bSRafael Espindola CFIIndexes.push_back(CFIIndex); 5635f613dfdSUlrich Weigand } 5648b19be46SUlrich Weigand // Complete the CFI for the FPR/VR saves, modelling them as taking effect 5655f613dfdSUlrich Weigand // after the last save. 566b1f25f1bSRafael Espindola for (auto CFIIndex : CFIIndexes) { 567b1f25f1bSRafael Espindola BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION)) 568b1f25f1bSRafael Espindola .addCFIIndex(CFIIndex); 569b1f25f1bSRafael Espindola } 5705f613dfdSUlrich Weigand } 5715f613dfdSUlrich Weigand 5725f613dfdSUlrich Weigand void SystemZFrameLowering::emitEpilogue(MachineFunction &MF, 5735f613dfdSUlrich Weigand MachineBasicBlock &MBB) const { 5745f613dfdSUlrich Weigand MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); 575fc6de428SEric Christopher auto *ZII = 576fc6de428SEric Christopher static_cast<const SystemZInstrInfo *>(MF.getSubtarget().getInstrInfo()); 5775f613dfdSUlrich Weigand SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); 57832063888SUlrich Weigand MachineFrameInfo &MFFrame = MF.getFrameInfo(); 5795f613dfdSUlrich Weigand 58022f94291SUlrich Weigand // See SystemZFrameLowering::emitPrologue 58122f94291SUlrich Weigand if (MF.getFunction().getCallingConv() == CallingConv::GHC) 58222f94291SUlrich Weigand return; 58322f94291SUlrich Weigand 5845f613dfdSUlrich Weigand // Skip the return instruction. 585709bda66SRichard Sandiford assert(MBBI->isReturn() && "Can only insert epilogue into returning blocks"); 5865f613dfdSUlrich Weigand 58732063888SUlrich Weigand uint64_t StackSize = MFFrame.getStackSize(); 58861f5ba5cSJonas Paulsson if (ZFI->getRestoreGPRRegs().LowGPR) { 5895f613dfdSUlrich Weigand --MBBI; 5905f613dfdSUlrich Weigand unsigned Opcode = MBBI->getOpcode(); 5915f613dfdSUlrich Weigand if (Opcode != SystemZ::LMG) 5925f613dfdSUlrich Weigand llvm_unreachable("Expected to see callee-save register restore code"); 5935f613dfdSUlrich Weigand 5945f613dfdSUlrich Weigand unsigned AddrOpNo = 2; 5955f613dfdSUlrich Weigand DebugLoc DL = MBBI->getDebugLoc(); 5965f613dfdSUlrich Weigand uint64_t Offset = StackSize + MBBI->getOperand(AddrOpNo + 1).getImm(); 5975f613dfdSUlrich Weigand unsigned NewOpcode = ZII->getOpcodeForOffset(Opcode, Offset); 5985f613dfdSUlrich Weigand 5995f613dfdSUlrich Weigand // If the offset is too large, use the largest stack-aligned offset 6005f613dfdSUlrich Weigand // and add the rest to the base register (the stack or frame pointer). 6015f613dfdSUlrich Weigand if (!NewOpcode) { 6025f613dfdSUlrich Weigand uint64_t NumBytes = Offset - 0x7fff8; 6035f613dfdSUlrich Weigand emitIncrement(MBB, MBBI, DL, MBBI->getOperand(AddrOpNo).getReg(), 6045f613dfdSUlrich Weigand NumBytes, ZII); 6055f613dfdSUlrich Weigand Offset -= NumBytes; 6065f613dfdSUlrich Weigand NewOpcode = ZII->getOpcodeForOffset(Opcode, Offset); 6075f613dfdSUlrich Weigand assert(NewOpcode && "No restore instruction available"); 6085f613dfdSUlrich Weigand } 6095f613dfdSUlrich Weigand 6105f613dfdSUlrich Weigand MBBI->setDesc(ZII->get(NewOpcode)); 6115f613dfdSUlrich Weigand MBBI->getOperand(AddrOpNo + 1).ChangeToImmediate(Offset); 6125f613dfdSUlrich Weigand } else if (StackSize) { 6135f613dfdSUlrich Weigand DebugLoc DL = MBBI->getDebugLoc(); 6145f613dfdSUlrich Weigand emitIncrement(MBB, MBBI, DL, SystemZ::R15D, StackSize, ZII); 6155f613dfdSUlrich Weigand } 6165f613dfdSUlrich Weigand } 6175f613dfdSUlrich Weigand 618515bfc66SJonas Paulsson void SystemZFrameLowering::inlineStackProbe(MachineFunction &MF, 619515bfc66SJonas Paulsson MachineBasicBlock &PrologMBB) const { 620515bfc66SJonas Paulsson auto *ZII = 621515bfc66SJonas Paulsson static_cast<const SystemZInstrInfo *>(MF.getSubtarget().getInstrInfo()); 622515bfc66SJonas Paulsson const SystemZSubtarget &STI = MF.getSubtarget<SystemZSubtarget>(); 623515bfc66SJonas Paulsson const SystemZTargetLowering &TLI = *STI.getTargetLowering(); 624515bfc66SJonas Paulsson 625515bfc66SJonas Paulsson MachineInstr *StackAllocMI = nullptr; 626515bfc66SJonas Paulsson for (MachineInstr &MI : PrologMBB) 627515bfc66SJonas Paulsson if (MI.getOpcode() == SystemZ::PROBED_STACKALLOC) { 628515bfc66SJonas Paulsson StackAllocMI = &MI; 629515bfc66SJonas Paulsson break; 630515bfc66SJonas Paulsson } 631515bfc66SJonas Paulsson if (StackAllocMI == nullptr) 632515bfc66SJonas Paulsson return; 633515bfc66SJonas Paulsson uint64_t StackSize = StackAllocMI->getOperand(0).getImm(); 634515bfc66SJonas Paulsson const unsigned ProbeSize = TLI.getStackProbeSize(MF); 635515bfc66SJonas Paulsson uint64_t NumFullBlocks = StackSize / ProbeSize; 636515bfc66SJonas Paulsson uint64_t Residual = StackSize % ProbeSize; 637515bfc66SJonas Paulsson int64_t SPOffsetFromCFA = -SystemZMC::CFAOffsetFromInitialSP; 638515bfc66SJonas Paulsson MachineBasicBlock *MBB = &PrologMBB; 639515bfc66SJonas Paulsson MachineBasicBlock::iterator MBBI = StackAllocMI; 640515bfc66SJonas Paulsson const DebugLoc DL = StackAllocMI->getDebugLoc(); 641515bfc66SJonas Paulsson 642515bfc66SJonas Paulsson // Allocate a block of Size bytes on the stack and probe it. 643515bfc66SJonas Paulsson auto allocateAndProbe = [&](MachineBasicBlock &InsMBB, 644515bfc66SJonas Paulsson MachineBasicBlock::iterator InsPt, unsigned Size, 645515bfc66SJonas Paulsson bool EmitCFI) -> void { 646515bfc66SJonas Paulsson emitIncrement(InsMBB, InsPt, DL, SystemZ::R15D, -int64_t(Size), ZII); 647515bfc66SJonas Paulsson if (EmitCFI) { 648515bfc66SJonas Paulsson SPOffsetFromCFA -= Size; 649515bfc66SJonas Paulsson buildCFAOffs(InsMBB, InsPt, DL, SPOffsetFromCFA, ZII); 650515bfc66SJonas Paulsson } 651515bfc66SJonas Paulsson // Probe by means of a volatile compare. 652515bfc66SJonas Paulsson MachineMemOperand *MMO = MF.getMachineMemOperand(MachinePointerInfo(), 653515bfc66SJonas Paulsson MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad, 8, Align(1)); 654515bfc66SJonas Paulsson BuildMI(InsMBB, InsPt, DL, ZII->get(SystemZ::CG)) 655515bfc66SJonas Paulsson .addReg(SystemZ::R0D, RegState::Undef) 656515bfc66SJonas Paulsson .addReg(SystemZ::R15D).addImm(Size - 8).addReg(0) 657515bfc66SJonas Paulsson .addMemOperand(MMO); 658515bfc66SJonas Paulsson }; 659515bfc66SJonas Paulsson 660515bfc66SJonas Paulsson if (NumFullBlocks < 3) { 661515bfc66SJonas Paulsson // Emit unrolled probe statements. 662515bfc66SJonas Paulsson for (unsigned int i = 0; i < NumFullBlocks; i++) 663515bfc66SJonas Paulsson allocateAndProbe(*MBB, MBBI, ProbeSize, true/*EmitCFI*/); 664515bfc66SJonas Paulsson } else { 665515bfc66SJonas Paulsson // Emit a loop probing the pages. 666515bfc66SJonas Paulsson uint64_t LoopAlloc = ProbeSize * NumFullBlocks; 667515bfc66SJonas Paulsson SPOffsetFromCFA -= LoopAlloc; 668515bfc66SJonas Paulsson 669515bfc66SJonas Paulsson BuildMI(*MBB, MBBI, DL, ZII->get(SystemZ::LGR), SystemZ::R1D) 670515bfc66SJonas Paulsson .addReg(SystemZ::R15D); 671515bfc66SJonas Paulsson buildDefCFAReg(*MBB, MBBI, DL, SystemZ::R1D, ZII); 672515bfc66SJonas Paulsson emitIncrement(*MBB, MBBI, DL, SystemZ::R1D, -int64_t(LoopAlloc), ZII); 673515bfc66SJonas Paulsson buildCFAOffs(*MBB, MBBI, DL, -int64_t(SystemZMC::CallFrameSize + LoopAlloc), 674515bfc66SJonas Paulsson ZII); 675515bfc66SJonas Paulsson 676515bfc66SJonas Paulsson MachineBasicBlock *DoneMBB = SystemZ::splitBlockBefore(MBBI, MBB); 677515bfc66SJonas Paulsson MachineBasicBlock *LoopMBB = SystemZ::emitBlockAfter(MBB); 678515bfc66SJonas Paulsson MBB->addSuccessor(LoopMBB); 679515bfc66SJonas Paulsson LoopMBB->addSuccessor(LoopMBB); 680515bfc66SJonas Paulsson LoopMBB->addSuccessor(DoneMBB); 681515bfc66SJonas Paulsson 682515bfc66SJonas Paulsson MBB = LoopMBB; 683515bfc66SJonas Paulsson allocateAndProbe(*MBB, MBB->end(), ProbeSize, false/*EmitCFI*/); 684515bfc66SJonas Paulsson BuildMI(*MBB, MBB->end(), DL, ZII->get(SystemZ::CLGR)) 685515bfc66SJonas Paulsson .addReg(SystemZ::R15D).addReg(SystemZ::R1D); 686515bfc66SJonas Paulsson BuildMI(*MBB, MBB->end(), DL, ZII->get(SystemZ::BRC)) 687515bfc66SJonas Paulsson .addImm(SystemZ::CCMASK_ICMP).addImm(SystemZ::CCMASK_CMP_GT).addMBB(MBB); 688515bfc66SJonas Paulsson 689515bfc66SJonas Paulsson MBB = DoneMBB; 690515bfc66SJonas Paulsson MBBI = DoneMBB->begin(); 691515bfc66SJonas Paulsson buildDefCFAReg(*MBB, MBBI, DL, SystemZ::R15D, ZII); 692515bfc66SJonas Paulsson 693515bfc66SJonas Paulsson recomputeLiveIns(*DoneMBB); 694515bfc66SJonas Paulsson recomputeLiveIns(*LoopMBB); 695515bfc66SJonas Paulsson } 696515bfc66SJonas Paulsson 697515bfc66SJonas Paulsson if (Residual) 698515bfc66SJonas Paulsson allocateAndProbe(*MBB, MBBI, Residual, true/*EmitCFI*/); 699515bfc66SJonas Paulsson 700515bfc66SJonas Paulsson StackAllocMI->eraseFromParent(); 701515bfc66SJonas Paulsson } 702515bfc66SJonas Paulsson 7035f613dfdSUlrich Weigand bool SystemZFrameLowering::hasFP(const MachineFunction &MF) const { 7045f613dfdSUlrich Weigand return (MF.getTarget().Options.DisableFramePointerElim(MF) || 705941a705bSMatthias Braun MF.getFrameInfo().hasVarSizedObjects() || 7065f613dfdSUlrich Weigand MF.getInfo<SystemZMachineFunctionInfo>()->getManipulatesSP()); 7075f613dfdSUlrich Weigand } 7085f613dfdSUlrich Weigand 7095f613dfdSUlrich Weigand bool 7105f613dfdSUlrich Weigand SystemZFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { 7115f613dfdSUlrich Weigand // The ABI requires us to allocate 160 bytes of stack space for the callee, 7125f613dfdSUlrich Weigand // with any outgoing stack arguments being placed above that. It seems 7135f613dfdSUlrich Weigand // better to make that area a permanent feature of the frame even if 7145f613dfdSUlrich Weigand // we're using a frame pointer. 7155f613dfdSUlrich Weigand return true; 7165f613dfdSUlrich Weigand } 7175f613dfdSUlrich Weigand 71861f5ba5cSJonas Paulsson int SystemZFrameLowering::getFrameIndexReference(const MachineFunction &MF, 71961f5ba5cSJonas Paulsson int FI, 7202481f26aSMatt Arsenault Register &FrameReg) const { 72161f5ba5cSJonas Paulsson // Our incoming SP is actually SystemZMC::CallFrameSize below the CFA, so 72261f5ba5cSJonas Paulsson // add that difference here. 72361f5ba5cSJonas Paulsson int64_t Offset = 72461f5ba5cSJonas Paulsson TargetFrameLowering::getFrameIndexReference(MF, FI, FrameReg); 72561f5ba5cSJonas Paulsson return Offset + SystemZMC::CallFrameSize; 72661f5ba5cSJonas Paulsson } 72761f5ba5cSJonas Paulsson 728e1a2e90fSHans Wennborg MachineBasicBlock::iterator SystemZFrameLowering:: 7295f613dfdSUlrich Weigand eliminateCallFramePseudoInstr(MachineFunction &MF, 7305f613dfdSUlrich Weigand MachineBasicBlock &MBB, 7315f613dfdSUlrich Weigand MachineBasicBlock::iterator MI) const { 7325f613dfdSUlrich Weigand switch (MI->getOpcode()) { 7335f613dfdSUlrich Weigand case SystemZ::ADJCALLSTACKDOWN: 7345f613dfdSUlrich Weigand case SystemZ::ADJCALLSTACKUP: 7355f613dfdSUlrich Weigand assert(hasReservedCallFrame(MF) && 7365f613dfdSUlrich Weigand "ADJSTACKDOWN and ADJSTACKUP should be no-ops"); 737e1a2e90fSHans Wennborg return MBB.erase(MI); 7385f613dfdSUlrich Weigand break; 7395f613dfdSUlrich Weigand 7405f613dfdSUlrich Weigand default: 7415f613dfdSUlrich Weigand llvm_unreachable("Unexpected call frame instruction"); 7425f613dfdSUlrich Weigand } 7435f613dfdSUlrich Weigand } 74461f5ba5cSJonas Paulsson 74582879c29SJonas Paulsson unsigned SystemZFrameLowering::getRegSpillOffset(MachineFunction &MF, 7462481f26aSMatt Arsenault Register Reg) const { 74782879c29SJonas Paulsson bool IsVarArg = MF.getFunction().isVarArg(); 74882879c29SJonas Paulsson bool BackChain = MF.getFunction().hasFnAttribute("backchain"); 74982879c29SJonas Paulsson bool SoftFloat = MF.getSubtarget<SystemZSubtarget>().hasSoftFloat(); 75082879c29SJonas Paulsson unsigned Offset = RegSpillOffsets[Reg]; 75182879c29SJonas Paulsson if (usePackedStack(MF) && !(IsVarArg && !SoftFloat)) { 75282879c29SJonas Paulsson if (SystemZ::GR64BitRegClass.contains(Reg)) 75382879c29SJonas Paulsson // Put all GPRs at the top of the Register save area with packed 75482879c29SJonas Paulsson // stack. Make room for the backchain if needed. 75582879c29SJonas Paulsson Offset += BackChain ? 24 : 32; 75682879c29SJonas Paulsson else 75782879c29SJonas Paulsson Offset = 0; 75882879c29SJonas Paulsson } 75982879c29SJonas Paulsson return Offset; 76082879c29SJonas Paulsson } 76182879c29SJonas Paulsson 76261f5ba5cSJonas Paulsson int SystemZFrameLowering:: 76361f5ba5cSJonas Paulsson getOrCreateFramePointerSaveIndex(MachineFunction &MF) const { 76461f5ba5cSJonas Paulsson SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); 76561f5ba5cSJonas Paulsson int FI = ZFI->getFramePointerSaveIndex(); 76661f5ba5cSJonas Paulsson if (!FI) { 76761f5ba5cSJonas Paulsson MachineFrameInfo &MFFrame = MF.getFrameInfo(); 76882879c29SJonas Paulsson // The back chain is stored topmost with packed-stack. 76982879c29SJonas Paulsson int Offset = usePackedStack(MF) ? -8 : -SystemZMC::CallFrameSize; 77082879c29SJonas Paulsson FI = MFFrame.CreateFixedObject(8, Offset, false); 77161f5ba5cSJonas Paulsson ZFI->setFramePointerSaveIndex(FI); 77261f5ba5cSJonas Paulsson } 77361f5ba5cSJonas Paulsson return FI; 77461f5ba5cSJonas Paulsson } 77582879c29SJonas Paulsson 77682879c29SJonas Paulsson bool SystemZFrameLowering::usePackedStack(MachineFunction &MF) const { 77782879c29SJonas Paulsson bool HasPackedStackAttr = MF.getFunction().hasFnAttribute("packed-stack"); 77882879c29SJonas Paulsson bool BackChain = MF.getFunction().hasFnAttribute("backchain"); 77982879c29SJonas Paulsson bool SoftFloat = MF.getSubtarget<SystemZSubtarget>().hasSoftFloat(); 78082879c29SJonas Paulsson if (HasPackedStackAttr && BackChain && !SoftFloat) 78182879c29SJonas Paulsson report_fatal_error("packed-stack + backchain + hard-float is unsupported."); 78282879c29SJonas Paulsson bool CallConv = MF.getFunction().getCallingConv() != CallingConv::GHC; 78382879c29SJonas Paulsson return HasPackedStackAttr && CallConv; 78482879c29SJonas Paulsson } 785