xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/M68k/M68kFrameLowering.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
104eeddc0SDimitry 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;
16004eeddc0SDimitry Andric       Register 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);
360349cc55cSDimitry 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 
403349cc55cSDimitry 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;
409349cc55cSDimitry 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;
429349cc55cSDimitry 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());
46604eeddc0SDimitry Andric     Register 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();
48804eeddc0SDimitry Andric   Register 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 
549*bdd1243dSDimitry Andric     BuildMI(MBB, MBBI, DL, TII.get(M68k::LINK16))
550*bdd1243dSDimitry Andric         .addReg(M68k::WA6, RegState::Kill)
551*bdd1243dSDimitry Andric         .addImm(-NumBytes)
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     if (NeedsDwarfCFI) {
570fe6060f1SDimitry Andric       // Mark effective beginning of when frame pointer becomes valid.
571fe6060f1SDimitry Andric       // Define the current CFA to use the FP register.
572fe6060f1SDimitry Andric       unsigned DwarfFramePtr = TRI->getDwarfRegNum(MachineFramePtr, true);
573fe6060f1SDimitry Andric       BuildCFI(MBB, MBBI, DL,
574fe6060f1SDimitry Andric                MCCFIInstruction::createDefCfaRegister(nullptr, DwarfFramePtr));
575fe6060f1SDimitry Andric     }
576fe6060f1SDimitry Andric 
577fe6060f1SDimitry Andric     // Mark the FramePtr as live-in in every block. Don't do this again for
578fe6060f1SDimitry Andric     // funclet prologues.
579fe6060f1SDimitry Andric     for (MachineBasicBlock &EveryMBB : MF)
580fe6060f1SDimitry Andric       EveryMBB.addLiveIn(MachineFramePtr);
581fe6060f1SDimitry Andric   } else {
582fe6060f1SDimitry Andric     NumBytes = StackSize - MMFI->getCalleeSavedFrameSize();
583fe6060f1SDimitry Andric   }
584fe6060f1SDimitry Andric 
585fe6060f1SDimitry Andric   // Skip the callee-saved push instructions.
586fe6060f1SDimitry Andric   bool PushedRegs = false;
587fe6060f1SDimitry Andric   int StackOffset = 2 * stackGrowth;
588fe6060f1SDimitry Andric 
589fe6060f1SDimitry Andric   while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup) &&
590fe6060f1SDimitry Andric          MBBI->getOpcode() == M68k::PUSH32r) {
591fe6060f1SDimitry Andric     PushedRegs = true;
592fe6060f1SDimitry Andric     ++MBBI;
593fe6060f1SDimitry Andric 
594fe6060f1SDimitry Andric     if (!HasFP && NeedsDwarfCFI) {
595fe6060f1SDimitry Andric       // Mark callee-saved push instruction.
596fe6060f1SDimitry Andric       // Define the current CFA rule to use the provided offset.
597fe6060f1SDimitry Andric       assert(StackSize);
598fe6060f1SDimitry Andric       BuildCFI(MBB, MBBI, DL,
599fe6060f1SDimitry Andric                MCCFIInstruction::cfiDefCfaOffset(nullptr, StackOffset));
600fe6060f1SDimitry Andric       StackOffset += stackGrowth;
601fe6060f1SDimitry Andric     }
602fe6060f1SDimitry Andric   }
603fe6060f1SDimitry Andric 
604fe6060f1SDimitry Andric   // Realign stack after we pushed callee-saved registers (so that we'll be
605fe6060f1SDimitry Andric   // able to calculate their offsets from the frame pointer).
606fe6060f1SDimitry Andric   if (TRI->hasStackRealignment(MF)) {
607fe6060f1SDimitry Andric     assert(HasFP && "There should be a frame pointer if stack is realigned.");
608fe6060f1SDimitry Andric     BuildStackAlignAND(MBB, MBBI, DL, StackPtr, MaxAlign);
609fe6060f1SDimitry Andric   }
610fe6060f1SDimitry Andric 
611fe6060f1SDimitry Andric   // If there is an SUB32ri of SP immediately before this instruction, merge
612fe6060f1SDimitry Andric   // the two. This can be the case when tail call elimination is enabled and
613fe6060f1SDimitry Andric   // the callee has more arguments then the caller.
614fe6060f1SDimitry Andric   NumBytes -= mergeSPUpdates(MBB, MBBI, true);
615fe6060f1SDimitry Andric 
616fe6060f1SDimitry Andric   // Adjust stack pointer: ESP -= numbytes.
617*bdd1243dSDimitry Andric   if (!HasFP)
618fe6060f1SDimitry Andric     emitSPUpdate(MBB, MBBI, -(int64_t)NumBytes, /*InEpilogue=*/false);
619fe6060f1SDimitry Andric 
620fe6060f1SDimitry Andric   unsigned SPOrEstablisher = StackPtr;
621fe6060f1SDimitry Andric 
622fe6060f1SDimitry Andric   // If we need a base pointer, set it up here. It's whatever the value
623fe6060f1SDimitry Andric   // of the stack pointer is at this point. Any variable size objects
624fe6060f1SDimitry Andric   // will be allocated after this, so we can still use the base pointer
625fe6060f1SDimitry Andric   // to reference locals.
626fe6060f1SDimitry Andric   if (TRI->hasBasePointer(MF)) {
627fe6060f1SDimitry Andric     // Update the base pointer with the current stack pointer.
628fe6060f1SDimitry Andric     BuildMI(MBB, MBBI, DL, TII.get(M68k::MOV32aa), BasePtr)
629fe6060f1SDimitry Andric         .addReg(SPOrEstablisher)
630fe6060f1SDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
631fe6060f1SDimitry Andric     if (MMFI->getRestoreBasePointer()) {
632fe6060f1SDimitry Andric       // Stash value of base pointer.  Saving SP instead of FP shortens
633fe6060f1SDimitry Andric       // dependence chain. Used by SjLj EH.
634fe6060f1SDimitry Andric       unsigned Opm = M68k::MOV32ja;
635fe6060f1SDimitry Andric       M68k::addRegIndirectWithDisp(BuildMI(MBB, MBBI, DL, TII.get(Opm)),
636fe6060f1SDimitry Andric                                    FramePtr, true,
637fe6060f1SDimitry Andric                                    MMFI->getRestoreBasePointerOffset())
638fe6060f1SDimitry Andric           .addReg(SPOrEstablisher)
639fe6060f1SDimitry Andric           .setMIFlag(MachineInstr::FrameSetup);
640fe6060f1SDimitry Andric     }
641fe6060f1SDimitry Andric   }
642fe6060f1SDimitry Andric 
643fe6060f1SDimitry Andric   if (((!HasFP && NumBytes) || PushedRegs) && NeedsDwarfCFI) {
644fe6060f1SDimitry Andric     // Mark end of stack pointer adjustment.
645fe6060f1SDimitry Andric     if (!HasFP && NumBytes) {
646fe6060f1SDimitry Andric       // Define the current CFA rule to use the provided offset.
647fe6060f1SDimitry Andric       assert(StackSize);
648fe6060f1SDimitry Andric       BuildCFI(
649fe6060f1SDimitry Andric           MBB, MBBI, DL,
650fe6060f1SDimitry Andric           MCCFIInstruction::cfiDefCfaOffset(nullptr, -StackSize + stackGrowth));
651fe6060f1SDimitry Andric     }
652fe6060f1SDimitry Andric 
653fe6060f1SDimitry Andric     // Emit DWARF info specifying the offsets of the callee-saved registers.
654fe6060f1SDimitry Andric     if (PushedRegs)
655fe6060f1SDimitry Andric       emitPrologueCalleeSavedFrameMoves(MBB, MBBI, DL);
656fe6060f1SDimitry Andric   }
657fe6060f1SDimitry Andric 
658fe6060f1SDimitry Andric   // TODO Interrupt handlers
659fe6060f1SDimitry Andric   // M68k Interrupt handling function cannot assume anything about the
660fe6060f1SDimitry Andric   // direction flag (DF in CCR register). Clear this flag by creating "cld"
661fe6060f1SDimitry Andric   // instruction in each prologue of interrupt handler function. The "cld"
662fe6060f1SDimitry Andric   // instruction should only in these cases:
663fe6060f1SDimitry Andric   // 1. The interrupt handling function uses any of the "rep" instructions.
664fe6060f1SDimitry Andric   // 2. Interrupt handling function calls another function.
665fe6060f1SDimitry Andric }
666fe6060f1SDimitry Andric 
667fe6060f1SDimitry Andric static bool isTailCallOpcode(unsigned Opc) {
668fe6060f1SDimitry Andric   return Opc == M68k::TCRETURNj || Opc == M68k::TCRETURNq;
669fe6060f1SDimitry Andric }
670fe6060f1SDimitry Andric 
671fe6060f1SDimitry Andric void M68kFrameLowering::emitEpilogue(MachineFunction &MF,
672fe6060f1SDimitry Andric                                      MachineBasicBlock &MBB) const {
673fe6060f1SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
674fe6060f1SDimitry Andric   M68kMachineFunctionInfo *MMFI = MF.getInfo<M68kMachineFunctionInfo>();
675fe6060f1SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
676*bdd1243dSDimitry Andric   std::optional<unsigned> RetOpcode;
677fe6060f1SDimitry Andric   if (MBBI != MBB.end())
678fe6060f1SDimitry Andric     RetOpcode = MBBI->getOpcode();
679fe6060f1SDimitry Andric   DebugLoc DL;
680fe6060f1SDimitry Andric   if (MBBI != MBB.end())
681fe6060f1SDimitry Andric     DL = MBBI->getDebugLoc();
68204eeddc0SDimitry Andric   Register FramePtr = TRI->getFrameRegister(MF);
683fe6060f1SDimitry Andric   unsigned MachineFramePtr = FramePtr;
684fe6060f1SDimitry Andric 
685fe6060f1SDimitry Andric   // Get the number of bytes to allocate from the FrameInfo.
686fe6060f1SDimitry Andric   uint64_t StackSize = MFI.getStackSize();
687fe6060f1SDimitry Andric   uint64_t MaxAlign = calculateMaxStackAlign(MF);
688fe6060f1SDimitry Andric   unsigned CSSize = MMFI->getCalleeSavedFrameSize();
689fe6060f1SDimitry Andric   uint64_t NumBytes = 0;
690fe6060f1SDimitry Andric 
691fe6060f1SDimitry Andric   if (hasFP(MF)) {
692fe6060f1SDimitry Andric     // Calculate required stack adjustment.
693fe6060f1SDimitry Andric     uint64_t FrameSize = StackSize - SlotSize;
694fe6060f1SDimitry Andric     NumBytes = FrameSize - CSSize;
695fe6060f1SDimitry Andric 
696fe6060f1SDimitry Andric     // Callee-saved registers were pushed on stack before the stack was
697fe6060f1SDimitry Andric     // realigned.
698fe6060f1SDimitry Andric     if (TRI->hasStackRealignment(MF))
699fe6060f1SDimitry Andric       NumBytes = alignTo(FrameSize, MaxAlign);
700fe6060f1SDimitry Andric 
701fe6060f1SDimitry Andric   } else {
702fe6060f1SDimitry Andric     NumBytes = StackSize - CSSize;
703fe6060f1SDimitry Andric   }
704fe6060f1SDimitry Andric 
705fe6060f1SDimitry Andric   // Skip the callee-saved pop instructions.
706fe6060f1SDimitry Andric   while (MBBI != MBB.begin()) {
707fe6060f1SDimitry Andric     MachineBasicBlock::iterator PI = std::prev(MBBI);
708fe6060f1SDimitry Andric     unsigned Opc = PI->getOpcode();
709fe6060f1SDimitry Andric 
710fe6060f1SDimitry Andric     if ((Opc != M68k::POP32r || !PI->getFlag(MachineInstr::FrameDestroy)) &&
711fe6060f1SDimitry Andric         Opc != M68k::DBG_VALUE && !PI->isTerminator())
712fe6060f1SDimitry Andric       break;
713fe6060f1SDimitry Andric 
714fe6060f1SDimitry Andric     --MBBI;
715fe6060f1SDimitry Andric   }
716fe6060f1SDimitry Andric   MachineBasicBlock::iterator FirstCSPop = MBBI;
717fe6060f1SDimitry Andric 
718fe6060f1SDimitry Andric   if (MBBI != MBB.end())
719fe6060f1SDimitry Andric     DL = MBBI->getDebugLoc();
720fe6060f1SDimitry Andric 
721fe6060f1SDimitry Andric   // If there is an ADD32ri or SUB32ri of SP immediately before this
722fe6060f1SDimitry Andric   // instruction, merge the two instructions.
723fe6060f1SDimitry Andric   if (NumBytes || MFI.hasVarSizedObjects())
724fe6060f1SDimitry Andric     NumBytes += mergeSPUpdates(MBB, MBBI, true);
725fe6060f1SDimitry Andric 
726fe6060f1SDimitry Andric   // If dynamic alloca is used, then reset SP to point to the last callee-saved
727fe6060f1SDimitry Andric   // slot before popping them off! Same applies for the case, when stack was
728fe6060f1SDimitry Andric   // realigned. Don't do this if this was a funclet epilogue, since the funclets
729fe6060f1SDimitry Andric   // will not do realignment or dynamic stack allocation.
730fe6060f1SDimitry Andric   if ((TRI->hasStackRealignment(MF) || MFI.hasVarSizedObjects())) {
731fe6060f1SDimitry Andric     if (TRI->hasStackRealignment(MF))
732fe6060f1SDimitry Andric       MBBI = FirstCSPop;
733fe6060f1SDimitry Andric     uint64_t LEAAmount = -CSSize;
734fe6060f1SDimitry Andric 
735fe6060f1SDimitry Andric     // 'move %FramePtr, SP' will not be recognized as an epilogue sequence.
736fe6060f1SDimitry Andric     // However, we may use this sequence if we have a frame pointer because the
737fe6060f1SDimitry Andric     // effects of the prologue can safely be undone.
738fe6060f1SDimitry Andric     if (LEAAmount != 0) {
739fe6060f1SDimitry Andric       unsigned Opc = M68k::LEA32p;
740fe6060f1SDimitry Andric       M68k::addRegIndirectWithDisp(
741fe6060f1SDimitry Andric           BuildMI(MBB, MBBI, DL, TII.get(Opc), StackPtr), FramePtr, false,
742fe6060f1SDimitry Andric           LEAAmount);
743fe6060f1SDimitry Andric       --MBBI;
744fe6060f1SDimitry Andric     } else {
745*bdd1243dSDimitry Andric       BuildMI(MBB, MBBI, DL, TII.get(M68k::UNLK))
746*bdd1243dSDimitry Andric           .addReg(MachineFramePtr, RegState::Kill)
747*bdd1243dSDimitry Andric           .setMIFlag(MachineInstr::FrameDestroy);
748fe6060f1SDimitry Andric       --MBBI;
749fe6060f1SDimitry Andric     }
750*bdd1243dSDimitry Andric   } else if (hasFP(MF)) {
751*bdd1243dSDimitry Andric     BuildMI(MBB, MBBI, DL, TII.get(M68k::UNLK))
752*bdd1243dSDimitry Andric         .addReg(MachineFramePtr, RegState::Kill)
753*bdd1243dSDimitry Andric         .setMIFlag(MachineInstr::FrameDestroy);
754fe6060f1SDimitry Andric   } else if (NumBytes) {
755fe6060f1SDimitry Andric     // Adjust stack pointer back: SP += numbytes.
756fe6060f1SDimitry Andric     emitSPUpdate(MBB, MBBI, NumBytes, /*InEpilogue=*/true);
757fe6060f1SDimitry Andric     --MBBI;
758fe6060f1SDimitry Andric   }
759fe6060f1SDimitry Andric 
760fe6060f1SDimitry Andric   if (!RetOpcode || !isTailCallOpcode(*RetOpcode)) {
761fe6060f1SDimitry Andric     // Add the return addr area delta back since we are not tail calling.
762fe6060f1SDimitry Andric     int Offset = -1 * MMFI->getTCReturnAddrDelta();
763fe6060f1SDimitry Andric     assert(Offset >= 0 && "TCDelta should never be positive");
764fe6060f1SDimitry Andric     if (Offset) {
765fe6060f1SDimitry Andric       MBBI = MBB.getFirstTerminator();
766fe6060f1SDimitry Andric 
767fe6060f1SDimitry Andric       // Check for possible merge with preceding ADD instruction.
768fe6060f1SDimitry Andric       Offset += mergeSPUpdates(MBB, MBBI, true);
769fe6060f1SDimitry Andric       emitSPUpdate(MBB, MBBI, Offset, /*InEpilogue=*/true);
770fe6060f1SDimitry Andric     }
771fe6060f1SDimitry Andric   }
772fe6060f1SDimitry Andric }
773fe6060f1SDimitry Andric 
774fe6060f1SDimitry Andric void M68kFrameLowering::determineCalleeSaves(MachineFunction &MF,
775fe6060f1SDimitry Andric                                              BitVector &SavedRegs,
776fe6060f1SDimitry Andric                                              RegScavenger *RS) const {
777fe6060f1SDimitry Andric   TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
778fe6060f1SDimitry Andric 
779fe6060f1SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
780fe6060f1SDimitry Andric 
781fe6060f1SDimitry Andric   M68kMachineFunctionInfo *M68kFI = MF.getInfo<M68kMachineFunctionInfo>();
782fe6060f1SDimitry Andric   int64_t TailCallReturnAddrDelta = M68kFI->getTCReturnAddrDelta();
783fe6060f1SDimitry Andric 
784fe6060f1SDimitry Andric   if (TailCallReturnAddrDelta < 0) {
785fe6060f1SDimitry Andric     // create RETURNADDR area
786fe6060f1SDimitry Andric     //   arg
787fe6060f1SDimitry Andric     //   arg
788fe6060f1SDimitry Andric     //   RETADDR
789fe6060f1SDimitry Andric     //   { ...
790fe6060f1SDimitry Andric     //     RETADDR area
791fe6060f1SDimitry Andric     //     ...
792fe6060f1SDimitry Andric     //   }
793fe6060f1SDimitry Andric     //   [FP]
794fe6060f1SDimitry Andric     MFI.CreateFixedObject(-TailCallReturnAddrDelta,
795fe6060f1SDimitry Andric                           TailCallReturnAddrDelta - SlotSize, true);
796fe6060f1SDimitry Andric   }
797fe6060f1SDimitry Andric 
798fe6060f1SDimitry Andric   // Spill the BasePtr if it's used.
799fe6060f1SDimitry Andric   if (TRI->hasBasePointer(MF)) {
800fe6060f1SDimitry Andric     SavedRegs.set(TRI->getBaseRegister());
801fe6060f1SDimitry Andric   }
802fe6060f1SDimitry Andric }
803fe6060f1SDimitry Andric 
804fe6060f1SDimitry Andric bool M68kFrameLowering::assignCalleeSavedSpillSlots(
805fe6060f1SDimitry Andric     MachineFunction &MF, const TargetRegisterInfo *TRI,
806fe6060f1SDimitry Andric     std::vector<CalleeSavedInfo> &CSI) const {
807fe6060f1SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
808fe6060f1SDimitry Andric   M68kMachineFunctionInfo *M68kFI = MF.getInfo<M68kMachineFunctionInfo>();
809fe6060f1SDimitry Andric 
810fe6060f1SDimitry Andric   int SpillSlotOffset = getOffsetOfLocalArea() + M68kFI->getTCReturnAddrDelta();
811fe6060f1SDimitry Andric 
812fe6060f1SDimitry Andric   if (hasFP(MF)) {
813fe6060f1SDimitry Andric     // emitPrologue always spills frame register the first thing.
814fe6060f1SDimitry Andric     SpillSlotOffset -= SlotSize;
815fe6060f1SDimitry Andric     MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
816fe6060f1SDimitry Andric 
817fe6060f1SDimitry Andric     // Since emitPrologue and emitEpilogue will handle spilling and restoring of
818fe6060f1SDimitry Andric     // the frame register, we can delete it from CSI list and not have to worry
819fe6060f1SDimitry Andric     // about avoiding it later.
82004eeddc0SDimitry Andric     Register FPReg = TRI->getFrameRegister(MF);
821fe6060f1SDimitry Andric     for (unsigned i = 0, e = CSI.size(); i < e; ++i) {
822fe6060f1SDimitry Andric       if (TRI->regsOverlap(CSI[i].getReg(), FPReg)) {
823fe6060f1SDimitry Andric         CSI.erase(CSI.begin() + i);
824fe6060f1SDimitry Andric         break;
825fe6060f1SDimitry Andric       }
826fe6060f1SDimitry Andric     }
827fe6060f1SDimitry Andric   }
828fe6060f1SDimitry Andric 
829fe6060f1SDimitry Andric   // The rest is fine
830fe6060f1SDimitry Andric   return false;
831fe6060f1SDimitry Andric }
832fe6060f1SDimitry Andric 
833fe6060f1SDimitry Andric bool M68kFrameLowering::spillCalleeSavedRegisters(
834fe6060f1SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
835fe6060f1SDimitry Andric     ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
836fe6060f1SDimitry Andric   auto &MRI = *static_cast<const M68kRegisterInfo *>(TRI);
837fe6060f1SDimitry Andric   auto DL = MBB.findDebugLoc(MI);
838fe6060f1SDimitry Andric 
839fe6060f1SDimitry Andric   int FI = 0;
840fe6060f1SDimitry Andric   unsigned Mask = 0;
841fe6060f1SDimitry Andric   for (const auto &Info : CSI) {
842fe6060f1SDimitry Andric     FI = std::max(FI, Info.getFrameIdx());
84304eeddc0SDimitry Andric     Register Reg = Info.getReg();
844fe6060f1SDimitry Andric     unsigned Shift = MRI.getSpillRegisterOrder(Reg);
845fe6060f1SDimitry Andric     Mask |= 1 << Shift;
846fe6060f1SDimitry Andric   }
847fe6060f1SDimitry Andric 
848fe6060f1SDimitry Andric   auto I =
849fe6060f1SDimitry Andric       M68k::addFrameReference(BuildMI(MBB, MI, DL, TII.get(M68k::MOVM32pm)), FI)
850fe6060f1SDimitry Andric           .addImm(Mask)
851fe6060f1SDimitry Andric           .setMIFlag(MachineInstr::FrameSetup);
852fe6060f1SDimitry Andric 
853fe6060f1SDimitry Andric   // Append implicit registers and mem locations
854fe6060f1SDimitry Andric   const MachineFunction &MF = *MBB.getParent();
855fe6060f1SDimitry Andric   const MachineRegisterInfo &RI = MF.getRegInfo();
856fe6060f1SDimitry Andric   for (const auto &Info : CSI) {
85704eeddc0SDimitry Andric     Register Reg = Info.getReg();
858fe6060f1SDimitry Andric     bool IsLiveIn = RI.isLiveIn(Reg);
859fe6060f1SDimitry Andric     if (!IsLiveIn)
860fe6060f1SDimitry Andric       MBB.addLiveIn(Reg);
861fe6060f1SDimitry Andric     I.addReg(Reg, IsLiveIn ? RegState::Implicit : RegState::ImplicitKill);
862fe6060f1SDimitry Andric     M68k::addMemOperand(I, Info.getFrameIdx(), 0);
863fe6060f1SDimitry Andric   }
864fe6060f1SDimitry Andric 
865fe6060f1SDimitry Andric   return true;
866fe6060f1SDimitry Andric }
867fe6060f1SDimitry Andric 
868fe6060f1SDimitry Andric bool M68kFrameLowering::restoreCalleeSavedRegisters(
869fe6060f1SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
870fe6060f1SDimitry Andric     MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
871fe6060f1SDimitry Andric   auto &MRI = *static_cast<const M68kRegisterInfo *>(TRI);
872fe6060f1SDimitry Andric   auto DL = MBB.findDebugLoc(MI);
873fe6060f1SDimitry Andric 
874fe6060f1SDimitry Andric   int FI = 0;
875fe6060f1SDimitry Andric   unsigned Mask = 0;
876fe6060f1SDimitry Andric   for (const auto &Info : CSI) {
877fe6060f1SDimitry Andric     FI = std::max(FI, Info.getFrameIdx());
87804eeddc0SDimitry Andric     Register Reg = Info.getReg();
879fe6060f1SDimitry Andric     unsigned Shift = MRI.getSpillRegisterOrder(Reg);
880fe6060f1SDimitry Andric     Mask |= 1 << Shift;
881fe6060f1SDimitry Andric   }
882fe6060f1SDimitry Andric 
883fe6060f1SDimitry Andric   auto I = M68k::addFrameReference(
884fe6060f1SDimitry Andric                BuildMI(MBB, MI, DL, TII.get(M68k::MOVM32mp)).addImm(Mask), FI)
885fe6060f1SDimitry Andric                .setMIFlag(MachineInstr::FrameDestroy);
886fe6060f1SDimitry Andric 
887fe6060f1SDimitry Andric   // Append implicit registers and mem locations
888fe6060f1SDimitry Andric   for (const auto &Info : CSI) {
889fe6060f1SDimitry Andric     I.addReg(Info.getReg(), RegState::ImplicitDefine);
890fe6060f1SDimitry Andric     M68k::addMemOperand(I, Info.getFrameIdx(), 0);
891fe6060f1SDimitry Andric   }
892fe6060f1SDimitry Andric 
893fe6060f1SDimitry Andric   return true;
894fe6060f1SDimitry Andric }
895