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
M68kFrameLowering(const M68kSubtarget & STI,Align Alignment)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
hasFP(const MachineFunction & MF) const43fe6060f1SDimitry 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
hasReservedCallFrame(const MachineFunction & MF) const53fe6060f1SDimitry Andric bool M68kFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
54fe6060f1SDimitry Andric return !MF.getFrameInfo().hasVarSizedObjects() &&
55fe6060f1SDimitry Andric !MF.getInfo<M68kMachineFunctionInfo>()->getHasPushSequences();
56fe6060f1SDimitry Andric }
57fe6060f1SDimitry Andric
canSimplifyCallFramePseudos(const MachineFunction & MF) const58fe6060f1SDimitry 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
needsFrameIndexResolution(const MachineFunction & MF) const65fe6060f1SDimitry 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
getFrameIndexReference(const MachineFunction & MF,int FI,Register & FrameReg) const76fe6060f1SDimitry 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.
findDeadCallerSavedReg(MachineBasicBlock & MBB,MachineBasicBlock::iterator & MBBI,const M68kRegisterInfo * TRI)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
isRegLiveIn(MachineBasicBlock & MBB,unsigned Reg)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
calculateMaxStackAlign(const MachineFunction & MF) const184fe6060f1SDimitry 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
BuildStackAlignAND(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,const DebugLoc & DL,unsigned Reg,uint64_t MaxAlign) const197fe6060f1SDimitry 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
eliminateCallFramePseudoInstr(MachineFunction & MF,MachineBasicBlock & MBB,MachineBasicBlock::iterator I) const227fe6060f1SDimitry 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.
emitSPUpdate(MachineBasicBlock & MBB,MachineBasicBlock::iterator & MBBI,int64_t NumBytes,bool InEpilogue) const335fe6060f1SDimitry 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
mergeSPUpdates(MachineBasicBlock & MBB,MachineBasicBlock::iterator & MBBI,bool MergeWithPrevious) const382fe6060f1SDimitry 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
BuildStackAdjustment(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,const DebugLoc & DL,int64_t Offset,bool InEpilogue) const418fe6060f1SDimitry 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
BuildCFI(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,const DebugLoc & DL,const MCCFIInstruction & CFIInst) const438fe6060f1SDimitry 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
emitPrologueCalleeSavedFrameMoves(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,const DebugLoc & DL) const448fe6060f1SDimitry 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
emitPrologue(MachineFunction & MF,MachineBasicBlock & MBB) const471fe6060f1SDimitry 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
isTailCallOpcode(unsigned Opc)664fe6060f1SDimitry Andric static bool isTailCallOpcode(unsigned Opc) {
665fe6060f1SDimitry Andric return Opc == M68k::TCRETURNj || Opc == M68k::TCRETURNq;
666fe6060f1SDimitry Andric }
667fe6060f1SDimitry Andric
emitEpilogue(MachineFunction & MF,MachineBasicBlock & MBB) const668fe6060f1SDimitry 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
determineCalleeSaves(MachineFunction & MF,BitVector & SavedRegs,RegScavenger * RS) const771fe6060f1SDimitry 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
assignCalleeSavedSpillSlots(MachineFunction & MF,const TargetRegisterInfo * TRI,std::vector<CalleeSavedInfo> & CSI) const801fe6060f1SDimitry 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
spillCalleeSavedRegisters(MachineBasicBlock & MBB,MachineBasicBlock::iterator MI,ArrayRef<CalleeSavedInfo> CSI,const TargetRegisterInfo * TRI) const830fe6060f1SDimitry 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
restoreCalleeSavedRegisters(MachineBasicBlock & MBB,MachineBasicBlock::iterator MI,MutableArrayRef<CalleeSavedInfo> CSI,const TargetRegisterInfo * TRI) const865fe6060f1SDimitry 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