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