1284c1978SDimitry Andric //===-- SystemZFrameLowering.cpp - Frame lowering for SystemZ -------------===//
2284c1978SDimitry Andric //
3284c1978SDimitry Andric //                     The LLVM Compiler Infrastructure
4284c1978SDimitry Andric //
5284c1978SDimitry Andric // This file is distributed under the University of Illinois Open Source
6284c1978SDimitry Andric // License. See LICENSE.TXT for details.
7284c1978SDimitry Andric //
8284c1978SDimitry Andric //===----------------------------------------------------------------------===//
9284c1978SDimitry Andric 
10284c1978SDimitry Andric #include "SystemZFrameLowering.h"
11284c1978SDimitry Andric #include "SystemZCallingConv.h"
12284c1978SDimitry Andric #include "SystemZInstrBuilder.h"
1391bc56edSDimitry Andric #include "SystemZInstrInfo.h"
14284c1978SDimitry Andric #include "SystemZMachineFunctionInfo.h"
1591bc56edSDimitry Andric #include "SystemZRegisterInfo.h"
1639d628a0SDimitry Andric #include "SystemZSubtarget.h"
17284c1978SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
18284c1978SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
19f785676fSDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h"
20284c1978SDimitry Andric #include "llvm/IR/Function.h"
21284c1978SDimitry Andric 
22284c1978SDimitry Andric using namespace llvm;
23284c1978SDimitry Andric 
24f785676fSDimitry Andric namespace {
25284c1978SDimitry Andric // The ABI-defined register save slots, relative to the incoming stack
26284c1978SDimitry Andric // pointer.
27f785676fSDimitry Andric static const TargetFrameLowering::SpillSlot SpillOffsetTable[] = {
28284c1978SDimitry Andric   { SystemZ::R2D,  0x10 },
29284c1978SDimitry Andric   { SystemZ::R3D,  0x18 },
30284c1978SDimitry Andric   { SystemZ::R4D,  0x20 },
31284c1978SDimitry Andric   { SystemZ::R5D,  0x28 },
32284c1978SDimitry Andric   { SystemZ::R6D,  0x30 },
33284c1978SDimitry Andric   { SystemZ::R7D,  0x38 },
34284c1978SDimitry Andric   { SystemZ::R8D,  0x40 },
35284c1978SDimitry Andric   { SystemZ::R9D,  0x48 },
36284c1978SDimitry Andric   { SystemZ::R10D, 0x50 },
37284c1978SDimitry Andric   { SystemZ::R11D, 0x58 },
38284c1978SDimitry Andric   { SystemZ::R12D, 0x60 },
39284c1978SDimitry Andric   { SystemZ::R13D, 0x68 },
40284c1978SDimitry Andric   { SystemZ::R14D, 0x70 },
41284c1978SDimitry Andric   { SystemZ::R15D, 0x78 },
42284c1978SDimitry Andric   { SystemZ::F0D,  0x80 },
43284c1978SDimitry Andric   { SystemZ::F2D,  0x88 },
44284c1978SDimitry Andric   { SystemZ::F4D,  0x90 },
45284c1978SDimitry Andric   { SystemZ::F6D,  0x98 }
46284c1978SDimitry Andric };
4791bc56edSDimitry Andric } // end anonymous namespace
48284c1978SDimitry Andric 
SystemZFrameLowering()4991bc56edSDimitry Andric SystemZFrameLowering::SystemZFrameLowering()
50f785676fSDimitry Andric     : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 8,
517d523365SDimitry Andric                           -SystemZMC::CallFrameSize, 8,
527d523365SDimitry Andric                           false /* StackRealignable */) {
53284c1978SDimitry Andric   // Create a mapping from register number to save slot offset.
54284c1978SDimitry Andric   RegSpillOffsets.grow(SystemZ::NUM_TARGET_REGS);
55284c1978SDimitry Andric   for (unsigned I = 0, E = array_lengthof(SpillOffsetTable); I != E; ++I)
56f785676fSDimitry Andric     RegSpillOffsets[SpillOffsetTable[I].Reg] = SpillOffsetTable[I].Offset;
57f785676fSDimitry Andric }
58f785676fSDimitry Andric 
59f785676fSDimitry Andric const TargetFrameLowering::SpillSlot *
getCalleeSavedSpillSlots(unsigned & NumEntries) const60f785676fSDimitry Andric SystemZFrameLowering::getCalleeSavedSpillSlots(unsigned &NumEntries) const {
61f785676fSDimitry Andric   NumEntries = array_lengthof(SpillOffsetTable);
62f785676fSDimitry Andric   return SpillOffsetTable;
63284c1978SDimitry Andric }
64284c1978SDimitry Andric 
determineCalleeSaves(MachineFunction & MF,BitVector & SavedRegs,RegScavenger * RS) const65875ed548SDimitry Andric void SystemZFrameLowering::determineCalleeSaves(MachineFunction &MF,
66875ed548SDimitry Andric                                                 BitVector &SavedRegs,
67284c1978SDimitry Andric                                                 RegScavenger *RS) const {
68875ed548SDimitry Andric   TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
69875ed548SDimitry Andric 
70d88c1a5aSDimitry Andric   MachineFrameInfo &MFFrame = MF.getFrameInfo();
7139d628a0SDimitry Andric   const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
72284c1978SDimitry Andric   bool HasFP = hasFP(MF);
73284c1978SDimitry Andric   SystemZMachineFunctionInfo *MFI = MF.getInfo<SystemZMachineFunctionInfo>();
742cab237bSDimitry Andric   bool IsVarArg = MF.getFunction().isVarArg();
75284c1978SDimitry Andric 
76284c1978SDimitry Andric   // va_start stores incoming FPR varargs in the normal way, but delegates
77284c1978SDimitry Andric   // the saving of incoming GPR varargs to spillCalleeSavedRegisters().
78284c1978SDimitry Andric   // Record these pending uses, which typically include the call-saved
79284c1978SDimitry Andric   // argument register R6D.
80284c1978SDimitry Andric   if (IsVarArg)
81284c1978SDimitry Andric     for (unsigned I = MFI->getVarArgsFirstGPR(); I < SystemZ::NumArgGPRs; ++I)
82875ed548SDimitry Andric       SavedRegs.set(SystemZ::ArgGPRs[I]);
83284c1978SDimitry Andric 
843ca95b02SDimitry Andric   // If there are any landing pads, entering them will modify r6/r7.
85d88c1a5aSDimitry Andric   if (!MF.getLandingPads().empty()) {
863ca95b02SDimitry Andric     SavedRegs.set(SystemZ::R6D);
873ca95b02SDimitry Andric     SavedRegs.set(SystemZ::R7D);
883ca95b02SDimitry Andric   }
893ca95b02SDimitry Andric 
90284c1978SDimitry Andric   // If the function requires a frame pointer, record that the hard
91284c1978SDimitry Andric   // frame pointer will be clobbered.
92284c1978SDimitry Andric   if (HasFP)
93875ed548SDimitry Andric     SavedRegs.set(SystemZ::R11D);
94284c1978SDimitry Andric 
95284c1978SDimitry Andric   // If the function calls other functions, record that the return
96284c1978SDimitry Andric   // address register will be clobbered.
97d88c1a5aSDimitry Andric   if (MFFrame.hasCalls())
98875ed548SDimitry Andric     SavedRegs.set(SystemZ::R14D);
99284c1978SDimitry Andric 
100284c1978SDimitry Andric   // If we are saving GPRs other than the stack pointer, we might as well
101284c1978SDimitry Andric   // save and restore the stack pointer at the same time, via STMG and LMG.
102284c1978SDimitry Andric   // This allows the deallocation to be done by the LMG, rather than needing
103284c1978SDimitry Andric   // a separate %r15 addition.
10491bc56edSDimitry Andric   const MCPhysReg *CSRegs = TRI->getCalleeSavedRegs(&MF);
105284c1978SDimitry Andric   for (unsigned I = 0; CSRegs[I]; ++I) {
106284c1978SDimitry Andric     unsigned Reg = CSRegs[I];
107875ed548SDimitry Andric     if (SystemZ::GR64BitRegClass.contains(Reg) && SavedRegs.test(Reg)) {
108875ed548SDimitry Andric       SavedRegs.set(SystemZ::R15D);
109284c1978SDimitry Andric       break;
110284c1978SDimitry Andric     }
111284c1978SDimitry Andric   }
112284c1978SDimitry Andric }
113284c1978SDimitry Andric 
114284c1978SDimitry Andric // Add GPR64 to the save instruction being built by MIB, which is in basic
115284c1978SDimitry Andric // block MBB.  IsImplicit says whether this is an explicit operand to the
116284c1978SDimitry Andric // instruction, or an implicit one that comes between the explicit start
117284c1978SDimitry Andric // and end registers.
addSavedGPR(MachineBasicBlock & MBB,MachineInstrBuilder & MIB,unsigned GPR64,bool IsImplicit)118284c1978SDimitry Andric static void addSavedGPR(MachineBasicBlock &MBB, MachineInstrBuilder &MIB,
119284c1978SDimitry Andric                         unsigned GPR64, bool IsImplicit) {
12039d628a0SDimitry Andric   const TargetRegisterInfo *RI =
12139d628a0SDimitry Andric       MBB.getParent()->getSubtarget().getRegisterInfo();
122f785676fSDimitry Andric   unsigned GPR32 = RI->getSubReg(GPR64, SystemZ::subreg_l32);
123284c1978SDimitry Andric   bool IsLive = MBB.isLiveIn(GPR64) || MBB.isLiveIn(GPR32);
124284c1978SDimitry Andric   if (!IsLive || !IsImplicit) {
125284c1978SDimitry Andric     MIB.addReg(GPR64, getImplRegState(IsImplicit) | getKillRegState(!IsLive));
126284c1978SDimitry Andric     if (!IsLive)
127284c1978SDimitry Andric       MBB.addLiveIn(GPR64);
128284c1978SDimitry Andric   }
129284c1978SDimitry Andric }
130284c1978SDimitry Andric 
131284c1978SDimitry Andric bool SystemZFrameLowering::
spillCalleeSavedRegisters(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,const std::vector<CalleeSavedInfo> & CSI,const TargetRegisterInfo * TRI) const132284c1978SDimitry Andric spillCalleeSavedRegisters(MachineBasicBlock &MBB,
133284c1978SDimitry Andric                           MachineBasicBlock::iterator MBBI,
134284c1978SDimitry Andric                           const std::vector<CalleeSavedInfo> &CSI,
135284c1978SDimitry Andric                           const TargetRegisterInfo *TRI) const {
136284c1978SDimitry Andric   if (CSI.empty())
137284c1978SDimitry Andric     return false;
138284c1978SDimitry Andric 
139284c1978SDimitry Andric   MachineFunction &MF = *MBB.getParent();
14039d628a0SDimitry Andric   const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
141284c1978SDimitry Andric   SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>();
1422cab237bSDimitry Andric   bool IsVarArg = MF.getFunction().isVarArg();
1437d523365SDimitry Andric   DebugLoc DL;
144284c1978SDimitry Andric 
145284c1978SDimitry Andric   // Scan the call-saved GPRs and find the bounds of the register spill area.
146284c1978SDimitry Andric   unsigned LowGPR = 0;
147284c1978SDimitry Andric   unsigned HighGPR = SystemZ::R15D;
148284c1978SDimitry Andric   unsigned StartOffset = -1U;
149284c1978SDimitry Andric   for (unsigned I = 0, E = CSI.size(); I != E; ++I) {
150284c1978SDimitry Andric     unsigned Reg = CSI[I].getReg();
151284c1978SDimitry Andric     if (SystemZ::GR64BitRegClass.contains(Reg)) {
152284c1978SDimitry Andric       unsigned Offset = RegSpillOffsets[Reg];
153284c1978SDimitry Andric       assert(Offset && "Unexpected GPR save");
154284c1978SDimitry Andric       if (StartOffset > Offset) {
155284c1978SDimitry Andric         LowGPR = Reg;
156284c1978SDimitry Andric         StartOffset = Offset;
157284c1978SDimitry Andric       }
158284c1978SDimitry Andric     }
159284c1978SDimitry Andric   }
160284c1978SDimitry Andric 
161f785676fSDimitry Andric   // Save the range of call-saved registers, for use by the epilogue inserter.
162284c1978SDimitry Andric   ZFI->setLowSavedGPR(LowGPR);
163284c1978SDimitry Andric   ZFI->setHighSavedGPR(HighGPR);
164284c1978SDimitry Andric 
165284c1978SDimitry Andric   // Include the GPR varargs, if any.  R6D is call-saved, so would
166284c1978SDimitry Andric   // be included by the loop above, but we also need to handle the
167284c1978SDimitry Andric   // call-clobbered argument registers.
168284c1978SDimitry Andric   if (IsVarArg) {
169284c1978SDimitry Andric     unsigned FirstGPR = ZFI->getVarArgsFirstGPR();
170284c1978SDimitry Andric     if (FirstGPR < SystemZ::NumArgGPRs) {
171284c1978SDimitry Andric       unsigned Reg = SystemZ::ArgGPRs[FirstGPR];
172284c1978SDimitry Andric       unsigned Offset = RegSpillOffsets[Reg];
173284c1978SDimitry Andric       if (StartOffset > Offset) {
174284c1978SDimitry Andric         LowGPR = Reg; StartOffset = Offset;
175284c1978SDimitry Andric       }
176284c1978SDimitry Andric     }
177284c1978SDimitry Andric   }
178284c1978SDimitry Andric 
179284c1978SDimitry Andric   // Save GPRs
180284c1978SDimitry Andric   if (LowGPR) {
181284c1978SDimitry Andric     assert(LowGPR != HighGPR && "Should be saving %r15 and something else");
182284c1978SDimitry Andric 
183284c1978SDimitry Andric     // Build an STMG instruction.
184284c1978SDimitry Andric     MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(SystemZ::STMG));
185284c1978SDimitry Andric 
186284c1978SDimitry Andric     // Add the explicit register operands.
18791bc56edSDimitry Andric     addSavedGPR(MBB, MIB, LowGPR, false);
18891bc56edSDimitry Andric     addSavedGPR(MBB, MIB, HighGPR, false);
189284c1978SDimitry Andric 
190284c1978SDimitry Andric     // Add the address.
191284c1978SDimitry Andric     MIB.addReg(SystemZ::R15D).addImm(StartOffset);
192284c1978SDimitry Andric 
193284c1978SDimitry Andric     // Make sure all call-saved GPRs are included as operands and are
194284c1978SDimitry Andric     // marked as live on entry.
195284c1978SDimitry Andric     for (unsigned I = 0, E = CSI.size(); I != E; ++I) {
196284c1978SDimitry Andric       unsigned Reg = CSI[I].getReg();
197284c1978SDimitry Andric       if (SystemZ::GR64BitRegClass.contains(Reg))
19891bc56edSDimitry Andric         addSavedGPR(MBB, MIB, Reg, true);
199284c1978SDimitry Andric     }
200284c1978SDimitry Andric 
201284c1978SDimitry Andric     // ...likewise GPR varargs.
202284c1978SDimitry Andric     if (IsVarArg)
203284c1978SDimitry Andric       for (unsigned I = ZFI->getVarArgsFirstGPR(); I < SystemZ::NumArgGPRs; ++I)
20491bc56edSDimitry Andric         addSavedGPR(MBB, MIB, SystemZ::ArgGPRs[I], true);
205284c1978SDimitry Andric   }
206284c1978SDimitry Andric 
207*4ba319b5SDimitry Andric   // Save FPRs/VRs in the normal TargetInstrInfo way.
208284c1978SDimitry Andric   for (unsigned I = 0, E = CSI.size(); I != E; ++I) {
209284c1978SDimitry Andric     unsigned Reg = CSI[I].getReg();
210284c1978SDimitry Andric     if (SystemZ::FP64BitRegClass.contains(Reg)) {
211284c1978SDimitry Andric       MBB.addLiveIn(Reg);
212284c1978SDimitry Andric       TII->storeRegToStackSlot(MBB, MBBI, Reg, true, CSI[I].getFrameIdx(),
213284c1978SDimitry Andric                                &SystemZ::FP64BitRegClass, TRI);
214284c1978SDimitry Andric     }
215*4ba319b5SDimitry Andric     if (SystemZ::VR128BitRegClass.contains(Reg)) {
216*4ba319b5SDimitry Andric       MBB.addLiveIn(Reg);
217*4ba319b5SDimitry Andric       TII->storeRegToStackSlot(MBB, MBBI, Reg, true, CSI[I].getFrameIdx(),
218*4ba319b5SDimitry Andric                                &SystemZ::VR128BitRegClass, TRI);
219*4ba319b5SDimitry Andric     }
220284c1978SDimitry Andric   }
221284c1978SDimitry Andric 
222284c1978SDimitry Andric   return true;
223284c1978SDimitry Andric }
224284c1978SDimitry Andric 
225284c1978SDimitry Andric bool SystemZFrameLowering::
restoreCalleeSavedRegisters(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,std::vector<CalleeSavedInfo> & CSI,const TargetRegisterInfo * TRI) const226284c1978SDimitry Andric restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
227284c1978SDimitry Andric                             MachineBasicBlock::iterator MBBI,
2282cab237bSDimitry Andric                             std::vector<CalleeSavedInfo> &CSI,
229284c1978SDimitry Andric                             const TargetRegisterInfo *TRI) const {
230284c1978SDimitry Andric   if (CSI.empty())
231284c1978SDimitry Andric     return false;
232284c1978SDimitry Andric 
233284c1978SDimitry Andric   MachineFunction &MF = *MBB.getParent();
23439d628a0SDimitry Andric   const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
235284c1978SDimitry Andric   SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>();
236284c1978SDimitry Andric   bool HasFP = hasFP(MF);
237284c1978SDimitry Andric   DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
238284c1978SDimitry Andric 
239*4ba319b5SDimitry Andric   // Restore FPRs/VRs in the normal TargetInstrInfo way.
240284c1978SDimitry Andric   for (unsigned I = 0, E = CSI.size(); I != E; ++I) {
241284c1978SDimitry Andric     unsigned Reg = CSI[I].getReg();
242284c1978SDimitry Andric     if (SystemZ::FP64BitRegClass.contains(Reg))
243284c1978SDimitry Andric       TII->loadRegFromStackSlot(MBB, MBBI, Reg, CSI[I].getFrameIdx(),
244284c1978SDimitry Andric                                 &SystemZ::FP64BitRegClass, TRI);
245*4ba319b5SDimitry Andric     if (SystemZ::VR128BitRegClass.contains(Reg))
246*4ba319b5SDimitry Andric       TII->loadRegFromStackSlot(MBB, MBBI, Reg, CSI[I].getFrameIdx(),
247*4ba319b5SDimitry Andric                                 &SystemZ::VR128BitRegClass, TRI);
248284c1978SDimitry Andric   }
249284c1978SDimitry Andric 
250284c1978SDimitry Andric   // Restore call-saved GPRs (but not call-clobbered varargs, which at
251284c1978SDimitry Andric   // this point might hold return values).
252284c1978SDimitry Andric   unsigned LowGPR = ZFI->getLowSavedGPR();
253284c1978SDimitry Andric   unsigned HighGPR = ZFI->getHighSavedGPR();
254284c1978SDimitry Andric   unsigned StartOffset = RegSpillOffsets[LowGPR];
255284c1978SDimitry Andric   if (LowGPR) {
256284c1978SDimitry Andric     // If we saved any of %r2-%r5 as varargs, we should also be saving
257284c1978SDimitry Andric     // and restoring %r6.  If we're saving %r6 or above, we should be
258284c1978SDimitry Andric     // restoring it too.
259284c1978SDimitry Andric     assert(LowGPR != HighGPR && "Should be loading %r15 and something else");
260284c1978SDimitry Andric 
261284c1978SDimitry Andric     // Build an LMG instruction.
262284c1978SDimitry Andric     MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(SystemZ::LMG));
263284c1978SDimitry Andric 
264284c1978SDimitry Andric     // Add the explicit register operands.
265284c1978SDimitry Andric     MIB.addReg(LowGPR, RegState::Define);
266284c1978SDimitry Andric     MIB.addReg(HighGPR, RegState::Define);
267284c1978SDimitry Andric 
268284c1978SDimitry Andric     // Add the address.
269284c1978SDimitry Andric     MIB.addReg(HasFP ? SystemZ::R11D : SystemZ::R15D);
270284c1978SDimitry Andric     MIB.addImm(StartOffset);
271284c1978SDimitry Andric 
272284c1978SDimitry Andric     // Do a second scan adding regs as being defined by instruction
273284c1978SDimitry Andric     for (unsigned I = 0, E = CSI.size(); I != E; ++I) {
274284c1978SDimitry Andric       unsigned Reg = CSI[I].getReg();
2753ca95b02SDimitry Andric       if (Reg != LowGPR && Reg != HighGPR &&
2763ca95b02SDimitry Andric           SystemZ::GR64BitRegClass.contains(Reg))
277284c1978SDimitry Andric         MIB.addReg(Reg, RegState::ImplicitDefine);
278284c1978SDimitry Andric     }
279284c1978SDimitry Andric   }
280284c1978SDimitry Andric 
281284c1978SDimitry Andric   return true;
282284c1978SDimitry Andric }
283284c1978SDimitry Andric 
284f785676fSDimitry Andric void SystemZFrameLowering::
processFunctionBeforeFrameFinalized(MachineFunction & MF,RegScavenger * RS) const285f785676fSDimitry Andric processFunctionBeforeFrameFinalized(MachineFunction &MF,
286f785676fSDimitry Andric                                     RegScavenger *RS) const {
287d88c1a5aSDimitry Andric   MachineFrameInfo &MFFrame = MF.getFrameInfo();
288edd7eaddSDimitry Andric   // Get the size of our stack frame to be allocated ...
289edd7eaddSDimitry Andric   uint64_t StackSize = (MFFrame.estimateStackSize(MF) +
290edd7eaddSDimitry Andric                         SystemZMC::CallFrameSize);
291edd7eaddSDimitry Andric   // ... and the maximum offset we may need to reach into the
292edd7eaddSDimitry Andric   // caller's frame to access the save area or stack arguments.
293edd7eaddSDimitry Andric   int64_t MaxArgOffset = SystemZMC::CallFrameSize;
294edd7eaddSDimitry Andric   for (int I = MFFrame.getObjectIndexBegin(); I != 0; ++I)
295edd7eaddSDimitry Andric     if (MFFrame.getObjectOffset(I) >= 0) {
296edd7eaddSDimitry Andric       int64_t ArgOffset = SystemZMC::CallFrameSize +
297edd7eaddSDimitry Andric                           MFFrame.getObjectOffset(I) +
298edd7eaddSDimitry Andric                           MFFrame.getObjectSize(I);
299edd7eaddSDimitry Andric       MaxArgOffset = std::max(MaxArgOffset, ArgOffset);
300edd7eaddSDimitry Andric     }
301edd7eaddSDimitry Andric 
302edd7eaddSDimitry Andric   uint64_t MaxReach = StackSize + MaxArgOffset;
303f785676fSDimitry Andric   if (!isUInt<12>(MaxReach)) {
304f785676fSDimitry Andric     // We may need register scavenging slots if some parts of the frame
305f785676fSDimitry Andric     // are outside the reach of an unsigned 12-bit displacement.
306f785676fSDimitry Andric     // Create 2 for the case where both addresses in an MVC are
307f785676fSDimitry Andric     // out of range.
308d88c1a5aSDimitry Andric     RS->addScavengingFrameIndex(MFFrame.CreateStackObject(8, 8, false));
309d88c1a5aSDimitry Andric     RS->addScavengingFrameIndex(MFFrame.CreateStackObject(8, 8, false));
310f785676fSDimitry Andric   }
311f785676fSDimitry Andric }
312f785676fSDimitry Andric 
313284c1978SDimitry Andric // Emit instructions before MBBI (in MBB) to add NumBytes to Reg.
emitIncrement(MachineBasicBlock & MBB,MachineBasicBlock::iterator & MBBI,const DebugLoc & DL,unsigned Reg,int64_t NumBytes,const TargetInstrInfo * TII)314284c1978SDimitry Andric static void emitIncrement(MachineBasicBlock &MBB,
315284c1978SDimitry Andric                           MachineBasicBlock::iterator &MBBI,
316284c1978SDimitry Andric                           const DebugLoc &DL,
317284c1978SDimitry Andric                           unsigned Reg, int64_t NumBytes,
318284c1978SDimitry Andric                           const TargetInstrInfo *TII) {
319284c1978SDimitry Andric   while (NumBytes) {
320284c1978SDimitry Andric     unsigned Opcode;
321284c1978SDimitry Andric     int64_t ThisVal = NumBytes;
322284c1978SDimitry Andric     if (isInt<16>(NumBytes))
323284c1978SDimitry Andric       Opcode = SystemZ::AGHI;
324284c1978SDimitry Andric     else {
325284c1978SDimitry Andric       Opcode = SystemZ::AGFI;
326284c1978SDimitry Andric       // Make sure we maintain 8-byte stack alignment.
32739d628a0SDimitry Andric       int64_t MinVal = -uint64_t(1) << 31;
328284c1978SDimitry Andric       int64_t MaxVal = (int64_t(1) << 31) - 8;
329284c1978SDimitry Andric       if (ThisVal < MinVal)
330284c1978SDimitry Andric         ThisVal = MinVal;
331284c1978SDimitry Andric       else if (ThisVal > MaxVal)
332284c1978SDimitry Andric         ThisVal = MaxVal;
333284c1978SDimitry Andric     }
334284c1978SDimitry Andric     MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII->get(Opcode), Reg)
335284c1978SDimitry Andric       .addReg(Reg).addImm(ThisVal);
336f785676fSDimitry Andric     // The CC implicit def is dead.
337284c1978SDimitry Andric     MI->getOperand(3).setIsDead();
338284c1978SDimitry Andric     NumBytes -= ThisVal;
339284c1978SDimitry Andric   }
340284c1978SDimitry Andric }
341284c1978SDimitry Andric 
emitPrologue(MachineFunction & MF,MachineBasicBlock & MBB) const342ff0cc061SDimitry Andric void SystemZFrameLowering::emitPrologue(MachineFunction &MF,
343ff0cc061SDimitry Andric                                         MachineBasicBlock &MBB) const {
344ff0cc061SDimitry Andric   assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");
345d88c1a5aSDimitry Andric   MachineFrameInfo &MFFrame = MF.getFrameInfo();
34691bc56edSDimitry Andric   auto *ZII =
34739d628a0SDimitry Andric       static_cast<const SystemZInstrInfo *>(MF.getSubtarget().getInstrInfo());
348284c1978SDimitry Andric   SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>();
349284c1978SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.begin();
350284c1978SDimitry Andric   MachineModuleInfo &MMI = MF.getMMI();
351f785676fSDimitry Andric   const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo();
352d88c1a5aSDimitry Andric   const std::vector<CalleeSavedInfo> &CSI = MFFrame.getCalleeSavedInfo();
353284c1978SDimitry Andric   bool HasFP = hasFP(MF);
3547d523365SDimitry Andric 
3557d523365SDimitry Andric   // Debug location must be unknown since the first debug location is used
3567d523365SDimitry Andric   // to determine the end of the prologue.
3577d523365SDimitry Andric   DebugLoc DL;
358284c1978SDimitry Andric 
359284c1978SDimitry Andric   // The current offset of the stack pointer from the CFA.
360284c1978SDimitry Andric   int64_t SPOffsetFromCFA = -SystemZMC::CFAOffsetFromInitialSP;
361284c1978SDimitry Andric 
362284c1978SDimitry Andric   if (ZFI->getLowSavedGPR()) {
363284c1978SDimitry Andric     // Skip over the GPR saves.
364284c1978SDimitry Andric     if (MBBI != MBB.end() && MBBI->getOpcode() == SystemZ::STMG)
365284c1978SDimitry Andric       ++MBBI;
366284c1978SDimitry Andric     else
367284c1978SDimitry Andric       llvm_unreachable("Couldn't skip over GPR saves");
368284c1978SDimitry Andric 
369284c1978SDimitry Andric     // Add CFI for the GPR saves.
37091bc56edSDimitry Andric     for (auto &Save : CSI) {
37191bc56edSDimitry Andric       unsigned Reg = Save.getReg();
372284c1978SDimitry Andric       if (SystemZ::GR64BitRegClass.contains(Reg)) {
373284c1978SDimitry Andric         int64_t Offset = SPOffsetFromCFA + RegSpillOffsets[Reg];
374d88c1a5aSDimitry Andric         unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
37591bc56edSDimitry Andric             nullptr, MRI->getDwarfRegNum(Reg, true), Offset));
37691bc56edSDimitry Andric         BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION))
37791bc56edSDimitry Andric             .addCFIIndex(CFIIndex);
378284c1978SDimitry Andric       }
379284c1978SDimitry Andric     }
380284c1978SDimitry Andric   }
381284c1978SDimitry Andric 
382*4ba319b5SDimitry Andric   uint64_t StackSize = MFFrame.getStackSize();
383*4ba319b5SDimitry Andric   // We need to allocate the ABI-defined 160-byte base area whenever
384*4ba319b5SDimitry Andric   // we allocate stack space for our own use and whenever we call another
385*4ba319b5SDimitry Andric   // function.
386*4ba319b5SDimitry Andric   if (StackSize || MFFrame.hasVarSizedObjects() || MFFrame.hasCalls()) {
387*4ba319b5SDimitry Andric     StackSize += SystemZMC::CallFrameSize;
388*4ba319b5SDimitry Andric     MFFrame.setStackSize(StackSize);
389*4ba319b5SDimitry Andric   }
390*4ba319b5SDimitry Andric 
391284c1978SDimitry Andric   if (StackSize) {
3923ca95b02SDimitry Andric     // Determine if we want to store a backchain.
3932cab237bSDimitry Andric     bool StoreBackchain = MF.getFunction().hasFnAttribute("backchain");
3943ca95b02SDimitry Andric 
3953ca95b02SDimitry Andric     // If we need backchain, save current stack pointer.  R1 is free at this
3963ca95b02SDimitry Andric     // point.
3973ca95b02SDimitry Andric     if (StoreBackchain)
3983ca95b02SDimitry Andric       BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::LGR))
3993ca95b02SDimitry Andric         .addReg(SystemZ::R1D, RegState::Define).addReg(SystemZ::R15D);
4003ca95b02SDimitry Andric 
401284c1978SDimitry Andric     // Allocate StackSize bytes.
402284c1978SDimitry Andric     int64_t Delta = -int64_t(StackSize);
403284c1978SDimitry Andric     emitIncrement(MBB, MBBI, DL, SystemZ::R15D, Delta, ZII);
404284c1978SDimitry Andric 
405284c1978SDimitry Andric     // Add CFI for the allocation.
406d88c1a5aSDimitry Andric     unsigned CFIIndex = MF.addFrameInst(
40791bc56edSDimitry Andric         MCCFIInstruction::createDefCfaOffset(nullptr, SPOffsetFromCFA + Delta));
40891bc56edSDimitry Andric     BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION))
40991bc56edSDimitry Andric         .addCFIIndex(CFIIndex);
410284c1978SDimitry Andric     SPOffsetFromCFA += Delta;
4113ca95b02SDimitry Andric 
4123ca95b02SDimitry Andric     if (StoreBackchain)
4133ca95b02SDimitry Andric       BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::STG))
4143ca95b02SDimitry Andric         .addReg(SystemZ::R1D, RegState::Kill).addReg(SystemZ::R15D).addImm(0).addReg(0);
415284c1978SDimitry Andric   }
416284c1978SDimitry Andric 
417284c1978SDimitry Andric   if (HasFP) {
418284c1978SDimitry Andric     // Copy the base of the frame to R11.
419284c1978SDimitry Andric     BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::LGR), SystemZ::R11D)
420284c1978SDimitry Andric       .addReg(SystemZ::R15D);
421284c1978SDimitry Andric 
422284c1978SDimitry Andric     // Add CFI for the new frame location.
423f785676fSDimitry Andric     unsigned HardFP = MRI->getDwarfRegNum(SystemZ::R11D, true);
424d88c1a5aSDimitry Andric     unsigned CFIIndex = MF.addFrameInst(
42591bc56edSDimitry Andric         MCCFIInstruction::createDefCfaRegister(nullptr, HardFP));
42691bc56edSDimitry Andric     BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION))
42791bc56edSDimitry Andric         .addCFIIndex(CFIIndex);
428284c1978SDimitry Andric 
429284c1978SDimitry Andric     // Mark the FramePtr as live at the beginning of every block except
430284c1978SDimitry Andric     // the entry block.  (We'll have marked R11 as live on entry when
431284c1978SDimitry Andric     // saving the GPRs.)
43291bc56edSDimitry Andric     for (auto I = std::next(MF.begin()), E = MF.end(); I != E; ++I)
433284c1978SDimitry Andric       I->addLiveIn(SystemZ::R11D);
434284c1978SDimitry Andric   }
435284c1978SDimitry Andric 
436*4ba319b5SDimitry Andric   // Skip over the FPR/VR saves.
43791bc56edSDimitry Andric   SmallVector<unsigned, 8> CFIIndexes;
43891bc56edSDimitry Andric   for (auto &Save : CSI) {
43991bc56edSDimitry Andric     unsigned Reg = Save.getReg();
440284c1978SDimitry Andric     if (SystemZ::FP64BitRegClass.contains(Reg)) {
441284c1978SDimitry Andric       if (MBBI != MBB.end() &&
442284c1978SDimitry Andric           (MBBI->getOpcode() == SystemZ::STD ||
443284c1978SDimitry Andric            MBBI->getOpcode() == SystemZ::STDY))
444284c1978SDimitry Andric         ++MBBI;
445284c1978SDimitry Andric       else
446284c1978SDimitry Andric         llvm_unreachable("Couldn't skip over FPR save");
447*4ba319b5SDimitry Andric     } else if (SystemZ::VR128BitRegClass.contains(Reg)) {
448*4ba319b5SDimitry Andric       if (MBBI != MBB.end() &&
449*4ba319b5SDimitry Andric           MBBI->getOpcode() == SystemZ::VST)
450*4ba319b5SDimitry Andric         ++MBBI;
451*4ba319b5SDimitry Andric       else
452*4ba319b5SDimitry Andric         llvm_unreachable("Couldn't skip over VR save");
453*4ba319b5SDimitry Andric     } else
454*4ba319b5SDimitry Andric       continue;
455284c1978SDimitry Andric 
456284c1978SDimitry Andric     // Add CFI for the this save.
45791bc56edSDimitry Andric     unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true);
4587d523365SDimitry Andric     unsigned IgnoredFrameReg;
4597d523365SDimitry Andric     int64_t Offset =
4607d523365SDimitry Andric         getFrameIndexReference(MF, Save.getFrameIdx(), IgnoredFrameReg);
4617d523365SDimitry Andric 
462d88c1a5aSDimitry Andric     unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
46391bc56edSDimitry Andric           nullptr, DwarfReg, SPOffsetFromCFA + Offset));
46491bc56edSDimitry Andric     CFIIndexes.push_back(CFIIndex);
465284c1978SDimitry Andric   }
466*4ba319b5SDimitry Andric   // Complete the CFI for the FPR/VR saves, modelling them as taking effect
467284c1978SDimitry Andric   // after the last save.
46891bc56edSDimitry Andric   for (auto CFIIndex : CFIIndexes) {
46991bc56edSDimitry Andric     BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION))
47091bc56edSDimitry Andric         .addCFIIndex(CFIIndex);
47191bc56edSDimitry Andric   }
472284c1978SDimitry Andric }
473284c1978SDimitry Andric 
emitEpilogue(MachineFunction & MF,MachineBasicBlock & MBB) const474284c1978SDimitry Andric void SystemZFrameLowering::emitEpilogue(MachineFunction &MF,
475284c1978SDimitry Andric                                         MachineBasicBlock &MBB) const {
476284c1978SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
47791bc56edSDimitry Andric   auto *ZII =
47839d628a0SDimitry Andric       static_cast<const SystemZInstrInfo *>(MF.getSubtarget().getInstrInfo());
479284c1978SDimitry Andric   SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>();
480*4ba319b5SDimitry Andric   MachineFrameInfo &MFFrame = MF.getFrameInfo();
481284c1978SDimitry Andric 
482284c1978SDimitry Andric   // Skip the return instruction.
483f785676fSDimitry Andric   assert(MBBI->isReturn() && "Can only insert epilogue into returning blocks");
484284c1978SDimitry Andric 
485*4ba319b5SDimitry Andric   uint64_t StackSize = MFFrame.getStackSize();
486284c1978SDimitry Andric   if (ZFI->getLowSavedGPR()) {
487284c1978SDimitry Andric     --MBBI;
488284c1978SDimitry Andric     unsigned Opcode = MBBI->getOpcode();
489284c1978SDimitry Andric     if (Opcode != SystemZ::LMG)
490284c1978SDimitry Andric       llvm_unreachable("Expected to see callee-save register restore code");
491284c1978SDimitry Andric 
492284c1978SDimitry Andric     unsigned AddrOpNo = 2;
493284c1978SDimitry Andric     DebugLoc DL = MBBI->getDebugLoc();
494284c1978SDimitry Andric     uint64_t Offset = StackSize + MBBI->getOperand(AddrOpNo + 1).getImm();
495284c1978SDimitry Andric     unsigned NewOpcode = ZII->getOpcodeForOffset(Opcode, Offset);
496284c1978SDimitry Andric 
497284c1978SDimitry Andric     // If the offset is too large, use the largest stack-aligned offset
498284c1978SDimitry Andric     // and add the rest to the base register (the stack or frame pointer).
499284c1978SDimitry Andric     if (!NewOpcode) {
500284c1978SDimitry Andric       uint64_t NumBytes = Offset - 0x7fff8;
501284c1978SDimitry Andric       emitIncrement(MBB, MBBI, DL, MBBI->getOperand(AddrOpNo).getReg(),
502284c1978SDimitry Andric                     NumBytes, ZII);
503284c1978SDimitry Andric       Offset -= NumBytes;
504284c1978SDimitry Andric       NewOpcode = ZII->getOpcodeForOffset(Opcode, Offset);
505284c1978SDimitry Andric       assert(NewOpcode && "No restore instruction available");
506284c1978SDimitry Andric     }
507284c1978SDimitry Andric 
508284c1978SDimitry Andric     MBBI->setDesc(ZII->get(NewOpcode));
509284c1978SDimitry Andric     MBBI->getOperand(AddrOpNo + 1).ChangeToImmediate(Offset);
510284c1978SDimitry Andric   } else if (StackSize) {
511284c1978SDimitry Andric     DebugLoc DL = MBBI->getDebugLoc();
512284c1978SDimitry Andric     emitIncrement(MBB, MBBI, DL, SystemZ::R15D, StackSize, ZII);
513284c1978SDimitry Andric   }
514284c1978SDimitry Andric }
515284c1978SDimitry Andric 
hasFP(const MachineFunction & MF) const516284c1978SDimitry Andric bool SystemZFrameLowering::hasFP(const MachineFunction &MF) const {
517284c1978SDimitry Andric   return (MF.getTarget().Options.DisableFramePointerElim(MF) ||
518d88c1a5aSDimitry Andric           MF.getFrameInfo().hasVarSizedObjects() ||
519284c1978SDimitry Andric           MF.getInfo<SystemZMachineFunctionInfo>()->getManipulatesSP());
520284c1978SDimitry Andric }
521284c1978SDimitry Andric 
522284c1978SDimitry Andric bool
hasReservedCallFrame(const MachineFunction & MF) const523284c1978SDimitry Andric SystemZFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
524284c1978SDimitry Andric   // The ABI requires us to allocate 160 bytes of stack space for the callee,
525284c1978SDimitry Andric   // with any outgoing stack arguments being placed above that.  It seems
526284c1978SDimitry Andric   // better to make that area a permanent feature of the frame even if
527284c1978SDimitry Andric   // we're using a frame pointer.
528284c1978SDimitry Andric   return true;
529284c1978SDimitry Andric }
530284c1978SDimitry Andric 
5313ca95b02SDimitry Andric MachineBasicBlock::iterator SystemZFrameLowering::
eliminateCallFramePseudoInstr(MachineFunction & MF,MachineBasicBlock & MBB,MachineBasicBlock::iterator MI) const532284c1978SDimitry Andric eliminateCallFramePseudoInstr(MachineFunction &MF,
533284c1978SDimitry Andric                               MachineBasicBlock &MBB,
534284c1978SDimitry Andric                               MachineBasicBlock::iterator MI) const {
535284c1978SDimitry Andric   switch (MI->getOpcode()) {
536284c1978SDimitry Andric   case SystemZ::ADJCALLSTACKDOWN:
537284c1978SDimitry Andric   case SystemZ::ADJCALLSTACKUP:
538284c1978SDimitry Andric     assert(hasReservedCallFrame(MF) &&
539284c1978SDimitry Andric            "ADJSTACKDOWN and ADJSTACKUP should be no-ops");
5403ca95b02SDimitry Andric     return MBB.erase(MI);
541284c1978SDimitry Andric     break;
542284c1978SDimitry Andric 
543284c1978SDimitry Andric   default:
544284c1978SDimitry Andric     llvm_unreachable("Unexpected call frame instruction");
545284c1978SDimitry Andric   }
546284c1978SDimitry Andric }
547