xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/M68k/M68kFrameLowering.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
1fe6060f1SDimitry Andric //===-- M68kFrameLowering.cpp - M68k Frame Information ------*- C++ -*-===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric ///
9fe6060f1SDimitry Andric /// \file
10fe6060f1SDimitry Andric /// This file contains the M68k implementation of TargetFrameLowering class.
11fe6060f1SDimitry Andric ///
12fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
13fe6060f1SDimitry Andric 
14fe6060f1SDimitry Andric #include "M68kFrameLowering.h"
15fe6060f1SDimitry Andric 
16fe6060f1SDimitry Andric #include "M68kInstrBuilder.h"
17fe6060f1SDimitry Andric #include "M68kInstrInfo.h"
18fe6060f1SDimitry Andric #include "M68kMachineFunction.h"
19fe6060f1SDimitry Andric #include "M68kSubtarget.h"
20fe6060f1SDimitry Andric 
21fe6060f1SDimitry Andric #include "llvm/ADT/SmallSet.h"
22fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
23fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
24fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
25fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
26fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
27fe6060f1SDimitry Andric #include "llvm/IR/DataLayout.h"
28fe6060f1SDimitry Andric #include "llvm/IR/Function.h"
29fe6060f1SDimitry Andric #include "llvm/Support/Alignment.h"
30fe6060f1SDimitry Andric #include "llvm/Support/CommandLine.h"
31fe6060f1SDimitry Andric #include "llvm/Target/TargetMachine.h"
32fe6060f1SDimitry Andric #include "llvm/Target/TargetOptions.h"
33fe6060f1SDimitry Andric 
34fe6060f1SDimitry Andric using namespace llvm;
35fe6060f1SDimitry Andric 
36fe6060f1SDimitry Andric M68kFrameLowering::M68kFrameLowering(const M68kSubtarget &STI, Align Alignment)
37fe6060f1SDimitry Andric     : TargetFrameLowering(StackGrowsDown, Alignment, -4), STI(STI),
38fe6060f1SDimitry Andric       TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) {
39fe6060f1SDimitry Andric   SlotSize = STI.getSlotSize();
40fe6060f1SDimitry Andric   StackPtr = TRI->getStackRegister();
41fe6060f1SDimitry Andric }
42fe6060f1SDimitry Andric 
43fe6060f1SDimitry Andric bool M68kFrameLowering::hasFP(const MachineFunction &MF) const {
44fe6060f1SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
45fe6060f1SDimitry Andric   const TargetRegisterInfo *TRI = STI.getRegisterInfo();
46fe6060f1SDimitry Andric 
47fe6060f1SDimitry Andric   return MF.getTarget().Options.DisableFramePointerElim(MF) ||
48fe6060f1SDimitry Andric          MFI.hasVarSizedObjects() || MFI.isFrameAddressTaken() ||
49fe6060f1SDimitry Andric          TRI->hasStackRealignment(MF);
50fe6060f1SDimitry Andric }
51fe6060f1SDimitry Andric 
52fe6060f1SDimitry Andric // FIXME Make sure no other factors prevent us from reserving call frame
53fe6060f1SDimitry Andric bool M68kFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
54fe6060f1SDimitry Andric   return !MF.getFrameInfo().hasVarSizedObjects() &&
55fe6060f1SDimitry Andric          !MF.getInfo<M68kMachineFunctionInfo>()->getHasPushSequences();
56fe6060f1SDimitry Andric }
57fe6060f1SDimitry Andric 
58fe6060f1SDimitry Andric bool M68kFrameLowering::canSimplifyCallFramePseudos(
59fe6060f1SDimitry Andric     const MachineFunction &MF) const {
60fe6060f1SDimitry Andric   return hasReservedCallFrame(MF) ||
61fe6060f1SDimitry Andric          (hasFP(MF) && !TRI->hasStackRealignment(MF)) ||
62fe6060f1SDimitry Andric          TRI->hasBasePointer(MF);
63fe6060f1SDimitry Andric }
64fe6060f1SDimitry Andric 
65fe6060f1SDimitry Andric bool M68kFrameLowering::needsFrameIndexResolution(
66fe6060f1SDimitry Andric     const MachineFunction &MF) const {
67fe6060f1SDimitry Andric   return MF.getFrameInfo().hasStackObjects() ||
68fe6060f1SDimitry Andric          MF.getInfo<M68kMachineFunctionInfo>()->getHasPushSequences();
69fe6060f1SDimitry Andric }
70fe6060f1SDimitry Andric 
71fe6060f1SDimitry Andric // NOTE: this only has a subset of the full frame index logic. In
72fe6060f1SDimitry Andric // particular, the FI < 0 and AfterFPPop logic is handled in
73fe6060f1SDimitry Andric // M68kRegisterInfo::eliminateFrameIndex, but not here. Possibly
74fe6060f1SDimitry Andric // (probably?) it should be moved into here.
75fe6060f1SDimitry Andric StackOffset
76fe6060f1SDimitry Andric M68kFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
77fe6060f1SDimitry Andric                                           Register &FrameReg) const {
78fe6060f1SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
79fe6060f1SDimitry Andric 
80fe6060f1SDimitry Andric   // We can't calculate offset from frame pointer if the stack is realigned,
81fe6060f1SDimitry Andric   // so enforce usage of stack/base pointer.  The base pointer is used when we
82fe6060f1SDimitry Andric   // have dynamic allocas in addition to dynamic realignment.
83fe6060f1SDimitry Andric   if (TRI->hasBasePointer(MF))
84fe6060f1SDimitry Andric     FrameReg = TRI->getBaseRegister();
85fe6060f1SDimitry Andric   else if (TRI->hasStackRealignment(MF))
86fe6060f1SDimitry Andric     FrameReg = TRI->getStackRegister();
87fe6060f1SDimitry Andric   else
88fe6060f1SDimitry Andric     FrameReg = TRI->getFrameRegister(MF);
89fe6060f1SDimitry Andric 
90fe6060f1SDimitry Andric   // Offset will hold the offset from the stack pointer at function entry to the
91fe6060f1SDimitry Andric   // object.
92fe6060f1SDimitry Andric   // We need to factor in additional offsets applied during the prologue to the
93fe6060f1SDimitry Andric   // frame, base, and stack pointer depending on which is used.
94fe6060f1SDimitry Andric   int Offset = MFI.getObjectOffset(FI) - getOffsetOfLocalArea();
95fe6060f1SDimitry Andric   const M68kMachineFunctionInfo *MMFI = MF.getInfo<M68kMachineFunctionInfo>();
96fe6060f1SDimitry Andric   uint64_t StackSize = MFI.getStackSize();
97fe6060f1SDimitry Andric   bool HasFP = hasFP(MF);
98fe6060f1SDimitry Andric 
99fe6060f1SDimitry Andric   // TODO: Support tail calls
100fe6060f1SDimitry Andric   if (TRI->hasBasePointer(MF)) {
101fe6060f1SDimitry Andric     assert(HasFP && "VLAs and dynamic stack realign, but no FP?!");
102fe6060f1SDimitry Andric     if (FI < 0) {
103fe6060f1SDimitry Andric       // Skip the saved FP.
104fe6060f1SDimitry Andric       return StackOffset::getFixed(Offset + SlotSize);
105fe6060f1SDimitry Andric     }
106fe6060f1SDimitry Andric 
107fe6060f1SDimitry Andric     assert((-(Offset + StackSize)) % MFI.getObjectAlign(FI).value() == 0);
108fe6060f1SDimitry Andric     return StackOffset::getFixed(Offset + StackSize);
109fe6060f1SDimitry Andric   }
110fe6060f1SDimitry Andric   if (TRI->hasStackRealignment(MF)) {
111fe6060f1SDimitry Andric     if (FI < 0) {
112fe6060f1SDimitry Andric       // Skip the saved FP.
113fe6060f1SDimitry Andric       return StackOffset::getFixed(Offset + SlotSize);
114fe6060f1SDimitry Andric     }
115fe6060f1SDimitry Andric 
116fe6060f1SDimitry Andric     assert((-(Offset + StackSize)) % MFI.getObjectAlign(FI).value() == 0);
117fe6060f1SDimitry Andric     return StackOffset::getFixed(Offset + StackSize);
118fe6060f1SDimitry Andric   }
119fe6060f1SDimitry Andric 
120fe6060f1SDimitry Andric   if (!HasFP)
121fe6060f1SDimitry Andric     return StackOffset::getFixed(Offset + StackSize);
122fe6060f1SDimitry Andric 
123fe6060f1SDimitry Andric   // Skip the saved FP.
124fe6060f1SDimitry Andric   Offset += SlotSize;
125fe6060f1SDimitry Andric 
126fe6060f1SDimitry Andric   // Skip the RETADDR move area
127fe6060f1SDimitry Andric   int TailCallReturnAddrDelta = MMFI->getTCReturnAddrDelta();
128fe6060f1SDimitry Andric   if (TailCallReturnAddrDelta < 0)
129fe6060f1SDimitry Andric     Offset -= TailCallReturnAddrDelta;
130fe6060f1SDimitry Andric 
131fe6060f1SDimitry Andric   return StackOffset::getFixed(Offset);
132fe6060f1SDimitry Andric }
133fe6060f1SDimitry Andric 
134fe6060f1SDimitry Andric /// Return a caller-saved register that isn't live
135fe6060f1SDimitry Andric /// when it reaches the "return" instruction. We can then pop a stack object
136fe6060f1SDimitry Andric /// to this register without worry about clobbering it.
137fe6060f1SDimitry Andric static unsigned findDeadCallerSavedReg(MachineBasicBlock &MBB,
138fe6060f1SDimitry Andric                                        MachineBasicBlock::iterator &MBBI,
139fe6060f1SDimitry Andric                                        const M68kRegisterInfo *TRI) {
140fe6060f1SDimitry Andric   const MachineFunction *MF = MBB.getParent();
141fe6060f1SDimitry Andric   if (MF->callsEHReturn())
142fe6060f1SDimitry Andric     return 0;
143fe6060f1SDimitry Andric 
144fe6060f1SDimitry Andric   const TargetRegisterClass &AvailableRegs = *TRI->getRegsForTailCall(*MF);
145fe6060f1SDimitry Andric 
146fe6060f1SDimitry Andric   if (MBBI == MBB.end())
147fe6060f1SDimitry Andric     return 0;
148fe6060f1SDimitry Andric 
149fe6060f1SDimitry Andric   switch (MBBI->getOpcode()) {
150fe6060f1SDimitry Andric   default:
151fe6060f1SDimitry Andric     return 0;
152fe6060f1SDimitry Andric   case TargetOpcode::PATCHABLE_RET:
153fe6060f1SDimitry Andric   case M68k::RET: {
154fe6060f1SDimitry Andric     SmallSet<uint16_t, 8> Uses;
155fe6060f1SDimitry Andric 
156fe6060f1SDimitry Andric     for (unsigned i = 0, e = MBBI->getNumOperands(); i != e; ++i) {
157fe6060f1SDimitry Andric       MachineOperand &MO = MBBI->getOperand(i);
158fe6060f1SDimitry Andric       if (!MO.isReg() || MO.isDef())
159fe6060f1SDimitry Andric         continue;
160fe6060f1SDimitry Andric       unsigned Reg = MO.getReg();
161fe6060f1SDimitry Andric       if (!Reg)
162fe6060f1SDimitry Andric         continue;
163fe6060f1SDimitry Andric       for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI)
164fe6060f1SDimitry Andric         Uses.insert(*AI);
165fe6060f1SDimitry Andric     }
166fe6060f1SDimitry Andric 
167fe6060f1SDimitry Andric     for (auto CS : AvailableRegs)
168fe6060f1SDimitry Andric       if (!Uses.count(CS))
169fe6060f1SDimitry Andric         return CS;
170fe6060f1SDimitry Andric   }
171fe6060f1SDimitry Andric   }
172fe6060f1SDimitry Andric 
173fe6060f1SDimitry Andric   return 0;
174fe6060f1SDimitry Andric }
175fe6060f1SDimitry Andric 
176fe6060f1SDimitry Andric static bool isRegLiveIn(MachineBasicBlock &MBB, unsigned Reg) {
177fe6060f1SDimitry Andric   return llvm::any_of(MBB.liveins(),
178fe6060f1SDimitry Andric                       [Reg](MachineBasicBlock::RegisterMaskPair RegMask) {
179fe6060f1SDimitry Andric                         return RegMask.PhysReg == Reg;
180fe6060f1SDimitry Andric                       });
181fe6060f1SDimitry Andric }
182fe6060f1SDimitry Andric 
183fe6060f1SDimitry Andric uint64_t
184fe6060f1SDimitry Andric M68kFrameLowering::calculateMaxStackAlign(const MachineFunction &MF) const {
185fe6060f1SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
186fe6060f1SDimitry Andric   uint64_t MaxAlign = MFI.getMaxAlign().value(); // Desired stack alignment.
187fe6060f1SDimitry Andric   unsigned StackAlign = getStackAlignment();     // ABI alignment
188fe6060f1SDimitry Andric   if (MF.getFunction().hasFnAttribute("stackrealign")) {
189fe6060f1SDimitry Andric     if (MFI.hasCalls())
190fe6060f1SDimitry Andric       MaxAlign = (StackAlign > MaxAlign) ? StackAlign : MaxAlign;
191fe6060f1SDimitry Andric     else if (MaxAlign < SlotSize)
192fe6060f1SDimitry Andric       MaxAlign = SlotSize;
193fe6060f1SDimitry Andric   }
194fe6060f1SDimitry Andric   return MaxAlign;
195fe6060f1SDimitry Andric }
196fe6060f1SDimitry Andric 
197fe6060f1SDimitry Andric void M68kFrameLowering::BuildStackAlignAND(MachineBasicBlock &MBB,
198fe6060f1SDimitry Andric                                            MachineBasicBlock::iterator MBBI,
199fe6060f1SDimitry Andric                                            const DebugLoc &DL, unsigned Reg,
200fe6060f1SDimitry Andric                                            uint64_t MaxAlign) const {
201fe6060f1SDimitry Andric   uint64_t Val = -MaxAlign;
202fe6060f1SDimitry Andric   unsigned AndOp = M68k::AND32di;
203fe6060f1SDimitry Andric   unsigned MovOp = M68k::MOV32rr;
204fe6060f1SDimitry Andric 
205fe6060f1SDimitry Andric   // This function is normally used with SP which is Address Register, but AND,
206fe6060f1SDimitry Andric   // or any other logical instructions in M68k do not support ARs so we need
207fe6060f1SDimitry Andric   // to use a temp Data Register to perform the op.
208fe6060f1SDimitry Andric   unsigned Tmp = M68k::D0;
209fe6060f1SDimitry Andric 
210fe6060f1SDimitry Andric   BuildMI(MBB, MBBI, DL, TII.get(MovOp), Tmp)
211fe6060f1SDimitry Andric       .addReg(Reg)
212fe6060f1SDimitry Andric       .setMIFlag(MachineInstr::FrameSetup);
213fe6060f1SDimitry Andric 
214fe6060f1SDimitry Andric   MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(AndOp), Tmp)
215fe6060f1SDimitry Andric                          .addReg(Tmp)
216fe6060f1SDimitry Andric                          .addImm(Val)
217fe6060f1SDimitry Andric                          .setMIFlag(MachineInstr::FrameSetup);
218fe6060f1SDimitry Andric 
219fe6060f1SDimitry Andric   // The CCR implicit def is dead.
220fe6060f1SDimitry Andric   MI->getOperand(3).setIsDead();
221fe6060f1SDimitry Andric 
222fe6060f1SDimitry Andric   BuildMI(MBB, MBBI, DL, TII.get(MovOp), Reg)
223fe6060f1SDimitry Andric       .addReg(Tmp)
224fe6060f1SDimitry Andric       .setMIFlag(MachineInstr::FrameSetup);
225fe6060f1SDimitry Andric }
226fe6060f1SDimitry Andric 
227fe6060f1SDimitry Andric MachineBasicBlock::iterator M68kFrameLowering::eliminateCallFramePseudoInstr(
228fe6060f1SDimitry Andric     MachineFunction &MF, MachineBasicBlock &MBB,
229fe6060f1SDimitry Andric     MachineBasicBlock::iterator I) const {
230fe6060f1SDimitry Andric   bool ReserveCallFrame = hasReservedCallFrame(MF);
231fe6060f1SDimitry Andric   unsigned Opcode = I->getOpcode();
232fe6060f1SDimitry Andric   bool IsDestroy = Opcode == TII.getCallFrameDestroyOpcode();
233fe6060f1SDimitry Andric   DebugLoc DL = I->getDebugLoc();
234fe6060f1SDimitry Andric   uint64_t Amount = !ReserveCallFrame ? I->getOperand(0).getImm() : 0;
235fe6060f1SDimitry Andric   uint64_t InternalAmt = (IsDestroy && Amount) ? I->getOperand(1).getImm() : 0;
236fe6060f1SDimitry Andric   I = MBB.erase(I);
237fe6060f1SDimitry Andric 
238fe6060f1SDimitry Andric   if (!ReserveCallFrame) {
239fe6060f1SDimitry Andric     // If the stack pointer can be changed after prologue, turn the
240fe6060f1SDimitry Andric     // adjcallstackup instruction into a 'sub %SP, <amt>' and the
241fe6060f1SDimitry Andric     // adjcallstackdown instruction into 'add %SP, <amt>'
242fe6060f1SDimitry Andric 
243fe6060f1SDimitry Andric     // We need to keep the stack aligned properly.  To do this, we round the
244fe6060f1SDimitry Andric     // amount of space needed for the outgoing arguments up to the next
245fe6060f1SDimitry Andric     // alignment boundary.
246fe6060f1SDimitry Andric     unsigned StackAlign = getStackAlignment();
247fe6060f1SDimitry Andric     Amount = alignTo(Amount, StackAlign);
248fe6060f1SDimitry Andric 
249fe6060f1SDimitry Andric     MachineModuleInfo &MMI = MF.getMMI();
250fe6060f1SDimitry Andric     const auto &Fn = MF.getFunction();
251fe6060f1SDimitry Andric     bool DwarfCFI = MMI.hasDebugInfo() || Fn.needsUnwindTableEntry();
252fe6060f1SDimitry Andric 
253fe6060f1SDimitry Andric     // If we have any exception handlers in this function, and we adjust
254fe6060f1SDimitry Andric     // the SP before calls, we may need to indicate this to the unwinder
255fe6060f1SDimitry Andric     // using GNU_ARGS_SIZE. Note that this may be necessary even when
256fe6060f1SDimitry Andric     // Amount == 0, because the preceding function may have set a non-0
257fe6060f1SDimitry Andric     // GNU_ARGS_SIZE.
258fe6060f1SDimitry Andric     // TODO: We don't need to reset this between subsequent functions,
259fe6060f1SDimitry Andric     // if it didn't change.
260fe6060f1SDimitry Andric     bool HasDwarfEHHandlers = !MF.getLandingPads().empty();
261fe6060f1SDimitry Andric 
262fe6060f1SDimitry Andric     if (HasDwarfEHHandlers && !IsDestroy &&
263fe6060f1SDimitry Andric         MF.getInfo<M68kMachineFunctionInfo>()->getHasPushSequences()) {
264fe6060f1SDimitry Andric       BuildCFI(MBB, I, DL,
265fe6060f1SDimitry Andric                MCCFIInstruction::createGnuArgsSize(nullptr, Amount));
266fe6060f1SDimitry Andric     }
267fe6060f1SDimitry Andric 
268fe6060f1SDimitry Andric     if (Amount == 0)
269fe6060f1SDimitry Andric       return I;
270fe6060f1SDimitry Andric 
271fe6060f1SDimitry Andric     // Factor out the amount that gets handled inside the sequence
272fe6060f1SDimitry Andric     // (Pushes of argument for frame setup, callee pops for frame destroy)
273fe6060f1SDimitry Andric     Amount -= InternalAmt;
274fe6060f1SDimitry Andric 
275fe6060f1SDimitry Andric     // TODO: This is needed only if we require precise CFA.
276fe6060f1SDimitry Andric     // If this is a callee-pop calling convention, emit a CFA adjust for
277fe6060f1SDimitry Andric     // the amount the callee popped.
278fe6060f1SDimitry Andric     if (IsDestroy && InternalAmt && DwarfCFI && !hasFP(MF))
279fe6060f1SDimitry Andric       BuildCFI(MBB, I, DL,
280fe6060f1SDimitry Andric                MCCFIInstruction::createAdjustCfaOffset(nullptr, -InternalAmt));
281fe6060f1SDimitry Andric 
282fe6060f1SDimitry Andric     // Add Amount to SP to destroy a frame, or subtract to setup.
283fe6060f1SDimitry Andric     int64_t StackAdjustment = IsDestroy ? Amount : -Amount;
284fe6060f1SDimitry Andric     int64_t CfaAdjustment = -StackAdjustment;
285fe6060f1SDimitry Andric 
286fe6060f1SDimitry Andric     if (StackAdjustment) {
287fe6060f1SDimitry Andric       // Merge with any previous or following adjustment instruction. Note: the
288fe6060f1SDimitry Andric       // instructions merged with here do not have CFI, so their stack
289fe6060f1SDimitry Andric       // adjustments do not feed into CfaAdjustment.
290fe6060f1SDimitry Andric       StackAdjustment += mergeSPUpdates(MBB, I, true);
291fe6060f1SDimitry Andric       StackAdjustment += mergeSPUpdates(MBB, I, false);
292fe6060f1SDimitry Andric 
293fe6060f1SDimitry Andric       if (StackAdjustment) {
294fe6060f1SDimitry Andric         BuildStackAdjustment(MBB, I, DL, StackAdjustment, false);
295fe6060f1SDimitry Andric       }
296fe6060f1SDimitry Andric     }
297fe6060f1SDimitry Andric 
298fe6060f1SDimitry Andric     if (DwarfCFI && !hasFP(MF)) {
299fe6060f1SDimitry Andric       // If we don't have FP, but need to generate unwind information,
300fe6060f1SDimitry Andric       // we need to set the correct CFA offset after the stack adjustment.
301fe6060f1SDimitry Andric       // How much we adjust the CFA offset depends on whether we're emitting
302fe6060f1SDimitry Andric       // CFI only for EH purposes or for debugging. EH only requires the CFA
303fe6060f1SDimitry Andric       // offset to be correct at each call site, while for debugging we want
304fe6060f1SDimitry Andric       // it to be more precise.
305fe6060f1SDimitry Andric 
306fe6060f1SDimitry Andric       // TODO: When not using precise CFA, we also need to adjust for the
307fe6060f1SDimitry Andric       // InternalAmt here.
308fe6060f1SDimitry Andric       if (CfaAdjustment) {
309fe6060f1SDimitry Andric         BuildCFI(
310fe6060f1SDimitry Andric             MBB, I, DL,
311fe6060f1SDimitry Andric             MCCFIInstruction::createAdjustCfaOffset(nullptr, CfaAdjustment));
312fe6060f1SDimitry Andric       }
313fe6060f1SDimitry Andric     }
314fe6060f1SDimitry Andric 
315fe6060f1SDimitry Andric     return I;
316fe6060f1SDimitry Andric   }
317fe6060f1SDimitry Andric 
318fe6060f1SDimitry Andric   if (IsDestroy && InternalAmt) {
319fe6060f1SDimitry Andric     // If we are performing frame pointer elimination and if the callee pops
320fe6060f1SDimitry Andric     // something off the stack pointer, add it back.  We do this until we have
321fe6060f1SDimitry Andric     // more advanced stack pointer tracking ability.
322fe6060f1SDimitry Andric     // We are not tracking the stack pointer adjustment by the callee, so make
323fe6060f1SDimitry Andric     // sure we restore the stack pointer immediately after the call, there may
324fe6060f1SDimitry Andric     // be spill code inserted between the CALL and ADJCALLSTACKUP instructions.
325fe6060f1SDimitry Andric     MachineBasicBlock::iterator CI = I;
326fe6060f1SDimitry Andric     MachineBasicBlock::iterator B = MBB.begin();
327fe6060f1SDimitry Andric     while (CI != B && !std::prev(CI)->isCall())
328fe6060f1SDimitry Andric       --CI;
329fe6060f1SDimitry Andric     BuildStackAdjustment(MBB, CI, DL, -InternalAmt, /*InEpilogue=*/false);
330fe6060f1SDimitry Andric   }
331fe6060f1SDimitry Andric 
332fe6060f1SDimitry Andric   return I;
333fe6060f1SDimitry Andric }
334fe6060f1SDimitry Andric 
335fe6060f1SDimitry Andric /// Emit a series of instructions to increment / decrement the stack pointer by
336fe6060f1SDimitry Andric /// a constant value.
337fe6060f1SDimitry Andric void M68kFrameLowering::emitSPUpdate(MachineBasicBlock &MBB,
338fe6060f1SDimitry Andric                                      MachineBasicBlock::iterator &MBBI,
339fe6060f1SDimitry Andric                                      int64_t NumBytes, bool InEpilogue) const {
340fe6060f1SDimitry Andric   bool IsSub = NumBytes < 0;
341fe6060f1SDimitry Andric   uint64_t Offset = IsSub ? -NumBytes : NumBytes;
342fe6060f1SDimitry Andric 
343fe6060f1SDimitry Andric   uint64_t Chunk = (1LL << 31) - 1;
344fe6060f1SDimitry Andric   DebugLoc DL = MBB.findDebugLoc(MBBI);
345fe6060f1SDimitry Andric 
346fe6060f1SDimitry Andric   while (Offset) {
347fe6060f1SDimitry Andric     if (Offset > Chunk) {
348fe6060f1SDimitry Andric       // Rather than emit a long series of instructions for large offsets,
349fe6060f1SDimitry Andric       // load the offset into a register and do one sub/add
350fe6060f1SDimitry Andric       Register Reg;
351fe6060f1SDimitry Andric 
352fe6060f1SDimitry Andric       if (IsSub && !isRegLiveIn(MBB, M68k::D0))
353fe6060f1SDimitry Andric         Reg = M68k::D0;
354fe6060f1SDimitry Andric       else
355fe6060f1SDimitry Andric         Reg = findDeadCallerSavedReg(MBB, MBBI, TRI);
356fe6060f1SDimitry Andric 
357fe6060f1SDimitry Andric       if (Reg) {
358fe6060f1SDimitry Andric         unsigned Opc = M68k::MOV32ri;
359fe6060f1SDimitry Andric         BuildMI(MBB, MBBI, DL, TII.get(Opc), Reg).addImm(Offset);
360*349cc55cSDimitry Andric         Opc = IsSub ? M68k::SUB32ar : M68k::ADD32ar;
361fe6060f1SDimitry Andric         MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opc), StackPtr)
362fe6060f1SDimitry Andric                                .addReg(StackPtr)
363fe6060f1SDimitry Andric                                .addReg(Reg);
364fe6060f1SDimitry Andric         // ??? still no CCR
365fe6060f1SDimitry Andric         MI->getOperand(3).setIsDead(); // The CCR implicit def is dead.
366fe6060f1SDimitry Andric         Offset = 0;
367fe6060f1SDimitry Andric         continue;
368fe6060f1SDimitry Andric       }
369fe6060f1SDimitry Andric     }
370fe6060f1SDimitry Andric 
371fe6060f1SDimitry Andric     uint64_t ThisVal = std::min(Offset, Chunk);
372fe6060f1SDimitry Andric 
373fe6060f1SDimitry Andric     MachineInstrBuilder MI = BuildStackAdjustment(
374fe6060f1SDimitry Andric         MBB, MBBI, DL, IsSub ? -ThisVal : ThisVal, InEpilogue);
375fe6060f1SDimitry Andric     if (IsSub)
376fe6060f1SDimitry Andric       MI.setMIFlag(MachineInstr::FrameSetup);
377fe6060f1SDimitry Andric     else
378fe6060f1SDimitry Andric       MI.setMIFlag(MachineInstr::FrameDestroy);
379fe6060f1SDimitry Andric 
380fe6060f1SDimitry Andric     Offset -= ThisVal;
381fe6060f1SDimitry Andric   }
382fe6060f1SDimitry Andric }
383fe6060f1SDimitry Andric 
384fe6060f1SDimitry Andric int M68kFrameLowering::mergeSPUpdates(MachineBasicBlock &MBB,
385fe6060f1SDimitry Andric                                       MachineBasicBlock::iterator &MBBI,
386fe6060f1SDimitry Andric                                       bool MergeWithPrevious) const {
387fe6060f1SDimitry Andric   if ((MergeWithPrevious && MBBI == MBB.begin()) ||
388fe6060f1SDimitry Andric       (!MergeWithPrevious && MBBI == MBB.end()))
389fe6060f1SDimitry Andric     return 0;
390fe6060f1SDimitry Andric 
391fe6060f1SDimitry Andric   MachineBasicBlock::iterator PI = MergeWithPrevious ? std::prev(MBBI) : MBBI;
392fe6060f1SDimitry Andric   MachineBasicBlock::iterator NI =
393fe6060f1SDimitry Andric       MergeWithPrevious ? nullptr : std::next(MBBI);
394fe6060f1SDimitry Andric   unsigned Opc = PI->getOpcode();
395fe6060f1SDimitry Andric   int Offset = 0;
396fe6060f1SDimitry Andric 
397fe6060f1SDimitry Andric   if (!MergeWithPrevious && NI != MBB.end() &&
398fe6060f1SDimitry Andric       NI->getOpcode() == TargetOpcode::CFI_INSTRUCTION) {
399fe6060f1SDimitry Andric     // Don't merge with the next instruction if it has CFI.
400fe6060f1SDimitry Andric     return Offset;
401fe6060f1SDimitry Andric   }
402fe6060f1SDimitry Andric 
403*349cc55cSDimitry Andric   if (Opc == M68k::ADD32ai && PI->getOperand(0).getReg() == StackPtr) {
404fe6060f1SDimitry Andric     assert(PI->getOperand(1).getReg() == StackPtr);
405fe6060f1SDimitry Andric     Offset += PI->getOperand(2).getImm();
406fe6060f1SDimitry Andric     MBB.erase(PI);
407fe6060f1SDimitry Andric     if (!MergeWithPrevious)
408fe6060f1SDimitry Andric       MBBI = NI;
409*349cc55cSDimitry Andric   } else if (Opc == M68k::SUB32ai && PI->getOperand(0).getReg() == StackPtr) {
410fe6060f1SDimitry Andric     assert(PI->getOperand(1).getReg() == StackPtr);
411fe6060f1SDimitry Andric     Offset -= PI->getOperand(2).getImm();
412fe6060f1SDimitry Andric     MBB.erase(PI);
413fe6060f1SDimitry Andric     if (!MergeWithPrevious)
414fe6060f1SDimitry Andric       MBBI = NI;
415fe6060f1SDimitry Andric   }
416fe6060f1SDimitry Andric 
417fe6060f1SDimitry Andric   return Offset;
418fe6060f1SDimitry Andric }
419fe6060f1SDimitry Andric 
420fe6060f1SDimitry Andric MachineInstrBuilder M68kFrameLowering::BuildStackAdjustment(
421fe6060f1SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
422fe6060f1SDimitry Andric     const DebugLoc &DL, int64_t Offset, bool InEpilogue) const {
423fe6060f1SDimitry Andric   assert(Offset != 0 && "zero offset stack adjustment requested");
424fe6060f1SDimitry Andric 
425fe6060f1SDimitry Andric   // TODO can `lea` be used to adjust stack?
426fe6060f1SDimitry Andric 
427fe6060f1SDimitry Andric   bool IsSub = Offset < 0;
428fe6060f1SDimitry Andric   uint64_t AbsOffset = IsSub ? -Offset : Offset;
429*349cc55cSDimitry Andric   unsigned Opc = IsSub ? M68k::SUB32ai : M68k::ADD32ai;
430fe6060f1SDimitry Andric 
431fe6060f1SDimitry Andric   MachineInstrBuilder MI = BuildMI(MBB, MBBI, DL, TII.get(Opc), StackPtr)
432fe6060f1SDimitry Andric                                .addReg(StackPtr)
433fe6060f1SDimitry Andric                                .addImm(AbsOffset);
434fe6060f1SDimitry Andric   // FIXME Update CCR as well. For now we just
435fe6060f1SDimitry Andric   // conservatively say CCR implicit def is dead
436fe6060f1SDimitry Andric   MI->getOperand(3).setIsDead();
437fe6060f1SDimitry Andric   return MI;
438fe6060f1SDimitry Andric }
439fe6060f1SDimitry Andric 
440fe6060f1SDimitry Andric void M68kFrameLowering::BuildCFI(MachineBasicBlock &MBB,
441fe6060f1SDimitry Andric                                  MachineBasicBlock::iterator MBBI,
442fe6060f1SDimitry Andric                                  const DebugLoc &DL,
443fe6060f1SDimitry Andric                                  const MCCFIInstruction &CFIInst) const {
444fe6060f1SDimitry Andric   MachineFunction &MF = *MBB.getParent();
445fe6060f1SDimitry Andric   unsigned CFIIndex = MF.addFrameInst(CFIInst);
446fe6060f1SDimitry Andric   BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
447fe6060f1SDimitry Andric       .addCFIIndex(CFIIndex);
448fe6060f1SDimitry Andric }
449fe6060f1SDimitry Andric 
450fe6060f1SDimitry Andric void M68kFrameLowering::emitPrologueCalleeSavedFrameMoves(
451fe6060f1SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
452fe6060f1SDimitry Andric     const DebugLoc &DL) const {
453fe6060f1SDimitry Andric   MachineFunction &MF = *MBB.getParent();
454fe6060f1SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
455fe6060f1SDimitry Andric   MachineModuleInfo &MMI = MF.getMMI();
456fe6060f1SDimitry Andric   const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo();
457fe6060f1SDimitry Andric 
458fe6060f1SDimitry Andric   // Add callee saved registers to move list.
459fe6060f1SDimitry Andric   const auto &CSI = MFI.getCalleeSavedInfo();
460fe6060f1SDimitry Andric   if (CSI.empty())
461fe6060f1SDimitry Andric     return;
462fe6060f1SDimitry Andric 
463fe6060f1SDimitry Andric   // Calculate offsets.
464fe6060f1SDimitry Andric   for (const auto &I : CSI) {
465fe6060f1SDimitry Andric     int64_t Offset = MFI.getObjectOffset(I.getFrameIdx());
466fe6060f1SDimitry Andric     unsigned Reg = I.getReg();
467fe6060f1SDimitry Andric 
468fe6060f1SDimitry Andric     unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true);
469fe6060f1SDimitry Andric     BuildCFI(MBB, MBBI, DL,
470fe6060f1SDimitry Andric              MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset));
471fe6060f1SDimitry Andric   }
472fe6060f1SDimitry Andric }
473fe6060f1SDimitry Andric 
474fe6060f1SDimitry Andric void M68kFrameLowering::emitPrologue(MachineFunction &MF,
475fe6060f1SDimitry Andric                                      MachineBasicBlock &MBB) const {
476fe6060f1SDimitry Andric   assert(&STI == &MF.getSubtarget<M68kSubtarget>() &&
477fe6060f1SDimitry Andric          "MF used frame lowering for wrong subtarget");
478fe6060f1SDimitry Andric 
479fe6060f1SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.begin();
480fe6060f1SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
481fe6060f1SDimitry Andric   const auto &Fn = MF.getFunction();
482fe6060f1SDimitry Andric   MachineModuleInfo &MMI = MF.getMMI();
483fe6060f1SDimitry Andric   M68kMachineFunctionInfo *MMFI = MF.getInfo<M68kMachineFunctionInfo>();
484fe6060f1SDimitry Andric   uint64_t MaxAlign = calculateMaxStackAlign(MF); // Desired stack alignment.
485fe6060f1SDimitry Andric   uint64_t StackSize = MFI.getStackSize(); // Number of bytes to allocate.
486fe6060f1SDimitry Andric   bool HasFP = hasFP(MF);
487fe6060f1SDimitry Andric   bool NeedsDwarfCFI = MMI.hasDebugInfo() || Fn.needsUnwindTableEntry();
488fe6060f1SDimitry Andric   unsigned FramePtr = TRI->getFrameRegister(MF);
489fe6060f1SDimitry Andric   const unsigned MachineFramePtr = FramePtr;
490fe6060f1SDimitry Andric   unsigned BasePtr = TRI->getBaseRegister();
491fe6060f1SDimitry Andric 
492fe6060f1SDimitry Andric   // Debug location must be unknown since the first debug location is used
493fe6060f1SDimitry Andric   // to determine the end of the prologue.
494fe6060f1SDimitry Andric   DebugLoc DL;
495fe6060f1SDimitry Andric 
496fe6060f1SDimitry Andric   // Add RETADDR move area to callee saved frame size.
497fe6060f1SDimitry Andric   int TailCallReturnAddrDelta = MMFI->getTCReturnAddrDelta();
498fe6060f1SDimitry Andric 
499fe6060f1SDimitry Andric   if (TailCallReturnAddrDelta < 0) {
500fe6060f1SDimitry Andric     MMFI->setCalleeSavedFrameSize(MMFI->getCalleeSavedFrameSize() -
501fe6060f1SDimitry Andric                                   TailCallReturnAddrDelta);
502fe6060f1SDimitry Andric   }
503fe6060f1SDimitry Andric 
504fe6060f1SDimitry Andric   // Insert stack pointer adjustment for later moving of return addr.  Only
505fe6060f1SDimitry Andric   // applies to tail call optimized functions where the callee argument stack
506fe6060f1SDimitry Andric   // size is bigger than the callers.
507fe6060f1SDimitry Andric   if (TailCallReturnAddrDelta < 0) {
508fe6060f1SDimitry Andric     BuildStackAdjustment(MBB, MBBI, DL, TailCallReturnAddrDelta,
509fe6060f1SDimitry Andric                          /*InEpilogue=*/false)
510fe6060f1SDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
511fe6060f1SDimitry Andric   }
512fe6060f1SDimitry Andric 
513fe6060f1SDimitry Andric   // Mapping for machine moves:
514fe6060f1SDimitry Andric   //
515fe6060f1SDimitry Andric   //   DST: VirtualFP AND
516fe6060f1SDimitry Andric   //        SRC: VirtualFP              => DW_CFA_def_cfa_offset
517fe6060f1SDimitry Andric   //        ELSE                        => DW_CFA_def_cfa
518fe6060f1SDimitry Andric   //
519fe6060f1SDimitry Andric   //   SRC: VirtualFP AND
520fe6060f1SDimitry Andric   //        DST: Register               => DW_CFA_def_cfa_register
521fe6060f1SDimitry Andric   //
522fe6060f1SDimitry Andric   //   ELSE
523fe6060f1SDimitry Andric   //        OFFSET < 0                  => DW_CFA_offset_extended_sf
524fe6060f1SDimitry Andric   //        REG < 64                    => DW_CFA_offset + Reg
525fe6060f1SDimitry Andric   //        ELSE                        => DW_CFA_offset_extended
526fe6060f1SDimitry Andric 
527fe6060f1SDimitry Andric   uint64_t NumBytes = 0;
528fe6060f1SDimitry Andric   int stackGrowth = -SlotSize;
529fe6060f1SDimitry Andric 
530fe6060f1SDimitry Andric   if (HasFP) {
531fe6060f1SDimitry Andric     // Calculate required stack adjustment.
532fe6060f1SDimitry Andric     uint64_t FrameSize = StackSize - SlotSize;
533fe6060f1SDimitry Andric     // If required, include space for extra hidden slot for stashing base
534fe6060f1SDimitry Andric     // pointer.
535fe6060f1SDimitry Andric     if (MMFI->getRestoreBasePointer())
536fe6060f1SDimitry Andric       FrameSize += SlotSize;
537fe6060f1SDimitry Andric 
538fe6060f1SDimitry Andric     NumBytes = FrameSize - MMFI->getCalleeSavedFrameSize();
539fe6060f1SDimitry Andric 
540fe6060f1SDimitry Andric     // Callee-saved registers are pushed on stack before the stack is realigned.
541fe6060f1SDimitry Andric     if (TRI->hasStackRealignment(MF))
542fe6060f1SDimitry Andric       NumBytes = alignTo(NumBytes, MaxAlign);
543fe6060f1SDimitry Andric 
544fe6060f1SDimitry Andric     // Get the offset of the stack slot for the FP register, which is
545fe6060f1SDimitry Andric     // guaranteed to be the last slot by processFunctionBeforeFrameFinalized.
546fe6060f1SDimitry Andric     // Update the frame offset adjustment.
547fe6060f1SDimitry Andric     MFI.setOffsetAdjustment(-NumBytes);
548fe6060f1SDimitry Andric 
549fe6060f1SDimitry Andric     // Save FP into the appropriate stack slot.
550fe6060f1SDimitry Andric     BuildMI(MBB, MBBI, DL, TII.get(M68k::PUSH32r))
551fe6060f1SDimitry Andric         .addReg(MachineFramePtr, RegState::Kill)
552fe6060f1SDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
553fe6060f1SDimitry Andric 
554fe6060f1SDimitry Andric     if (NeedsDwarfCFI) {
555fe6060f1SDimitry Andric       // Mark the place where FP was saved.
556fe6060f1SDimitry Andric       // Define the current CFA rule to use the provided offset.
557fe6060f1SDimitry Andric       assert(StackSize);
558fe6060f1SDimitry Andric       BuildCFI(MBB, MBBI, DL,
559fe6060f1SDimitry Andric                MCCFIInstruction::cfiDefCfaOffset(nullptr, 2 * stackGrowth));
560fe6060f1SDimitry Andric 
561fe6060f1SDimitry Andric       // Change the rule for the FramePtr to be an "offset" rule.
562fe6060f1SDimitry Andric       int DwarfFramePtr = TRI->getDwarfRegNum(MachineFramePtr, true);
563fe6060f1SDimitry Andric       assert(DwarfFramePtr > 0);
564fe6060f1SDimitry Andric       BuildCFI(MBB, MBBI, DL,
565fe6060f1SDimitry Andric                MCCFIInstruction::createOffset(nullptr, DwarfFramePtr,
566fe6060f1SDimitry Andric                                               2 * stackGrowth));
567fe6060f1SDimitry Andric     }
568fe6060f1SDimitry Andric 
569fe6060f1SDimitry Andric     // Update FP with the new base value.
570fe6060f1SDimitry Andric     BuildMI(MBB, MBBI, DL, TII.get(M68k::MOV32aa), FramePtr)
571fe6060f1SDimitry Andric         .addReg(StackPtr)
572fe6060f1SDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
573fe6060f1SDimitry Andric 
574fe6060f1SDimitry Andric     if (NeedsDwarfCFI) {
575fe6060f1SDimitry Andric       // Mark effective beginning of when frame pointer becomes valid.
576fe6060f1SDimitry Andric       // Define the current CFA to use the FP register.
577fe6060f1SDimitry Andric       unsigned DwarfFramePtr = TRI->getDwarfRegNum(MachineFramePtr, true);
578fe6060f1SDimitry Andric       BuildCFI(MBB, MBBI, DL,
579fe6060f1SDimitry Andric                MCCFIInstruction::createDefCfaRegister(nullptr, DwarfFramePtr));
580fe6060f1SDimitry Andric     }
581fe6060f1SDimitry Andric 
582fe6060f1SDimitry Andric     // Mark the FramePtr as live-in in every block. Don't do this again for
583fe6060f1SDimitry Andric     // funclet prologues.
584fe6060f1SDimitry Andric     for (MachineBasicBlock &EveryMBB : MF)
585fe6060f1SDimitry Andric       EveryMBB.addLiveIn(MachineFramePtr);
586fe6060f1SDimitry Andric   } else {
587fe6060f1SDimitry Andric     NumBytes = StackSize - MMFI->getCalleeSavedFrameSize();
588fe6060f1SDimitry Andric   }
589fe6060f1SDimitry Andric 
590fe6060f1SDimitry Andric   // Skip the callee-saved push instructions.
591fe6060f1SDimitry Andric   bool PushedRegs = false;
592fe6060f1SDimitry Andric   int StackOffset = 2 * stackGrowth;
593fe6060f1SDimitry Andric 
594fe6060f1SDimitry Andric   while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup) &&
595fe6060f1SDimitry Andric          MBBI->getOpcode() == M68k::PUSH32r) {
596fe6060f1SDimitry Andric     PushedRegs = true;
597fe6060f1SDimitry Andric     ++MBBI;
598fe6060f1SDimitry Andric 
599fe6060f1SDimitry Andric     if (!HasFP && NeedsDwarfCFI) {
600fe6060f1SDimitry Andric       // Mark callee-saved push instruction.
601fe6060f1SDimitry Andric       // Define the current CFA rule to use the provided offset.
602fe6060f1SDimitry Andric       assert(StackSize);
603fe6060f1SDimitry Andric       BuildCFI(MBB, MBBI, DL,
604fe6060f1SDimitry Andric                MCCFIInstruction::cfiDefCfaOffset(nullptr, StackOffset));
605fe6060f1SDimitry Andric       StackOffset += stackGrowth;
606fe6060f1SDimitry Andric     }
607fe6060f1SDimitry Andric   }
608fe6060f1SDimitry Andric 
609fe6060f1SDimitry Andric   // Realign stack after we pushed callee-saved registers (so that we'll be
610fe6060f1SDimitry Andric   // able to calculate their offsets from the frame pointer).
611fe6060f1SDimitry Andric   if (TRI->hasStackRealignment(MF)) {
612fe6060f1SDimitry Andric     assert(HasFP && "There should be a frame pointer if stack is realigned.");
613fe6060f1SDimitry Andric     BuildStackAlignAND(MBB, MBBI, DL, StackPtr, MaxAlign);
614fe6060f1SDimitry Andric   }
615fe6060f1SDimitry Andric 
616fe6060f1SDimitry Andric   // If there is an SUB32ri of SP immediately before this instruction, merge
617fe6060f1SDimitry Andric   // the two. This can be the case when tail call elimination is enabled and
618fe6060f1SDimitry Andric   // the callee has more arguments then the caller.
619fe6060f1SDimitry Andric   NumBytes -= mergeSPUpdates(MBB, MBBI, true);
620fe6060f1SDimitry Andric 
621fe6060f1SDimitry Andric   // Adjust stack pointer: ESP -= numbytes.
622fe6060f1SDimitry Andric   emitSPUpdate(MBB, MBBI, -(int64_t)NumBytes, /*InEpilogue=*/false);
623fe6060f1SDimitry Andric 
624fe6060f1SDimitry Andric   unsigned SPOrEstablisher = StackPtr;
625fe6060f1SDimitry Andric 
626fe6060f1SDimitry Andric   // If we need a base pointer, set it up here. It's whatever the value
627fe6060f1SDimitry Andric   // of the stack pointer is at this point. Any variable size objects
628fe6060f1SDimitry Andric   // will be allocated after this, so we can still use the base pointer
629fe6060f1SDimitry Andric   // to reference locals.
630fe6060f1SDimitry Andric   if (TRI->hasBasePointer(MF)) {
631fe6060f1SDimitry Andric     // Update the base pointer with the current stack pointer.
632fe6060f1SDimitry Andric     BuildMI(MBB, MBBI, DL, TII.get(M68k::MOV32aa), BasePtr)
633fe6060f1SDimitry Andric         .addReg(SPOrEstablisher)
634fe6060f1SDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
635fe6060f1SDimitry Andric     if (MMFI->getRestoreBasePointer()) {
636fe6060f1SDimitry Andric       // Stash value of base pointer.  Saving SP instead of FP shortens
637fe6060f1SDimitry Andric       // dependence chain. Used by SjLj EH.
638fe6060f1SDimitry Andric       unsigned Opm = M68k::MOV32ja;
639fe6060f1SDimitry Andric       M68k::addRegIndirectWithDisp(BuildMI(MBB, MBBI, DL, TII.get(Opm)),
640fe6060f1SDimitry Andric                                    FramePtr, true,
641fe6060f1SDimitry Andric                                    MMFI->getRestoreBasePointerOffset())
642fe6060f1SDimitry Andric           .addReg(SPOrEstablisher)
643fe6060f1SDimitry Andric           .setMIFlag(MachineInstr::FrameSetup);
644fe6060f1SDimitry Andric     }
645fe6060f1SDimitry Andric   }
646fe6060f1SDimitry Andric 
647fe6060f1SDimitry Andric   if (((!HasFP && NumBytes) || PushedRegs) && NeedsDwarfCFI) {
648fe6060f1SDimitry Andric     // Mark end of stack pointer adjustment.
649fe6060f1SDimitry Andric     if (!HasFP && NumBytes) {
650fe6060f1SDimitry Andric       // Define the current CFA rule to use the provided offset.
651fe6060f1SDimitry Andric       assert(StackSize);
652fe6060f1SDimitry Andric       BuildCFI(
653fe6060f1SDimitry Andric           MBB, MBBI, DL,
654fe6060f1SDimitry Andric           MCCFIInstruction::cfiDefCfaOffset(nullptr, -StackSize + stackGrowth));
655fe6060f1SDimitry Andric     }
656fe6060f1SDimitry Andric 
657fe6060f1SDimitry Andric     // Emit DWARF info specifying the offsets of the callee-saved registers.
658fe6060f1SDimitry Andric     if (PushedRegs)
659fe6060f1SDimitry Andric       emitPrologueCalleeSavedFrameMoves(MBB, MBBI, DL);
660fe6060f1SDimitry Andric   }
661fe6060f1SDimitry Andric 
662fe6060f1SDimitry Andric   // TODO Interrupt handlers
663fe6060f1SDimitry Andric   // M68k Interrupt handling function cannot assume anything about the
664fe6060f1SDimitry Andric   // direction flag (DF in CCR register). Clear this flag by creating "cld"
665fe6060f1SDimitry Andric   // instruction in each prologue of interrupt handler function. The "cld"
666fe6060f1SDimitry Andric   // instruction should only in these cases:
667fe6060f1SDimitry Andric   // 1. The interrupt handling function uses any of the "rep" instructions.
668fe6060f1SDimitry Andric   // 2. Interrupt handling function calls another function.
669fe6060f1SDimitry Andric }
670fe6060f1SDimitry Andric 
671fe6060f1SDimitry Andric static bool isTailCallOpcode(unsigned Opc) {
672fe6060f1SDimitry Andric   return Opc == M68k::TCRETURNj || Opc == M68k::TCRETURNq;
673fe6060f1SDimitry Andric }
674fe6060f1SDimitry Andric 
675fe6060f1SDimitry Andric void M68kFrameLowering::emitEpilogue(MachineFunction &MF,
676fe6060f1SDimitry Andric                                      MachineBasicBlock &MBB) const {
677fe6060f1SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
678fe6060f1SDimitry Andric   M68kMachineFunctionInfo *MMFI = MF.getInfo<M68kMachineFunctionInfo>();
679fe6060f1SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
680fe6060f1SDimitry Andric   Optional<unsigned> RetOpcode;
681fe6060f1SDimitry Andric   if (MBBI != MBB.end())
682fe6060f1SDimitry Andric     RetOpcode = MBBI->getOpcode();
683fe6060f1SDimitry Andric   DebugLoc DL;
684fe6060f1SDimitry Andric   if (MBBI != MBB.end())
685fe6060f1SDimitry Andric     DL = MBBI->getDebugLoc();
686fe6060f1SDimitry Andric   unsigned FramePtr = TRI->getFrameRegister(MF);
687fe6060f1SDimitry Andric   unsigned MachineFramePtr = FramePtr;
688fe6060f1SDimitry Andric 
689fe6060f1SDimitry Andric   // Get the number of bytes to allocate from the FrameInfo.
690fe6060f1SDimitry Andric   uint64_t StackSize = MFI.getStackSize();
691fe6060f1SDimitry Andric   uint64_t MaxAlign = calculateMaxStackAlign(MF);
692fe6060f1SDimitry Andric   unsigned CSSize = MMFI->getCalleeSavedFrameSize();
693fe6060f1SDimitry Andric   uint64_t NumBytes = 0;
694fe6060f1SDimitry Andric 
695fe6060f1SDimitry Andric   if (hasFP(MF)) {
696fe6060f1SDimitry Andric     // Calculate required stack adjustment.
697fe6060f1SDimitry Andric     uint64_t FrameSize = StackSize - SlotSize;
698fe6060f1SDimitry Andric     NumBytes = FrameSize - CSSize;
699fe6060f1SDimitry Andric 
700fe6060f1SDimitry Andric     // Callee-saved registers were pushed on stack before the stack was
701fe6060f1SDimitry Andric     // realigned.
702fe6060f1SDimitry Andric     if (TRI->hasStackRealignment(MF))
703fe6060f1SDimitry Andric       NumBytes = alignTo(FrameSize, MaxAlign);
704fe6060f1SDimitry Andric 
705fe6060f1SDimitry Andric     // Pop FP.
706fe6060f1SDimitry Andric     BuildMI(MBB, MBBI, DL, TII.get(M68k::POP32r), MachineFramePtr)
707fe6060f1SDimitry Andric         .setMIFlag(MachineInstr::FrameDestroy);
708fe6060f1SDimitry Andric   } else {
709fe6060f1SDimitry Andric     NumBytes = StackSize - CSSize;
710fe6060f1SDimitry Andric   }
711fe6060f1SDimitry Andric 
712fe6060f1SDimitry Andric   // Skip the callee-saved pop instructions.
713fe6060f1SDimitry Andric   while (MBBI != MBB.begin()) {
714fe6060f1SDimitry Andric     MachineBasicBlock::iterator PI = std::prev(MBBI);
715fe6060f1SDimitry Andric     unsigned Opc = PI->getOpcode();
716fe6060f1SDimitry Andric 
717fe6060f1SDimitry Andric     if ((Opc != M68k::POP32r || !PI->getFlag(MachineInstr::FrameDestroy)) &&
718fe6060f1SDimitry Andric         Opc != M68k::DBG_VALUE && !PI->isTerminator())
719fe6060f1SDimitry Andric       break;
720fe6060f1SDimitry Andric 
721fe6060f1SDimitry Andric     --MBBI;
722fe6060f1SDimitry Andric   }
723fe6060f1SDimitry Andric   MachineBasicBlock::iterator FirstCSPop = MBBI;
724fe6060f1SDimitry Andric 
725fe6060f1SDimitry Andric   if (MBBI != MBB.end())
726fe6060f1SDimitry Andric     DL = MBBI->getDebugLoc();
727fe6060f1SDimitry Andric 
728fe6060f1SDimitry Andric   // If there is an ADD32ri or SUB32ri of SP immediately before this
729fe6060f1SDimitry Andric   // instruction, merge the two instructions.
730fe6060f1SDimitry Andric   if (NumBytes || MFI.hasVarSizedObjects())
731fe6060f1SDimitry Andric     NumBytes += mergeSPUpdates(MBB, MBBI, true);
732fe6060f1SDimitry Andric 
733fe6060f1SDimitry Andric   // If dynamic alloca is used, then reset SP to point to the last callee-saved
734fe6060f1SDimitry Andric   // slot before popping them off! Same applies for the case, when stack was
735fe6060f1SDimitry Andric   // realigned. Don't do this if this was a funclet epilogue, since the funclets
736fe6060f1SDimitry Andric   // will not do realignment or dynamic stack allocation.
737fe6060f1SDimitry Andric   if ((TRI->hasStackRealignment(MF) || MFI.hasVarSizedObjects())) {
738fe6060f1SDimitry Andric     if (TRI->hasStackRealignment(MF))
739fe6060f1SDimitry Andric       MBBI = FirstCSPop;
740fe6060f1SDimitry Andric     uint64_t LEAAmount = -CSSize;
741fe6060f1SDimitry Andric 
742fe6060f1SDimitry Andric     // 'move %FramePtr, SP' will not be recognized as an epilogue sequence.
743fe6060f1SDimitry Andric     // However, we may use this sequence if we have a frame pointer because the
744fe6060f1SDimitry Andric     // effects of the prologue can safely be undone.
745fe6060f1SDimitry Andric     if (LEAAmount != 0) {
746fe6060f1SDimitry Andric       unsigned Opc = M68k::LEA32p;
747fe6060f1SDimitry Andric       M68k::addRegIndirectWithDisp(
748fe6060f1SDimitry Andric           BuildMI(MBB, MBBI, DL, TII.get(Opc), StackPtr), FramePtr, false,
749fe6060f1SDimitry Andric           LEAAmount);
750fe6060f1SDimitry Andric       --MBBI;
751fe6060f1SDimitry Andric     } else {
752fe6060f1SDimitry Andric       unsigned Opc = (M68k::MOV32rr);
753fe6060f1SDimitry Andric       BuildMI(MBB, MBBI, DL, TII.get(Opc), StackPtr).addReg(FramePtr);
754fe6060f1SDimitry Andric       --MBBI;
755fe6060f1SDimitry Andric     }
756fe6060f1SDimitry Andric   } else if (NumBytes) {
757fe6060f1SDimitry Andric     // Adjust stack pointer back: SP += numbytes.
758fe6060f1SDimitry Andric     emitSPUpdate(MBB, MBBI, NumBytes, /*InEpilogue=*/true);
759fe6060f1SDimitry Andric     --MBBI;
760fe6060f1SDimitry Andric   }
761fe6060f1SDimitry Andric 
762fe6060f1SDimitry Andric   if (!RetOpcode || !isTailCallOpcode(*RetOpcode)) {
763fe6060f1SDimitry Andric     // Add the return addr area delta back since we are not tail calling.
764fe6060f1SDimitry Andric     int Offset = -1 * MMFI->getTCReturnAddrDelta();
765fe6060f1SDimitry Andric     assert(Offset >= 0 && "TCDelta should never be positive");
766fe6060f1SDimitry Andric     if (Offset) {
767fe6060f1SDimitry Andric       MBBI = MBB.getFirstTerminator();
768fe6060f1SDimitry Andric 
769fe6060f1SDimitry Andric       // Check for possible merge with preceding ADD instruction.
770fe6060f1SDimitry Andric       Offset += mergeSPUpdates(MBB, MBBI, true);
771fe6060f1SDimitry Andric       emitSPUpdate(MBB, MBBI, Offset, /*InEpilogue=*/true);
772fe6060f1SDimitry Andric     }
773fe6060f1SDimitry Andric   }
774fe6060f1SDimitry Andric }
775fe6060f1SDimitry Andric 
776fe6060f1SDimitry Andric void M68kFrameLowering::determineCalleeSaves(MachineFunction &MF,
777fe6060f1SDimitry Andric                                              BitVector &SavedRegs,
778fe6060f1SDimitry Andric                                              RegScavenger *RS) const {
779fe6060f1SDimitry Andric   TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
780fe6060f1SDimitry Andric 
781fe6060f1SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
782fe6060f1SDimitry Andric 
783fe6060f1SDimitry Andric   M68kMachineFunctionInfo *M68kFI = MF.getInfo<M68kMachineFunctionInfo>();
784fe6060f1SDimitry Andric   int64_t TailCallReturnAddrDelta = M68kFI->getTCReturnAddrDelta();
785fe6060f1SDimitry Andric 
786fe6060f1SDimitry Andric   if (TailCallReturnAddrDelta < 0) {
787fe6060f1SDimitry Andric     // create RETURNADDR area
788fe6060f1SDimitry Andric     //   arg
789fe6060f1SDimitry Andric     //   arg
790fe6060f1SDimitry Andric     //   RETADDR
791fe6060f1SDimitry Andric     //   { ...
792fe6060f1SDimitry Andric     //     RETADDR area
793fe6060f1SDimitry Andric     //     ...
794fe6060f1SDimitry Andric     //   }
795fe6060f1SDimitry Andric     //   [FP]
796fe6060f1SDimitry Andric     MFI.CreateFixedObject(-TailCallReturnAddrDelta,
797fe6060f1SDimitry Andric                           TailCallReturnAddrDelta - SlotSize, true);
798fe6060f1SDimitry Andric   }
799fe6060f1SDimitry Andric 
800fe6060f1SDimitry Andric   // Spill the BasePtr if it's used.
801fe6060f1SDimitry Andric   if (TRI->hasBasePointer(MF)) {
802fe6060f1SDimitry Andric     SavedRegs.set(TRI->getBaseRegister());
803fe6060f1SDimitry Andric   }
804fe6060f1SDimitry Andric }
805fe6060f1SDimitry Andric 
806fe6060f1SDimitry Andric bool M68kFrameLowering::assignCalleeSavedSpillSlots(
807fe6060f1SDimitry Andric     MachineFunction &MF, const TargetRegisterInfo *TRI,
808fe6060f1SDimitry Andric     std::vector<CalleeSavedInfo> &CSI) const {
809fe6060f1SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
810fe6060f1SDimitry Andric   M68kMachineFunctionInfo *M68kFI = MF.getInfo<M68kMachineFunctionInfo>();
811fe6060f1SDimitry Andric 
812fe6060f1SDimitry Andric   int SpillSlotOffset = getOffsetOfLocalArea() + M68kFI->getTCReturnAddrDelta();
813fe6060f1SDimitry Andric 
814fe6060f1SDimitry Andric   if (hasFP(MF)) {
815fe6060f1SDimitry Andric     // emitPrologue always spills frame register the first thing.
816fe6060f1SDimitry Andric     SpillSlotOffset -= SlotSize;
817fe6060f1SDimitry Andric     MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
818fe6060f1SDimitry Andric 
819fe6060f1SDimitry Andric     // Since emitPrologue and emitEpilogue will handle spilling and restoring of
820fe6060f1SDimitry Andric     // the frame register, we can delete it from CSI list and not have to worry
821fe6060f1SDimitry Andric     // about avoiding it later.
822fe6060f1SDimitry Andric     unsigned FPReg = TRI->getFrameRegister(MF);
823fe6060f1SDimitry Andric     for (unsigned i = 0, e = CSI.size(); i < e; ++i) {
824fe6060f1SDimitry Andric       if (TRI->regsOverlap(CSI[i].getReg(), FPReg)) {
825fe6060f1SDimitry Andric         CSI.erase(CSI.begin() + i);
826fe6060f1SDimitry Andric         break;
827fe6060f1SDimitry Andric       }
828fe6060f1SDimitry Andric     }
829fe6060f1SDimitry Andric   }
830fe6060f1SDimitry Andric 
831fe6060f1SDimitry Andric   // The rest is fine
832fe6060f1SDimitry Andric   return false;
833fe6060f1SDimitry Andric }
834fe6060f1SDimitry Andric 
835fe6060f1SDimitry Andric bool M68kFrameLowering::spillCalleeSavedRegisters(
836fe6060f1SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
837fe6060f1SDimitry Andric     ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
838fe6060f1SDimitry Andric   auto &MRI = *static_cast<const M68kRegisterInfo *>(TRI);
839fe6060f1SDimitry Andric   auto DL = MBB.findDebugLoc(MI);
840fe6060f1SDimitry Andric 
841fe6060f1SDimitry Andric   int FI = 0;
842fe6060f1SDimitry Andric   unsigned Mask = 0;
843fe6060f1SDimitry Andric   for (const auto &Info : CSI) {
844fe6060f1SDimitry Andric     FI = std::max(FI, Info.getFrameIdx());
845fe6060f1SDimitry Andric     unsigned Reg = Info.getReg();
846fe6060f1SDimitry Andric     unsigned Shift = MRI.getSpillRegisterOrder(Reg);
847fe6060f1SDimitry Andric     Mask |= 1 << Shift;
848fe6060f1SDimitry Andric   }
849fe6060f1SDimitry Andric 
850fe6060f1SDimitry Andric   auto I =
851fe6060f1SDimitry Andric       M68k::addFrameReference(BuildMI(MBB, MI, DL, TII.get(M68k::MOVM32pm)), FI)
852fe6060f1SDimitry Andric           .addImm(Mask)
853fe6060f1SDimitry Andric           .setMIFlag(MachineInstr::FrameSetup);
854fe6060f1SDimitry Andric 
855fe6060f1SDimitry Andric   // Append implicit registers and mem locations
856fe6060f1SDimitry Andric   const MachineFunction &MF = *MBB.getParent();
857fe6060f1SDimitry Andric   const MachineRegisterInfo &RI = MF.getRegInfo();
858fe6060f1SDimitry Andric   for (const auto &Info : CSI) {
859fe6060f1SDimitry Andric     unsigned Reg = Info.getReg();
860fe6060f1SDimitry Andric     bool IsLiveIn = RI.isLiveIn(Reg);
861fe6060f1SDimitry Andric     if (!IsLiveIn)
862fe6060f1SDimitry Andric       MBB.addLiveIn(Reg);
863fe6060f1SDimitry Andric     I.addReg(Reg, IsLiveIn ? RegState::Implicit : RegState::ImplicitKill);
864fe6060f1SDimitry Andric     M68k::addMemOperand(I, Info.getFrameIdx(), 0);
865fe6060f1SDimitry Andric   }
866fe6060f1SDimitry Andric 
867fe6060f1SDimitry Andric   return true;
868fe6060f1SDimitry Andric }
869fe6060f1SDimitry Andric 
870fe6060f1SDimitry Andric bool M68kFrameLowering::restoreCalleeSavedRegisters(
871fe6060f1SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
872fe6060f1SDimitry Andric     MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
873fe6060f1SDimitry Andric   auto &MRI = *static_cast<const M68kRegisterInfo *>(TRI);
874fe6060f1SDimitry Andric   auto DL = MBB.findDebugLoc(MI);
875fe6060f1SDimitry Andric 
876fe6060f1SDimitry Andric   int FI = 0;
877fe6060f1SDimitry Andric   unsigned Mask = 0;
878fe6060f1SDimitry Andric   for (const auto &Info : CSI) {
879fe6060f1SDimitry Andric     FI = std::max(FI, Info.getFrameIdx());
880fe6060f1SDimitry Andric     unsigned Reg = Info.getReg();
881fe6060f1SDimitry Andric     unsigned Shift = MRI.getSpillRegisterOrder(Reg);
882fe6060f1SDimitry Andric     Mask |= 1 << Shift;
883fe6060f1SDimitry Andric   }
884fe6060f1SDimitry Andric 
885fe6060f1SDimitry Andric   auto I = M68k::addFrameReference(
886fe6060f1SDimitry Andric                BuildMI(MBB, MI, DL, TII.get(M68k::MOVM32mp)).addImm(Mask), FI)
887fe6060f1SDimitry Andric                .setMIFlag(MachineInstr::FrameDestroy);
888fe6060f1SDimitry Andric 
889fe6060f1SDimitry Andric   // Append implicit registers and mem locations
890fe6060f1SDimitry Andric   for (const auto &Info : CSI) {
891fe6060f1SDimitry Andric     I.addReg(Info.getReg(), RegState::ImplicitDefine);
892fe6060f1SDimitry Andric     M68k::addMemOperand(I, Info.getFrameIdx(), 0);
893fe6060f1SDimitry Andric   }
894fe6060f1SDimitry Andric 
895fe6060f1SDimitry Andric   return true;
896fe6060f1SDimitry Andric }
897