498 lines · cpp
1//===- ARCFrameLowering.cpp - ARC Frame Information -------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains the ARC implementation of the TargetFrameLowering class.10//11//===----------------------------------------------------------------------===//12 13#include "ARCFrameLowering.h"14#include "ARCMachineFunctionInfo.h"15#include "ARCSubtarget.h"16#include "llvm/CodeGen/MachineInstrBuilder.h"17#include "llvm/CodeGen/MachineModuleInfo.h"18#include "llvm/CodeGen/RegisterScavenging.h"19#include "llvm/CodeGen/TargetRegisterInfo.h"20#include "llvm/IR/Function.h"21#include "llvm/Support/Debug.h"22 23#define DEBUG_TYPE "arc-frame-lowering"24 25using namespace llvm;26 27static cl::opt<bool>28 UseSaveRestoreFunclet("arc-save-restore-funclet", cl::Hidden,29 cl::desc("Use arc callee save/restore functions"),30 cl::init(true));31 32static const char *store_funclet_name[] = {33 "__st_r13_to_r15", "__st_r13_to_r16", "__st_r13_to_r17", "__st_r13_to_r18",34 "__st_r13_to_r19", "__st_r13_to_r20", "__st_r13_to_r21", "__st_r13_to_r22",35 "__st_r13_to_r23", "__st_r13_to_r24", "__st_r13_to_r25",36};37 38static const char *load_funclet_name[] = {39 "__ld_r13_to_r15", "__ld_r13_to_r16", "__ld_r13_to_r17", "__ld_r13_to_r18",40 "__ld_r13_to_r19", "__ld_r13_to_r20", "__ld_r13_to_r21", "__ld_r13_to_r22",41 "__ld_r13_to_r23", "__ld_r13_to_r24", "__ld_r13_to_r25",42};43 44static void generateStackAdjustment(MachineBasicBlock &MBB,45 MachineBasicBlock::iterator MBBI,46 const ARCInstrInfo &TII, DebugLoc dl,47 int Amount, int StackPtr) {48 unsigned AdjOp;49 if (!Amount)50 return;51 bool Positive;52 unsigned AbsAmount;53 if (Amount < 0) {54 AbsAmount = -Amount;55 Positive = false;56 } else {57 AbsAmount = Amount;58 Positive = true;59 }60 61 LLVM_DEBUG(dbgs() << "Internal: adjust stack by: " << Amount << ","62 << AbsAmount << "\n");63 64 assert((AbsAmount % 4 == 0) && "Stack adjustments must be 4-byte aligned.");65 if (isUInt<6>(AbsAmount))66 AdjOp = Positive ? ARC::ADD_rru6 : ARC::SUB_rru6;67 else if (isInt<12>(AbsAmount))68 AdjOp = Positive ? ARC::ADD_rrs12 : ARC::SUB_rrs12;69 else70 AdjOp = Positive ? ARC::ADD_rrlimm : ARC::SUB_rrlimm;71 72 BuildMI(MBB, MBBI, dl, TII.get(AdjOp), StackPtr)73 .addReg(StackPtr)74 .addImm(AbsAmount);75}76 77static unsigned determineLastCalleeSave(ArrayRef<CalleeSavedInfo> CSI) {78 unsigned Last = 0;79 for (auto Reg : CSI) {80 assert(Reg.getReg() >= ARC::R13 && Reg.getReg() <= ARC::R25 &&81 "Unexpected callee saved reg.");82 if (Reg.getReg() > Last)83 Last = Reg.getReg();84 }85 return Last;86}87 88void ARCFrameLowering::determineCalleeSaves(MachineFunction &MF,89 BitVector &SavedRegs,90 RegScavenger *RS) const {91 LLVM_DEBUG(dbgs() << "Determine Callee Saves: " << MF.getName() << "\n");92 TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);93 SavedRegs.set(ARC::BLINK);94}95 96void ARCFrameLowering::adjustStackToMatchRecords(97 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,98 bool Allocate) const {99 MachineFunction &MF = *MBB.getParent();100 int ScalarAlloc = MF.getFrameInfo().getStackSize();101 102 if (Allocate) {103 // Allocate by adjusting by the negative of what the record holder tracked104 // it tracked a positive offset in a downward growing stack.105 ScalarAlloc = -ScalarAlloc;106 }107 108 generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), DebugLoc(),109 ScalarAlloc, ARC::SP);110}111 112/// Insert prolog code into the function.113/// For ARC, this inserts a call to a function that puts required callee saved114/// registers onto the stack, when enough callee saved registers are required.115void ARCFrameLowering::emitPrologue(MachineFunction &MF,116 MachineBasicBlock &MBB) const {117 LLVM_DEBUG(dbgs() << "Emit Prologue: " << MF.getName() << "\n");118 auto *AFI = MF.getInfo<ARCFunctionInfo>();119 MCContext &Context = MF.getContext();120 const MCRegisterInfo *MRI = Context.getRegisterInfo();121 const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();122 MachineBasicBlock::iterator MBBI = MBB.begin();123 // Debug location must be unknown since the first debug location is used124 // to determine the end of the prologue.125 DebugLoc dl;126 MachineFrameInfo &MFI = MF.getFrameInfo();127 const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();128 unsigned Last = determineLastCalleeSave(CSI);129 unsigned StackSlotsUsedByFunclet = 0;130 bool SavedBlink = false;131 unsigned AlreadyAdjusted = 0;132 if (MF.getFunction().isVarArg()) {133 // Add in the varargs area here first.134 LLVM_DEBUG(dbgs() << "Varargs\n");135 unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex());136 unsigned Opc = ARC::SUB_rrlimm;137 if (isUInt<6>(VarArgsBytes))138 Opc = ARC::SUB_rru6;139 else if (isInt<12>(VarArgsBytes))140 Opc = ARC::SUB_rrs12;141 BuildMI(MBB, MBBI, dl, TII->get(Opc), ARC::SP)142 .addReg(ARC::SP)143 .addImm(VarArgsBytes);144 }145 if (hasFP(MF)) {146 LLVM_DEBUG(dbgs() << "Saving FP\n");147 BuildMI(MBB, MBBI, dl, TII->get(ARC::ST_AW_rs9))148 .addReg(ARC::SP, RegState::Define)149 .addReg(ARC::FP)150 .addReg(ARC::SP)151 .addImm(-4);152 AlreadyAdjusted += 4;153 }154 if (UseSaveRestoreFunclet && Last > ARC::R14) {155 LLVM_DEBUG(dbgs() << "Creating store funclet.\n");156 // BL to __save_r13_to_<TRI->getRegAsmName()>157 StackSlotsUsedByFunclet = Last - ARC::R12;158 BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK));159 BuildMI(MBB, MBBI, dl, TII->get(ARC::SUB_rru6))160 .addReg(ARC::SP)161 .addReg(ARC::SP)162 .addImm(4 * StackSlotsUsedByFunclet);163 BuildMI(MBB, MBBI, dl, TII->get(ARC::BL))164 .addExternalSymbol(store_funclet_name[Last - ARC::R15])165 .addReg(ARC::BLINK, RegState::Implicit | RegState::Kill);166 AlreadyAdjusted += 4 * (StackSlotsUsedByFunclet + 1);167 SavedBlink = true;168 }169 // If we haven't saved BLINK, but we need to...do that now.170 if (MFI.hasCalls() && !SavedBlink) {171 LLVM_DEBUG(dbgs() << "Creating save blink.\n");172 BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK));173 AlreadyAdjusted += 4;174 }175 if (AFI->MaxCallStackReq > 0)176 MFI.setStackSize(MFI.getStackSize() + AFI->MaxCallStackReq);177 // We have already saved some of the stack...178 LLVM_DEBUG(dbgs() << "Adjusting stack by: "179 << (MFI.getStackSize() - AlreadyAdjusted) << "\n");180 generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), dl,181 -(MFI.getStackSize() - AlreadyAdjusted), ARC::SP);182 183 if (hasFP(MF)) {184 LLVM_DEBUG(dbgs() << "Setting FP from SP.\n");185 BuildMI(MBB, MBBI, dl,186 TII->get(isUInt<6>(MFI.getStackSize()) ? ARC::ADD_rru6187 : ARC::ADD_rrlimm),188 ARC::FP)189 .addReg(ARC::SP)190 .addImm(MFI.getStackSize());191 }192 193 // Emit CFI records:194 // .cfi_def_cfa_offset StackSize195 // .cfi_offset fp, -StackSize196 // .cfi_offset blink, -StackSize+4197 unsigned CFIIndex = MF.addFrameInst(198 MCCFIInstruction::cfiDefCfaOffset(nullptr, MFI.getStackSize()));199 BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))200 .addCFIIndex(CFIIndex)201 .setMIFlags(MachineInstr::FrameSetup);202 203 int CurOffset = -4;204 if (hasFP(MF)) {205 CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(206 nullptr, MRI->getDwarfRegNum(ARC::FP, true), CurOffset));207 BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))208 .addCFIIndex(CFIIndex)209 .setMIFlags(MachineInstr::FrameSetup);210 CurOffset -= 4;211 }212 213 if (MFI.hasCalls()) {214 CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(215 nullptr, MRI->getDwarfRegNum(ARC::BLINK, true), CurOffset));216 BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))217 .addCFIIndex(CFIIndex)218 .setMIFlags(MachineInstr::FrameSetup);219 }220 // CFI for the rest of the registers.221 for (const auto &Entry : CSI) {222 MCRegister Reg = Entry.getReg();223 int FI = Entry.getFrameIdx();224 // Skip BLINK and FP.225 if ((hasFP(MF) && Reg == ARC::FP) || (MFI.hasCalls() && Reg == ARC::BLINK))226 continue;227 CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(228 nullptr, MRI->getDwarfRegNum(Reg, true), MFI.getObjectOffset(FI)));229 BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))230 .addCFIIndex(CFIIndex)231 .setMIFlags(MachineInstr::FrameSetup);232 }233}234 235/// Insert epilog code into the function.236/// For ARC, this inserts a call to a function that restores callee saved237/// registers onto the stack, when enough callee saved registers are required.238void ARCFrameLowering::emitEpilogue(MachineFunction &MF,239 MachineBasicBlock &MBB) const {240 LLVM_DEBUG(dbgs() << "Emit Epilogue: " << MF.getName() << "\n");241 auto *AFI = MF.getInfo<ARCFunctionInfo>();242 const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();243 MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();244 MachineFrameInfo &MFI = MF.getFrameInfo();245 uint64_t StackSize = MF.getFrameInfo().getStackSize();246 bool SavedBlink = false;247 unsigned AmountAboveFunclet = 0;248 // If we have variable sized frame objects, then we have to move249 // the stack pointer to a known spot (fp - StackSize).250 // Then, replace the frame pointer by (new) [sp,StackSize-4].251 // Then, move the stack pointer the rest of the way (sp = sp + StackSize).252 if (hasFP(MF)) {253 unsigned Opc = ARC::SUB_rrlimm;254 if (isUInt<6>(StackSize))255 Opc = ARC::SUB_rru6;256 BuildMI(MBB, MBBI, DebugLoc(), TII->get(Opc), ARC::SP)257 .addReg(ARC::FP)258 .addImm(StackSize);259 AmountAboveFunclet += 4;260 }261 262 // Now, move the stack pointer to the bottom of the save area for the funclet.263 const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();264 unsigned Last = determineLastCalleeSave(CSI);265 unsigned StackSlotsUsedByFunclet = 0;266 // Now, restore the callee save registers.267 if (UseSaveRestoreFunclet && Last > ARC::R14) {268 // BL to __ld_r13_to_<TRI->getRegAsmName()>269 StackSlotsUsedByFunclet = Last - ARC::R12;270 AmountAboveFunclet += 4 * (StackSlotsUsedByFunclet + 1);271 SavedBlink = true;272 }273 274 if (MFI.hasCalls() && !SavedBlink) {275 AmountAboveFunclet += 4;276 SavedBlink = true;277 }278 279 // Move the stack pointer up to the point of the funclet.280 if (unsigned MoveAmount = StackSize - AmountAboveFunclet) {281 unsigned Opc = ARC::ADD_rrlimm;282 if (isUInt<6>(MoveAmount))283 Opc = ARC::ADD_rru6;284 else if (isInt<12>(MoveAmount))285 Opc = ARC::ADD_rrs12;286 BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc), ARC::SP)287 .addReg(ARC::SP)288 .addImm(StackSize - AmountAboveFunclet);289 }290 291 if (StackSlotsUsedByFunclet) {292 // This part of the adjustment will always be < 64 bytes.293 BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::BL))294 .addExternalSymbol(load_funclet_name[Last - ARC::R15])295 .addReg(ARC::BLINK, RegState::Implicit | RegState::Kill);296 unsigned Opc = ARC::ADD_rrlimm;297 if (isUInt<6>(4 * StackSlotsUsedByFunclet))298 Opc = ARC::ADD_rru6;299 else if (isInt<12>(4 * StackSlotsUsedByFunclet))300 Opc = ARC::ADD_rrs12;301 BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc), ARC::SP)302 .addReg(ARC::SP)303 .addImm(4 * (StackSlotsUsedByFunclet));304 }305 // Now, pop blink if necessary.306 if (SavedBlink) {307 BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::POP_S_BLINK));308 }309 // Now, pop fp if necessary.310 if (hasFP(MF)) {311 BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::LD_AB_rs9))312 .addReg(ARC::FP, RegState::Define)313 .addReg(ARC::SP, RegState::Define)314 .addReg(ARC::SP)315 .addImm(4);316 }317 318 // Relieve the varargs area if necessary.319 if (MF.getFunction().isVarArg()) {320 // Add in the varargs area here first.321 LLVM_DEBUG(dbgs() << "Varargs\n");322 unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex());323 unsigned Opc = ARC::ADD_rrlimm;324 if (isUInt<6>(VarArgsBytes))325 Opc = ARC::ADD_rru6;326 else if (isInt<12>(VarArgsBytes))327 Opc = ARC::ADD_rrs12;328 BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc))329 .addReg(ARC::SP)330 .addReg(ARC::SP)331 .addImm(VarArgsBytes);332 }333}334 335static std::vector<CalleeSavedInfo>::iterator336getSavedReg(std::vector<CalleeSavedInfo> &V, unsigned reg) {337 for (auto I = V.begin(), E = V.end(); I != E; ++I) {338 if (reg == I->getReg())339 return I;340 }341 return V.end();342}343 344bool ARCFrameLowering::assignCalleeSavedSpillSlots(345 MachineFunction &MF, const TargetRegisterInfo *TRI,346 std::vector<CalleeSavedInfo> &CSI) const {347 // Use this opportunity to assign the spill slots for all of the potential348 // callee save registers (blink, fp, r13->r25) that we care about the349 // placement for. We can calculate all of that data here.350 int CurOffset = -4;351 unsigned Last = determineLastCalleeSave(CSI);352 MachineFrameInfo &MFI = MF.getFrameInfo();353 if (hasFP(MF)) {354 // Create a fixed slot at for FP355 int StackObj = MFI.CreateFixedSpillStackObject(4, CurOffset, true);356 LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj << ") for FP at "357 << CurOffset << "\n");358 (void)StackObj;359 CurOffset -= 4;360 }361 if (MFI.hasCalls() || (UseSaveRestoreFunclet && Last > ARC::R14)) {362 // Create a fixed slot for BLINK.363 int StackObj = MFI.CreateFixedSpillStackObject(4, CurOffset, true);364 LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj365 << ") for BLINK at " << CurOffset << "\n");366 (void)StackObj;367 CurOffset -= 4;368 }369 370 // Create slots for last down to r13.371 for (unsigned Which = Last; Which > ARC::R12; Which--) {372 auto RegI = getSavedReg(CSI, Which);373 if (RegI == CSI.end() || RegI->getFrameIdx() == 0) {374 // Always create the stack slot. If for some reason the register isn't in375 // the save list, then don't worry about it.376 int FI = MFI.CreateFixedSpillStackObject(4, CurOffset, true);377 if (RegI != CSI.end())378 RegI->setFrameIdx(FI);379 } else380 MFI.setObjectOffset(RegI->getFrameIdx(), CurOffset);381 CurOffset -= 4;382 }383 for (auto &I : CSI) {384 if (I.getReg() > ARC::R12)385 continue;386 if (I.getFrameIdx() == 0) {387 I.setFrameIdx(MFI.CreateFixedSpillStackObject(4, CurOffset, true));388 LLVM_DEBUG(dbgs() << "Creating fixed object (" << I.getFrameIdx()389 << ") for other register at " << CurOffset << "\n");390 } else {391 MFI.setObjectOffset(I.getFrameIdx(), CurOffset);392 LLVM_DEBUG(dbgs() << "Updating fixed object (" << I.getFrameIdx()393 << ") for other register at " << CurOffset << "\n");394 }395 CurOffset -= 4;396 }397 return true;398}399 400bool ARCFrameLowering::spillCalleeSavedRegisters(401 MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,402 ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {403 LLVM_DEBUG(dbgs() << "Spill callee saved registers: "404 << MBB.getParent()->getName() << "\n");405 // There are routines for saving at least 3 registers (r13 to r15, etc.)406 unsigned Last = determineLastCalleeSave(CSI);407 if (UseSaveRestoreFunclet && Last > ARC::R14) {408 // Use setObjectOffset for these registers.409 // Needs to be in or before processFunctionBeforeFrameFinalized.410 // Or, do assignCalleeSaveSpillSlots?411 // Will be handled in prolog.412 return true;413 }414 return false;415}416 417bool ARCFrameLowering::restoreCalleeSavedRegisters(418 MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,419 MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {420 LLVM_DEBUG(dbgs() << "Restore callee saved registers: "421 << MBB.getParent()->getName() << "\n");422 // There are routines for saving at least 3 registers (r13 to r15, etc.)423 unsigned Last = determineLastCalleeSave(CSI);424 if (UseSaveRestoreFunclet && Last > ARC::R14) {425 // Will be handled in epilog.426 return true;427 }428 return false;429}430 431// Adjust local variables that are 4-bytes or larger to 4-byte boundary432void ARCFrameLowering::processFunctionBeforeFrameFinalized(433 MachineFunction &MF, RegScavenger *RS) const {434 const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();435 LLVM_DEBUG(dbgs() << "Process function before frame finalized: "436 << MF.getName() << "\n");437 MachineFrameInfo &MFI = MF.getFrameInfo();438 LLVM_DEBUG(dbgs() << "Current stack size: " << MFI.getStackSize() << "\n");439 const TargetRegisterClass *RC = &ARC::GPR32RegClass;440 if (MFI.hasStackObjects()) {441 int RegScavFI = MFI.CreateSpillStackObject(RegInfo->getSpillSize(*RC),442 RegInfo->getSpillAlign(*RC));443 RS->addScavengingFrameIndex(RegScavFI);444 LLVM_DEBUG(dbgs() << "Created scavenging index RegScavFI=" << RegScavFI445 << "\n");446 }447}448 449static void emitRegUpdate(MachineBasicBlock &MBB,450 MachineBasicBlock::iterator &MBBI, DebugLoc dl,451 unsigned Reg, int NumBytes, bool IsAdd,452 const ARCInstrInfo *TII) {453 unsigned Opc;454 if (isUInt<6>(NumBytes))455 Opc = IsAdd ? ARC::ADD_rru6 : ARC::SUB_rru6;456 else if (isInt<12>(NumBytes))457 Opc = IsAdd ? ARC::ADD_rrs12 : ARC::SUB_rrs12;458 else459 Opc = IsAdd ? ARC::ADD_rrlimm : ARC::SUB_rrlimm;460 461 BuildMI(MBB, MBBI, dl, TII->get(Opc), Reg)462 .addReg(Reg, RegState::Kill)463 .addImm(NumBytes);464}465 466MachineBasicBlock::iterator ARCFrameLowering::eliminateCallFramePseudoInstr(467 MachineFunction &MF, MachineBasicBlock &MBB,468 MachineBasicBlock::iterator I) const {469 LLVM_DEBUG(dbgs() << "EmitCallFramePseudo: " << MF.getName() << "\n");470 const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();471 MachineInstr &Old = *I;472 DebugLoc dl = Old.getDebugLoc();473 unsigned Amt = Old.getOperand(0).getImm();474 auto *AFI = MF.getInfo<ARCFunctionInfo>();475 if (!hasFP(MF)) {476 if (Amt > AFI->MaxCallStackReq && Old.getOpcode() == ARC::ADJCALLSTACKDOWN)477 AFI->MaxCallStackReq = Amt;478 } else {479 if (Amt != 0) {480 assert((Old.getOpcode() == ARC::ADJCALLSTACKDOWN ||481 Old.getOpcode() == ARC::ADJCALLSTACKUP) &&482 "Unknown Frame Pseudo.");483 bool IsAdd = (Old.getOpcode() == ARC::ADJCALLSTACKUP);484 emitRegUpdate(MBB, I, dl, ARC::SP, Amt, IsAdd, TII);485 }486 }487 return MBB.erase(I);488}489 490bool ARCFrameLowering::hasFPImpl(const MachineFunction &MF) const {491 const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();492 bool HasFP = MF.getTarget().Options.DisableFramePointerElim(MF) ||493 MF.getFrameInfo().hasVarSizedObjects() ||494 MF.getFrameInfo().isFrameAddressTaken() ||495 RegInfo->hasStackRealignment(MF);496 return HasFP;497}498