Path: blob/main/contrib/llvm-project/llvm/lib/Target/AVR/AVRFrameLowering.cpp
35266 views
//===-- AVRFrameLowering.cpp - AVR Frame Information ----------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains the AVR implementation of TargetFrameLowering class.9//10//===----------------------------------------------------------------------===//1112#include "AVRFrameLowering.h"1314#include "AVR.h"15#include "AVRInstrInfo.h"16#include "AVRMachineFunctionInfo.h"17#include "AVRTargetMachine.h"18#include "MCTargetDesc/AVRMCTargetDesc.h"1920#include "llvm/CodeGen/MachineFrameInfo.h"21#include "llvm/CodeGen/MachineFunction.h"22#include "llvm/CodeGen/MachineFunctionPass.h"23#include "llvm/CodeGen/MachineInstrBuilder.h"24#include "llvm/CodeGen/MachineRegisterInfo.h"25#include "llvm/IR/Function.h"2627namespace llvm {2829AVRFrameLowering::AVRFrameLowering()30: TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(1), -2) {}3132bool AVRFrameLowering::canSimplifyCallFramePseudos(33const MachineFunction &MF) const {34// Always simplify call frame pseudo instructions, even when35// hasReservedCallFrame is false.36return true;37}3839bool AVRFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {40// Reserve call frame memory in function prologue under the following41// conditions:42// - Y pointer is reserved to be the frame pointer.43// - The function does not contain variable sized objects.4445const MachineFrameInfo &MFI = MF.getFrameInfo();46return hasFP(MF) && !MFI.hasVarSizedObjects();47}4849void AVRFrameLowering::emitPrologue(MachineFunction &MF,50MachineBasicBlock &MBB) const {51MachineBasicBlock::iterator MBBI = MBB.begin();52DebugLoc DL = (MBBI != MBB.end()) ? MBBI->getDebugLoc() : DebugLoc();53const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();54const AVRInstrInfo &TII = *STI.getInstrInfo();55const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();56const MachineRegisterInfo &MRI = MF.getRegInfo();57bool HasFP = hasFP(MF);5859// Interrupt handlers re-enable interrupts in function entry.60if (AFI->isInterruptHandler()) {61BuildMI(MBB, MBBI, DL, TII.get(AVR::BSETs))62.addImm(0x07)63.setMIFlag(MachineInstr::FrameSetup);64}6566// Emit special prologue code to save R1, R0 and SREG in interrupt/signal67// handlers before saving any other registers.68if (AFI->isInterruptOrSignalHandler()) {69BuildMI(MBB, MBBI, DL, TII.get(AVR::PUSHRr))70.addReg(STI.getTmpRegister(), RegState::Kill)71.setMIFlag(MachineInstr::FrameSetup);7273BuildMI(MBB, MBBI, DL, TII.get(AVR::INRdA), STI.getTmpRegister())74.addImm(STI.getIORegSREG())75.setMIFlag(MachineInstr::FrameSetup);76BuildMI(MBB, MBBI, DL, TII.get(AVR::PUSHRr))77.addReg(STI.getTmpRegister(), RegState::Kill)78.setMIFlag(MachineInstr::FrameSetup);79if (!MRI.reg_empty(STI.getZeroRegister())) {80BuildMI(MBB, MBBI, DL, TII.get(AVR::PUSHRr))81.addReg(STI.getZeroRegister(), RegState::Kill)82.setMIFlag(MachineInstr::FrameSetup);83BuildMI(MBB, MBBI, DL, TII.get(AVR::EORRdRr))84.addReg(STI.getZeroRegister(), RegState::Define)85.addReg(STI.getZeroRegister(), RegState::Kill)86.addReg(STI.getZeroRegister(), RegState::Kill)87.setMIFlag(MachineInstr::FrameSetup);88}89}9091// Early exit if the frame pointer is not needed in this function.92if (!HasFP) {93return;94}9596const MachineFrameInfo &MFI = MF.getFrameInfo();97unsigned FrameSize = MFI.getStackSize() - AFI->getCalleeSavedFrameSize();9899// Skip the callee-saved push instructions.100while (101(MBBI != MBB.end()) && MBBI->getFlag(MachineInstr::FrameSetup) &&102(MBBI->getOpcode() == AVR::PUSHRr || MBBI->getOpcode() == AVR::PUSHWRr)) {103++MBBI;104}105106// Update Y with the new base value.107BuildMI(MBB, MBBI, DL, TII.get(AVR::SPREAD), AVR::R29R28)108.addReg(AVR::SP)109.setMIFlag(MachineInstr::FrameSetup);110111// Mark the FramePtr as live-in in every block except the entry.112for (MachineBasicBlock &MBBJ : llvm::drop_begin(MF)) {113MBBJ.addLiveIn(AVR::R29R28);114}115116if (!FrameSize) {117return;118}119120// Reserve the necessary frame memory by doing FP -= <size>.121unsigned Opcode = (isUInt<6>(FrameSize) && STI.hasADDSUBIW()) ? AVR::SBIWRdK122: AVR::SUBIWRdK;123124MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opcode), AVR::R29R28)125.addReg(AVR::R29R28, RegState::Kill)126.addImm(FrameSize)127.setMIFlag(MachineInstr::FrameSetup);128// The SREG implicit def is dead.129MI->getOperand(3).setIsDead();130131// Write back R29R28 to SP and temporarily disable interrupts.132BuildMI(MBB, MBBI, DL, TII.get(AVR::SPWRITE), AVR::SP)133.addReg(AVR::R29R28)134.setMIFlag(MachineInstr::FrameSetup);135}136137static void restoreStatusRegister(MachineFunction &MF, MachineBasicBlock &MBB) {138const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();139const MachineRegisterInfo &MRI = MF.getRegInfo();140141MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();142143DebugLoc DL = MBBI->getDebugLoc();144const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();145const AVRInstrInfo &TII = *STI.getInstrInfo();146147// Emit special epilogue code to restore R1, R0 and SREG in interrupt/signal148// handlers at the very end of the function, just before reti.149if (AFI->isInterruptOrSignalHandler()) {150if (!MRI.reg_empty(STI.getZeroRegister())) {151BuildMI(MBB, MBBI, DL, TII.get(AVR::POPRd), STI.getZeroRegister());152}153BuildMI(MBB, MBBI, DL, TII.get(AVR::POPRd), STI.getTmpRegister());154BuildMI(MBB, MBBI, DL, TII.get(AVR::OUTARr))155.addImm(STI.getIORegSREG())156.addReg(STI.getTmpRegister(), RegState::Kill);157BuildMI(MBB, MBBI, DL, TII.get(AVR::POPRd), STI.getTmpRegister());158}159}160161void AVRFrameLowering::emitEpilogue(MachineFunction &MF,162MachineBasicBlock &MBB) const {163const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();164165// Early exit if the frame pointer is not needed in this function except for166// signal/interrupt handlers where special code generation is required.167if (!hasFP(MF) && !AFI->isInterruptOrSignalHandler()) {168return;169}170171MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();172assert(MBBI->getDesc().isReturn() &&173"Can only insert epilog into returning blocks");174175DebugLoc DL = MBBI->getDebugLoc();176const MachineFrameInfo &MFI = MF.getFrameInfo();177unsigned FrameSize = MFI.getStackSize() - AFI->getCalleeSavedFrameSize();178const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();179const AVRInstrInfo &TII = *STI.getInstrInfo();180181// Early exit if there is no need to restore the frame pointer.182if (!FrameSize && !MF.getFrameInfo().hasVarSizedObjects()) {183restoreStatusRegister(MF, MBB);184return;185}186187// Skip the callee-saved pop instructions.188while (MBBI != MBB.begin()) {189MachineBasicBlock::iterator PI = std::prev(MBBI);190int Opc = PI->getOpcode();191192if (Opc != AVR::POPRd && Opc != AVR::POPWRd && !PI->isTerminator()) {193break;194}195196--MBBI;197}198199if (FrameSize) {200unsigned Opcode;201202// Select the optimal opcode depending on how big it is.203if (isUInt<6>(FrameSize) && STI.hasADDSUBIW()) {204Opcode = AVR::ADIWRdK;205} else {206Opcode = AVR::SUBIWRdK;207FrameSize = -FrameSize;208}209210// Restore the frame pointer by doing FP += <size>.211MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opcode), AVR::R29R28)212.addReg(AVR::R29R28, RegState::Kill)213.addImm(FrameSize);214// The SREG implicit def is dead.215MI->getOperand(3).setIsDead();216}217218// Write back R29R28 to SP and temporarily disable interrupts.219BuildMI(MBB, MBBI, DL, TII.get(AVR::SPWRITE), AVR::SP)220.addReg(AVR::R29R28, RegState::Kill);221222restoreStatusRegister(MF, MBB);223}224225// Return true if the specified function should have a dedicated frame226// pointer register. This is true if the function meets any of the following227// conditions:228// - a register has been spilled229// - has allocas230// - input arguments are passed using the stack231//232// Notice that strictly this is not a frame pointer because it contains SP after233// frame allocation instead of having the original SP in function entry.234bool AVRFrameLowering::hasFP(const MachineFunction &MF) const {235const AVRMachineFunctionInfo *FuncInfo = MF.getInfo<AVRMachineFunctionInfo>();236237return (FuncInfo->getHasSpills() || FuncInfo->getHasAllocas() ||238FuncInfo->getHasStackArgs() ||239MF.getFrameInfo().hasVarSizedObjects());240}241242bool AVRFrameLowering::spillCalleeSavedRegisters(243MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,244ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {245if (CSI.empty()) {246return false;247}248249unsigned CalleeFrameSize = 0;250DebugLoc DL = MBB.findDebugLoc(MI);251MachineFunction &MF = *MBB.getParent();252const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();253const TargetInstrInfo &TII = *STI.getInstrInfo();254AVRMachineFunctionInfo *AVRFI = MF.getInfo<AVRMachineFunctionInfo>();255256for (const CalleeSavedInfo &I : llvm::reverse(CSI)) {257Register Reg = I.getReg();258bool IsNotLiveIn = !MBB.isLiveIn(Reg);259260// Check if Reg is a sub register of a 16-bit livein register, and then261// add it to the livein list.262if (IsNotLiveIn)263for (const auto &LiveIn : MBB.liveins())264if (STI.getRegisterInfo()->isSubRegister(LiveIn.PhysReg, Reg)) {265IsNotLiveIn = false;266MBB.addLiveIn(Reg);267break;268}269270assert(TRI->getRegSizeInBits(*TRI->getMinimalPhysRegClass(Reg)) == 8 &&271"Invalid register size");272273// Add the callee-saved register as live-in only if it is not already a274// live-in register, this usually happens with arguments that are passed275// through callee-saved registers.276if (IsNotLiveIn) {277MBB.addLiveIn(Reg);278}279280// Do not kill the register when it is an input argument.281BuildMI(MBB, MI, DL, TII.get(AVR::PUSHRr))282.addReg(Reg, getKillRegState(IsNotLiveIn))283.setMIFlag(MachineInstr::FrameSetup);284++CalleeFrameSize;285}286287AVRFI->setCalleeSavedFrameSize(CalleeFrameSize);288289return true;290}291292bool AVRFrameLowering::restoreCalleeSavedRegisters(293MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,294MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {295if (CSI.empty()) {296return false;297}298299DebugLoc DL = MBB.findDebugLoc(MI);300const MachineFunction &MF = *MBB.getParent();301const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();302const TargetInstrInfo &TII = *STI.getInstrInfo();303304for (const CalleeSavedInfo &CCSI : CSI) {305Register Reg = CCSI.getReg();306307assert(TRI->getRegSizeInBits(*TRI->getMinimalPhysRegClass(Reg)) == 8 &&308"Invalid register size");309310BuildMI(MBB, MI, DL, TII.get(AVR::POPRd), Reg);311}312313return true;314}315316/// Replace pseudo store instructions that pass arguments through the stack with317/// real instructions.318static void fixStackStores(MachineBasicBlock &MBB,319MachineBasicBlock::iterator StartMI,320const TargetInstrInfo &TII) {321// Iterate through the BB until we hit a call instruction or we reach the end.322for (MachineInstr &MI :323llvm::make_early_inc_range(llvm::make_range(StartMI, MBB.end()))) {324if (MI.isCall())325break;326327unsigned Opcode = MI.getOpcode();328329// Only care of pseudo store instructions where SP is the base pointer.330if (Opcode != AVR::STDSPQRr && Opcode != AVR::STDWSPQRr)331continue;332333assert(MI.getOperand(0).getReg() == AVR::SP &&334"SP is expected as base pointer");335336// Replace this instruction with a regular store. Use Y as the base337// pointer since it is guaranteed to contain a copy of SP.338unsigned STOpc =339(Opcode == AVR::STDWSPQRr) ? AVR::STDWPtrQRr : AVR::STDPtrQRr;340341MI.setDesc(TII.get(STOpc));342MI.getOperand(0).setReg(AVR::R31R30);343}344}345346MachineBasicBlock::iterator AVRFrameLowering::eliminateCallFramePseudoInstr(347MachineFunction &MF, MachineBasicBlock &MBB,348MachineBasicBlock::iterator MI) const {349const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();350const AVRInstrInfo &TII = *STI.getInstrInfo();351352if (hasReservedCallFrame(MF)) {353return MBB.erase(MI);354}355356DebugLoc DL = MI->getDebugLoc();357unsigned int Opcode = MI->getOpcode();358int Amount = TII.getFrameSize(*MI);359360if (Amount == 0) {361return MBB.erase(MI);362}363364assert(getStackAlign() == Align(1) && "Unsupported stack alignment");365366if (Opcode == TII.getCallFrameSetupOpcode()) {367// Update the stack pointer.368// In many cases this can be done far more efficiently by pushing the369// relevant values directly to the stack. However, doing that correctly370// (in the right order, possibly skipping some empty space for undef371// values, etc) is tricky and thus left to be optimized in the future.372BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP);373374MachineInstr *New =375BuildMI(MBB, MI, DL, TII.get(AVR::SUBIWRdK), AVR::R31R30)376.addReg(AVR::R31R30, RegState::Kill)377.addImm(Amount);378New->getOperand(3).setIsDead();379380BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP).addReg(AVR::R31R30);381382// Make sure the remaining stack stores are converted to real store383// instructions.384fixStackStores(MBB, MI, TII);385} else {386assert(Opcode == TII.getCallFrameDestroyOpcode());387388// Note that small stack changes could be implemented more efficiently389// with a few pop instructions instead of the 8-9 instructions now390// required.391392// Select the best opcode to adjust SP based on the offset size.393unsigned AddOpcode;394395if (isUInt<6>(Amount) && STI.hasADDSUBIW()) {396AddOpcode = AVR::ADIWRdK;397} else {398AddOpcode = AVR::SUBIWRdK;399Amount = -Amount;400}401402// Build the instruction sequence.403BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP);404405MachineInstr *New = BuildMI(MBB, MI, DL, TII.get(AddOpcode), AVR::R31R30)406.addReg(AVR::R31R30, RegState::Kill)407.addImm(Amount);408New->getOperand(3).setIsDead();409410BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP)411.addReg(AVR::R31R30, RegState::Kill);412}413414return MBB.erase(MI);415}416417void AVRFrameLowering::determineCalleeSaves(MachineFunction &MF,418BitVector &SavedRegs,419RegScavenger *RS) const {420TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);421422// If we have a frame pointer, the Y register needs to be saved as well.423if (hasFP(MF)) {424SavedRegs.set(AVR::R29);425SavedRegs.set(AVR::R28);426}427}428/// The frame analyzer pass.429///430/// Scans the function for allocas and used arguments431/// that are passed through the stack.432struct AVRFrameAnalyzer : public MachineFunctionPass {433static char ID;434AVRFrameAnalyzer() : MachineFunctionPass(ID) {}435436bool runOnMachineFunction(MachineFunction &MF) override {437const MachineFrameInfo &MFI = MF.getFrameInfo();438AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();439440// If there are no fixed frame indexes during this stage it means there441// are allocas present in the function.442if (MFI.getNumObjects() != MFI.getNumFixedObjects()) {443// Check for the type of allocas present in the function. We only care444// about fixed size allocas so do not give false positives if only445// variable sized allocas are present.446for (unsigned i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) {447// Variable sized objects have size 0.448if (MFI.getObjectSize(i)) {449AFI->setHasAllocas(true);450break;451}452}453}454455// If there are fixed frame indexes present, scan the function to see if456// they are really being used.457if (MFI.getNumFixedObjects() == 0) {458return false;459}460461// Ok fixed frame indexes present, now scan the function to see if they462// are really being used, otherwise we can ignore them.463for (const MachineBasicBlock &BB : MF) {464for (const MachineInstr &MI : BB) {465int Opcode = MI.getOpcode();466467if ((Opcode != AVR::LDDRdPtrQ) && (Opcode != AVR::LDDWRdPtrQ) &&468(Opcode != AVR::STDPtrQRr) && (Opcode != AVR::STDWPtrQRr) &&469(Opcode != AVR::FRMIDX)) {470continue;471}472473for (const MachineOperand &MO : MI.operands()) {474if (!MO.isFI()) {475continue;476}477478if (MFI.isFixedObjectIndex(MO.getIndex())) {479AFI->setHasStackArgs(true);480return false;481}482}483}484}485486return false;487}488489StringRef getPassName() const override { return "AVR Frame Analyzer"; }490};491492char AVRFrameAnalyzer::ID = 0;493494/// Creates instance of the frame analyzer pass.495FunctionPass *createAVRFrameAnalyzerPass() { return new AVRFrameAnalyzer(); }496497} // end of namespace llvm498499500