xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/M68k/M68kFrameLowering.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
249*0fca6ea1SDimitry Andric     bool DwarfCFI = MF.needsFrameMoves();
250fe6060f1SDimitry Andric 
251fe6060f1SDimitry Andric     // If we have any exception handlers in this function, and we adjust
252fe6060f1SDimitry Andric     // the SP before calls, we may need to indicate this to the unwinder
253fe6060f1SDimitry Andric     // using GNU_ARGS_SIZE. Note that this may be necessary even when
254fe6060f1SDimitry Andric     // Amount == 0, because the preceding function may have set a non-0
255fe6060f1SDimitry Andric     // GNU_ARGS_SIZE.
256fe6060f1SDimitry Andric     // TODO: We don't need to reset this between subsequent functions,
257fe6060f1SDimitry Andric     // if it didn't change.
258fe6060f1SDimitry Andric     bool HasDwarfEHHandlers = !MF.getLandingPads().empty();
259fe6060f1SDimitry Andric 
260fe6060f1SDimitry Andric     if (HasDwarfEHHandlers && !IsDestroy &&
261fe6060f1SDimitry Andric         MF.getInfo<M68kMachineFunctionInfo>()->getHasPushSequences()) {
262fe6060f1SDimitry Andric       BuildCFI(MBB, I, DL,
263fe6060f1SDimitry Andric                MCCFIInstruction::createGnuArgsSize(nullptr, Amount));
264fe6060f1SDimitry Andric     }
265fe6060f1SDimitry Andric 
266fe6060f1SDimitry Andric     if (Amount == 0)
267fe6060f1SDimitry Andric       return I;
268fe6060f1SDimitry Andric 
269fe6060f1SDimitry Andric     // Factor out the amount that gets handled inside the sequence
270fe6060f1SDimitry Andric     // (Pushes of argument for frame setup, callee pops for frame destroy)
271fe6060f1SDimitry Andric     Amount -= InternalAmt;
272fe6060f1SDimitry Andric 
273fe6060f1SDimitry Andric     // TODO: This is needed only if we require precise CFA.
274fe6060f1SDimitry Andric     // If this is a callee-pop calling convention, emit a CFA adjust for
275fe6060f1SDimitry Andric     // the amount the callee popped.
276fe6060f1SDimitry Andric     if (IsDestroy && InternalAmt && DwarfCFI && !hasFP(MF))
277fe6060f1SDimitry Andric       BuildCFI(MBB, I, DL,
278fe6060f1SDimitry Andric                MCCFIInstruction::createAdjustCfaOffset(nullptr, -InternalAmt));
279fe6060f1SDimitry Andric 
280fe6060f1SDimitry Andric     // Add Amount to SP to destroy a frame, or subtract to setup.
281fe6060f1SDimitry Andric     int64_t StackAdjustment = IsDestroy ? Amount : -Amount;
282fe6060f1SDimitry Andric     int64_t CfaAdjustment = -StackAdjustment;
283fe6060f1SDimitry Andric 
284fe6060f1SDimitry Andric     if (StackAdjustment) {
285fe6060f1SDimitry Andric       // Merge with any previous or following adjustment instruction. Note: the
286fe6060f1SDimitry Andric       // instructions merged with here do not have CFI, so their stack
287fe6060f1SDimitry Andric       // adjustments do not feed into CfaAdjustment.
288fe6060f1SDimitry Andric       StackAdjustment += mergeSPUpdates(MBB, I, true);
289fe6060f1SDimitry Andric       StackAdjustment += mergeSPUpdates(MBB, I, false);
290fe6060f1SDimitry Andric 
291fe6060f1SDimitry Andric       if (StackAdjustment) {
292fe6060f1SDimitry Andric         BuildStackAdjustment(MBB, I, DL, StackAdjustment, false);
293fe6060f1SDimitry Andric       }
294fe6060f1SDimitry Andric     }
295fe6060f1SDimitry Andric 
296fe6060f1SDimitry Andric     if (DwarfCFI && !hasFP(MF)) {
297fe6060f1SDimitry Andric       // If we don't have FP, but need to generate unwind information,
298fe6060f1SDimitry Andric       // we need to set the correct CFA offset after the stack adjustment.
299fe6060f1SDimitry Andric       // How much we adjust the CFA offset depends on whether we're emitting
300fe6060f1SDimitry Andric       // CFI only for EH purposes or for debugging. EH only requires the CFA
301fe6060f1SDimitry Andric       // offset to be correct at each call site, while for debugging we want
302fe6060f1SDimitry Andric       // it to be more precise.
303fe6060f1SDimitry Andric 
304fe6060f1SDimitry Andric       // TODO: When not using precise CFA, we also need to adjust for the
305fe6060f1SDimitry Andric       // InternalAmt here.
306fe6060f1SDimitry Andric       if (CfaAdjustment) {
307fe6060f1SDimitry Andric         BuildCFI(
308fe6060f1SDimitry Andric             MBB, I, DL,
309fe6060f1SDimitry Andric             MCCFIInstruction::createAdjustCfaOffset(nullptr, CfaAdjustment));
310fe6060f1SDimitry Andric       }
311fe6060f1SDimitry Andric     }
312fe6060f1SDimitry Andric 
313fe6060f1SDimitry Andric     return I;
314fe6060f1SDimitry Andric   }
315fe6060f1SDimitry Andric 
316fe6060f1SDimitry Andric   if (IsDestroy && InternalAmt) {
317fe6060f1SDimitry Andric     // If we are performing frame pointer elimination and if the callee pops
318fe6060f1SDimitry Andric     // something off the stack pointer, add it back.  We do this until we have
319fe6060f1SDimitry Andric     // more advanced stack pointer tracking ability.
320fe6060f1SDimitry Andric     // We are not tracking the stack pointer adjustment by the callee, so make
321fe6060f1SDimitry Andric     // sure we restore the stack pointer immediately after the call, there may
322fe6060f1SDimitry Andric     // be spill code inserted between the CALL and ADJCALLSTACKUP instructions.
323fe6060f1SDimitry Andric     MachineBasicBlock::iterator CI = I;
324fe6060f1SDimitry Andric     MachineBasicBlock::iterator B = MBB.begin();
325fe6060f1SDimitry Andric     while (CI != B && !std::prev(CI)->isCall())
326fe6060f1SDimitry Andric       --CI;
327fe6060f1SDimitry Andric     BuildStackAdjustment(MBB, CI, DL, -InternalAmt, /*InEpilogue=*/false);
328fe6060f1SDimitry Andric   }
329fe6060f1SDimitry Andric 
330fe6060f1SDimitry Andric   return I;
331fe6060f1SDimitry Andric }
332fe6060f1SDimitry Andric 
333fe6060f1SDimitry Andric /// Emit a series of instructions to increment / decrement the stack pointer by
334fe6060f1SDimitry Andric /// a constant value.
335fe6060f1SDimitry Andric void M68kFrameLowering::emitSPUpdate(MachineBasicBlock &MBB,
336fe6060f1SDimitry Andric                                      MachineBasicBlock::iterator &MBBI,
337fe6060f1SDimitry Andric                                      int64_t NumBytes, bool InEpilogue) const {
338fe6060f1SDimitry Andric   bool IsSub = NumBytes < 0;
339fe6060f1SDimitry Andric   uint64_t Offset = IsSub ? -NumBytes : NumBytes;
340fe6060f1SDimitry Andric 
341fe6060f1SDimitry Andric   uint64_t Chunk = (1LL << 31) - 1;
342fe6060f1SDimitry Andric   DebugLoc DL = MBB.findDebugLoc(MBBI);
343fe6060f1SDimitry Andric 
344fe6060f1SDimitry Andric   while (Offset) {
345fe6060f1SDimitry Andric     if (Offset > Chunk) {
346fe6060f1SDimitry Andric       // Rather than emit a long series of instructions for large offsets,
347fe6060f1SDimitry Andric       // load the offset into a register and do one sub/add
348fe6060f1SDimitry Andric       Register Reg;
349fe6060f1SDimitry Andric 
350fe6060f1SDimitry Andric       if (IsSub && !isRegLiveIn(MBB, M68k::D0))
351fe6060f1SDimitry Andric         Reg = M68k::D0;
352fe6060f1SDimitry Andric       else
353fe6060f1SDimitry Andric         Reg = findDeadCallerSavedReg(MBB, MBBI, TRI);
354fe6060f1SDimitry Andric 
355fe6060f1SDimitry Andric       if (Reg) {
356fe6060f1SDimitry Andric         unsigned Opc = M68k::MOV32ri;
357fe6060f1SDimitry Andric         BuildMI(MBB, MBBI, DL, TII.get(Opc), Reg).addImm(Offset);
358349cc55cSDimitry Andric         Opc = IsSub ? M68k::SUB32ar : M68k::ADD32ar;
359fe6060f1SDimitry Andric         MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opc), StackPtr)
360fe6060f1SDimitry Andric                                .addReg(StackPtr)
361fe6060f1SDimitry Andric                                .addReg(Reg);
362fe6060f1SDimitry Andric         // ??? still no CCR
363fe6060f1SDimitry Andric         MI->getOperand(3).setIsDead(); // The CCR implicit def is dead.
364fe6060f1SDimitry Andric         Offset = 0;
365fe6060f1SDimitry Andric         continue;
366fe6060f1SDimitry Andric       }
367fe6060f1SDimitry Andric     }
368fe6060f1SDimitry Andric 
369fe6060f1SDimitry Andric     uint64_t ThisVal = std::min(Offset, Chunk);
370fe6060f1SDimitry Andric 
371fe6060f1SDimitry Andric     MachineInstrBuilder MI = BuildStackAdjustment(
372fe6060f1SDimitry Andric         MBB, MBBI, DL, IsSub ? -ThisVal : ThisVal, InEpilogue);
373fe6060f1SDimitry Andric     if (IsSub)
374fe6060f1SDimitry Andric       MI.setMIFlag(MachineInstr::FrameSetup);
375fe6060f1SDimitry Andric     else
376fe6060f1SDimitry Andric       MI.setMIFlag(MachineInstr::FrameDestroy);
377fe6060f1SDimitry Andric 
378fe6060f1SDimitry Andric     Offset -= ThisVal;
379fe6060f1SDimitry Andric   }
380fe6060f1SDimitry Andric }
381fe6060f1SDimitry Andric 
382fe6060f1SDimitry Andric int M68kFrameLowering::mergeSPUpdates(MachineBasicBlock &MBB,
383fe6060f1SDimitry Andric                                       MachineBasicBlock::iterator &MBBI,
384fe6060f1SDimitry Andric                                       bool MergeWithPrevious) const {
385fe6060f1SDimitry Andric   if ((MergeWithPrevious && MBBI == MBB.begin()) ||
386fe6060f1SDimitry Andric       (!MergeWithPrevious && MBBI == MBB.end()))
387fe6060f1SDimitry Andric     return 0;
388fe6060f1SDimitry Andric 
389fe6060f1SDimitry Andric   MachineBasicBlock::iterator PI = MergeWithPrevious ? std::prev(MBBI) : MBBI;
390fe6060f1SDimitry Andric   MachineBasicBlock::iterator NI =
391fe6060f1SDimitry Andric       MergeWithPrevious ? nullptr : std::next(MBBI);
392fe6060f1SDimitry Andric   unsigned Opc = PI->getOpcode();
393fe6060f1SDimitry Andric   int Offset = 0;
394fe6060f1SDimitry Andric 
395fe6060f1SDimitry Andric   if (!MergeWithPrevious && NI != MBB.end() &&
396fe6060f1SDimitry Andric       NI->getOpcode() == TargetOpcode::CFI_INSTRUCTION) {
397fe6060f1SDimitry Andric     // Don't merge with the next instruction if it has CFI.
398fe6060f1SDimitry Andric     return Offset;
399fe6060f1SDimitry Andric   }
400fe6060f1SDimitry Andric 
401349cc55cSDimitry Andric   if (Opc == M68k::ADD32ai && PI->getOperand(0).getReg() == StackPtr) {
402fe6060f1SDimitry Andric     assert(PI->getOperand(1).getReg() == StackPtr);
403fe6060f1SDimitry Andric     Offset += PI->getOperand(2).getImm();
404fe6060f1SDimitry Andric     MBB.erase(PI);
405fe6060f1SDimitry Andric     if (!MergeWithPrevious)
406fe6060f1SDimitry Andric       MBBI = NI;
407349cc55cSDimitry Andric   } else if (Opc == M68k::SUB32ai && PI->getOperand(0).getReg() == StackPtr) {
408fe6060f1SDimitry Andric     assert(PI->getOperand(1).getReg() == StackPtr);
409fe6060f1SDimitry Andric     Offset -= PI->getOperand(2).getImm();
410fe6060f1SDimitry Andric     MBB.erase(PI);
411fe6060f1SDimitry Andric     if (!MergeWithPrevious)
412fe6060f1SDimitry Andric       MBBI = NI;
413fe6060f1SDimitry Andric   }
414fe6060f1SDimitry Andric 
415fe6060f1SDimitry Andric   return Offset;
416fe6060f1SDimitry Andric }
417fe6060f1SDimitry Andric 
418fe6060f1SDimitry Andric MachineInstrBuilder M68kFrameLowering::BuildStackAdjustment(
419fe6060f1SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
420fe6060f1SDimitry Andric     const DebugLoc &DL, int64_t Offset, bool InEpilogue) const {
421fe6060f1SDimitry Andric   assert(Offset != 0 && "zero offset stack adjustment requested");
422fe6060f1SDimitry Andric 
423fe6060f1SDimitry Andric   // TODO can `lea` be used to adjust stack?
424fe6060f1SDimitry Andric 
425fe6060f1SDimitry Andric   bool IsSub = Offset < 0;
426fe6060f1SDimitry Andric   uint64_t AbsOffset = IsSub ? -Offset : Offset;
427349cc55cSDimitry Andric   unsigned Opc = IsSub ? M68k::SUB32ai : M68k::ADD32ai;
428fe6060f1SDimitry Andric 
429fe6060f1SDimitry Andric   MachineInstrBuilder MI = BuildMI(MBB, MBBI, DL, TII.get(Opc), StackPtr)
430fe6060f1SDimitry Andric                                .addReg(StackPtr)
431fe6060f1SDimitry Andric                                .addImm(AbsOffset);
432fe6060f1SDimitry Andric   // FIXME Update CCR as well. For now we just
433fe6060f1SDimitry Andric   // conservatively say CCR implicit def is dead
434fe6060f1SDimitry Andric   MI->getOperand(3).setIsDead();
435fe6060f1SDimitry Andric   return MI;
436fe6060f1SDimitry Andric }
437fe6060f1SDimitry Andric 
438fe6060f1SDimitry Andric void M68kFrameLowering::BuildCFI(MachineBasicBlock &MBB,
439fe6060f1SDimitry Andric                                  MachineBasicBlock::iterator MBBI,
440fe6060f1SDimitry Andric                                  const DebugLoc &DL,
441fe6060f1SDimitry Andric                                  const MCCFIInstruction &CFIInst) const {
442fe6060f1SDimitry Andric   MachineFunction &MF = *MBB.getParent();
443fe6060f1SDimitry Andric   unsigned CFIIndex = MF.addFrameInst(CFIInst);
444fe6060f1SDimitry Andric   BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
445fe6060f1SDimitry Andric       .addCFIIndex(CFIIndex);
446fe6060f1SDimitry Andric }
447fe6060f1SDimitry Andric 
448fe6060f1SDimitry Andric void M68kFrameLowering::emitPrologueCalleeSavedFrameMoves(
449fe6060f1SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
450fe6060f1SDimitry Andric     const DebugLoc &DL) const {
451fe6060f1SDimitry Andric   MachineFunction &MF = *MBB.getParent();
452fe6060f1SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
453*0fca6ea1SDimitry Andric   const MCRegisterInfo *MRI = MF.getContext().getRegisterInfo();
454fe6060f1SDimitry Andric 
455fe6060f1SDimitry Andric   // Add callee saved registers to move list.
456fe6060f1SDimitry Andric   const auto &CSI = MFI.getCalleeSavedInfo();
457fe6060f1SDimitry Andric   if (CSI.empty())
458fe6060f1SDimitry Andric     return;
459fe6060f1SDimitry Andric 
460fe6060f1SDimitry Andric   // Calculate offsets.
461fe6060f1SDimitry Andric   for (const auto &I : CSI) {
462fe6060f1SDimitry Andric     int64_t Offset = MFI.getObjectOffset(I.getFrameIdx());
46304eeddc0SDimitry Andric     Register Reg = I.getReg();
464fe6060f1SDimitry Andric 
465fe6060f1SDimitry Andric     unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true);
466fe6060f1SDimitry Andric     BuildCFI(MBB, MBBI, DL,
467fe6060f1SDimitry Andric              MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset));
468fe6060f1SDimitry Andric   }
469fe6060f1SDimitry Andric }
470fe6060f1SDimitry Andric 
471fe6060f1SDimitry Andric void M68kFrameLowering::emitPrologue(MachineFunction &MF,
472fe6060f1SDimitry Andric                                      MachineBasicBlock &MBB) const {
473fe6060f1SDimitry Andric   assert(&STI == &MF.getSubtarget<M68kSubtarget>() &&
474fe6060f1SDimitry Andric          "MF used frame lowering for wrong subtarget");
475fe6060f1SDimitry Andric 
476fe6060f1SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.begin();
477fe6060f1SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
478fe6060f1SDimitry Andric   const auto &Fn = MF.getFunction();
479fe6060f1SDimitry Andric   MachineModuleInfo &MMI = MF.getMMI();
480fe6060f1SDimitry Andric   M68kMachineFunctionInfo *MMFI = MF.getInfo<M68kMachineFunctionInfo>();
481fe6060f1SDimitry Andric   uint64_t MaxAlign = calculateMaxStackAlign(MF); // Desired stack alignment.
482fe6060f1SDimitry Andric   uint64_t StackSize = MFI.getStackSize(); // Number of bytes to allocate.
483fe6060f1SDimitry Andric   bool HasFP = hasFP(MF);
484fe6060f1SDimitry Andric   bool NeedsDwarfCFI = MMI.hasDebugInfo() || Fn.needsUnwindTableEntry();
48504eeddc0SDimitry Andric   Register FramePtr = TRI->getFrameRegister(MF);
486fe6060f1SDimitry Andric   const unsigned MachineFramePtr = FramePtr;
487fe6060f1SDimitry Andric   unsigned BasePtr = TRI->getBaseRegister();
488fe6060f1SDimitry Andric 
489fe6060f1SDimitry Andric   // Debug location must be unknown since the first debug location is used
490fe6060f1SDimitry Andric   // to determine the end of the prologue.
491fe6060f1SDimitry Andric   DebugLoc DL;
492fe6060f1SDimitry Andric 
493fe6060f1SDimitry Andric   // Add RETADDR move area to callee saved frame size.
494fe6060f1SDimitry Andric   int TailCallReturnAddrDelta = MMFI->getTCReturnAddrDelta();
495fe6060f1SDimitry Andric 
496fe6060f1SDimitry Andric   if (TailCallReturnAddrDelta < 0) {
497fe6060f1SDimitry Andric     MMFI->setCalleeSavedFrameSize(MMFI->getCalleeSavedFrameSize() -
498fe6060f1SDimitry Andric                                   TailCallReturnAddrDelta);
499fe6060f1SDimitry Andric   }
500fe6060f1SDimitry Andric 
501fe6060f1SDimitry Andric   // Insert stack pointer adjustment for later moving of return addr.  Only
502fe6060f1SDimitry Andric   // applies to tail call optimized functions where the callee argument stack
503fe6060f1SDimitry Andric   // size is bigger than the callers.
504fe6060f1SDimitry Andric   if (TailCallReturnAddrDelta < 0) {
505fe6060f1SDimitry Andric     BuildStackAdjustment(MBB, MBBI, DL, TailCallReturnAddrDelta,
506fe6060f1SDimitry Andric                          /*InEpilogue=*/false)
507fe6060f1SDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
508fe6060f1SDimitry Andric   }
509fe6060f1SDimitry Andric 
510fe6060f1SDimitry Andric   // Mapping for machine moves:
511fe6060f1SDimitry Andric   //
512fe6060f1SDimitry Andric   //   DST: VirtualFP AND
513fe6060f1SDimitry Andric   //        SRC: VirtualFP              => DW_CFA_def_cfa_offset
514fe6060f1SDimitry Andric   //        ELSE                        => DW_CFA_def_cfa
515fe6060f1SDimitry Andric   //
516fe6060f1SDimitry Andric   //   SRC: VirtualFP AND
517fe6060f1SDimitry Andric   //        DST: Register               => DW_CFA_def_cfa_register
518fe6060f1SDimitry Andric   //
519fe6060f1SDimitry Andric   //   ELSE
520fe6060f1SDimitry Andric   //        OFFSET < 0                  => DW_CFA_offset_extended_sf
521fe6060f1SDimitry Andric   //        REG < 64                    => DW_CFA_offset + Reg
522fe6060f1SDimitry Andric   //        ELSE                        => DW_CFA_offset_extended
523fe6060f1SDimitry Andric 
524fe6060f1SDimitry Andric   uint64_t NumBytes = 0;
525fe6060f1SDimitry Andric   int stackGrowth = -SlotSize;
526fe6060f1SDimitry Andric 
527fe6060f1SDimitry Andric   if (HasFP) {
528fe6060f1SDimitry Andric     // Calculate required stack adjustment.
529fe6060f1SDimitry Andric     uint64_t FrameSize = StackSize - SlotSize;
530fe6060f1SDimitry Andric     // If required, include space for extra hidden slot for stashing base
531fe6060f1SDimitry Andric     // pointer.
532fe6060f1SDimitry Andric     if (MMFI->getRestoreBasePointer())
533fe6060f1SDimitry Andric       FrameSize += SlotSize;
534fe6060f1SDimitry Andric 
535fe6060f1SDimitry Andric     NumBytes = FrameSize - MMFI->getCalleeSavedFrameSize();
536fe6060f1SDimitry Andric 
537fe6060f1SDimitry Andric     // Callee-saved registers are pushed on stack before the stack is realigned.
538fe6060f1SDimitry Andric     if (TRI->hasStackRealignment(MF))
539fe6060f1SDimitry Andric       NumBytes = alignTo(NumBytes, MaxAlign);
540fe6060f1SDimitry Andric 
541fe6060f1SDimitry Andric     // Get the offset of the stack slot for the FP register, which is
542fe6060f1SDimitry Andric     // guaranteed to be the last slot by processFunctionBeforeFrameFinalized.
543fe6060f1SDimitry Andric     // Update the frame offset adjustment.
544fe6060f1SDimitry Andric     MFI.setOffsetAdjustment(-NumBytes);
545fe6060f1SDimitry Andric 
546bdd1243dSDimitry Andric     BuildMI(MBB, MBBI, DL, TII.get(M68k::LINK16))
547bdd1243dSDimitry Andric         .addReg(M68k::WA6, RegState::Kill)
548bdd1243dSDimitry Andric         .addImm(-NumBytes)
549fe6060f1SDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
550fe6060f1SDimitry Andric 
551fe6060f1SDimitry Andric     if (NeedsDwarfCFI) {
552fe6060f1SDimitry Andric       // Mark the place where FP was saved.
553fe6060f1SDimitry Andric       // Define the current CFA rule to use the provided offset.
554fe6060f1SDimitry Andric       assert(StackSize);
555fe6060f1SDimitry Andric       BuildCFI(MBB, MBBI, DL,
556fe6060f1SDimitry Andric                MCCFIInstruction::cfiDefCfaOffset(nullptr, 2 * stackGrowth));
557fe6060f1SDimitry Andric 
558fe6060f1SDimitry Andric       // Change the rule for the FramePtr to be an "offset" rule.
559fe6060f1SDimitry Andric       int DwarfFramePtr = TRI->getDwarfRegNum(MachineFramePtr, true);
560fe6060f1SDimitry Andric       assert(DwarfFramePtr > 0);
561fe6060f1SDimitry Andric       BuildCFI(MBB, MBBI, DL,
562fe6060f1SDimitry Andric                MCCFIInstruction::createOffset(nullptr, DwarfFramePtr,
563fe6060f1SDimitry Andric                                               2 * stackGrowth));
564fe6060f1SDimitry Andric     }
565fe6060f1SDimitry Andric 
566fe6060f1SDimitry Andric     if (NeedsDwarfCFI) {
567fe6060f1SDimitry Andric       // Mark effective beginning of when frame pointer becomes valid.
568fe6060f1SDimitry Andric       // Define the current CFA to use the FP register.
569fe6060f1SDimitry Andric       unsigned DwarfFramePtr = TRI->getDwarfRegNum(MachineFramePtr, true);
570fe6060f1SDimitry Andric       BuildCFI(MBB, MBBI, DL,
571fe6060f1SDimitry Andric                MCCFIInstruction::createDefCfaRegister(nullptr, DwarfFramePtr));
572fe6060f1SDimitry Andric     }
573fe6060f1SDimitry Andric 
574fe6060f1SDimitry Andric     // Mark the FramePtr as live-in in every block. Don't do this again for
575fe6060f1SDimitry Andric     // funclet prologues.
576fe6060f1SDimitry Andric     for (MachineBasicBlock &EveryMBB : MF)
577fe6060f1SDimitry Andric       EveryMBB.addLiveIn(MachineFramePtr);
578fe6060f1SDimitry Andric   } else {
579fe6060f1SDimitry Andric     NumBytes = StackSize - MMFI->getCalleeSavedFrameSize();
580fe6060f1SDimitry Andric   }
581fe6060f1SDimitry Andric 
582fe6060f1SDimitry Andric   // Skip the callee-saved push instructions.
583fe6060f1SDimitry Andric   bool PushedRegs = false;
584fe6060f1SDimitry Andric   int StackOffset = 2 * stackGrowth;
585fe6060f1SDimitry Andric 
586fe6060f1SDimitry Andric   while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup) &&
587fe6060f1SDimitry Andric          MBBI->getOpcode() == M68k::PUSH32r) {
588fe6060f1SDimitry Andric     PushedRegs = true;
589fe6060f1SDimitry Andric     ++MBBI;
590fe6060f1SDimitry Andric 
591fe6060f1SDimitry Andric     if (!HasFP && NeedsDwarfCFI) {
592fe6060f1SDimitry Andric       // Mark callee-saved push instruction.
593fe6060f1SDimitry Andric       // Define the current CFA rule to use the provided offset.
594fe6060f1SDimitry Andric       assert(StackSize);
595fe6060f1SDimitry Andric       BuildCFI(MBB, MBBI, DL,
596fe6060f1SDimitry Andric                MCCFIInstruction::cfiDefCfaOffset(nullptr, StackOffset));
597fe6060f1SDimitry Andric       StackOffset += stackGrowth;
598fe6060f1SDimitry Andric     }
599fe6060f1SDimitry Andric   }
600fe6060f1SDimitry Andric 
601fe6060f1SDimitry Andric   // Realign stack after we pushed callee-saved registers (so that we'll be
602fe6060f1SDimitry Andric   // able to calculate their offsets from the frame pointer).
603fe6060f1SDimitry Andric   if (TRI->hasStackRealignment(MF)) {
604fe6060f1SDimitry Andric     assert(HasFP && "There should be a frame pointer if stack is realigned.");
605fe6060f1SDimitry Andric     BuildStackAlignAND(MBB, MBBI, DL, StackPtr, MaxAlign);
606fe6060f1SDimitry Andric   }
607fe6060f1SDimitry Andric 
608fe6060f1SDimitry Andric   // If there is an SUB32ri of SP immediately before this instruction, merge
609fe6060f1SDimitry Andric   // the two. This can be the case when tail call elimination is enabled and
610fe6060f1SDimitry Andric   // the callee has more arguments then the caller.
611fe6060f1SDimitry Andric   NumBytes -= mergeSPUpdates(MBB, MBBI, true);
612fe6060f1SDimitry Andric 
613fe6060f1SDimitry Andric   // Adjust stack pointer: ESP -= numbytes.
614bdd1243dSDimitry Andric   if (!HasFP)
615fe6060f1SDimitry Andric     emitSPUpdate(MBB, MBBI, -(int64_t)NumBytes, /*InEpilogue=*/false);
616fe6060f1SDimitry Andric 
617fe6060f1SDimitry Andric   unsigned SPOrEstablisher = StackPtr;
618fe6060f1SDimitry Andric 
619fe6060f1SDimitry Andric   // If we need a base pointer, set it up here. It's whatever the value
620fe6060f1SDimitry Andric   // of the stack pointer is at this point. Any variable size objects
621fe6060f1SDimitry Andric   // will be allocated after this, so we can still use the base pointer
622fe6060f1SDimitry Andric   // to reference locals.
623fe6060f1SDimitry Andric   if (TRI->hasBasePointer(MF)) {
624fe6060f1SDimitry Andric     // Update the base pointer with the current stack pointer.
625fe6060f1SDimitry Andric     BuildMI(MBB, MBBI, DL, TII.get(M68k::MOV32aa), BasePtr)
626fe6060f1SDimitry Andric         .addReg(SPOrEstablisher)
627fe6060f1SDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
628fe6060f1SDimitry Andric     if (MMFI->getRestoreBasePointer()) {
629fe6060f1SDimitry Andric       // Stash value of base pointer.  Saving SP instead of FP shortens
630fe6060f1SDimitry Andric       // dependence chain. Used by SjLj EH.
631fe6060f1SDimitry Andric       unsigned Opm = M68k::MOV32ja;
632fe6060f1SDimitry Andric       M68k::addRegIndirectWithDisp(BuildMI(MBB, MBBI, DL, TII.get(Opm)),
633fe6060f1SDimitry Andric                                    FramePtr, true,
634fe6060f1SDimitry Andric                                    MMFI->getRestoreBasePointerOffset())
635fe6060f1SDimitry Andric           .addReg(SPOrEstablisher)
636fe6060f1SDimitry Andric           .setMIFlag(MachineInstr::FrameSetup);
637fe6060f1SDimitry Andric     }
638fe6060f1SDimitry Andric   }
639fe6060f1SDimitry Andric 
640fe6060f1SDimitry Andric   if (((!HasFP && NumBytes) || PushedRegs) && NeedsDwarfCFI) {
641fe6060f1SDimitry Andric     // Mark end of stack pointer adjustment.
642fe6060f1SDimitry Andric     if (!HasFP && NumBytes) {
643fe6060f1SDimitry Andric       // Define the current CFA rule to use the provided offset.
644fe6060f1SDimitry Andric       assert(StackSize);
645fe6060f1SDimitry Andric       BuildCFI(
646fe6060f1SDimitry Andric           MBB, MBBI, DL,
647fe6060f1SDimitry Andric           MCCFIInstruction::cfiDefCfaOffset(nullptr, -StackSize + stackGrowth));
648fe6060f1SDimitry Andric     }
649fe6060f1SDimitry Andric 
650fe6060f1SDimitry Andric     // Emit DWARF info specifying the offsets of the callee-saved registers.
651fe6060f1SDimitry Andric     if (PushedRegs)
652fe6060f1SDimitry Andric       emitPrologueCalleeSavedFrameMoves(MBB, MBBI, DL);
653fe6060f1SDimitry Andric   }
654fe6060f1SDimitry Andric 
655fe6060f1SDimitry Andric   // TODO Interrupt handlers
656fe6060f1SDimitry Andric   // M68k Interrupt handling function cannot assume anything about the
657fe6060f1SDimitry Andric   // direction flag (DF in CCR register). Clear this flag by creating "cld"
658fe6060f1SDimitry Andric   // instruction in each prologue of interrupt handler function. The "cld"
659fe6060f1SDimitry Andric   // instruction should only in these cases:
660fe6060f1SDimitry Andric   // 1. The interrupt handling function uses any of the "rep" instructions.
661fe6060f1SDimitry Andric   // 2. Interrupt handling function calls another function.
662fe6060f1SDimitry Andric }
663fe6060f1SDimitry Andric 
664fe6060f1SDimitry Andric static bool isTailCallOpcode(unsigned Opc) {
665fe6060f1SDimitry Andric   return Opc == M68k::TCRETURNj || Opc == M68k::TCRETURNq;
666fe6060f1SDimitry Andric }
667fe6060f1SDimitry Andric 
668fe6060f1SDimitry Andric void M68kFrameLowering::emitEpilogue(MachineFunction &MF,
669fe6060f1SDimitry Andric                                      MachineBasicBlock &MBB) const {
670fe6060f1SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
671fe6060f1SDimitry Andric   M68kMachineFunctionInfo *MMFI = MF.getInfo<M68kMachineFunctionInfo>();
672fe6060f1SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
673bdd1243dSDimitry Andric   std::optional<unsigned> RetOpcode;
674fe6060f1SDimitry Andric   if (MBBI != MBB.end())
675fe6060f1SDimitry Andric     RetOpcode = MBBI->getOpcode();
676fe6060f1SDimitry Andric   DebugLoc DL;
677fe6060f1SDimitry Andric   if (MBBI != MBB.end())
678fe6060f1SDimitry Andric     DL = MBBI->getDebugLoc();
67904eeddc0SDimitry Andric   Register FramePtr = TRI->getFrameRegister(MF);
680fe6060f1SDimitry Andric   unsigned MachineFramePtr = FramePtr;
681fe6060f1SDimitry Andric 
682fe6060f1SDimitry Andric   // Get the number of bytes to allocate from the FrameInfo.
683fe6060f1SDimitry Andric   uint64_t StackSize = MFI.getStackSize();
684fe6060f1SDimitry Andric   uint64_t MaxAlign = calculateMaxStackAlign(MF);
685fe6060f1SDimitry Andric   unsigned CSSize = MMFI->getCalleeSavedFrameSize();
686fe6060f1SDimitry Andric   uint64_t NumBytes = 0;
687fe6060f1SDimitry Andric 
688fe6060f1SDimitry Andric   if (hasFP(MF)) {
689fe6060f1SDimitry Andric     // Calculate required stack adjustment.
690fe6060f1SDimitry Andric     uint64_t FrameSize = StackSize - SlotSize;
691fe6060f1SDimitry Andric     NumBytes = FrameSize - CSSize;
692fe6060f1SDimitry Andric 
693fe6060f1SDimitry Andric     // Callee-saved registers were pushed on stack before the stack was
694fe6060f1SDimitry Andric     // realigned.
695fe6060f1SDimitry Andric     if (TRI->hasStackRealignment(MF))
696fe6060f1SDimitry Andric       NumBytes = alignTo(FrameSize, MaxAlign);
697fe6060f1SDimitry Andric 
698fe6060f1SDimitry Andric   } else {
699fe6060f1SDimitry Andric     NumBytes = StackSize - CSSize;
700fe6060f1SDimitry Andric   }
701fe6060f1SDimitry Andric 
702fe6060f1SDimitry Andric   // Skip the callee-saved pop instructions.
703fe6060f1SDimitry Andric   while (MBBI != MBB.begin()) {
704fe6060f1SDimitry Andric     MachineBasicBlock::iterator PI = std::prev(MBBI);
705fe6060f1SDimitry Andric     unsigned Opc = PI->getOpcode();
706fe6060f1SDimitry Andric 
707fe6060f1SDimitry Andric     if ((Opc != M68k::POP32r || !PI->getFlag(MachineInstr::FrameDestroy)) &&
708fe6060f1SDimitry Andric         Opc != M68k::DBG_VALUE && !PI->isTerminator())
709fe6060f1SDimitry Andric       break;
710fe6060f1SDimitry Andric 
711fe6060f1SDimitry Andric     --MBBI;
712fe6060f1SDimitry Andric   }
713fe6060f1SDimitry Andric   MachineBasicBlock::iterator FirstCSPop = MBBI;
714fe6060f1SDimitry Andric 
715fe6060f1SDimitry Andric   if (MBBI != MBB.end())
716fe6060f1SDimitry Andric     DL = MBBI->getDebugLoc();
717fe6060f1SDimitry Andric 
718fe6060f1SDimitry Andric   // If there is an ADD32ri or SUB32ri of SP immediately before this
719fe6060f1SDimitry Andric   // instruction, merge the two instructions.
720fe6060f1SDimitry Andric   if (NumBytes || MFI.hasVarSizedObjects())
721fe6060f1SDimitry Andric     NumBytes += mergeSPUpdates(MBB, MBBI, true);
722fe6060f1SDimitry Andric 
723fe6060f1SDimitry Andric   // If dynamic alloca is used, then reset SP to point to the last callee-saved
724fe6060f1SDimitry Andric   // slot before popping them off! Same applies for the case, when stack was
725fe6060f1SDimitry Andric   // realigned. Don't do this if this was a funclet epilogue, since the funclets
726fe6060f1SDimitry Andric   // will not do realignment or dynamic stack allocation.
727fe6060f1SDimitry Andric   if ((TRI->hasStackRealignment(MF) || MFI.hasVarSizedObjects())) {
728fe6060f1SDimitry Andric     if (TRI->hasStackRealignment(MF))
729fe6060f1SDimitry Andric       MBBI = FirstCSPop;
730fe6060f1SDimitry Andric     uint64_t LEAAmount = -CSSize;
731fe6060f1SDimitry Andric 
732fe6060f1SDimitry Andric     // 'move %FramePtr, SP' will not be recognized as an epilogue sequence.
733fe6060f1SDimitry Andric     // However, we may use this sequence if we have a frame pointer because the
734fe6060f1SDimitry Andric     // effects of the prologue can safely be undone.
735fe6060f1SDimitry Andric     if (LEAAmount != 0) {
736fe6060f1SDimitry Andric       unsigned Opc = M68k::LEA32p;
737fe6060f1SDimitry Andric       M68k::addRegIndirectWithDisp(
738fe6060f1SDimitry Andric           BuildMI(MBB, MBBI, DL, TII.get(Opc), StackPtr), FramePtr, false,
739fe6060f1SDimitry Andric           LEAAmount);
740fe6060f1SDimitry Andric       --MBBI;
741fe6060f1SDimitry Andric     } else {
742bdd1243dSDimitry Andric       BuildMI(MBB, MBBI, DL, TII.get(M68k::UNLK))
743bdd1243dSDimitry Andric           .addReg(MachineFramePtr, RegState::Kill)
744bdd1243dSDimitry Andric           .setMIFlag(MachineInstr::FrameDestroy);
745fe6060f1SDimitry Andric       --MBBI;
746fe6060f1SDimitry Andric     }
747bdd1243dSDimitry Andric   } else if (hasFP(MF)) {
748bdd1243dSDimitry Andric     BuildMI(MBB, MBBI, DL, TII.get(M68k::UNLK))
749bdd1243dSDimitry Andric         .addReg(MachineFramePtr, RegState::Kill)
750bdd1243dSDimitry Andric         .setMIFlag(MachineInstr::FrameDestroy);
751fe6060f1SDimitry Andric   } else if (NumBytes) {
752fe6060f1SDimitry Andric     // Adjust stack pointer back: SP += numbytes.
753fe6060f1SDimitry Andric     emitSPUpdate(MBB, MBBI, NumBytes, /*InEpilogue=*/true);
754fe6060f1SDimitry Andric     --MBBI;
755fe6060f1SDimitry Andric   }
756fe6060f1SDimitry Andric 
757fe6060f1SDimitry Andric   if (!RetOpcode || !isTailCallOpcode(*RetOpcode)) {
758fe6060f1SDimitry Andric     // Add the return addr area delta back since we are not tail calling.
759fe6060f1SDimitry Andric     int Offset = -1 * MMFI->getTCReturnAddrDelta();
760fe6060f1SDimitry Andric     assert(Offset >= 0 && "TCDelta should never be positive");
761fe6060f1SDimitry Andric     if (Offset) {
762fe6060f1SDimitry Andric       MBBI = MBB.getFirstTerminator();
763fe6060f1SDimitry Andric 
764fe6060f1SDimitry Andric       // Check for possible merge with preceding ADD instruction.
765fe6060f1SDimitry Andric       Offset += mergeSPUpdates(MBB, MBBI, true);
766fe6060f1SDimitry Andric       emitSPUpdate(MBB, MBBI, Offset, /*InEpilogue=*/true);
767fe6060f1SDimitry Andric     }
768fe6060f1SDimitry Andric   }
769fe6060f1SDimitry Andric }
770fe6060f1SDimitry Andric 
771fe6060f1SDimitry Andric void M68kFrameLowering::determineCalleeSaves(MachineFunction &MF,
772fe6060f1SDimitry Andric                                              BitVector &SavedRegs,
773fe6060f1SDimitry Andric                                              RegScavenger *RS) const {
774fe6060f1SDimitry Andric   TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
775fe6060f1SDimitry Andric 
776fe6060f1SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
777fe6060f1SDimitry Andric 
778fe6060f1SDimitry Andric   M68kMachineFunctionInfo *M68kFI = MF.getInfo<M68kMachineFunctionInfo>();
779fe6060f1SDimitry Andric   int64_t TailCallReturnAddrDelta = M68kFI->getTCReturnAddrDelta();
780fe6060f1SDimitry Andric 
781fe6060f1SDimitry Andric   if (TailCallReturnAddrDelta < 0) {
782fe6060f1SDimitry Andric     // create RETURNADDR area
783fe6060f1SDimitry Andric     //   arg
784fe6060f1SDimitry Andric     //   arg
785fe6060f1SDimitry Andric     //   RETADDR
786fe6060f1SDimitry Andric     //   { ...
787fe6060f1SDimitry Andric     //     RETADDR area
788fe6060f1SDimitry Andric     //     ...
789fe6060f1SDimitry Andric     //   }
790fe6060f1SDimitry Andric     //   [FP]
791fe6060f1SDimitry Andric     MFI.CreateFixedObject(-TailCallReturnAddrDelta,
792fe6060f1SDimitry Andric                           TailCallReturnAddrDelta - SlotSize, true);
793fe6060f1SDimitry Andric   }
794fe6060f1SDimitry Andric 
795fe6060f1SDimitry Andric   // Spill the BasePtr if it's used.
796fe6060f1SDimitry Andric   if (TRI->hasBasePointer(MF)) {
797fe6060f1SDimitry Andric     SavedRegs.set(TRI->getBaseRegister());
798fe6060f1SDimitry Andric   }
799fe6060f1SDimitry Andric }
800fe6060f1SDimitry Andric 
801fe6060f1SDimitry Andric bool M68kFrameLowering::assignCalleeSavedSpillSlots(
802fe6060f1SDimitry Andric     MachineFunction &MF, const TargetRegisterInfo *TRI,
803fe6060f1SDimitry Andric     std::vector<CalleeSavedInfo> &CSI) const {
804fe6060f1SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
805fe6060f1SDimitry Andric   M68kMachineFunctionInfo *M68kFI = MF.getInfo<M68kMachineFunctionInfo>();
806fe6060f1SDimitry Andric 
807fe6060f1SDimitry Andric   int SpillSlotOffset = getOffsetOfLocalArea() + M68kFI->getTCReturnAddrDelta();
808fe6060f1SDimitry Andric 
809fe6060f1SDimitry Andric   if (hasFP(MF)) {
810fe6060f1SDimitry Andric     // emitPrologue always spills frame register the first thing.
811fe6060f1SDimitry Andric     SpillSlotOffset -= SlotSize;
812fe6060f1SDimitry Andric     MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
813fe6060f1SDimitry Andric 
814fe6060f1SDimitry Andric     // Since emitPrologue and emitEpilogue will handle spilling and restoring of
815fe6060f1SDimitry Andric     // the frame register, we can delete it from CSI list and not have to worry
816fe6060f1SDimitry Andric     // about avoiding it later.
81704eeddc0SDimitry Andric     Register FPReg = TRI->getFrameRegister(MF);
818fe6060f1SDimitry Andric     for (unsigned i = 0, e = CSI.size(); i < e; ++i) {
819fe6060f1SDimitry Andric       if (TRI->regsOverlap(CSI[i].getReg(), FPReg)) {
820fe6060f1SDimitry Andric         CSI.erase(CSI.begin() + i);
821fe6060f1SDimitry Andric         break;
822fe6060f1SDimitry Andric       }
823fe6060f1SDimitry Andric     }
824fe6060f1SDimitry Andric   }
825fe6060f1SDimitry Andric 
826fe6060f1SDimitry Andric   // The rest is fine
827fe6060f1SDimitry Andric   return false;
828fe6060f1SDimitry Andric }
829fe6060f1SDimitry Andric 
830fe6060f1SDimitry Andric bool M68kFrameLowering::spillCalleeSavedRegisters(
831fe6060f1SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
832fe6060f1SDimitry Andric     ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
833fe6060f1SDimitry Andric   auto &MRI = *static_cast<const M68kRegisterInfo *>(TRI);
834fe6060f1SDimitry Andric   auto DL = MBB.findDebugLoc(MI);
835fe6060f1SDimitry Andric 
836fe6060f1SDimitry Andric   int FI = 0;
837fe6060f1SDimitry Andric   unsigned Mask = 0;
838fe6060f1SDimitry Andric   for (const auto &Info : CSI) {
839fe6060f1SDimitry Andric     FI = std::max(FI, Info.getFrameIdx());
84004eeddc0SDimitry Andric     Register Reg = Info.getReg();
841fe6060f1SDimitry Andric     unsigned Shift = MRI.getSpillRegisterOrder(Reg);
842fe6060f1SDimitry Andric     Mask |= 1 << Shift;
843fe6060f1SDimitry Andric   }
844fe6060f1SDimitry Andric 
845fe6060f1SDimitry Andric   auto I =
846fe6060f1SDimitry Andric       M68k::addFrameReference(BuildMI(MBB, MI, DL, TII.get(M68k::MOVM32pm)), FI)
847fe6060f1SDimitry Andric           .addImm(Mask)
848fe6060f1SDimitry Andric           .setMIFlag(MachineInstr::FrameSetup);
849fe6060f1SDimitry Andric 
850fe6060f1SDimitry Andric   // Append implicit registers and mem locations
851fe6060f1SDimitry Andric   const MachineFunction &MF = *MBB.getParent();
852fe6060f1SDimitry Andric   const MachineRegisterInfo &RI = MF.getRegInfo();
853fe6060f1SDimitry Andric   for (const auto &Info : CSI) {
85404eeddc0SDimitry Andric     Register Reg = Info.getReg();
855fe6060f1SDimitry Andric     bool IsLiveIn = RI.isLiveIn(Reg);
856fe6060f1SDimitry Andric     if (!IsLiveIn)
857fe6060f1SDimitry Andric       MBB.addLiveIn(Reg);
858fe6060f1SDimitry Andric     I.addReg(Reg, IsLiveIn ? RegState::Implicit : RegState::ImplicitKill);
859fe6060f1SDimitry Andric     M68k::addMemOperand(I, Info.getFrameIdx(), 0);
860fe6060f1SDimitry Andric   }
861fe6060f1SDimitry Andric 
862fe6060f1SDimitry Andric   return true;
863fe6060f1SDimitry Andric }
864fe6060f1SDimitry Andric 
865fe6060f1SDimitry Andric bool M68kFrameLowering::restoreCalleeSavedRegisters(
866fe6060f1SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
867fe6060f1SDimitry Andric     MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
868fe6060f1SDimitry Andric   auto &MRI = *static_cast<const M68kRegisterInfo *>(TRI);
869fe6060f1SDimitry Andric   auto DL = MBB.findDebugLoc(MI);
870fe6060f1SDimitry Andric 
871fe6060f1SDimitry Andric   int FI = 0;
872fe6060f1SDimitry Andric   unsigned Mask = 0;
873fe6060f1SDimitry Andric   for (const auto &Info : CSI) {
874fe6060f1SDimitry Andric     FI = std::max(FI, Info.getFrameIdx());
87504eeddc0SDimitry Andric     Register Reg = Info.getReg();
876fe6060f1SDimitry Andric     unsigned Shift = MRI.getSpillRegisterOrder(Reg);
877fe6060f1SDimitry Andric     Mask |= 1 << Shift;
878fe6060f1SDimitry Andric   }
879fe6060f1SDimitry Andric 
880fe6060f1SDimitry Andric   auto I = M68k::addFrameReference(
881fe6060f1SDimitry Andric                BuildMI(MBB, MI, DL, TII.get(M68k::MOVM32mp)).addImm(Mask), FI)
882fe6060f1SDimitry Andric                .setMIFlag(MachineInstr::FrameDestroy);
883fe6060f1SDimitry Andric 
884fe6060f1SDimitry Andric   // Append implicit registers and mem locations
885fe6060f1SDimitry Andric   for (const auto &Info : CSI) {
886fe6060f1SDimitry Andric     I.addReg(Info.getReg(), RegState::ImplicitDefine);
887fe6060f1SDimitry Andric     M68k::addMemOperand(I, Info.getFrameIdx(), 0);
888fe6060f1SDimitry Andric   }
889fe6060f1SDimitry Andric 
890fe6060f1SDimitry Andric   return true;
891fe6060f1SDimitry Andric }
892