Path: blob/main/contrib/llvm-project/llvm/lib/Target/ARC/ARCFrameLowering.cpp
35266 views
//===- ARCFrameLowering.cpp - ARC Frame Information -------------*- C++ -*-===//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 ARC implementation of the TargetFrameLowering class.9//10//===----------------------------------------------------------------------===//1112#include "ARCFrameLowering.h"13#include "ARCMachineFunctionInfo.h"14#include "ARCSubtarget.h"15#include "llvm/CodeGen/MachineInstrBuilder.h"16#include "llvm/CodeGen/MachineModuleInfo.h"17#include "llvm/CodeGen/RegisterScavenging.h"18#include "llvm/CodeGen/TargetRegisterInfo.h"19#include "llvm/IR/Function.h"20#include "llvm/Support/Debug.h"2122#define DEBUG_TYPE "arc-frame-lowering"2324using namespace llvm;2526static cl::opt<bool>27UseSaveRestoreFunclet("arc-save-restore-funclet", cl::Hidden,28cl::desc("Use arc callee save/restore functions"),29cl::init(true));3031static const char *store_funclet_name[] = {32"__st_r13_to_r15", "__st_r13_to_r16", "__st_r13_to_r17", "__st_r13_to_r18",33"__st_r13_to_r19", "__st_r13_to_r20", "__st_r13_to_r21", "__st_r13_to_r22",34"__st_r13_to_r23", "__st_r13_to_r24", "__st_r13_to_r25",35};3637static const char *load_funclet_name[] = {38"__ld_r13_to_r15", "__ld_r13_to_r16", "__ld_r13_to_r17", "__ld_r13_to_r18",39"__ld_r13_to_r19", "__ld_r13_to_r20", "__ld_r13_to_r21", "__ld_r13_to_r22",40"__ld_r13_to_r23", "__ld_r13_to_r24", "__ld_r13_to_r25",41};4243static void generateStackAdjustment(MachineBasicBlock &MBB,44MachineBasicBlock::iterator MBBI,45const ARCInstrInfo &TII, DebugLoc dl,46int Amount, int StackPtr) {47unsigned AdjOp;48if (!Amount)49return;50bool Positive;51unsigned AbsAmount;52if (Amount < 0) {53AbsAmount = -Amount;54Positive = false;55} else {56AbsAmount = Amount;57Positive = true;58}5960LLVM_DEBUG(dbgs() << "Internal: adjust stack by: " << Amount << ","61<< AbsAmount << "\n");6263assert((AbsAmount % 4 == 0) && "Stack adjustments must be 4-byte aligned.");64if (isUInt<6>(AbsAmount))65AdjOp = Positive ? ARC::ADD_rru6 : ARC::SUB_rru6;66else if (isInt<12>(AbsAmount))67AdjOp = Positive ? ARC::ADD_rrs12 : ARC::SUB_rrs12;68else69AdjOp = Positive ? ARC::ADD_rrlimm : ARC::SUB_rrlimm;7071BuildMI(MBB, MBBI, dl, TII.get(AdjOp), StackPtr)72.addReg(StackPtr)73.addImm(AbsAmount);74}7576static unsigned determineLastCalleeSave(ArrayRef<CalleeSavedInfo> CSI) {77unsigned Last = 0;78for (auto Reg : CSI) {79assert(Reg.getReg() >= ARC::R13 && Reg.getReg() <= ARC::R25 &&80"Unexpected callee saved reg.");81if (Reg.getReg() > Last)82Last = Reg.getReg();83}84return Last;85}8687void ARCFrameLowering::determineCalleeSaves(MachineFunction &MF,88BitVector &SavedRegs,89RegScavenger *RS) const {90LLVM_DEBUG(dbgs() << "Determine Callee Saves: " << MF.getName() << "\n");91TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);92SavedRegs.set(ARC::BLINK);93}9495void ARCFrameLowering::adjustStackToMatchRecords(96MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,97bool Allocate) const {98MachineFunction &MF = *MBB.getParent();99int ScalarAlloc = MF.getFrameInfo().getStackSize();100101if (Allocate) {102// Allocate by adjusting by the negative of what the record holder tracked103// it tracked a positive offset in a downward growing stack.104ScalarAlloc = -ScalarAlloc;105}106107generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), DebugLoc(),108ScalarAlloc, ARC::SP);109}110111/// Insert prolog code into the function.112/// For ARC, this inserts a call to a function that puts required callee saved113/// registers onto the stack, when enough callee saved registers are required.114void ARCFrameLowering::emitPrologue(MachineFunction &MF,115MachineBasicBlock &MBB) const {116LLVM_DEBUG(dbgs() << "Emit Prologue: " << MF.getName() << "\n");117auto *AFI = MF.getInfo<ARCFunctionInfo>();118MCContext &Context = MF.getContext();119const MCRegisterInfo *MRI = Context.getRegisterInfo();120const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();121MachineBasicBlock::iterator MBBI = MBB.begin();122// Debug location must be unknown since the first debug location is used123// to determine the end of the prologue.124DebugLoc dl;125MachineFrameInfo &MFI = MF.getFrameInfo();126const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();127unsigned Last = determineLastCalleeSave(CSI);128unsigned StackSlotsUsedByFunclet = 0;129bool SavedBlink = false;130unsigned AlreadyAdjusted = 0;131if (MF.getFunction().isVarArg()) {132// Add in the varargs area here first.133LLVM_DEBUG(dbgs() << "Varargs\n");134unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex());135unsigned Opc = ARC::SUB_rrlimm;136if (isUInt<6>(VarArgsBytes))137Opc = ARC::SUB_rru6;138else if (isInt<12>(VarArgsBytes))139Opc = ARC::SUB_rrs12;140BuildMI(MBB, MBBI, dl, TII->get(Opc), ARC::SP)141.addReg(ARC::SP)142.addImm(VarArgsBytes);143}144if (hasFP(MF)) {145LLVM_DEBUG(dbgs() << "Saving FP\n");146BuildMI(MBB, MBBI, dl, TII->get(ARC::ST_AW_rs9))147.addReg(ARC::SP, RegState::Define)148.addReg(ARC::FP)149.addReg(ARC::SP)150.addImm(-4);151AlreadyAdjusted += 4;152}153if (UseSaveRestoreFunclet && Last > ARC::R14) {154LLVM_DEBUG(dbgs() << "Creating store funclet.\n");155// BL to __save_r13_to_<TRI->getRegAsmName()>156StackSlotsUsedByFunclet = Last - ARC::R12;157BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK));158BuildMI(MBB, MBBI, dl, TII->get(ARC::SUB_rru6))159.addReg(ARC::SP)160.addReg(ARC::SP)161.addImm(4 * StackSlotsUsedByFunclet);162BuildMI(MBB, MBBI, dl, TII->get(ARC::BL))163.addExternalSymbol(store_funclet_name[Last - ARC::R15])164.addReg(ARC::BLINK, RegState::Implicit | RegState::Kill);165AlreadyAdjusted += 4 * (StackSlotsUsedByFunclet + 1);166SavedBlink = true;167}168// If we haven't saved BLINK, but we need to...do that now.169if (MFI.hasCalls() && !SavedBlink) {170LLVM_DEBUG(dbgs() << "Creating save blink.\n");171BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK));172AlreadyAdjusted += 4;173}174if (AFI->MaxCallStackReq > 0)175MFI.setStackSize(MFI.getStackSize() + AFI->MaxCallStackReq);176// We have already saved some of the stack...177LLVM_DEBUG(dbgs() << "Adjusting stack by: "178<< (MFI.getStackSize() - AlreadyAdjusted) << "\n");179generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), dl,180-(MFI.getStackSize() - AlreadyAdjusted), ARC::SP);181182if (hasFP(MF)) {183LLVM_DEBUG(dbgs() << "Setting FP from SP.\n");184BuildMI(MBB, MBBI, dl,185TII->get(isUInt<6>(MFI.getStackSize()) ? ARC::ADD_rru6186: ARC::ADD_rrlimm),187ARC::FP)188.addReg(ARC::SP)189.addImm(MFI.getStackSize());190}191192// Emit CFI records:193// .cfi_def_cfa_offset StackSize194// .cfi_offset fp, -StackSize195// .cfi_offset blink, -StackSize+4196unsigned CFIIndex = MF.addFrameInst(197MCCFIInstruction::cfiDefCfaOffset(nullptr, MFI.getStackSize()));198BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))199.addCFIIndex(CFIIndex)200.setMIFlags(MachineInstr::FrameSetup);201202int CurOffset = -4;203if (hasFP(MF)) {204CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(205nullptr, MRI->getDwarfRegNum(ARC::FP, true), CurOffset));206BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))207.addCFIIndex(CFIIndex)208.setMIFlags(MachineInstr::FrameSetup);209CurOffset -= 4;210}211212if (MFI.hasCalls()) {213CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(214nullptr, MRI->getDwarfRegNum(ARC::BLINK, true), CurOffset));215BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))216.addCFIIndex(CFIIndex)217.setMIFlags(MachineInstr::FrameSetup);218}219// CFI for the rest of the registers.220for (const auto &Entry : CSI) {221unsigned Reg = Entry.getReg();222int FI = Entry.getFrameIdx();223// Skip BLINK and FP.224if ((hasFP(MF) && Reg == ARC::FP) || (MFI.hasCalls() && Reg == ARC::BLINK))225continue;226CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(227nullptr, MRI->getDwarfRegNum(Reg, true), MFI.getObjectOffset(FI)));228BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))229.addCFIIndex(CFIIndex)230.setMIFlags(MachineInstr::FrameSetup);231}232}233234/// Insert epilog code into the function.235/// For ARC, this inserts a call to a function that restores callee saved236/// registers onto the stack, when enough callee saved registers are required.237void ARCFrameLowering::emitEpilogue(MachineFunction &MF,238MachineBasicBlock &MBB) const {239LLVM_DEBUG(dbgs() << "Emit Epilogue: " << MF.getName() << "\n");240auto *AFI = MF.getInfo<ARCFunctionInfo>();241const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();242MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();243MachineFrameInfo &MFI = MF.getFrameInfo();244uint64_t StackSize = MF.getFrameInfo().getStackSize();245bool SavedBlink = false;246unsigned AmountAboveFunclet = 0;247// If we have variable sized frame objects, then we have to move248// the stack pointer to a known spot (fp - StackSize).249// Then, replace the frame pointer by (new) [sp,StackSize-4].250// Then, move the stack pointer the rest of the way (sp = sp + StackSize).251if (hasFP(MF)) {252unsigned Opc = ARC::SUB_rrlimm;253if (isUInt<6>(StackSize))254Opc = ARC::SUB_rru6;255BuildMI(MBB, MBBI, DebugLoc(), TII->get(Opc), ARC::SP)256.addReg(ARC::FP)257.addImm(StackSize);258AmountAboveFunclet += 4;259}260261// Now, move the stack pointer to the bottom of the save area for the funclet.262const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();263unsigned Last = determineLastCalleeSave(CSI);264unsigned StackSlotsUsedByFunclet = 0;265// Now, restore the callee save registers.266if (UseSaveRestoreFunclet && Last > ARC::R14) {267// BL to __ld_r13_to_<TRI->getRegAsmName()>268StackSlotsUsedByFunclet = Last - ARC::R12;269AmountAboveFunclet += 4 * (StackSlotsUsedByFunclet + 1);270SavedBlink = true;271}272273if (MFI.hasCalls() && !SavedBlink) {274AmountAboveFunclet += 4;275SavedBlink = true;276}277278// Move the stack pointer up to the point of the funclet.279if (unsigned MoveAmount = StackSize - AmountAboveFunclet) {280unsigned Opc = ARC::ADD_rrlimm;281if (isUInt<6>(MoveAmount))282Opc = ARC::ADD_rru6;283else if (isInt<12>(MoveAmount))284Opc = ARC::ADD_rrs12;285BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc), ARC::SP)286.addReg(ARC::SP)287.addImm(StackSize - AmountAboveFunclet);288}289290if (StackSlotsUsedByFunclet) {291// This part of the adjustment will always be < 64 bytes.292BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::BL))293.addExternalSymbol(load_funclet_name[Last - ARC::R15])294.addReg(ARC::BLINK, RegState::Implicit | RegState::Kill);295unsigned Opc = ARC::ADD_rrlimm;296if (isUInt<6>(4 * StackSlotsUsedByFunclet))297Opc = ARC::ADD_rru6;298else if (isInt<12>(4 * StackSlotsUsedByFunclet))299Opc = ARC::ADD_rrs12;300BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc), ARC::SP)301.addReg(ARC::SP)302.addImm(4 * (StackSlotsUsedByFunclet));303}304// Now, pop blink if necessary.305if (SavedBlink) {306BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::POP_S_BLINK));307}308// Now, pop fp if necessary.309if (hasFP(MF)) {310BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::LD_AB_rs9))311.addReg(ARC::FP, RegState::Define)312.addReg(ARC::SP, RegState::Define)313.addReg(ARC::SP)314.addImm(4);315}316317// Relieve the varargs area if necessary.318if (MF.getFunction().isVarArg()) {319// Add in the varargs area here first.320LLVM_DEBUG(dbgs() << "Varargs\n");321unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex());322unsigned Opc = ARC::ADD_rrlimm;323if (isUInt<6>(VarArgsBytes))324Opc = ARC::ADD_rru6;325else if (isInt<12>(VarArgsBytes))326Opc = ARC::ADD_rrs12;327BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc))328.addReg(ARC::SP)329.addReg(ARC::SP)330.addImm(VarArgsBytes);331}332}333334static std::vector<CalleeSavedInfo>::iterator335getSavedReg(std::vector<CalleeSavedInfo> &V, unsigned reg) {336for (auto I = V.begin(), E = V.end(); I != E; ++I) {337if (reg == I->getReg())338return I;339}340return V.end();341}342343bool ARCFrameLowering::assignCalleeSavedSpillSlots(344MachineFunction &MF, const TargetRegisterInfo *TRI,345std::vector<CalleeSavedInfo> &CSI) const {346// Use this opportunity to assign the spill slots for all of the potential347// callee save registers (blink, fp, r13->r25) that we care about the348// placement for. We can calculate all of that data here.349int CurOffset = -4;350unsigned Last = determineLastCalleeSave(CSI);351MachineFrameInfo &MFI = MF.getFrameInfo();352if (hasFP(MF)) {353// Create a fixed slot at for FP354int StackObj = MFI.CreateFixedSpillStackObject(4, CurOffset, true);355LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj << ") for FP at "356<< CurOffset << "\n");357(void)StackObj;358CurOffset -= 4;359}360if (MFI.hasCalls() || (UseSaveRestoreFunclet && Last > ARC::R14)) {361// Create a fixed slot for BLINK.362int StackObj = MFI.CreateFixedSpillStackObject(4, CurOffset, true);363LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj364<< ") for BLINK at " << CurOffset << "\n");365(void)StackObj;366CurOffset -= 4;367}368369// Create slots for last down to r13.370for (unsigned Which = Last; Which > ARC::R12; Which--) {371auto RegI = getSavedReg(CSI, Which);372if (RegI == CSI.end() || RegI->getFrameIdx() == 0) {373// Always create the stack slot. If for some reason the register isn't in374// the save list, then don't worry about it.375int FI = MFI.CreateFixedSpillStackObject(4, CurOffset, true);376if (RegI != CSI.end())377RegI->setFrameIdx(FI);378} else379MFI.setObjectOffset(RegI->getFrameIdx(), CurOffset);380CurOffset -= 4;381}382for (auto &I : CSI) {383if (I.getReg() > ARC::R12)384continue;385if (I.getFrameIdx() == 0) {386I.setFrameIdx(MFI.CreateFixedSpillStackObject(4, CurOffset, true));387LLVM_DEBUG(dbgs() << "Creating fixed object (" << I.getFrameIdx()388<< ") for other register at " << CurOffset << "\n");389} else {390MFI.setObjectOffset(I.getFrameIdx(), CurOffset);391LLVM_DEBUG(dbgs() << "Updating fixed object (" << I.getFrameIdx()392<< ") for other register at " << CurOffset << "\n");393}394CurOffset -= 4;395}396return true;397}398399bool ARCFrameLowering::spillCalleeSavedRegisters(400MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,401ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {402LLVM_DEBUG(dbgs() << "Spill callee saved registers: "403<< MBB.getParent()->getName() << "\n");404// There are routines for saving at least 3 registers (r13 to r15, etc.)405unsigned Last = determineLastCalleeSave(CSI);406if (UseSaveRestoreFunclet && Last > ARC::R14) {407// Use setObjectOffset for these registers.408// Needs to be in or before processFunctionBeforeFrameFinalized.409// Or, do assignCalleeSaveSpillSlots?410// Will be handled in prolog.411return true;412}413return false;414}415416bool ARCFrameLowering::restoreCalleeSavedRegisters(417MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,418MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {419LLVM_DEBUG(dbgs() << "Restore callee saved registers: "420<< MBB.getParent()->getName() << "\n");421// There are routines for saving at least 3 registers (r13 to r15, etc.)422unsigned Last = determineLastCalleeSave(CSI);423if (UseSaveRestoreFunclet && Last > ARC::R14) {424// Will be handled in epilog.425return true;426}427return false;428}429430// Adjust local variables that are 4-bytes or larger to 4-byte boundary431void ARCFrameLowering::processFunctionBeforeFrameFinalized(432MachineFunction &MF, RegScavenger *RS) const {433const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();434LLVM_DEBUG(dbgs() << "Process function before frame finalized: "435<< MF.getName() << "\n");436MachineFrameInfo &MFI = MF.getFrameInfo();437LLVM_DEBUG(dbgs() << "Current stack size: " << MFI.getStackSize() << "\n");438const TargetRegisterClass *RC = &ARC::GPR32RegClass;439if (MFI.hasStackObjects()) {440int RegScavFI = MFI.CreateStackObject(RegInfo->getSpillSize(*RC),441RegInfo->getSpillAlign(*RC), false);442RS->addScavengingFrameIndex(RegScavFI);443LLVM_DEBUG(dbgs() << "Created scavenging index RegScavFI=" << RegScavFI444<< "\n");445}446}447448static void emitRegUpdate(MachineBasicBlock &MBB,449MachineBasicBlock::iterator &MBBI, DebugLoc dl,450unsigned Reg, int NumBytes, bool IsAdd,451const ARCInstrInfo *TII) {452unsigned Opc;453if (isUInt<6>(NumBytes))454Opc = IsAdd ? ARC::ADD_rru6 : ARC::SUB_rru6;455else if (isInt<12>(NumBytes))456Opc = IsAdd ? ARC::ADD_rrs12 : ARC::SUB_rrs12;457else458Opc = IsAdd ? ARC::ADD_rrlimm : ARC::SUB_rrlimm;459460BuildMI(MBB, MBBI, dl, TII->get(Opc), Reg)461.addReg(Reg, RegState::Kill)462.addImm(NumBytes);463}464465MachineBasicBlock::iterator ARCFrameLowering::eliminateCallFramePseudoInstr(466MachineFunction &MF, MachineBasicBlock &MBB,467MachineBasicBlock::iterator I) const {468LLVM_DEBUG(dbgs() << "EmitCallFramePseudo: " << MF.getName() << "\n");469const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();470MachineInstr &Old = *I;471DebugLoc dl = Old.getDebugLoc();472unsigned Amt = Old.getOperand(0).getImm();473auto *AFI = MF.getInfo<ARCFunctionInfo>();474if (!hasFP(MF)) {475if (Amt > AFI->MaxCallStackReq && Old.getOpcode() == ARC::ADJCALLSTACKDOWN)476AFI->MaxCallStackReq = Amt;477} else {478if (Amt != 0) {479assert((Old.getOpcode() == ARC::ADJCALLSTACKDOWN ||480Old.getOpcode() == ARC::ADJCALLSTACKUP) &&481"Unknown Frame Pseudo.");482bool IsAdd = (Old.getOpcode() == ARC::ADJCALLSTACKUP);483emitRegUpdate(MBB, I, dl, ARC::SP, Amt, IsAdd, TII);484}485}486return MBB.erase(I);487}488489bool ARCFrameLowering::hasFP(const MachineFunction &MF) const {490const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();491bool HasFP = MF.getTarget().Options.DisableFramePointerElim(MF) ||492MF.getFrameInfo().hasVarSizedObjects() ||493MF.getFrameInfo().isFrameAddressTaken() ||494RegInfo->hasStackRealignment(MF);495return HasFP;496}497498499