1192405a3SDylan McKay //===-- AVRFrameLowering.cpp - AVR Frame Information ----------------------===//
2192405a3SDylan McKay //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6192405a3SDylan McKay //
7192405a3SDylan McKay //===----------------------------------------------------------------------===//
8192405a3SDylan McKay //
9192405a3SDylan McKay // This file contains the AVR implementation of TargetFrameLowering class.
10192405a3SDylan McKay //
11192405a3SDylan McKay //===----------------------------------------------------------------------===//
12192405a3SDylan McKay 
13192405a3SDylan McKay #include "AVRFrameLowering.h"
14192405a3SDylan McKay 
15192405a3SDylan McKay #include "AVR.h"
16192405a3SDylan McKay #include "AVRInstrInfo.h"
17192405a3SDylan McKay #include "AVRMachineFunctionInfo.h"
18192405a3SDylan McKay #include "AVRTargetMachine.h"
19192405a3SDylan McKay #include "MCTargetDesc/AVRMCTargetDesc.h"
20192405a3SDylan McKay 
21192405a3SDylan McKay #include "llvm/CodeGen/MachineFrameInfo.h"
22192405a3SDylan McKay #include "llvm/CodeGen/MachineFunction.h"
23192405a3SDylan McKay #include "llvm/CodeGen/MachineFunctionPass.h"
24192405a3SDylan McKay #include "llvm/CodeGen/MachineInstrBuilder.h"
25192405a3SDylan McKay #include "llvm/CodeGen/MachineRegisterInfo.h"
26192405a3SDylan McKay #include "llvm/IR/Function.h"
27192405a3SDylan McKay 
287c2d41aaSDylan McKay #include <vector>
297c2d41aaSDylan McKay 
30192405a3SDylan McKay namespace llvm {
31192405a3SDylan McKay 
AVRFrameLowering()32192405a3SDylan McKay AVRFrameLowering::AVRFrameLowering()
33805c157eSGuillaume Chatelet     : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(1), -2) {}
34192405a3SDylan McKay 
canSimplifyCallFramePseudos(const MachineFunction & MF) const35192405a3SDylan McKay bool AVRFrameLowering::canSimplifyCallFramePseudos(
36192405a3SDylan McKay     const MachineFunction &MF) const {
37192405a3SDylan McKay   // Always simplify call frame pseudo instructions, even when
38192405a3SDylan McKay   // hasReservedCallFrame is false.
39192405a3SDylan McKay   return true;
40192405a3SDylan McKay }
41192405a3SDylan McKay 
hasReservedCallFrame(const MachineFunction & MF) const42192405a3SDylan McKay bool AVRFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
43192405a3SDylan McKay   // Reserve call frame memory in function prologue under the following
44192405a3SDylan McKay   // conditions:
45192405a3SDylan McKay   // - Y pointer is reserved to be the frame pointer.
46192405a3SDylan McKay   // - The function does not contain variable sized objects.
47b16b6d57SDylan McKay 
48192405a3SDylan McKay   const MachineFrameInfo &MFI = MF.getFrameInfo();
49b16b6d57SDylan McKay   return hasFP(MF) && !MFI.hasVarSizedObjects();
50192405a3SDylan McKay }
51192405a3SDylan McKay 
emitPrologue(MachineFunction & MF,MachineBasicBlock & MBB) const52192405a3SDylan McKay void AVRFrameLowering::emitPrologue(MachineFunction &MF,
53192405a3SDylan McKay                                     MachineBasicBlock &MBB) const {
54192405a3SDylan McKay   MachineBasicBlock::iterator MBBI = MBB.begin();
55192405a3SDylan McKay   DebugLoc DL = (MBBI != MBB.end()) ? MBBI->getDebugLoc() : DebugLoc();
56192405a3SDylan McKay   const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
57192405a3SDylan McKay   const AVRInstrInfo &TII = *STI.getInstrInfo();
58339b3426SDylan McKay   const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
59634339abSDylan McKay   bool HasFP = hasFP(MF);
60192405a3SDylan McKay 
61192405a3SDylan McKay   // Interrupt handlers re-enable interrupts in function entry.
627b808b10SDylan McKay   if (AFI->isInterruptHandler()) {
63192405a3SDylan McKay     BuildMI(MBB, MBBI, DL, TII.get(AVR::BSETs))
64192405a3SDylan McKay         .addImm(0x07)
65192405a3SDylan McKay         .setMIFlag(MachineInstr::FrameSetup);
66192405a3SDylan McKay   }
67192405a3SDylan McKay 
6828355efdSDylan McKay   // Emit special prologue code to save R1, R0 and SREG in interrupt/signal
6928355efdSDylan McKay   // handlers before saving any other registers.
707b808b10SDylan McKay   if (AFI->isInterruptOrSignalHandler()) {
71192405a3SDylan McKay     BuildMI(MBB, MBBI, DL, TII.get(AVR::PUSHWRr))
72192405a3SDylan McKay         .addReg(AVR::R1R0, RegState::Kill)
73192405a3SDylan McKay         .setMIFlag(MachineInstr::FrameSetup);
74634339abSDylan McKay 
75192405a3SDylan McKay     BuildMI(MBB, MBBI, DL, TII.get(AVR::INRdA), AVR::R0)
7631666478SAyke van Laethem         .addImm(STI.getIORegSREG())
77192405a3SDylan McKay         .setMIFlag(MachineInstr::FrameSetup);
78192405a3SDylan McKay     BuildMI(MBB, MBBI, DL, TII.get(AVR::PUSHRr))
79192405a3SDylan McKay         .addReg(AVR::R0, RegState::Kill)
80192405a3SDylan McKay         .setMIFlag(MachineInstr::FrameSetup);
81192405a3SDylan McKay     BuildMI(MBB, MBBI, DL, TII.get(AVR::EORRdRr))
82c85175c5SBen Shi         .addReg(AVR::R1, RegState::Define)
83c85175c5SBen Shi         .addReg(AVR::R1, RegState::Kill)
84c85175c5SBen Shi         .addReg(AVR::R1, RegState::Kill)
85c85175c5SBen Shi         .setMIFlag(MachineInstr::FrameSetup);
86192405a3SDylan McKay   }
87192405a3SDylan McKay 
88192405a3SDylan McKay   // Early exit if the frame pointer is not needed in this function.
89634339abSDylan McKay   if (!HasFP) {
90192405a3SDylan McKay     return;
91192405a3SDylan McKay   }
92192405a3SDylan McKay 
93192405a3SDylan McKay   const MachineFrameInfo &MFI = MF.getFrameInfo();
94192405a3SDylan McKay   unsigned FrameSize = MFI.getStackSize() - AFI->getCalleeSavedFrameSize();
95192405a3SDylan McKay 
96192405a3SDylan McKay   // Skip the callee-saved push instructions.
97192405a3SDylan McKay   while (
98192405a3SDylan McKay       (MBBI != MBB.end()) && MBBI->getFlag(MachineInstr::FrameSetup) &&
99192405a3SDylan McKay       (MBBI->getOpcode() == AVR::PUSHRr || MBBI->getOpcode() == AVR::PUSHWRr)) {
100192405a3SDylan McKay     ++MBBI;
101192405a3SDylan McKay   }
102192405a3SDylan McKay 
103192405a3SDylan McKay   // Update Y with the new base value.
104192405a3SDylan McKay   BuildMI(MBB, MBBI, DL, TII.get(AVR::SPREAD), AVR::R29R28)
105192405a3SDylan McKay       .addReg(AVR::SP)
106192405a3SDylan McKay       .setMIFlag(MachineInstr::FrameSetup);
107192405a3SDylan McKay 
108192405a3SDylan McKay   // Mark the FramePtr as live-in in every block except the entry.
109cfc74024SKazu Hirata   for (MachineBasicBlock &MBBJ : llvm::drop_begin(MF)) {
110cfc74024SKazu Hirata     MBBJ.addLiveIn(AVR::R29R28);
111192405a3SDylan McKay   }
112192405a3SDylan McKay 
113192405a3SDylan McKay   if (!FrameSize) {
114192405a3SDylan McKay     return;
115192405a3SDylan McKay   }
116192405a3SDylan McKay 
117192405a3SDylan McKay   // Reserve the necessary frame memory by doing FP -= <size>.
118192405a3SDylan McKay   unsigned Opcode = (isUInt<6>(FrameSize)) ? AVR::SBIWRdK : AVR::SUBIWRdK;
119192405a3SDylan McKay 
120192405a3SDylan McKay   MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opcode), AVR::R29R28)
121192405a3SDylan McKay                          .addReg(AVR::R29R28, RegState::Kill)
122192405a3SDylan McKay                          .addImm(FrameSize)
123192405a3SDylan McKay                          .setMIFlag(MachineInstr::FrameSetup);
124192405a3SDylan McKay   // The SREG implicit def is dead.
125192405a3SDylan McKay   MI->getOperand(3).setIsDead();
126192405a3SDylan McKay 
127192405a3SDylan McKay   // Write back R29R28 to SP and temporarily disable interrupts.
128192405a3SDylan McKay   BuildMI(MBB, MBBI, DL, TII.get(AVR::SPWRITE), AVR::SP)
129192405a3SDylan McKay       .addReg(AVR::R29R28)
130192405a3SDylan McKay       .setMIFlag(MachineInstr::FrameSetup);
131192405a3SDylan McKay }
132192405a3SDylan McKay 
restoreStatusRegister(MachineFunction & MF,MachineBasicBlock & MBB)1331fedd90cSAndrew Dona-Couch static void restoreStatusRegister(MachineFunction &MF, MachineBasicBlock &MBB) {
1341fedd90cSAndrew Dona-Couch   const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
1351fedd90cSAndrew Dona-Couch 
1361fedd90cSAndrew Dona-Couch   MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
1371fedd90cSAndrew Dona-Couch 
1381fedd90cSAndrew Dona-Couch   DebugLoc DL = MBBI->getDebugLoc();
1391fedd90cSAndrew Dona-Couch   const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
1401fedd90cSAndrew Dona-Couch   const AVRInstrInfo &TII = *STI.getInstrInfo();
1411fedd90cSAndrew Dona-Couch 
1421fedd90cSAndrew Dona-Couch   // Emit special epilogue code to restore R1, R0 and SREG in interrupt/signal
1431fedd90cSAndrew Dona-Couch   // handlers at the very end of the function, just before reti.
1441fedd90cSAndrew Dona-Couch   if (AFI->isInterruptOrSignalHandler()) {
1451fedd90cSAndrew Dona-Couch     BuildMI(MBB, MBBI, DL, TII.get(AVR::POPRd), AVR::R0);
1461fedd90cSAndrew Dona-Couch     BuildMI(MBB, MBBI, DL, TII.get(AVR::OUTARr))
14731666478SAyke van Laethem         .addImm(STI.getIORegSREG())
1481fedd90cSAndrew Dona-Couch         .addReg(AVR::R0, RegState::Kill);
1491fedd90cSAndrew Dona-Couch     BuildMI(MBB, MBBI, DL, TII.get(AVR::POPWRd), AVR::R1R0);
1501fedd90cSAndrew Dona-Couch   }
1511fedd90cSAndrew Dona-Couch }
1521fedd90cSAndrew Dona-Couch 
emitEpilogue(MachineFunction & MF,MachineBasicBlock & MBB) const153192405a3SDylan McKay void AVRFrameLowering::emitEpilogue(MachineFunction &MF,
154192405a3SDylan McKay                                     MachineBasicBlock &MBB) const {
155339b3426SDylan McKay   const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
156192405a3SDylan McKay 
157192405a3SDylan McKay   // Early exit if the frame pointer is not needed in this function except for
158192405a3SDylan McKay   // signal/interrupt handlers where special code generation is required.
1597b808b10SDylan McKay   if (!hasFP(MF) && !AFI->isInterruptOrSignalHandler()) {
160192405a3SDylan McKay     return;
161192405a3SDylan McKay   }
162192405a3SDylan McKay 
163192405a3SDylan McKay   MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
164552b7856SDylan McKay   assert(MBBI->getDesc().isReturn() &&
165192405a3SDylan McKay          "Can only insert epilog into returning blocks");
166552b7856SDylan McKay 
167192405a3SDylan McKay   DebugLoc DL = MBBI->getDebugLoc();
168192405a3SDylan McKay   const MachineFrameInfo &MFI = MF.getFrameInfo();
169192405a3SDylan McKay   unsigned FrameSize = MFI.getStackSize() - AFI->getCalleeSavedFrameSize();
170192405a3SDylan McKay   const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
171192405a3SDylan McKay   const AVRInstrInfo &TII = *STI.getInstrInfo();
172192405a3SDylan McKay 
173192405a3SDylan McKay   // Early exit if there is no need to restore the frame pointer.
174f41d2d94SAyke van Laethem   if (!FrameSize && !MF.getFrameInfo().hasVarSizedObjects()) {
1751fedd90cSAndrew Dona-Couch     restoreStatusRegister(MF, MBB);
176192405a3SDylan McKay     return;
177192405a3SDylan McKay   }
178192405a3SDylan McKay 
179192405a3SDylan McKay   // Skip the callee-saved pop instructions.
180192405a3SDylan McKay   while (MBBI != MBB.begin()) {
181192405a3SDylan McKay     MachineBasicBlock::iterator PI = std::prev(MBBI);
182192405a3SDylan McKay     int Opc = PI->getOpcode();
183192405a3SDylan McKay 
184192405a3SDylan McKay     if (Opc != AVR::POPRd && Opc != AVR::POPWRd && !PI->isTerminator()) {
185192405a3SDylan McKay       break;
186192405a3SDylan McKay     }
187192405a3SDylan McKay 
188192405a3SDylan McKay     --MBBI;
189192405a3SDylan McKay   }
190192405a3SDylan McKay 
191f41d2d94SAyke van Laethem   if (FrameSize) {
192192405a3SDylan McKay     unsigned Opcode;
193192405a3SDylan McKay 
194192405a3SDylan McKay     // Select the optimal opcode depending on how big it is.
195192405a3SDylan McKay     if (isUInt<6>(FrameSize)) {
196192405a3SDylan McKay       Opcode = AVR::ADIWRdK;
197192405a3SDylan McKay     } else {
198192405a3SDylan McKay       Opcode = AVR::SUBIWRdK;
199192405a3SDylan McKay       FrameSize = -FrameSize;
200192405a3SDylan McKay     }
201192405a3SDylan McKay 
202192405a3SDylan McKay     // Restore the frame pointer by doing FP += <size>.
203192405a3SDylan McKay     MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opcode), AVR::R29R28)
204192405a3SDylan McKay                            .addReg(AVR::R29R28, RegState::Kill)
205192405a3SDylan McKay                            .addImm(FrameSize);
206192405a3SDylan McKay     // The SREG implicit def is dead.
207192405a3SDylan McKay     MI->getOperand(3).setIsDead();
208f41d2d94SAyke van Laethem   }
209192405a3SDylan McKay 
210192405a3SDylan McKay   // Write back R29R28 to SP and temporarily disable interrupts.
211192405a3SDylan McKay   BuildMI(MBB, MBBI, DL, TII.get(AVR::SPWRITE), AVR::SP)
212192405a3SDylan McKay       .addReg(AVR::R29R28, RegState::Kill);
2131fedd90cSAndrew Dona-Couch 
2141fedd90cSAndrew Dona-Couch   restoreStatusRegister(MF, MBB);
215192405a3SDylan McKay }
216192405a3SDylan McKay 
217192405a3SDylan McKay // Return true if the specified function should have a dedicated frame
218192405a3SDylan McKay // pointer register. This is true if the function meets any of the following
219192405a3SDylan McKay // conditions:
220192405a3SDylan McKay //  - a register has been spilled
221192405a3SDylan McKay //  - has allocas
222192405a3SDylan McKay //  - input arguments are passed using the stack
223192405a3SDylan McKay //
224192405a3SDylan McKay // Notice that strictly this is not a frame pointer because it contains SP after
225192405a3SDylan McKay // frame allocation instead of having the original SP in function entry.
hasFP(const MachineFunction & MF) const226192405a3SDylan McKay bool AVRFrameLowering::hasFP(const MachineFunction &MF) const {
227192405a3SDylan McKay   const AVRMachineFunctionInfo *FuncInfo = MF.getInfo<AVRMachineFunctionInfo>();
228192405a3SDylan McKay 
229c30d85bdSDylan McKay   return (FuncInfo->getHasSpills() || FuncInfo->getHasAllocas() ||
230f41d2d94SAyke van Laethem           FuncInfo->getHasStackArgs() ||
231f41d2d94SAyke van Laethem           MF.getFrameInfo().hasVarSizedObjects());
232192405a3SDylan McKay }
233192405a3SDylan McKay 
spillCalleeSavedRegisters(MachineBasicBlock & MBB,MachineBasicBlock::iterator MI,ArrayRef<CalleeSavedInfo> CSI,const TargetRegisterInfo * TRI) const234192405a3SDylan McKay bool AVRFrameLowering::spillCalleeSavedRegisters(
235192405a3SDylan McKay     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
236e4230a9fSBenjamin Kramer     ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
237192405a3SDylan McKay   if (CSI.empty()) {
238192405a3SDylan McKay     return false;
239192405a3SDylan McKay   }
240192405a3SDylan McKay 
241192405a3SDylan McKay   unsigned CalleeFrameSize = 0;
242192405a3SDylan McKay   DebugLoc DL = MBB.findDebugLoc(MI);
243192405a3SDylan McKay   MachineFunction &MF = *MBB.getParent();
244192405a3SDylan McKay   const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
245192405a3SDylan McKay   const TargetInstrInfo &TII = *STI.getInstrInfo();
246192405a3SDylan McKay   AVRMachineFunctionInfo *AVRFI = MF.getInfo<AVRMachineFunctionInfo>();
247192405a3SDylan McKay 
24848349967SKazu Hirata   for (const CalleeSavedInfo &I : llvm::reverse(CSI)) {
249d6b07348SJim Lin     Register Reg = I.getReg();
250192405a3SDylan McKay     bool IsNotLiveIn = !MBB.isLiveIn(Reg);
251192405a3SDylan McKay 
25244e25f37SKrzysztof Parzyszek     assert(TRI->getRegSizeInBits(*TRI->getMinimalPhysRegClass(Reg)) == 8 &&
253192405a3SDylan McKay            "Invalid register size");
254192405a3SDylan McKay 
255192405a3SDylan McKay     // Add the callee-saved register as live-in only if it is not already a
256192405a3SDylan McKay     // live-in register, this usually happens with arguments that are passed
257192405a3SDylan McKay     // through callee-saved registers.
258192405a3SDylan McKay     if (IsNotLiveIn) {
259192405a3SDylan McKay       MBB.addLiveIn(Reg);
260192405a3SDylan McKay     }
261192405a3SDylan McKay 
262192405a3SDylan McKay     // Do not kill the register when it is an input argument.
263192405a3SDylan McKay     BuildMI(MBB, MI, DL, TII.get(AVR::PUSHRr))
264192405a3SDylan McKay         .addReg(Reg, getKillRegState(IsNotLiveIn))
265192405a3SDylan McKay         .setMIFlag(MachineInstr::FrameSetup);
266192405a3SDylan McKay     ++CalleeFrameSize;
267192405a3SDylan McKay   }
268192405a3SDylan McKay 
269192405a3SDylan McKay   AVRFI->setCalleeSavedFrameSize(CalleeFrameSize);
270192405a3SDylan McKay 
271192405a3SDylan McKay   return true;
272192405a3SDylan McKay }
273192405a3SDylan McKay 
restoreCalleeSavedRegisters(MachineBasicBlock & MBB,MachineBasicBlock::iterator MI,MutableArrayRef<CalleeSavedInfo> CSI,const TargetRegisterInfo * TRI) const274192405a3SDylan McKay bool AVRFrameLowering::restoreCalleeSavedRegisters(
275192405a3SDylan McKay     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
276186dd631SBenjamin Kramer     MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
277192405a3SDylan McKay   if (CSI.empty()) {
278192405a3SDylan McKay     return false;
279192405a3SDylan McKay   }
280192405a3SDylan McKay 
281192405a3SDylan McKay   DebugLoc DL = MBB.findDebugLoc(MI);
282192405a3SDylan McKay   const MachineFunction &MF = *MBB.getParent();
283192405a3SDylan McKay   const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
284192405a3SDylan McKay   const TargetInstrInfo &TII = *STI.getInstrInfo();
285192405a3SDylan McKay 
2867c2d41aaSDylan McKay   for (const CalleeSavedInfo &CCSI : CSI) {
287d6b07348SJim Lin     Register Reg = CCSI.getReg();
288192405a3SDylan McKay 
28944e25f37SKrzysztof Parzyszek     assert(TRI->getRegSizeInBits(*TRI->getMinimalPhysRegClass(Reg)) == 8 &&
290192405a3SDylan McKay            "Invalid register size");
291192405a3SDylan McKay 
292192405a3SDylan McKay     BuildMI(MBB, MI, DL, TII.get(AVR::POPRd), Reg);
293192405a3SDylan McKay   }
294192405a3SDylan McKay 
295192405a3SDylan McKay   return true;
296192405a3SDylan McKay }
297192405a3SDylan McKay 
298192405a3SDylan McKay /// Replace pseudo store instructions that pass arguments through the stack with
2995aa8014cSAyke van Laethem /// real instructions.
fixStackStores(MachineBasicBlock & MBB,MachineBasicBlock::iterator StartMI,const TargetInstrInfo & TII)300192405a3SDylan McKay static void fixStackStores(MachineBasicBlock &MBB,
301f8f55f7eSNikita Popov                            MachineBasicBlock::iterator StartMI,
302*6641c57aSPatryk Wychowaniec                            const TargetInstrInfo &TII) {
303192405a3SDylan McKay   // Iterate through the BB until we hit a call instruction or we reach the end.
3042c4ba3e9SKazu Hirata   for (MachineInstr &MI :
305f8f55f7eSNikita Popov        llvm::make_early_inc_range(llvm::make_range(StartMI, MBB.end()))) {
3062c4ba3e9SKazu Hirata     if (MI.isCall())
3072c4ba3e9SKazu Hirata       break;
3082c4ba3e9SKazu Hirata 
3092c4ba3e9SKazu Hirata     unsigned Opcode = MI.getOpcode();
310192405a3SDylan McKay 
311192405a3SDylan McKay     // Only care of pseudo store instructions where SP is the base pointer.
3122c4ba3e9SKazu Hirata     if (Opcode != AVR::STDSPQRr && Opcode != AVR::STDWSPQRr)
313192405a3SDylan McKay       continue;
314192405a3SDylan McKay 
315192405a3SDylan McKay     assert(MI.getOperand(0).getReg() == AVR::SP &&
316*6641c57aSPatryk Wychowaniec            "SP is expected as base pointer");
317192405a3SDylan McKay 
318192405a3SDylan McKay     // Replace this instruction with a regular store. Use Y as the base
319192405a3SDylan McKay     // pointer since it is guaranteed to contain a copy of SP.
320192405a3SDylan McKay     unsigned STOpc =
321192405a3SDylan McKay         (Opcode == AVR::STDWSPQRr) ? AVR::STDWPtrQRr : AVR::STDPtrQRr;
322192405a3SDylan McKay 
323192405a3SDylan McKay     MI.setDesc(TII.get(STOpc));
324*6641c57aSPatryk Wychowaniec     MI.getOperand(0).setReg(AVR::R31R30);
325192405a3SDylan McKay   }
326192405a3SDylan McKay }
327192405a3SDylan McKay 
eliminateCallFramePseudoInstr(MachineFunction & MF,MachineBasicBlock & MBB,MachineBasicBlock::iterator MI) const328192405a3SDylan McKay MachineBasicBlock::iterator AVRFrameLowering::eliminateCallFramePseudoInstr(
329192405a3SDylan McKay     MachineFunction &MF, MachineBasicBlock &MBB,
330192405a3SDylan McKay     MachineBasicBlock::iterator MI) const {
331192405a3SDylan McKay   const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
332192405a3SDylan McKay   const AVRInstrInfo &TII = *STI.getInstrInfo();
333192405a3SDylan McKay 
3348fcc70f1SMatt Arsenault   if (hasReservedCallFrame(MF)) {
335192405a3SDylan McKay     return MBB.erase(MI);
336192405a3SDylan McKay   }
337192405a3SDylan McKay 
338192405a3SDylan McKay   DebugLoc DL = MI->getDebugLoc();
339192405a3SDylan McKay   unsigned int Opcode = MI->getOpcode();
340d526b13eSSerge Pavlov   int Amount = TII.getFrameSize(*MI);
341192405a3SDylan McKay 
342*6641c57aSPatryk Wychowaniec   if (Amount == 0) {
343*6641c57aSPatryk Wychowaniec     return MBB.erase(MI);
344*6641c57aSPatryk Wychowaniec   }
345*6641c57aSPatryk Wychowaniec 
3463ba550a0SGuillaume Chatelet   assert(getStackAlign() == Align(1) && "Unsupported stack alignment");
347192405a3SDylan McKay 
348192405a3SDylan McKay   if (Opcode == TII.getCallFrameSetupOpcode()) {
3495aa8014cSAyke van Laethem     // Update the stack pointer.
3505aa8014cSAyke van Laethem     // In many cases this can be done far more efficiently by pushing the
3515aa8014cSAyke van Laethem     // relevant values directly to the stack. However, doing that correctly
3525aa8014cSAyke van Laethem     // (in the right order, possibly skipping some empty space for undef
3535aa8014cSAyke van Laethem     // values, etc) is tricky and thus left to be optimized in the future.
3545aa8014cSAyke van Laethem     BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP);
3555aa8014cSAyke van Laethem 
3565449d2daSShivam Gupta     MachineInstr *New =
3575449d2daSShivam Gupta         BuildMI(MBB, MI, DL, TII.get(AVR::SUBIWRdK), AVR::R31R30)
3585aa8014cSAyke van Laethem             .addReg(AVR::R31R30, RegState::Kill)
3595aa8014cSAyke van Laethem             .addImm(Amount);
3605aa8014cSAyke van Laethem     New->getOperand(3).setIsDead();
3615aa8014cSAyke van Laethem 
3625449d2daSShivam Gupta     BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP).addReg(AVR::R31R30);
3635aa8014cSAyke van Laethem 
3645aa8014cSAyke van Laethem     // Make sure the remaining stack stores are converted to real store
3655aa8014cSAyke van Laethem     // instructions.
366*6641c57aSPatryk Wychowaniec     fixStackStores(MBB, MI, TII);
367192405a3SDylan McKay   } else {
368192405a3SDylan McKay     assert(Opcode == TII.getCallFrameDestroyOpcode());
369192405a3SDylan McKay 
3705aa8014cSAyke van Laethem     // Note that small stack changes could be implemented more efficiently
3715aa8014cSAyke van Laethem     // with a few pop instructions instead of the 8-9 instructions now
3725aa8014cSAyke van Laethem     // required.
3735aa8014cSAyke van Laethem 
374192405a3SDylan McKay     // Select the best opcode to adjust SP based on the offset size.
375*6641c57aSPatryk Wychowaniec     unsigned AddOpcode;
376*6641c57aSPatryk Wychowaniec 
377192405a3SDylan McKay     if (isUInt<6>(Amount)) {
378*6641c57aSPatryk Wychowaniec       AddOpcode = AVR::ADIWRdK;
379192405a3SDylan McKay     } else {
380*6641c57aSPatryk Wychowaniec       AddOpcode = AVR::SUBIWRdK;
381192405a3SDylan McKay       Amount = -Amount;
382192405a3SDylan McKay     }
383192405a3SDylan McKay 
384192405a3SDylan McKay     // Build the instruction sequence.
385192405a3SDylan McKay     BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP);
386192405a3SDylan McKay 
387*6641c57aSPatryk Wychowaniec     MachineInstr *New = BuildMI(MBB, MI, DL, TII.get(AddOpcode), AVR::R31R30)
388192405a3SDylan McKay                             .addReg(AVR::R31R30, RegState::Kill)
389192405a3SDylan McKay                             .addImm(Amount);
390192405a3SDylan McKay     New->getOperand(3).setIsDead();
391192405a3SDylan McKay 
392192405a3SDylan McKay     BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP)
393192405a3SDylan McKay         .addReg(AVR::R31R30, RegState::Kill);
394192405a3SDylan McKay   }
395192405a3SDylan McKay 
396192405a3SDylan McKay   return MBB.erase(MI);
397192405a3SDylan McKay }
398192405a3SDylan McKay 
determineCalleeSaves(MachineFunction & MF,BitVector & SavedRegs,RegScavenger * RS) const399192405a3SDylan McKay void AVRFrameLowering::determineCalleeSaves(MachineFunction &MF,
400192405a3SDylan McKay                                             BitVector &SavedRegs,
401192405a3SDylan McKay                                             RegScavenger *RS) const {
402192405a3SDylan McKay   TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
403192405a3SDylan McKay 
404634339abSDylan McKay   // If we have a frame pointer, the Y register needs to be saved as well.
4053ab1c97eSAyke van Laethem   if (hasFP(MF)) {
4063ab1c97eSAyke van Laethem     SavedRegs.set(AVR::R29);
4073ab1c97eSAyke van Laethem     SavedRegs.set(AVR::R28);
4083ab1c97eSAyke van Laethem   }
409192405a3SDylan McKay }
410192405a3SDylan McKay /// The frame analyzer pass.
411192405a3SDylan McKay ///
412192405a3SDylan McKay /// Scans the function for allocas and used arguments
413192405a3SDylan McKay /// that are passed through the stack.
414192405a3SDylan McKay struct AVRFrameAnalyzer : public MachineFunctionPass {
415192405a3SDylan McKay   static char ID;
AVRFrameAnalyzerllvm::AVRFrameAnalyzer416192405a3SDylan McKay   AVRFrameAnalyzer() : MachineFunctionPass(ID) {}
417192405a3SDylan McKay 
runOnMachineFunctionllvm::AVRFrameAnalyzer418a19461d9SLogan Smith   bool runOnMachineFunction(MachineFunction &MF) override {
419192405a3SDylan McKay     const MachineFrameInfo &MFI = MF.getFrameInfo();
420*6641c57aSPatryk Wychowaniec     AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
421192405a3SDylan McKay 
422192405a3SDylan McKay     // If there are no fixed frame indexes during this stage it means there
423192405a3SDylan McKay     // are allocas present in the function.
424192405a3SDylan McKay     if (MFI.getNumObjects() != MFI.getNumFixedObjects()) {
425192405a3SDylan McKay       // Check for the type of allocas present in the function. We only care
426192405a3SDylan McKay       // about fixed size allocas so do not give false positives if only
427192405a3SDylan McKay       // variable sized allocas are present.
428192405a3SDylan McKay       for (unsigned i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) {
429192405a3SDylan McKay         // Variable sized objects have size 0.
430192405a3SDylan McKay         if (MFI.getObjectSize(i)) {
431*6641c57aSPatryk Wychowaniec           AFI->setHasAllocas(true);
432192405a3SDylan McKay           break;
433192405a3SDylan McKay         }
434192405a3SDylan McKay       }
435192405a3SDylan McKay     }
436192405a3SDylan McKay 
437192405a3SDylan McKay     // If there are fixed frame indexes present, scan the function to see if
438192405a3SDylan McKay     // they are really being used.
439192405a3SDylan McKay     if (MFI.getNumFixedObjects() == 0) {
440192405a3SDylan McKay       return false;
441192405a3SDylan McKay     }
442192405a3SDylan McKay 
443192405a3SDylan McKay     // Ok fixed frame indexes present, now scan the function to see if they
444192405a3SDylan McKay     // are really being used, otherwise we can ignore them.
445192405a3SDylan McKay     for (const MachineBasicBlock &BB : MF) {
446192405a3SDylan McKay       for (const MachineInstr &MI : BB) {
447192405a3SDylan McKay         int Opcode = MI.getOpcode();
448192405a3SDylan McKay 
449192405a3SDylan McKay         if ((Opcode != AVR::LDDRdPtrQ) && (Opcode != AVR::LDDWRdPtrQ) &&
450192405a3SDylan McKay             (Opcode != AVR::STDPtrQRr) && (Opcode != AVR::STDWPtrQRr)) {
451192405a3SDylan McKay           continue;
452192405a3SDylan McKay         }
453192405a3SDylan McKay 
454192405a3SDylan McKay         for (const MachineOperand &MO : MI.operands()) {
455192405a3SDylan McKay           if (!MO.isFI()) {
456192405a3SDylan McKay             continue;
457192405a3SDylan McKay           }
458192405a3SDylan McKay 
459192405a3SDylan McKay           if (MFI.isFixedObjectIndex(MO.getIndex())) {
460*6641c57aSPatryk Wychowaniec             AFI->setHasStackArgs(true);
461192405a3SDylan McKay             return false;
462192405a3SDylan McKay           }
463192405a3SDylan McKay         }
464192405a3SDylan McKay       }
465192405a3SDylan McKay     }
466192405a3SDylan McKay 
467192405a3SDylan McKay     return false;
468192405a3SDylan McKay   }
469192405a3SDylan McKay 
getPassNamellvm::AVRFrameAnalyzer470a19461d9SLogan Smith   StringRef getPassName() const override { return "AVR Frame Analyzer"; }
471192405a3SDylan McKay };
472192405a3SDylan McKay 
473192405a3SDylan McKay char AVRFrameAnalyzer::ID = 0;
474192405a3SDylan McKay 
475192405a3SDylan McKay /// Creates instance of the frame analyzer pass.
createAVRFrameAnalyzerPass()476192405a3SDylan McKay FunctionPass *createAVRFrameAnalyzerPass() { return new AVRFrameAnalyzer(); }
477192405a3SDylan McKay 
478192405a3SDylan McKay } // end of namespace llvm
479