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(); 3191606755dSJonas Paulsson SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); 3201606755dSJonas Paulsson MachineRegisterInfo *MRI = &MF.getRegInfo(); 32123762575SJonas Paulsson bool BackChain = MF.getFunction().hasFnAttribute("backchain"); 32261f5ba5cSJonas Paulsson 32323762575SJonas Paulsson if (!usePackedStack(MF) || BackChain) 32423762575SJonas Paulsson // Create the incoming register save area. 32561f5ba5cSJonas Paulsson getOrCreateFramePointerSaveIndex(MF); 32661f5ba5cSJonas Paulsson 327af98b748SUlrich Weigand // Get the size of our stack frame to be allocated ... 328af98b748SUlrich Weigand uint64_t StackSize = (MFFrame.estimateStackSize(MF) + 329af98b748SUlrich Weigand SystemZMC::CallFrameSize); 330af98b748SUlrich Weigand // ... and the maximum offset we may need to reach into the 331af98b748SUlrich Weigand // caller's frame to access the save area or stack arguments. 33261f5ba5cSJonas Paulsson int64_t MaxArgOffset = 0; 333af98b748SUlrich Weigand for (int I = MFFrame.getObjectIndexBegin(); I != 0; ++I) 334af98b748SUlrich Weigand if (MFFrame.getObjectOffset(I) >= 0) { 33561f5ba5cSJonas Paulsson int64_t ArgOffset = MFFrame.getObjectOffset(I) + 336af98b748SUlrich Weigand MFFrame.getObjectSize(I); 337af98b748SUlrich Weigand MaxArgOffset = std::max(MaxArgOffset, ArgOffset); 338af98b748SUlrich Weigand } 339af98b748SUlrich Weigand 340af98b748SUlrich Weigand uint64_t MaxReach = StackSize + MaxArgOffset; 34123943229SRichard Sandiford if (!isUInt<12>(MaxReach)) { 34223943229SRichard Sandiford // We may need register scavenging slots if some parts of the frame 3435dd52f8cSRichard Sandiford // are outside the reach of an unsigned 12-bit displacement. 34423943229SRichard Sandiford // Create 2 for the case where both addresses in an MVC are 34523943229SRichard Sandiford // out of range. 34628de229bSGuillaume Chatelet RS->addScavengingFrameIndex(MFFrame.CreateStackObject(8, Align(8), false)); 34728de229bSGuillaume Chatelet RS->addScavengingFrameIndex(MFFrame.CreateStackObject(8, Align(8), false)); 34823943229SRichard Sandiford } 3491606755dSJonas Paulsson 3501606755dSJonas Paulsson // If R6 is used as an argument register it is still callee saved. If it in 3511606755dSJonas Paulsson // this case is not clobbered (and restored) it should never be marked as 3521606755dSJonas Paulsson // killed. 3531606755dSJonas Paulsson if (MF.front().isLiveIn(SystemZ::R6D) && 3541606755dSJonas Paulsson ZFI->getRestoreGPRRegs().LowGPR != SystemZ::R6D) 3551606755dSJonas Paulsson for (auto &MO : MRI->use_nodbg_operands(SystemZ::R6D)) 3561606755dSJonas Paulsson MO.setIsKill(false); 3575dd52f8cSRichard Sandiford } 3585dd52f8cSRichard Sandiford 3595f613dfdSUlrich Weigand // Emit instructions before MBBI (in MBB) to add NumBytes to Reg. 3605f613dfdSUlrich Weigand static void emitIncrement(MachineBasicBlock &MBB, 3612481f26aSMatt Arsenault MachineBasicBlock::iterator &MBBI, const DebugLoc &DL, 3622481f26aSMatt Arsenault Register Reg, int64_t NumBytes, 3635f613dfdSUlrich Weigand const TargetInstrInfo *TII) { 3645f613dfdSUlrich Weigand while (NumBytes) { 3655f613dfdSUlrich Weigand unsigned Opcode; 3665f613dfdSUlrich Weigand int64_t ThisVal = NumBytes; 3675f613dfdSUlrich Weigand if (isInt<16>(NumBytes)) 3685f613dfdSUlrich Weigand Opcode = SystemZ::AGHI; 3695f613dfdSUlrich Weigand else { 3705f613dfdSUlrich Weigand Opcode = SystemZ::AGFI; 3715f613dfdSUlrich Weigand // Make sure we maintain 8-byte stack alignment. 372fffd56ecSAlexey Samsonov int64_t MinVal = -uint64_t(1) << 31; 3735f613dfdSUlrich Weigand int64_t MaxVal = (int64_t(1) << 31) - 8; 3745f613dfdSUlrich Weigand if (ThisVal < MinVal) 3755f613dfdSUlrich Weigand ThisVal = MinVal; 3765f613dfdSUlrich Weigand else if (ThisVal > MaxVal) 3775f613dfdSUlrich Weigand ThisVal = MaxVal; 3785f613dfdSUlrich Weigand } 3795f613dfdSUlrich Weigand MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII->get(Opcode), Reg) 3805f613dfdSUlrich Weigand .addReg(Reg).addImm(ThisVal); 38114a44495SRichard Sandiford // The CC implicit def is dead. 3825f613dfdSUlrich Weigand MI->getOperand(3).setIsDead(); 3835f613dfdSUlrich Weigand NumBytes -= ThisVal; 3845f613dfdSUlrich Weigand } 3855f613dfdSUlrich Weigand } 3865f613dfdSUlrich Weigand 387515bfc66SJonas Paulsson // Add CFI for the new CFA offset. 388515bfc66SJonas Paulsson static void buildCFAOffs(MachineBasicBlock &MBB, 389515bfc66SJonas Paulsson MachineBasicBlock::iterator MBBI, 390515bfc66SJonas Paulsson const DebugLoc &DL, int Offset, 391515bfc66SJonas Paulsson const SystemZInstrInfo *ZII) { 392515bfc66SJonas Paulsson unsigned CFIIndex = MBB.getParent()->addFrameInst( 393515bfc66SJonas Paulsson MCCFIInstruction::cfiDefCfaOffset(nullptr, -Offset)); 394515bfc66SJonas Paulsson BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION)) 395515bfc66SJonas Paulsson .addCFIIndex(CFIIndex); 396515bfc66SJonas Paulsson } 397515bfc66SJonas Paulsson 398515bfc66SJonas Paulsson // Add CFI for the new frame location. 399515bfc66SJonas Paulsson static void buildDefCFAReg(MachineBasicBlock &MBB, 400515bfc66SJonas Paulsson MachineBasicBlock::iterator MBBI, 401515bfc66SJonas Paulsson const DebugLoc &DL, unsigned Reg, 402515bfc66SJonas Paulsson const SystemZInstrInfo *ZII) { 403515bfc66SJonas Paulsson MachineFunction &MF = *MBB.getParent(); 404515bfc66SJonas Paulsson MachineModuleInfo &MMI = MF.getMMI(); 405515bfc66SJonas Paulsson const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); 406515bfc66SJonas Paulsson unsigned RegNum = MRI->getDwarfRegNum(Reg, true); 407515bfc66SJonas Paulsson unsigned CFIIndex = MF.addFrameInst( 408515bfc66SJonas Paulsson MCCFIInstruction::createDefCfaRegister(nullptr, RegNum)); 409515bfc66SJonas Paulsson BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION)) 410515bfc66SJonas Paulsson .addCFIIndex(CFIIndex); 411515bfc66SJonas Paulsson } 412515bfc66SJonas Paulsson 41361b305edSQuentin Colombet void SystemZFrameLowering::emitPrologue(MachineFunction &MF, 41461b305edSQuentin Colombet MachineBasicBlock &MBB) const { 41561b305edSQuentin Colombet assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported"); 416515bfc66SJonas Paulsson const SystemZSubtarget &STI = MF.getSubtarget<SystemZSubtarget>(); 417515bfc66SJonas Paulsson const SystemZTargetLowering &TLI = *STI.getTargetLowering(); 418941a705bSMatthias Braun MachineFrameInfo &MFFrame = MF.getFrameInfo(); 419515bfc66SJonas Paulsson auto *ZII = static_cast<const SystemZInstrInfo *>(STI.getInstrInfo()); 4205f613dfdSUlrich Weigand SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); 4215f613dfdSUlrich Weigand MachineBasicBlock::iterator MBBI = MBB.begin(); 4225f613dfdSUlrich Weigand MachineModuleInfo &MMI = MF.getMMI(); 423bc07a890SBill Wendling const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); 424941a705bSMatthias Braun const std::vector<CalleeSavedInfo> &CSI = MFFrame.getCalleeSavedInfo(); 4255f613dfdSUlrich Weigand bool HasFP = hasFP(MF); 426057c5a6bSOleg Ranevskyy 42722f94291SUlrich Weigand // In GHC calling convention C stack space, including the ABI-defined 42822f94291SUlrich Weigand // 160-byte base area, is (de)allocated by GHC itself. This stack space may 42922f94291SUlrich Weigand // be used by LLVM as spill slots for the tail recursive GHC functions. Thus 43022f94291SUlrich Weigand // do not allocate stack space here, too. 43122f94291SUlrich Weigand if (MF.getFunction().getCallingConv() == CallingConv::GHC) { 43222f94291SUlrich Weigand if (MFFrame.getStackSize() > 2048 * sizeof(long)) { 43322f94291SUlrich Weigand report_fatal_error( 43422f94291SUlrich Weigand "Pre allocated stack space for GHC function is too small"); 43522f94291SUlrich Weigand } 43622f94291SUlrich Weigand if (HasFP) { 43722f94291SUlrich Weigand report_fatal_error( 43822f94291SUlrich Weigand "In GHC calling convention a frame pointer is not supported"); 43922f94291SUlrich Weigand } 44022f94291SUlrich Weigand MFFrame.setStackSize(MFFrame.getStackSize() + SystemZMC::CallFrameSize); 44122f94291SUlrich Weigand return; 44222f94291SUlrich Weigand } 44322f94291SUlrich Weigand 444057c5a6bSOleg Ranevskyy // Debug location must be unknown since the first debug location is used 445057c5a6bSOleg Ranevskyy // to determine the end of the prologue. 446057c5a6bSOleg Ranevskyy DebugLoc DL; 4475f613dfdSUlrich Weigand 4485f613dfdSUlrich Weigand // The current offset of the stack pointer from the CFA. 4495f613dfdSUlrich Weigand int64_t SPOffsetFromCFA = -SystemZMC::CFAOffsetFromInitialSP; 4505f613dfdSUlrich Weigand 45161f5ba5cSJonas Paulsson if (ZFI->getSpillGPRRegs().LowGPR) { 4525f613dfdSUlrich Weigand // Skip over the GPR saves. 4535f613dfdSUlrich Weigand if (MBBI != MBB.end() && MBBI->getOpcode() == SystemZ::STMG) 4545f613dfdSUlrich Weigand ++MBBI; 4555f613dfdSUlrich Weigand else 4565f613dfdSUlrich Weigand llvm_unreachable("Couldn't skip over GPR saves"); 4575f613dfdSUlrich Weigand 4585f613dfdSUlrich Weigand // Add CFI for the GPR saves. 45928c111ecSRichard Sandiford for (auto &Save : CSI) { 46028c111ecSRichard Sandiford unsigned Reg = Save.getReg(); 4615f613dfdSUlrich Weigand if (SystemZ::GR64BitRegClass.contains(Reg)) { 46261f5ba5cSJonas Paulsson int FI = Save.getFrameIdx(); 46361f5ba5cSJonas Paulsson int64_t Offset = MFFrame.getObjectOffset(FI); 464f23ef437SMatthias Braun unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( 465b1f25f1bSRafael Espindola nullptr, MRI->getDwarfRegNum(Reg, true), Offset)); 466b1f25f1bSRafael Espindola BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION)) 467b1f25f1bSRafael Espindola .addCFIIndex(CFIIndex); 4685f613dfdSUlrich Weigand } 4695f613dfdSUlrich Weigand } 4705f613dfdSUlrich Weigand } 4715f613dfdSUlrich Weigand 47232063888SUlrich Weigand uint64_t StackSize = MFFrame.getStackSize(); 47332063888SUlrich Weigand // We need to allocate the ABI-defined 160-byte base area whenever 47432063888SUlrich Weigand // we allocate stack space for our own use and whenever we call another 47532063888SUlrich Weigand // function. 47661f5ba5cSJonas Paulsson bool HasStackObject = false; 47761f5ba5cSJonas Paulsson for (unsigned i = 0, e = MFFrame.getObjectIndexEnd(); i != e; ++i) 47861f5ba5cSJonas Paulsson if (!MFFrame.isDeadObjectIndex(i)) { 47961f5ba5cSJonas Paulsson HasStackObject = true; 48061f5ba5cSJonas Paulsson break; 48132063888SUlrich Weigand } 48261f5ba5cSJonas Paulsson if (HasStackObject || MFFrame.hasCalls()) 48361f5ba5cSJonas Paulsson StackSize += SystemZMC::CallFrameSize; 48461f5ba5cSJonas Paulsson // Don't allocate the incoming reg save area. 48561f5ba5cSJonas Paulsson StackSize = StackSize > SystemZMC::CallFrameSize 48661f5ba5cSJonas Paulsson ? StackSize - SystemZMC::CallFrameSize 48761f5ba5cSJonas Paulsson : 0; 48861f5ba5cSJonas Paulsson MFFrame.setStackSize(StackSize); 48932063888SUlrich Weigand 4905f613dfdSUlrich Weigand if (StackSize) { 4915f613dfdSUlrich Weigand // Allocate StackSize bytes. 4925f613dfdSUlrich Weigand int64_t Delta = -int64_t(StackSize); 493515bfc66SJonas Paulsson const unsigned ProbeSize = TLI.getStackProbeSize(MF); 494515bfc66SJonas Paulsson bool FreeProbe = (ZFI->getSpillGPRRegs().GPROffset && 495515bfc66SJonas Paulsson (ZFI->getSpillGPRRegs().GPROffset + StackSize) < ProbeSize); 496515bfc66SJonas Paulsson if (!FreeProbe && 497515bfc66SJonas Paulsson MF.getSubtarget().getTargetLowering()->hasInlineStackProbe(MF)) { 498515bfc66SJonas Paulsson // Stack probing may involve looping, but splitting the prologue block 499515bfc66SJonas Paulsson // is not possible at this point since it would invalidate the 500515bfc66SJonas Paulsson // SaveBlocks / RestoreBlocks sets of PEI in the single block function 501515bfc66SJonas Paulsson // case. Build a pseudo to be handled later by inlineStackProbe(). 502515bfc66SJonas Paulsson BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::PROBED_STACKALLOC)) 503515bfc66SJonas Paulsson .addImm(StackSize); 504515bfc66SJonas Paulsson } 505515bfc66SJonas Paulsson else { 50642f628c8SJonas Paulsson bool StoreBackchain = MF.getFunction().hasFnAttribute("backchain"); 50742f628c8SJonas Paulsson // If we need backchain, save current stack pointer. R1 is free at 50842f628c8SJonas Paulsson // this point. 50942f628c8SJonas Paulsson if (StoreBackchain) 51042f628c8SJonas Paulsson BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::LGR)) 51142f628c8SJonas Paulsson .addReg(SystemZ::R1D, RegState::Define).addReg(SystemZ::R15D); 5125f613dfdSUlrich Weigand emitIncrement(MBB, MBBI, DL, SystemZ::R15D, Delta, ZII); 513515bfc66SJonas Paulsson buildCFAOffs(MBB, MBBI, DL, SPOffsetFromCFA + Delta, ZII); 514*653b9769SJonas Paulsson if (StoreBackchain) 515ad1482c6SMarcin Koscielnicki BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::STG)) 51682879c29SJonas Paulsson .addReg(SystemZ::R1D, RegState::Kill).addReg(SystemZ::R15D) 517*653b9769SJonas Paulsson .addImm(getBackchainOffset(MF)).addReg(0); 5185f613dfdSUlrich Weigand } 51942f628c8SJonas Paulsson SPOffsetFromCFA += Delta; 52042f628c8SJonas Paulsson } 5215f613dfdSUlrich Weigand 5225f613dfdSUlrich Weigand if (HasFP) { 5235f613dfdSUlrich Weigand // Copy the base of the frame to R11. 5245f613dfdSUlrich Weigand BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::LGR), SystemZ::R11D) 5255f613dfdSUlrich Weigand .addReg(SystemZ::R15D); 5265f613dfdSUlrich Weigand 5275f613dfdSUlrich Weigand // Add CFI for the new frame location. 528515bfc66SJonas Paulsson buildDefCFAReg(MBB, MBBI, DL, SystemZ::R11D, ZII); 5295f613dfdSUlrich Weigand 5305f613dfdSUlrich Weigand // Mark the FramePtr as live at the beginning of every block except 5315f613dfdSUlrich Weigand // the entry block. (We'll have marked R11 as live on entry when 5325f613dfdSUlrich Weigand // saving the GPRs.) 53328c111ecSRichard Sandiford for (auto I = std::next(MF.begin()), E = MF.end(); I != E; ++I) 5345f613dfdSUlrich Weigand I->addLiveIn(SystemZ::R11D); 5355f613dfdSUlrich Weigand } 5365f613dfdSUlrich Weigand 5378b19be46SUlrich Weigand // Skip over the FPR/VR saves. 538b1f25f1bSRafael Espindola SmallVector<unsigned, 8> CFIIndexes; 53928c111ecSRichard Sandiford for (auto &Save : CSI) { 54028c111ecSRichard Sandiford unsigned Reg = Save.getReg(); 5415f613dfdSUlrich Weigand if (SystemZ::FP64BitRegClass.contains(Reg)) { 5425f613dfdSUlrich Weigand if (MBBI != MBB.end() && 5435f613dfdSUlrich Weigand (MBBI->getOpcode() == SystemZ::STD || 5445f613dfdSUlrich Weigand MBBI->getOpcode() == SystemZ::STDY)) 5455f613dfdSUlrich Weigand ++MBBI; 5465f613dfdSUlrich Weigand else 5475f613dfdSUlrich Weigand llvm_unreachable("Couldn't skip over FPR save"); 5488b19be46SUlrich Weigand } else if (SystemZ::VR128BitRegClass.contains(Reg)) { 5498b19be46SUlrich Weigand if (MBBI != MBB.end() && 5508b19be46SUlrich Weigand MBBI->getOpcode() == SystemZ::VST) 5518b19be46SUlrich Weigand ++MBBI; 5528b19be46SUlrich Weigand else 5538b19be46SUlrich Weigand llvm_unreachable("Couldn't skip over VR save"); 5548b19be46SUlrich Weigand } else 5558b19be46SUlrich Weigand continue; 5565f613dfdSUlrich Weigand 5575f613dfdSUlrich Weigand // Add CFI for the this save. 55828c111ecSRichard Sandiford unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true); 5592481f26aSMatt Arsenault Register IgnoredFrameReg; 5605567bafeSJames Y Knight int64_t Offset = 561d57bba7cSSander de Smalen getFrameIndexReference(MF, Save.getFrameIdx(), IgnoredFrameReg) 562d57bba7cSSander de Smalen .getFixed(); 5635567bafeSJames Y Knight 564f23ef437SMatthias Braun unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( 565b1f25f1bSRafael Espindola nullptr, DwarfReg, SPOffsetFromCFA + Offset)); 566b1f25f1bSRafael Espindola CFIIndexes.push_back(CFIIndex); 5675f613dfdSUlrich Weigand } 5688b19be46SUlrich Weigand // Complete the CFI for the FPR/VR saves, modelling them as taking effect 5695f613dfdSUlrich Weigand // after the last save. 570b1f25f1bSRafael Espindola for (auto CFIIndex : CFIIndexes) { 571b1f25f1bSRafael Espindola BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION)) 572b1f25f1bSRafael Espindola .addCFIIndex(CFIIndex); 573b1f25f1bSRafael Espindola } 5745f613dfdSUlrich Weigand } 5755f613dfdSUlrich Weigand 5765f613dfdSUlrich Weigand void SystemZFrameLowering::emitEpilogue(MachineFunction &MF, 5775f613dfdSUlrich Weigand MachineBasicBlock &MBB) const { 5785f613dfdSUlrich Weigand MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); 579fc6de428SEric Christopher auto *ZII = 580fc6de428SEric Christopher static_cast<const SystemZInstrInfo *>(MF.getSubtarget().getInstrInfo()); 5815f613dfdSUlrich Weigand SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); 58232063888SUlrich Weigand MachineFrameInfo &MFFrame = MF.getFrameInfo(); 5835f613dfdSUlrich Weigand 58422f94291SUlrich Weigand // See SystemZFrameLowering::emitPrologue 58522f94291SUlrich Weigand if (MF.getFunction().getCallingConv() == CallingConv::GHC) 58622f94291SUlrich Weigand return; 58722f94291SUlrich Weigand 5885f613dfdSUlrich Weigand // Skip the return instruction. 589709bda66SRichard Sandiford assert(MBBI->isReturn() && "Can only insert epilogue into returning blocks"); 5905f613dfdSUlrich Weigand 59132063888SUlrich Weigand uint64_t StackSize = MFFrame.getStackSize(); 59261f5ba5cSJonas Paulsson if (ZFI->getRestoreGPRRegs().LowGPR) { 5935f613dfdSUlrich Weigand --MBBI; 5945f613dfdSUlrich Weigand unsigned Opcode = MBBI->getOpcode(); 5955f613dfdSUlrich Weigand if (Opcode != SystemZ::LMG) 5965f613dfdSUlrich Weigand llvm_unreachable("Expected to see callee-save register restore code"); 5975f613dfdSUlrich Weigand 5985f613dfdSUlrich Weigand unsigned AddrOpNo = 2; 5995f613dfdSUlrich Weigand DebugLoc DL = MBBI->getDebugLoc(); 6005f613dfdSUlrich Weigand uint64_t Offset = StackSize + MBBI->getOperand(AddrOpNo + 1).getImm(); 6015f613dfdSUlrich Weigand unsigned NewOpcode = ZII->getOpcodeForOffset(Opcode, Offset); 6025f613dfdSUlrich Weigand 6035f613dfdSUlrich Weigand // If the offset is too large, use the largest stack-aligned offset 6045f613dfdSUlrich Weigand // and add the rest to the base register (the stack or frame pointer). 6055f613dfdSUlrich Weigand if (!NewOpcode) { 6065f613dfdSUlrich Weigand uint64_t NumBytes = Offset - 0x7fff8; 6075f613dfdSUlrich Weigand emitIncrement(MBB, MBBI, DL, MBBI->getOperand(AddrOpNo).getReg(), 6085f613dfdSUlrich Weigand NumBytes, ZII); 6095f613dfdSUlrich Weigand Offset -= NumBytes; 6105f613dfdSUlrich Weigand NewOpcode = ZII->getOpcodeForOffset(Opcode, Offset); 6115f613dfdSUlrich Weigand assert(NewOpcode && "No restore instruction available"); 6125f613dfdSUlrich Weigand } 6135f613dfdSUlrich Weigand 6145f613dfdSUlrich Weigand MBBI->setDesc(ZII->get(NewOpcode)); 6155f613dfdSUlrich Weigand MBBI->getOperand(AddrOpNo + 1).ChangeToImmediate(Offset); 6165f613dfdSUlrich Weigand } else if (StackSize) { 6175f613dfdSUlrich Weigand DebugLoc DL = MBBI->getDebugLoc(); 6185f613dfdSUlrich Weigand emitIncrement(MBB, MBBI, DL, SystemZ::R15D, StackSize, ZII); 6195f613dfdSUlrich Weigand } 6205f613dfdSUlrich Weigand } 6215f613dfdSUlrich Weigand 622515bfc66SJonas Paulsson void SystemZFrameLowering::inlineStackProbe(MachineFunction &MF, 623515bfc66SJonas Paulsson MachineBasicBlock &PrologMBB) const { 624515bfc66SJonas Paulsson auto *ZII = 625515bfc66SJonas Paulsson static_cast<const SystemZInstrInfo *>(MF.getSubtarget().getInstrInfo()); 626515bfc66SJonas Paulsson const SystemZSubtarget &STI = MF.getSubtarget<SystemZSubtarget>(); 627515bfc66SJonas Paulsson const SystemZTargetLowering &TLI = *STI.getTargetLowering(); 628515bfc66SJonas Paulsson 629515bfc66SJonas Paulsson MachineInstr *StackAllocMI = nullptr; 630515bfc66SJonas Paulsson for (MachineInstr &MI : PrologMBB) 631515bfc66SJonas Paulsson if (MI.getOpcode() == SystemZ::PROBED_STACKALLOC) { 632515bfc66SJonas Paulsson StackAllocMI = &MI; 633515bfc66SJonas Paulsson break; 634515bfc66SJonas Paulsson } 635515bfc66SJonas Paulsson if (StackAllocMI == nullptr) 636515bfc66SJonas Paulsson return; 637515bfc66SJonas Paulsson uint64_t StackSize = StackAllocMI->getOperand(0).getImm(); 638515bfc66SJonas Paulsson const unsigned ProbeSize = TLI.getStackProbeSize(MF); 639515bfc66SJonas Paulsson uint64_t NumFullBlocks = StackSize / ProbeSize; 640515bfc66SJonas Paulsson uint64_t Residual = StackSize % ProbeSize; 641515bfc66SJonas Paulsson int64_t SPOffsetFromCFA = -SystemZMC::CFAOffsetFromInitialSP; 642515bfc66SJonas Paulsson MachineBasicBlock *MBB = &PrologMBB; 643515bfc66SJonas Paulsson MachineBasicBlock::iterator MBBI = StackAllocMI; 644515bfc66SJonas Paulsson const DebugLoc DL = StackAllocMI->getDebugLoc(); 645515bfc66SJonas Paulsson 646515bfc66SJonas Paulsson // Allocate a block of Size bytes on the stack and probe it. 647515bfc66SJonas Paulsson auto allocateAndProbe = [&](MachineBasicBlock &InsMBB, 648515bfc66SJonas Paulsson MachineBasicBlock::iterator InsPt, unsigned Size, 649515bfc66SJonas Paulsson bool EmitCFI) -> void { 650515bfc66SJonas Paulsson emitIncrement(InsMBB, InsPt, DL, SystemZ::R15D, -int64_t(Size), ZII); 651515bfc66SJonas Paulsson if (EmitCFI) { 652515bfc66SJonas Paulsson SPOffsetFromCFA -= Size; 653515bfc66SJonas Paulsson buildCFAOffs(InsMBB, InsPt, DL, SPOffsetFromCFA, ZII); 654515bfc66SJonas Paulsson } 655515bfc66SJonas Paulsson // Probe by means of a volatile compare. 656515bfc66SJonas Paulsson MachineMemOperand *MMO = MF.getMachineMemOperand(MachinePointerInfo(), 657515bfc66SJonas Paulsson MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad, 8, Align(1)); 658515bfc66SJonas Paulsson BuildMI(InsMBB, InsPt, DL, ZII->get(SystemZ::CG)) 659515bfc66SJonas Paulsson .addReg(SystemZ::R0D, RegState::Undef) 660515bfc66SJonas Paulsson .addReg(SystemZ::R15D).addImm(Size - 8).addReg(0) 661515bfc66SJonas Paulsson .addMemOperand(MMO); 662515bfc66SJonas Paulsson }; 663515bfc66SJonas Paulsson 66442f628c8SJonas Paulsson bool StoreBackchain = MF.getFunction().hasFnAttribute("backchain"); 66542f628c8SJonas Paulsson if (StoreBackchain) 66642f628c8SJonas Paulsson BuildMI(*MBB, MBBI, DL, ZII->get(SystemZ::LGR)) 66742f628c8SJonas Paulsson .addReg(SystemZ::R1D, RegState::Define).addReg(SystemZ::R15D); 66842f628c8SJonas Paulsson 66942f628c8SJonas Paulsson MachineBasicBlock *DoneMBB = nullptr; 67042f628c8SJonas Paulsson MachineBasicBlock *LoopMBB = nullptr; 671515bfc66SJonas Paulsson if (NumFullBlocks < 3) { 672515bfc66SJonas Paulsson // Emit unrolled probe statements. 673515bfc66SJonas Paulsson for (unsigned int i = 0; i < NumFullBlocks; i++) 674515bfc66SJonas Paulsson allocateAndProbe(*MBB, MBBI, ProbeSize, true/*EmitCFI*/); 675515bfc66SJonas Paulsson } else { 676515bfc66SJonas Paulsson // Emit a loop probing the pages. 677515bfc66SJonas Paulsson uint64_t LoopAlloc = ProbeSize * NumFullBlocks; 678515bfc66SJonas Paulsson SPOffsetFromCFA -= LoopAlloc; 679515bfc66SJonas Paulsson 68042f628c8SJonas Paulsson // Use R0D to hold the exit value. 68142f628c8SJonas Paulsson BuildMI(*MBB, MBBI, DL, ZII->get(SystemZ::LGR), SystemZ::R0D) 682515bfc66SJonas Paulsson .addReg(SystemZ::R15D); 68342f628c8SJonas Paulsson buildDefCFAReg(*MBB, MBBI, DL, SystemZ::R0D, ZII); 68442f628c8SJonas Paulsson emitIncrement(*MBB, MBBI, DL, SystemZ::R0D, -int64_t(LoopAlloc), ZII); 685515bfc66SJonas Paulsson buildCFAOffs(*MBB, MBBI, DL, -int64_t(SystemZMC::CallFrameSize + LoopAlloc), 686515bfc66SJonas Paulsson ZII); 687515bfc66SJonas Paulsson 68842f628c8SJonas Paulsson DoneMBB = SystemZ::splitBlockBefore(MBBI, MBB); 68942f628c8SJonas Paulsson LoopMBB = SystemZ::emitBlockAfter(MBB); 690515bfc66SJonas Paulsson MBB->addSuccessor(LoopMBB); 691515bfc66SJonas Paulsson LoopMBB->addSuccessor(LoopMBB); 692515bfc66SJonas Paulsson LoopMBB->addSuccessor(DoneMBB); 693515bfc66SJonas Paulsson 694515bfc66SJonas Paulsson MBB = LoopMBB; 695515bfc66SJonas Paulsson allocateAndProbe(*MBB, MBB->end(), ProbeSize, false/*EmitCFI*/); 696515bfc66SJonas Paulsson BuildMI(*MBB, MBB->end(), DL, ZII->get(SystemZ::CLGR)) 69742f628c8SJonas Paulsson .addReg(SystemZ::R15D).addReg(SystemZ::R0D); 698515bfc66SJonas Paulsson BuildMI(*MBB, MBB->end(), DL, ZII->get(SystemZ::BRC)) 699515bfc66SJonas Paulsson .addImm(SystemZ::CCMASK_ICMP).addImm(SystemZ::CCMASK_CMP_GT).addMBB(MBB); 700515bfc66SJonas Paulsson 701515bfc66SJonas Paulsson MBB = DoneMBB; 702515bfc66SJonas Paulsson MBBI = DoneMBB->begin(); 703515bfc66SJonas Paulsson buildDefCFAReg(*MBB, MBBI, DL, SystemZ::R15D, ZII); 704515bfc66SJonas Paulsson } 705515bfc66SJonas Paulsson 706515bfc66SJonas Paulsson if (Residual) 707515bfc66SJonas Paulsson allocateAndProbe(*MBB, MBBI, Residual, true/*EmitCFI*/); 708515bfc66SJonas Paulsson 709*653b9769SJonas Paulsson if (StoreBackchain) 71042f628c8SJonas Paulsson BuildMI(*MBB, MBBI, DL, ZII->get(SystemZ::STG)) 71142f628c8SJonas Paulsson .addReg(SystemZ::R1D, RegState::Kill).addReg(SystemZ::R15D) 712*653b9769SJonas Paulsson .addImm(getBackchainOffset(MF)).addReg(0); 71342f628c8SJonas Paulsson 714515bfc66SJonas Paulsson StackAllocMI->eraseFromParent(); 71542f628c8SJonas Paulsson if (DoneMBB != nullptr) { 71642f628c8SJonas Paulsson // Compute the live-in lists for the new blocks. 71742f628c8SJonas Paulsson recomputeLiveIns(*DoneMBB); 71842f628c8SJonas Paulsson recomputeLiveIns(*LoopMBB); 71942f628c8SJonas Paulsson } 720515bfc66SJonas Paulsson } 721515bfc66SJonas Paulsson 7225f613dfdSUlrich Weigand bool SystemZFrameLowering::hasFP(const MachineFunction &MF) const { 7235f613dfdSUlrich Weigand return (MF.getTarget().Options.DisableFramePointerElim(MF) || 724941a705bSMatthias Braun MF.getFrameInfo().hasVarSizedObjects() || 7255f613dfdSUlrich Weigand MF.getInfo<SystemZMachineFunctionInfo>()->getManipulatesSP()); 7265f613dfdSUlrich Weigand } 7275f613dfdSUlrich Weigand 7285f613dfdSUlrich Weigand bool 7295f613dfdSUlrich Weigand SystemZFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { 7305f613dfdSUlrich Weigand // The ABI requires us to allocate 160 bytes of stack space for the callee, 7315f613dfdSUlrich Weigand // with any outgoing stack arguments being placed above that. It seems 7325f613dfdSUlrich Weigand // better to make that area a permanent feature of the frame even if 7335f613dfdSUlrich Weigand // we're using a frame pointer. 7345f613dfdSUlrich Weigand return true; 7355f613dfdSUlrich Weigand } 7365f613dfdSUlrich Weigand 737d57bba7cSSander de Smalen StackOffset 738d57bba7cSSander de Smalen SystemZFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, 7392481f26aSMatt Arsenault Register &FrameReg) const { 74061f5ba5cSJonas Paulsson // Our incoming SP is actually SystemZMC::CallFrameSize below the CFA, so 74161f5ba5cSJonas Paulsson // add that difference here. 742d57bba7cSSander de Smalen StackOffset Offset = 74361f5ba5cSJonas Paulsson TargetFrameLowering::getFrameIndexReference(MF, FI, FrameReg); 744d57bba7cSSander de Smalen return Offset + StackOffset::getFixed(SystemZMC::CallFrameSize); 74561f5ba5cSJonas Paulsson } 74661f5ba5cSJonas Paulsson 747e1a2e90fSHans Wennborg MachineBasicBlock::iterator SystemZFrameLowering:: 7485f613dfdSUlrich Weigand eliminateCallFramePseudoInstr(MachineFunction &MF, 7495f613dfdSUlrich Weigand MachineBasicBlock &MBB, 7505f613dfdSUlrich Weigand MachineBasicBlock::iterator MI) const { 7515f613dfdSUlrich Weigand switch (MI->getOpcode()) { 7525f613dfdSUlrich Weigand case SystemZ::ADJCALLSTACKDOWN: 7535f613dfdSUlrich Weigand case SystemZ::ADJCALLSTACKUP: 7545f613dfdSUlrich Weigand assert(hasReservedCallFrame(MF) && 7555f613dfdSUlrich Weigand "ADJSTACKDOWN and ADJSTACKUP should be no-ops"); 756e1a2e90fSHans Wennborg return MBB.erase(MI); 7575f613dfdSUlrich Weigand break; 7585f613dfdSUlrich Weigand 7595f613dfdSUlrich Weigand default: 7605f613dfdSUlrich Weigand llvm_unreachable("Unexpected call frame instruction"); 7615f613dfdSUlrich Weigand } 7625f613dfdSUlrich Weigand } 76361f5ba5cSJonas Paulsson 76482879c29SJonas Paulsson unsigned SystemZFrameLowering::getRegSpillOffset(MachineFunction &MF, 7652481f26aSMatt Arsenault Register Reg) const { 76682879c29SJonas Paulsson bool IsVarArg = MF.getFunction().isVarArg(); 76782879c29SJonas Paulsson bool BackChain = MF.getFunction().hasFnAttribute("backchain"); 76882879c29SJonas Paulsson bool SoftFloat = MF.getSubtarget<SystemZSubtarget>().hasSoftFloat(); 76982879c29SJonas Paulsson unsigned Offset = RegSpillOffsets[Reg]; 77082879c29SJonas Paulsson if (usePackedStack(MF) && !(IsVarArg && !SoftFloat)) { 77182879c29SJonas Paulsson if (SystemZ::GR64BitRegClass.contains(Reg)) 77282879c29SJonas Paulsson // Put all GPRs at the top of the Register save area with packed 77382879c29SJonas Paulsson // stack. Make room for the backchain if needed. 77482879c29SJonas Paulsson Offset += BackChain ? 24 : 32; 77582879c29SJonas Paulsson else 77682879c29SJonas Paulsson Offset = 0; 77782879c29SJonas Paulsson } 77882879c29SJonas Paulsson return Offset; 77982879c29SJonas Paulsson } 78082879c29SJonas Paulsson 78161f5ba5cSJonas Paulsson int SystemZFrameLowering:: 78261f5ba5cSJonas Paulsson getOrCreateFramePointerSaveIndex(MachineFunction &MF) const { 78361f5ba5cSJonas Paulsson SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); 78461f5ba5cSJonas Paulsson int FI = ZFI->getFramePointerSaveIndex(); 78561f5ba5cSJonas Paulsson if (!FI) { 78661f5ba5cSJonas Paulsson MachineFrameInfo &MFFrame = MF.getFrameInfo(); 787*653b9769SJonas Paulsson int Offset = getBackchainOffset(MF) - SystemZMC::CallFrameSize; 78882879c29SJonas Paulsson FI = MFFrame.CreateFixedObject(8, Offset, false); 78961f5ba5cSJonas Paulsson ZFI->setFramePointerSaveIndex(FI); 79061f5ba5cSJonas Paulsson } 79161f5ba5cSJonas Paulsson return FI; 79261f5ba5cSJonas Paulsson } 79382879c29SJonas Paulsson 79482879c29SJonas Paulsson bool SystemZFrameLowering::usePackedStack(MachineFunction &MF) const { 79582879c29SJonas Paulsson bool HasPackedStackAttr = MF.getFunction().hasFnAttribute("packed-stack"); 79682879c29SJonas Paulsson bool BackChain = MF.getFunction().hasFnAttribute("backchain"); 79782879c29SJonas Paulsson bool SoftFloat = MF.getSubtarget<SystemZSubtarget>().hasSoftFloat(); 79882879c29SJonas Paulsson if (HasPackedStackAttr && BackChain && !SoftFloat) 79982879c29SJonas Paulsson report_fatal_error("packed-stack + backchain + hard-float is unsupported."); 80082879c29SJonas Paulsson bool CallConv = MF.getFunction().getCallingConv() != CallingConv::GHC; 80182879c29SJonas Paulsson return HasPackedStackAttr && CallConv; 80282879c29SJonas Paulsson } 803