xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/AVR/AVRFrameLowering.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===-- AVRFrameLowering.cpp - AVR Frame Information ----------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains the AVR implementation of TargetFrameLowering class.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "AVRFrameLowering.h"
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "AVR.h"
160b57cec5SDimitry Andric #include "AVRInstrInfo.h"
170b57cec5SDimitry Andric #include "AVRMachineFunctionInfo.h"
180b57cec5SDimitry Andric #include "AVRTargetMachine.h"
190b57cec5SDimitry Andric #include "MCTargetDesc/AVRMCTargetDesc.h"
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
250b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
260b57cec5SDimitry Andric #include "llvm/IR/Function.h"
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric namespace llvm {
290b57cec5SDimitry Andric 
AVRFrameLowering()300b57cec5SDimitry Andric AVRFrameLowering::AVRFrameLowering()
315ffd83dbSDimitry Andric     : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(1), -2) {}
320b57cec5SDimitry Andric 
canSimplifyCallFramePseudos(const MachineFunction & MF) const330b57cec5SDimitry Andric bool AVRFrameLowering::canSimplifyCallFramePseudos(
340b57cec5SDimitry Andric     const MachineFunction &MF) const {
350b57cec5SDimitry Andric   // Always simplify call frame pseudo instructions, even when
360b57cec5SDimitry Andric   // hasReservedCallFrame is false.
370b57cec5SDimitry Andric   return true;
380b57cec5SDimitry Andric }
390b57cec5SDimitry Andric 
hasReservedCallFrame(const MachineFunction & MF) const400b57cec5SDimitry Andric bool AVRFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
410b57cec5SDimitry Andric   // Reserve call frame memory in function prologue under the following
420b57cec5SDimitry Andric   // conditions:
430b57cec5SDimitry Andric   // - Y pointer is reserved to be the frame pointer.
440b57cec5SDimitry Andric   // - The function does not contain variable sized objects.
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
470b57cec5SDimitry Andric   return hasFP(MF) && !MFI.hasVarSizedObjects();
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric 
emitPrologue(MachineFunction & MF,MachineBasicBlock & MBB) const500b57cec5SDimitry Andric void AVRFrameLowering::emitPrologue(MachineFunction &MF,
510b57cec5SDimitry Andric                                     MachineBasicBlock &MBB) const {
520b57cec5SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.begin();
530b57cec5SDimitry Andric   DebugLoc DL = (MBBI != MBB.end()) ? MBBI->getDebugLoc() : DebugLoc();
540b57cec5SDimitry Andric   const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
550b57cec5SDimitry Andric   const AVRInstrInfo &TII = *STI.getInstrInfo();
565ffd83dbSDimitry Andric   const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
57bdd1243dSDimitry Andric   const MachineRegisterInfo &MRI = MF.getRegInfo();
580b57cec5SDimitry Andric   bool HasFP = hasFP(MF);
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   // Interrupt handlers re-enable interrupts in function entry.
615ffd83dbSDimitry Andric   if (AFI->isInterruptHandler()) {
620b57cec5SDimitry Andric     BuildMI(MBB, MBBI, DL, TII.get(AVR::BSETs))
630b57cec5SDimitry Andric         .addImm(0x07)
640b57cec5SDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
650b57cec5SDimitry Andric   }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   // Emit special prologue code to save R1, R0 and SREG in interrupt/signal
680b57cec5SDimitry Andric   // handlers before saving any other registers.
695ffd83dbSDimitry Andric   if (AFI->isInterruptOrSignalHandler()) {
70bdd1243dSDimitry Andric     BuildMI(MBB, MBBI, DL, TII.get(AVR::PUSHRr))
71bdd1243dSDimitry Andric         .addReg(STI.getTmpRegister(), RegState::Kill)
720b57cec5SDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
730b57cec5SDimitry Andric 
74bdd1243dSDimitry Andric     BuildMI(MBB, MBBI, DL, TII.get(AVR::INRdA), STI.getTmpRegister())
7581ad6265SDimitry Andric         .addImm(STI.getIORegSREG())
760b57cec5SDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
770b57cec5SDimitry Andric     BuildMI(MBB, MBBI, DL, TII.get(AVR::PUSHRr))
78bdd1243dSDimitry Andric         .addReg(STI.getTmpRegister(), RegState::Kill)
79bdd1243dSDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
80bdd1243dSDimitry Andric     if (!MRI.reg_empty(STI.getZeroRegister())) {
81bdd1243dSDimitry Andric       BuildMI(MBB, MBBI, DL, TII.get(AVR::PUSHRr))
82bdd1243dSDimitry Andric           .addReg(STI.getZeroRegister(), RegState::Kill)
830b57cec5SDimitry Andric           .setMIFlag(MachineInstr::FrameSetup);
840b57cec5SDimitry Andric       BuildMI(MBB, MBBI, DL, TII.get(AVR::EORRdRr))
85bdd1243dSDimitry Andric           .addReg(STI.getZeroRegister(), RegState::Define)
86bdd1243dSDimitry Andric           .addReg(STI.getZeroRegister(), RegState::Kill)
87bdd1243dSDimitry Andric           .addReg(STI.getZeroRegister(), RegState::Kill)
88fe6060f1SDimitry Andric           .setMIFlag(MachineInstr::FrameSetup);
890b57cec5SDimitry Andric     }
90bdd1243dSDimitry Andric   }
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   // Early exit if the frame pointer is not needed in this function.
930b57cec5SDimitry Andric   if (!HasFP) {
940b57cec5SDimitry Andric     return;
950b57cec5SDimitry Andric   }
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
980b57cec5SDimitry Andric   unsigned FrameSize = MFI.getStackSize() - AFI->getCalleeSavedFrameSize();
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric   // Skip the callee-saved push instructions.
1010b57cec5SDimitry Andric   while (
1020b57cec5SDimitry Andric       (MBBI != MBB.end()) && MBBI->getFlag(MachineInstr::FrameSetup) &&
1030b57cec5SDimitry Andric       (MBBI->getOpcode() == AVR::PUSHRr || MBBI->getOpcode() == AVR::PUSHWRr)) {
1040b57cec5SDimitry Andric     ++MBBI;
1050b57cec5SDimitry Andric   }
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   // Update Y with the new base value.
1080b57cec5SDimitry Andric   BuildMI(MBB, MBBI, DL, TII.get(AVR::SPREAD), AVR::R29R28)
1090b57cec5SDimitry Andric       .addReg(AVR::SP)
1100b57cec5SDimitry Andric       .setMIFlag(MachineInstr::FrameSetup);
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   // Mark the FramePtr as live-in in every block except the entry.
113349cc55cSDimitry Andric   for (MachineBasicBlock &MBBJ : llvm::drop_begin(MF)) {
114349cc55cSDimitry Andric     MBBJ.addLiveIn(AVR::R29R28);
1150b57cec5SDimitry Andric   }
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   if (!FrameSize) {
1180b57cec5SDimitry Andric     return;
1190b57cec5SDimitry Andric   }
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   // Reserve the necessary frame memory by doing FP -= <size>.
122bdd1243dSDimitry Andric   unsigned Opcode = (isUInt<6>(FrameSize) && STI.hasADDSUBIW()) ? AVR::SBIWRdK
123bdd1243dSDimitry Andric                                                                 : AVR::SUBIWRdK;
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric   MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opcode), AVR::R29R28)
1260b57cec5SDimitry Andric                          .addReg(AVR::R29R28, RegState::Kill)
1270b57cec5SDimitry Andric                          .addImm(FrameSize)
1280b57cec5SDimitry Andric                          .setMIFlag(MachineInstr::FrameSetup);
1290b57cec5SDimitry Andric   // The SREG implicit def is dead.
1300b57cec5SDimitry Andric   MI->getOperand(3).setIsDead();
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric   // Write back R29R28 to SP and temporarily disable interrupts.
1330b57cec5SDimitry Andric   BuildMI(MBB, MBBI, DL, TII.get(AVR::SPWRITE), AVR::SP)
1340b57cec5SDimitry Andric       .addReg(AVR::R29R28)
1350b57cec5SDimitry Andric       .setMIFlag(MachineInstr::FrameSetup);
1360b57cec5SDimitry Andric }
1370b57cec5SDimitry Andric 
restoreStatusRegister(MachineFunction & MF,MachineBasicBlock & MBB)138e8d8bef9SDimitry Andric static void restoreStatusRegister(MachineFunction &MF, MachineBasicBlock &MBB) {
139e8d8bef9SDimitry Andric   const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
140bdd1243dSDimitry Andric   const MachineRegisterInfo &MRI = MF.getRegInfo();
141e8d8bef9SDimitry Andric 
142e8d8bef9SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
143e8d8bef9SDimitry Andric 
144e8d8bef9SDimitry Andric   DebugLoc DL = MBBI->getDebugLoc();
145e8d8bef9SDimitry Andric   const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
146e8d8bef9SDimitry Andric   const AVRInstrInfo &TII = *STI.getInstrInfo();
147e8d8bef9SDimitry Andric 
148e8d8bef9SDimitry Andric   // Emit special epilogue code to restore R1, R0 and SREG in interrupt/signal
149e8d8bef9SDimitry Andric   // handlers at the very end of the function, just before reti.
150e8d8bef9SDimitry Andric   if (AFI->isInterruptOrSignalHandler()) {
151bdd1243dSDimitry Andric     if (!MRI.reg_empty(STI.getZeroRegister())) {
152bdd1243dSDimitry Andric       BuildMI(MBB, MBBI, DL, TII.get(AVR::POPRd), STI.getZeroRegister());
153bdd1243dSDimitry Andric     }
154bdd1243dSDimitry Andric     BuildMI(MBB, MBBI, DL, TII.get(AVR::POPRd), STI.getTmpRegister());
155e8d8bef9SDimitry Andric     BuildMI(MBB, MBBI, DL, TII.get(AVR::OUTARr))
15681ad6265SDimitry Andric         .addImm(STI.getIORegSREG())
157bdd1243dSDimitry Andric         .addReg(STI.getTmpRegister(), RegState::Kill);
158bdd1243dSDimitry Andric     BuildMI(MBB, MBBI, DL, TII.get(AVR::POPRd), STI.getTmpRegister());
159e8d8bef9SDimitry Andric   }
160e8d8bef9SDimitry Andric }
161e8d8bef9SDimitry Andric 
emitEpilogue(MachineFunction & MF,MachineBasicBlock & MBB) const1620b57cec5SDimitry Andric void AVRFrameLowering::emitEpilogue(MachineFunction &MF,
1630b57cec5SDimitry Andric                                     MachineBasicBlock &MBB) const {
1645ffd83dbSDimitry Andric   const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric   // Early exit if the frame pointer is not needed in this function except for
1670b57cec5SDimitry Andric   // signal/interrupt handlers where special code generation is required.
1685ffd83dbSDimitry Andric   if (!hasFP(MF) && !AFI->isInterruptOrSignalHandler()) {
1690b57cec5SDimitry Andric     return;
1700b57cec5SDimitry Andric   }
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
1730b57cec5SDimitry Andric   assert(MBBI->getDesc().isReturn() &&
1740b57cec5SDimitry Andric          "Can only insert epilog into returning blocks");
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric   DebugLoc DL = MBBI->getDebugLoc();
1770b57cec5SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
1780b57cec5SDimitry Andric   unsigned FrameSize = MFI.getStackSize() - AFI->getCalleeSavedFrameSize();
1790b57cec5SDimitry Andric   const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
1800b57cec5SDimitry Andric   const AVRInstrInfo &TII = *STI.getInstrInfo();
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric   // Early exit if there is no need to restore the frame pointer.
18304eeddc0SDimitry Andric   if (!FrameSize && !MF.getFrameInfo().hasVarSizedObjects()) {
184e8d8bef9SDimitry Andric     restoreStatusRegister(MF, MBB);
1850b57cec5SDimitry Andric     return;
1860b57cec5SDimitry Andric   }
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric   // Skip the callee-saved pop instructions.
1890b57cec5SDimitry Andric   while (MBBI != MBB.begin()) {
1900b57cec5SDimitry Andric     MachineBasicBlock::iterator PI = std::prev(MBBI);
1910b57cec5SDimitry Andric     int Opc = PI->getOpcode();
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric     if (Opc != AVR::POPRd && Opc != AVR::POPWRd && !PI->isTerminator()) {
1940b57cec5SDimitry Andric       break;
1950b57cec5SDimitry Andric     }
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric     --MBBI;
1980b57cec5SDimitry Andric   }
1990b57cec5SDimitry Andric 
20004eeddc0SDimitry Andric   if (FrameSize) {
2010b57cec5SDimitry Andric     unsigned Opcode;
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric     // Select the optimal opcode depending on how big it is.
204bdd1243dSDimitry Andric     if (isUInt<6>(FrameSize) && STI.hasADDSUBIW()) {
2050b57cec5SDimitry Andric       Opcode = AVR::ADIWRdK;
2060b57cec5SDimitry Andric     } else {
2070b57cec5SDimitry Andric       Opcode = AVR::SUBIWRdK;
2080b57cec5SDimitry Andric       FrameSize = -FrameSize;
2090b57cec5SDimitry Andric     }
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric     // Restore the frame pointer by doing FP += <size>.
2120b57cec5SDimitry Andric     MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opcode), AVR::R29R28)
2130b57cec5SDimitry Andric                            .addReg(AVR::R29R28, RegState::Kill)
2140b57cec5SDimitry Andric                            .addImm(FrameSize);
2150b57cec5SDimitry Andric     // The SREG implicit def is dead.
2160b57cec5SDimitry Andric     MI->getOperand(3).setIsDead();
21704eeddc0SDimitry Andric   }
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric   // Write back R29R28 to SP and temporarily disable interrupts.
2200b57cec5SDimitry Andric   BuildMI(MBB, MBBI, DL, TII.get(AVR::SPWRITE), AVR::SP)
2210b57cec5SDimitry Andric       .addReg(AVR::R29R28, RegState::Kill);
222e8d8bef9SDimitry Andric 
223e8d8bef9SDimitry Andric   restoreStatusRegister(MF, MBB);
2240b57cec5SDimitry Andric }
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric // Return true if the specified function should have a dedicated frame
2270b57cec5SDimitry Andric // pointer register. This is true if the function meets any of the following
2280b57cec5SDimitry Andric // conditions:
2290b57cec5SDimitry Andric //  - a register has been spilled
2300b57cec5SDimitry Andric //  - has allocas
2310b57cec5SDimitry Andric //  - input arguments are passed using the stack
2320b57cec5SDimitry Andric //
2330b57cec5SDimitry Andric // Notice that strictly this is not a frame pointer because it contains SP after
2340b57cec5SDimitry Andric // frame allocation instead of having the original SP in function entry.
hasFP(const MachineFunction & MF) const2350b57cec5SDimitry Andric bool AVRFrameLowering::hasFP(const MachineFunction &MF) const {
2360b57cec5SDimitry Andric   const AVRMachineFunctionInfo *FuncInfo = MF.getInfo<AVRMachineFunctionInfo>();
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   return (FuncInfo->getHasSpills() || FuncInfo->getHasAllocas() ||
23904eeddc0SDimitry Andric           FuncInfo->getHasStackArgs() ||
24004eeddc0SDimitry Andric           MF.getFrameInfo().hasVarSizedObjects());
2410b57cec5SDimitry Andric }
2420b57cec5SDimitry Andric 
spillCalleeSavedRegisters(MachineBasicBlock & MBB,MachineBasicBlock::iterator MI,ArrayRef<CalleeSavedInfo> CSI,const TargetRegisterInfo * TRI) const2430b57cec5SDimitry Andric bool AVRFrameLowering::spillCalleeSavedRegisters(
2440b57cec5SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
2455ffd83dbSDimitry Andric     ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
2460b57cec5SDimitry Andric   if (CSI.empty()) {
2470b57cec5SDimitry Andric     return false;
2480b57cec5SDimitry Andric   }
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric   unsigned CalleeFrameSize = 0;
2510b57cec5SDimitry Andric   DebugLoc DL = MBB.findDebugLoc(MI);
2520b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
2530b57cec5SDimitry Andric   const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
2540b57cec5SDimitry Andric   const TargetInstrInfo &TII = *STI.getInstrInfo();
2550b57cec5SDimitry Andric   AVRMachineFunctionInfo *AVRFI = MF.getInfo<AVRMachineFunctionInfo>();
2560b57cec5SDimitry Andric 
2570eae32dcSDimitry Andric   for (const CalleeSavedInfo &I : llvm::reverse(CSI)) {
25804eeddc0SDimitry Andric     Register Reg = I.getReg();
2590b57cec5SDimitry Andric     bool IsNotLiveIn = !MBB.isLiveIn(Reg);
2600b57cec5SDimitry Andric 
261*06c3fb27SDimitry Andric     // Check if Reg is a sub register of a 16-bit livein register, and then
262*06c3fb27SDimitry Andric     // add it to the livein list.
263*06c3fb27SDimitry Andric     if (IsNotLiveIn)
264*06c3fb27SDimitry Andric       for (const auto &LiveIn : MBB.liveins())
265*06c3fb27SDimitry Andric         if (STI.getRegisterInfo()->isSubRegister(LiveIn.PhysReg, Reg)) {
266*06c3fb27SDimitry Andric           IsNotLiveIn = false;
267*06c3fb27SDimitry Andric           MBB.addLiveIn(Reg);
268*06c3fb27SDimitry Andric           break;
269*06c3fb27SDimitry Andric         }
270*06c3fb27SDimitry Andric 
2710b57cec5SDimitry Andric     assert(TRI->getRegSizeInBits(*TRI->getMinimalPhysRegClass(Reg)) == 8 &&
2720b57cec5SDimitry Andric            "Invalid register size");
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric     // Add the callee-saved register as live-in only if it is not already a
2750b57cec5SDimitry Andric     // live-in register, this usually happens with arguments that are passed
2760b57cec5SDimitry Andric     // through callee-saved registers.
2770b57cec5SDimitry Andric     if (IsNotLiveIn) {
2780b57cec5SDimitry Andric       MBB.addLiveIn(Reg);
2790b57cec5SDimitry Andric     }
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric     // Do not kill the register when it is an input argument.
2820b57cec5SDimitry Andric     BuildMI(MBB, MI, DL, TII.get(AVR::PUSHRr))
2830b57cec5SDimitry Andric         .addReg(Reg, getKillRegState(IsNotLiveIn))
2840b57cec5SDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
2850b57cec5SDimitry Andric     ++CalleeFrameSize;
2860b57cec5SDimitry Andric   }
2870b57cec5SDimitry Andric 
2880b57cec5SDimitry Andric   AVRFI->setCalleeSavedFrameSize(CalleeFrameSize);
2890b57cec5SDimitry Andric 
2900b57cec5SDimitry Andric   return true;
2910b57cec5SDimitry Andric }
2920b57cec5SDimitry Andric 
restoreCalleeSavedRegisters(MachineBasicBlock & MBB,MachineBasicBlock::iterator MI,MutableArrayRef<CalleeSavedInfo> CSI,const TargetRegisterInfo * TRI) const2930b57cec5SDimitry Andric bool AVRFrameLowering::restoreCalleeSavedRegisters(
2940b57cec5SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
2955ffd83dbSDimitry Andric     MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
2960b57cec5SDimitry Andric   if (CSI.empty()) {
2970b57cec5SDimitry Andric     return false;
2980b57cec5SDimitry Andric   }
2990b57cec5SDimitry Andric 
3000b57cec5SDimitry Andric   DebugLoc DL = MBB.findDebugLoc(MI);
3010b57cec5SDimitry Andric   const MachineFunction &MF = *MBB.getParent();
3020b57cec5SDimitry Andric   const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
3030b57cec5SDimitry Andric   const TargetInstrInfo &TII = *STI.getInstrInfo();
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric   for (const CalleeSavedInfo &CCSI : CSI) {
30604eeddc0SDimitry Andric     Register Reg = CCSI.getReg();
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric     assert(TRI->getRegSizeInBits(*TRI->getMinimalPhysRegClass(Reg)) == 8 &&
3090b57cec5SDimitry Andric            "Invalid register size");
3100b57cec5SDimitry Andric 
3110b57cec5SDimitry Andric     BuildMI(MBB, MI, DL, TII.get(AVR::POPRd), Reg);
3120b57cec5SDimitry Andric   }
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric   return true;
3150b57cec5SDimitry Andric }
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric /// Replace pseudo store instructions that pass arguments through the stack with
3185ffd83dbSDimitry Andric /// real instructions.
fixStackStores(MachineBasicBlock & MBB,MachineBasicBlock::iterator StartMI,const TargetInstrInfo & TII)3190b57cec5SDimitry Andric static void fixStackStores(MachineBasicBlock &MBB,
3201838bd0fSDimitry Andric                            MachineBasicBlock::iterator StartMI,
32181ad6265SDimitry Andric                            const TargetInstrInfo &TII) {
3220b57cec5SDimitry Andric   // Iterate through the BB until we hit a call instruction or we reach the end.
323349cc55cSDimitry Andric   for (MachineInstr &MI :
3241838bd0fSDimitry Andric        llvm::make_early_inc_range(llvm::make_range(StartMI, MBB.end()))) {
325349cc55cSDimitry Andric     if (MI.isCall())
326349cc55cSDimitry Andric       break;
327349cc55cSDimitry Andric 
328349cc55cSDimitry Andric     unsigned Opcode = MI.getOpcode();
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric     // Only care of pseudo store instructions where SP is the base pointer.
331349cc55cSDimitry Andric     if (Opcode != AVR::STDSPQRr && Opcode != AVR::STDWSPQRr)
3320b57cec5SDimitry Andric       continue;
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric     assert(MI.getOperand(0).getReg() == AVR::SP &&
33581ad6265SDimitry Andric            "SP is expected as base pointer");
3360b57cec5SDimitry Andric 
3370b57cec5SDimitry Andric     // Replace this instruction with a regular store. Use Y as the base
3380b57cec5SDimitry Andric     // pointer since it is guaranteed to contain a copy of SP.
3390b57cec5SDimitry Andric     unsigned STOpc =
3400b57cec5SDimitry Andric         (Opcode == AVR::STDWSPQRr) ? AVR::STDWPtrQRr : AVR::STDPtrQRr;
3410b57cec5SDimitry Andric 
3420b57cec5SDimitry Andric     MI.setDesc(TII.get(STOpc));
34381ad6265SDimitry Andric     MI.getOperand(0).setReg(AVR::R31R30);
3440b57cec5SDimitry Andric   }
3450b57cec5SDimitry Andric }
3460b57cec5SDimitry Andric 
eliminateCallFramePseudoInstr(MachineFunction & MF,MachineBasicBlock & MBB,MachineBasicBlock::iterator MI) const3470b57cec5SDimitry Andric MachineBasicBlock::iterator AVRFrameLowering::eliminateCallFramePseudoInstr(
3480b57cec5SDimitry Andric     MachineFunction &MF, MachineBasicBlock &MBB,
3490b57cec5SDimitry Andric     MachineBasicBlock::iterator MI) const {
3500b57cec5SDimitry Andric   const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
3510b57cec5SDimitry Andric   const AVRInstrInfo &TII = *STI.getInstrInfo();
3520b57cec5SDimitry Andric 
3530b57cec5SDimitry Andric   if (hasReservedCallFrame(MF)) {
3540b57cec5SDimitry Andric     return MBB.erase(MI);
3550b57cec5SDimitry Andric   }
3560b57cec5SDimitry Andric 
3570b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
3580b57cec5SDimitry Andric   unsigned int Opcode = MI->getOpcode();
3590b57cec5SDimitry Andric   int Amount = TII.getFrameSize(*MI);
3600b57cec5SDimitry Andric 
36181ad6265SDimitry Andric   if (Amount == 0) {
36281ad6265SDimitry Andric     return MBB.erase(MI);
36381ad6265SDimitry Andric   }
36481ad6265SDimitry Andric 
3655ffd83dbSDimitry Andric   assert(getStackAlign() == Align(1) && "Unsupported stack alignment");
3660b57cec5SDimitry Andric 
3670b57cec5SDimitry Andric   if (Opcode == TII.getCallFrameSetupOpcode()) {
3685ffd83dbSDimitry Andric     // Update the stack pointer.
3695ffd83dbSDimitry Andric     // In many cases this can be done far more efficiently by pushing the
3705ffd83dbSDimitry Andric     // relevant values directly to the stack. However, doing that correctly
3715ffd83dbSDimitry Andric     // (in the right order, possibly skipping some empty space for undef
3725ffd83dbSDimitry Andric     // values, etc) is tricky and thus left to be optimized in the future.
3735ffd83dbSDimitry Andric     BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP);
3745ffd83dbSDimitry Andric 
375349cc55cSDimitry Andric     MachineInstr *New =
376349cc55cSDimitry Andric         BuildMI(MBB, MI, DL, TII.get(AVR::SUBIWRdK), AVR::R31R30)
3775ffd83dbSDimitry Andric             .addReg(AVR::R31R30, RegState::Kill)
3785ffd83dbSDimitry Andric             .addImm(Amount);
3795ffd83dbSDimitry Andric     New->getOperand(3).setIsDead();
3805ffd83dbSDimitry Andric 
381349cc55cSDimitry Andric     BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP).addReg(AVR::R31R30);
3825ffd83dbSDimitry Andric 
3835ffd83dbSDimitry Andric     // Make sure the remaining stack stores are converted to real store
3845ffd83dbSDimitry Andric     // instructions.
38581ad6265SDimitry Andric     fixStackStores(MBB, MI, TII);
3860b57cec5SDimitry Andric   } else {
3870b57cec5SDimitry Andric     assert(Opcode == TII.getCallFrameDestroyOpcode());
3880b57cec5SDimitry Andric 
3895ffd83dbSDimitry Andric     // Note that small stack changes could be implemented more efficiently
3905ffd83dbSDimitry Andric     // with a few pop instructions instead of the 8-9 instructions now
3915ffd83dbSDimitry Andric     // required.
3925ffd83dbSDimitry Andric 
3930b57cec5SDimitry Andric     // Select the best opcode to adjust SP based on the offset size.
39481ad6265SDimitry Andric     unsigned AddOpcode;
39581ad6265SDimitry Andric 
396bdd1243dSDimitry Andric     if (isUInt<6>(Amount) && STI.hasADDSUBIW()) {
39781ad6265SDimitry Andric       AddOpcode = AVR::ADIWRdK;
3980b57cec5SDimitry Andric     } else {
39981ad6265SDimitry Andric       AddOpcode = AVR::SUBIWRdK;
4000b57cec5SDimitry Andric       Amount = -Amount;
4010b57cec5SDimitry Andric     }
4020b57cec5SDimitry Andric 
4030b57cec5SDimitry Andric     // Build the instruction sequence.
4040b57cec5SDimitry Andric     BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP);
4050b57cec5SDimitry Andric 
40681ad6265SDimitry Andric     MachineInstr *New = BuildMI(MBB, MI, DL, TII.get(AddOpcode), AVR::R31R30)
4070b57cec5SDimitry Andric                             .addReg(AVR::R31R30, RegState::Kill)
4080b57cec5SDimitry Andric                             .addImm(Amount);
4090b57cec5SDimitry Andric     New->getOperand(3).setIsDead();
4100b57cec5SDimitry Andric 
4110b57cec5SDimitry Andric     BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP)
4120b57cec5SDimitry Andric         .addReg(AVR::R31R30, RegState::Kill);
4130b57cec5SDimitry Andric   }
4140b57cec5SDimitry Andric 
4150b57cec5SDimitry Andric   return MBB.erase(MI);
4160b57cec5SDimitry Andric }
4170b57cec5SDimitry Andric 
determineCalleeSaves(MachineFunction & MF,BitVector & SavedRegs,RegScavenger * RS) const4180b57cec5SDimitry Andric void AVRFrameLowering::determineCalleeSaves(MachineFunction &MF,
4190b57cec5SDimitry Andric                                             BitVector &SavedRegs,
4200b57cec5SDimitry Andric                                             RegScavenger *RS) const {
4210b57cec5SDimitry Andric   TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
4220b57cec5SDimitry Andric 
4230b57cec5SDimitry Andric   // If we have a frame pointer, the Y register needs to be saved as well.
4245ffd83dbSDimitry Andric   if (hasFP(MF)) {
4255ffd83dbSDimitry Andric     SavedRegs.set(AVR::R29);
4265ffd83dbSDimitry Andric     SavedRegs.set(AVR::R28);
4275ffd83dbSDimitry Andric   }
4280b57cec5SDimitry Andric }
4290b57cec5SDimitry Andric /// The frame analyzer pass.
4300b57cec5SDimitry Andric ///
4310b57cec5SDimitry Andric /// Scans the function for allocas and used arguments
4320b57cec5SDimitry Andric /// that are passed through the stack.
4330b57cec5SDimitry Andric struct AVRFrameAnalyzer : public MachineFunctionPass {
4340b57cec5SDimitry Andric   static char ID;
AVRFrameAnalyzerllvm::AVRFrameAnalyzer4350b57cec5SDimitry Andric   AVRFrameAnalyzer() : MachineFunctionPass(ID) {}
4360b57cec5SDimitry Andric 
runOnMachineFunctionllvm::AVRFrameAnalyzer4375ffd83dbSDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override {
4380b57cec5SDimitry Andric     const MachineFrameInfo &MFI = MF.getFrameInfo();
43981ad6265SDimitry Andric     AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
4400b57cec5SDimitry Andric 
4410b57cec5SDimitry Andric     // If there are no fixed frame indexes during this stage it means there
4420b57cec5SDimitry Andric     // are allocas present in the function.
4430b57cec5SDimitry Andric     if (MFI.getNumObjects() != MFI.getNumFixedObjects()) {
4440b57cec5SDimitry Andric       // Check for the type of allocas present in the function. We only care
4450b57cec5SDimitry Andric       // about fixed size allocas so do not give false positives if only
4460b57cec5SDimitry Andric       // variable sized allocas are present.
4470b57cec5SDimitry Andric       for (unsigned i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) {
4480b57cec5SDimitry Andric         // Variable sized objects have size 0.
4490b57cec5SDimitry Andric         if (MFI.getObjectSize(i)) {
45081ad6265SDimitry Andric           AFI->setHasAllocas(true);
4510b57cec5SDimitry Andric           break;
4520b57cec5SDimitry Andric         }
4530b57cec5SDimitry Andric       }
4540b57cec5SDimitry Andric     }
4550b57cec5SDimitry Andric 
4560b57cec5SDimitry Andric     // If there are fixed frame indexes present, scan the function to see if
4570b57cec5SDimitry Andric     // they are really being used.
4580b57cec5SDimitry Andric     if (MFI.getNumFixedObjects() == 0) {
4590b57cec5SDimitry Andric       return false;
4600b57cec5SDimitry Andric     }
4610b57cec5SDimitry Andric 
4620b57cec5SDimitry Andric     // Ok fixed frame indexes present, now scan the function to see if they
4630b57cec5SDimitry Andric     // are really being used, otherwise we can ignore them.
4640b57cec5SDimitry Andric     for (const MachineBasicBlock &BB : MF) {
4650b57cec5SDimitry Andric       for (const MachineInstr &MI : BB) {
4660b57cec5SDimitry Andric         int Opcode = MI.getOpcode();
4670b57cec5SDimitry Andric 
4680b57cec5SDimitry Andric         if ((Opcode != AVR::LDDRdPtrQ) && (Opcode != AVR::LDDWRdPtrQ) &&
469bdd1243dSDimitry Andric             (Opcode != AVR::STDPtrQRr) && (Opcode != AVR::STDWPtrQRr) &&
470bdd1243dSDimitry Andric             (Opcode != AVR::FRMIDX)) {
4710b57cec5SDimitry Andric           continue;
4720b57cec5SDimitry Andric         }
4730b57cec5SDimitry Andric 
4740b57cec5SDimitry Andric         for (const MachineOperand &MO : MI.operands()) {
4750b57cec5SDimitry Andric           if (!MO.isFI()) {
4760b57cec5SDimitry Andric             continue;
4770b57cec5SDimitry Andric           }
4780b57cec5SDimitry Andric 
4790b57cec5SDimitry Andric           if (MFI.isFixedObjectIndex(MO.getIndex())) {
48081ad6265SDimitry Andric             AFI->setHasStackArgs(true);
4810b57cec5SDimitry Andric             return false;
4820b57cec5SDimitry Andric           }
4830b57cec5SDimitry Andric         }
4840b57cec5SDimitry Andric       }
4850b57cec5SDimitry Andric     }
4860b57cec5SDimitry Andric 
4870b57cec5SDimitry Andric     return false;
4880b57cec5SDimitry Andric   }
4890b57cec5SDimitry Andric 
getPassNamellvm::AVRFrameAnalyzer4905ffd83dbSDimitry Andric   StringRef getPassName() const override { return "AVR Frame Analyzer"; }
4910b57cec5SDimitry Andric };
4920b57cec5SDimitry Andric 
4930b57cec5SDimitry Andric char AVRFrameAnalyzer::ID = 0;
4940b57cec5SDimitry Andric 
4950b57cec5SDimitry Andric /// Creates instance of the frame analyzer pass.
createAVRFrameAnalyzerPass()4960b57cec5SDimitry Andric FunctionPass *createAVRFrameAnalyzerPass() { return new AVRFrameAnalyzer(); }
4970b57cec5SDimitry Andric 
4980b57cec5SDimitry Andric } // end of namespace llvm
499