| //===- ARCFrameLowering.cpp - ARC Frame Information -------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file contains the ARC implementation of the TargetFrameLowering class. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "ARCFrameLowering.h" |
| #include "ARCMachineFunctionInfo.h" |
| #include "ARCSubtarget.h" |
| #include "llvm/CodeGen/MachineInstrBuilder.h" |
| #include "llvm/CodeGen/MachineModuleInfo.h" |
| #include "llvm/CodeGen/RegisterScavenging.h" |
| #include "llvm/CodeGen/TargetRegisterInfo.h" |
| #include "llvm/IR/Function.h" |
| #include "llvm/Support/Debug.h" |
| |
| #define DEBUG_TYPE "arc-frame-lowering" |
| |
| using namespace llvm; |
| |
| static cl::opt<bool> |
| UseSaveRestoreFunclet("arc-save-restore-funclet", cl::Hidden, |
| cl::desc("Use arc callee save/restore functions"), |
| cl::init(true)); |
| |
| static const char *store_funclet_name[] = { |
| "__st_r13_to_r15", "__st_r13_to_r16", "__st_r13_to_r17", "__st_r13_to_r18", |
| "__st_r13_to_r19", "__st_r13_to_r20", "__st_r13_to_r21", "__st_r13_to_r22", |
| "__st_r13_to_r23", "__st_r13_to_r24", "__st_r13_to_r25", |
| }; |
| |
| static const char *load_funclet_name[] = { |
| "__ld_r13_to_r15", "__ld_r13_to_r16", "__ld_r13_to_r17", "__ld_r13_to_r18", |
| "__ld_r13_to_r19", "__ld_r13_to_r20", "__ld_r13_to_r21", "__ld_r13_to_r22", |
| "__ld_r13_to_r23", "__ld_r13_to_r24", "__ld_r13_to_r25", |
| }; |
| |
| static void generateStackAdjustment(MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator MBBI, |
| const ARCInstrInfo &TII, DebugLoc dl, |
| int Amount, int StackPtr) { |
| unsigned AdjOp; |
| if (!Amount) |
| return; |
| bool Positive; |
| unsigned AbsAmount; |
| if (Amount < 0) { |
| AbsAmount = -Amount; |
| Positive = false; |
| } else { |
| AbsAmount = Amount; |
| Positive = true; |
| } |
| |
| LLVM_DEBUG(dbgs() << "Internal: adjust stack by: " << Amount << "," |
| << AbsAmount << "\n"); |
| |
| assert((AbsAmount % 4 == 0) && "Stack adjustments must be 4-byte aligned."); |
| if (isUInt<6>(AbsAmount)) |
| AdjOp = Positive ? ARC::ADD_rru6 : ARC::SUB_rru6; |
| else |
| AdjOp = Positive ? ARC::ADD_rrlimm : ARC::SUB_rrlimm; |
| |
| BuildMI(MBB, MBBI, dl, TII.get(AdjOp), StackPtr) |
| .addReg(StackPtr) |
| .addImm(AbsAmount); |
| } |
| |
| static unsigned |
| determineLastCalleeSave(const std::vector<CalleeSavedInfo> &CSI) { |
| unsigned Last = 0; |
| for (auto Reg : CSI) { |
| assert(Reg.getReg() >= ARC::R13 && Reg.getReg() <= ARC::R25 && |
| "Unexpected callee saved reg."); |
| if (Reg.getReg() > Last) |
| Last = Reg.getReg(); |
| } |
| return Last; |
| } |
| |
| void ARCFrameLowering::determineCalleeSaves(MachineFunction &MF, |
| BitVector &SavedRegs, |
| RegScavenger *RS) const { |
| LLVM_DEBUG(dbgs() << "Determine Callee Saves: " << MF.getName() << "\n"); |
| TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); |
| SavedRegs.set(ARC::BLINK); |
| } |
| |
| void ARCFrameLowering::adjustStackToMatchRecords( |
| MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
| bool Allocate) const { |
| MachineFunction &MF = *MBB.getParent(); |
| int ScalarAlloc = MF.getFrameInfo().getStackSize(); |
| |
| if (Allocate) { |
| // Allocate by adjusting by the negative of what the record holder tracked |
| // it tracked a positive offset in a downward growing stack. |
| ScalarAlloc = -ScalarAlloc; |
| } |
| |
| generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), DebugLoc(), |
| ScalarAlloc, ARC::SP); |
| } |
| |
| /// Insert prolog code into the function. |
| /// For ARC, this inserts a call to a function that puts required callee saved |
| /// registers onto the stack, when enough callee saved registers are required. |
| void ARCFrameLowering::emitPrologue(MachineFunction &MF, |
| MachineBasicBlock &MBB) const { |
| LLVM_DEBUG(dbgs() << "Emit Prologue: " << MF.getName() << "\n"); |
| auto *AFI = MF.getInfo<ARCFunctionInfo>(); |
| MachineModuleInfo &MMI = MF.getMMI(); |
| MCContext &Context = MMI.getContext(); |
| const MCRegisterInfo *MRI = Context.getRegisterInfo(); |
| const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo(); |
| MachineBasicBlock::iterator MBBI = MBB.begin(); |
| // Debug location must be unknown since the first debug location is used |
| // to determine the end of the prologue. |
| DebugLoc dl; |
| MachineFrameInfo &MFI = MF.getFrameInfo(); |
| const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); |
| unsigned Last = determineLastCalleeSave(CSI); |
| unsigned StackSlotsUsedByFunclet = 0; |
| bool SavedBlink = false; |
| unsigned AlreadyAdjusted = 0; |
| if (MF.getFunction().isVarArg()) { |
| // Add in the varargs area here first. |
| LLVM_DEBUG(dbgs() << "Varargs\n"); |
| unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex()); |
| BuildMI(MBB, MBBI, dl, TII->get(ARC::SUB_rru6)) |
| .addReg(ARC::SP) |
| .addReg(ARC::SP) |
| .addImm(VarArgsBytes); |
| } |
| if (hasFP(MF)) { |
| LLVM_DEBUG(dbgs() << "Saving FP\n"); |
| BuildMI(MBB, MBBI, dl, TII->get(ARC::ST_AW_rs9)) |
| .addReg(ARC::SP, RegState::Define) |
| .addReg(ARC::FP) |
| .addReg(ARC::SP) |
| .addImm(-4); |
| AlreadyAdjusted += 4; |
| } |
| if (UseSaveRestoreFunclet && Last > ARC::R14) { |
| LLVM_DEBUG(dbgs() << "Creating store funclet.\n"); |
| // BL to __save_r13_to_<TRI->getRegAsmName()> |
| StackSlotsUsedByFunclet = Last - ARC::R12; |
| BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK)); |
| BuildMI(MBB, MBBI, dl, TII->get(ARC::SUB_rru6)) |
| .addReg(ARC::SP) |
| .addReg(ARC::SP) |
| .addImm(4 * StackSlotsUsedByFunclet); |
| BuildMI(MBB, MBBI, dl, TII->get(ARC::BL)) |
| .addExternalSymbol(store_funclet_name[Last - ARC::R15]) |
| .addReg(ARC::BLINK, RegState::Implicit | RegState::Kill); |
| AlreadyAdjusted += 4 * (StackSlotsUsedByFunclet + 1); |
| SavedBlink = true; |
| } |
| // If we haven't saved BLINK, but we need to...do that now. |
| if (MFI.hasCalls() && !SavedBlink) { |
| LLVM_DEBUG(dbgs() << "Creating save blink.\n"); |
| BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK)); |
| AlreadyAdjusted += 4; |
| } |
| if (AFI->MaxCallStackReq > 0) |
| MFI.setStackSize(MFI.getStackSize() + AFI->MaxCallStackReq); |
| // We have already saved some of the stack... |
| LLVM_DEBUG(dbgs() << "Adjusting stack by: " |
| << (MFI.getStackSize() - AlreadyAdjusted) << "\n"); |
| generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), dl, |
| -(MFI.getStackSize() - AlreadyAdjusted), ARC::SP); |
| |
| if (hasFP(MF)) { |
| LLVM_DEBUG(dbgs() << "Setting FP from SP.\n"); |
| BuildMI(MBB, MBBI, dl, |
| TII->get(isUInt<6>(MFI.getStackSize()) ? ARC::ADD_rru6 |
| : ARC::ADD_rrlimm), |
| ARC::FP) |
| .addReg(ARC::SP) |
| .addImm(MFI.getStackSize()); |
| } |
| |
| // Emit CFI records: |
| // .cfi_def_cfa_offset StackSize |
| // .cfi_offset fp, -StackSize |
| // .cfi_offset blink, -StackSize+4 |
| unsigned CFIIndex = MF.addFrameInst( |
| MCCFIInstruction::createDefCfaOffset(nullptr, -MFI.getStackSize())); |
| BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION)) |
| .addCFIIndex(CFIIndex) |
| .setMIFlags(MachineInstr::FrameSetup); |
| |
| int CurOffset = -4; |
| if (hasFP(MF)) { |
| CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( |
| nullptr, MRI->getDwarfRegNum(ARC::FP, true), CurOffset)); |
| BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION)) |
| .addCFIIndex(CFIIndex) |
| .setMIFlags(MachineInstr::FrameSetup); |
| CurOffset -= 4; |
| } |
| |
| if (MFI.hasCalls()) { |
| CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( |
| nullptr, MRI->getDwarfRegNum(ARC::BLINK, true), CurOffset)); |
| BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION)) |
| .addCFIIndex(CFIIndex) |
| .setMIFlags(MachineInstr::FrameSetup); |
| } |
| // CFI for the rest of the registers. |
| for (const auto &Entry : CSI) { |
| unsigned Reg = Entry.getReg(); |
| int FI = Entry.getFrameIdx(); |
| // Skip BLINK and FP. |
| if ((hasFP(MF) && Reg == ARC::FP) || (MFI.hasCalls() && Reg == ARC::BLINK)) |
| continue; |
| CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( |
| nullptr, MRI->getDwarfRegNum(Reg, true), MFI.getObjectOffset(FI))); |
| BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION)) |
| .addCFIIndex(CFIIndex) |
| .setMIFlags(MachineInstr::FrameSetup); |
| } |
| } |
| |
| /// Insert epilog code into the function. |
| /// For ARC, this inserts a call to a function that restores callee saved |
| /// registers onto the stack, when enough callee saved registers are required. |
| void ARCFrameLowering::emitEpilogue(MachineFunction &MF, |
| MachineBasicBlock &MBB) const { |
| LLVM_DEBUG(dbgs() << "Emit Epilogue: " << MF.getName() << "\n"); |
| auto *AFI = MF.getInfo<ARCFunctionInfo>(); |
| const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo(); |
| MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator(); |
| MachineFrameInfo &MFI = MF.getFrameInfo(); |
| uint64_t StackSize = MF.getFrameInfo().getStackSize(); |
| bool SavedBlink = false; |
| unsigned AmountAboveFunclet = 0; |
| // If we have variable sized frame objects, then we have to move |
| // the stack pointer to a known spot (fp - StackSize). |
| // Then, replace the frame pointer by (new) [sp,StackSize-4]. |
| // Then, move the stack pointer the rest of the way (sp = sp + StackSize). |
| if (hasFP(MF)) { |
| BuildMI(MBB, MBBI, DebugLoc(), TII->get(ARC::SUB_rru6), ARC::SP) |
| .addReg(ARC::FP) |
| .addImm(StackSize); |
| AmountAboveFunclet += 4; |
| } |
| |
| // Now, move the stack pointer to the bottom of the save area for the funclet. |
| const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); |
| unsigned Last = determineLastCalleeSave(CSI); |
| unsigned StackSlotsUsedByFunclet = 0; |
| // Now, restore the callee save registers. |
| if (UseSaveRestoreFunclet && Last > ARC::R14) { |
| // BL to __ld_r13_to_<TRI->getRegAsmName()> |
| StackSlotsUsedByFunclet = Last - ARC::R12; |
| AmountAboveFunclet += 4 * (StackSlotsUsedByFunclet + 1); |
| SavedBlink = true; |
| } |
| |
| if (MFI.hasCalls() && !SavedBlink) { |
| AmountAboveFunclet += 4; |
| SavedBlink = true; |
| } |
| |
| // Move the stack pointer up to the point of the funclet. |
| if (StackSize - AmountAboveFunclet) { |
| BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::ADD_rru6)) |
| .addReg(ARC::SP) |
| .addReg(ARC::SP) |
| .addImm(StackSize - AmountAboveFunclet); |
| } |
| |
| if (StackSlotsUsedByFunclet) { |
| BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::BL)) |
| .addExternalSymbol(load_funclet_name[Last - ARC::R15]) |
| .addReg(ARC::BLINK, RegState::Implicit | RegState::Kill); |
| BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::ADD_rru6)) |
| .addReg(ARC::SP) |
| .addReg(ARC::SP) |
| .addImm(4 * (StackSlotsUsedByFunclet)); |
| } |
| // Now, pop blink if necessary. |
| if (SavedBlink) { |
| BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::POP_S_BLINK)); |
| } |
| // Now, pop fp if necessary. |
| if (hasFP(MF)) { |
| BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::LD_AB_rs9)) |
| .addReg(ARC::SP, RegState::Define) |
| .addReg(ARC::FP, RegState::Define) |
| .addReg(ARC::SP) |
| .addImm(4); |
| } |
| |
| // Relieve the varargs area if necessary. |
| if (MF.getFunction().isVarArg()) { |
| // Add in the varargs area here first. |
| LLVM_DEBUG(dbgs() << "Varargs\n"); |
| unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex()); |
| BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::ADD_rru6)) |
| .addReg(ARC::SP) |
| .addReg(ARC::SP) |
| .addImm(VarArgsBytes); |
| } |
| } |
| |
| static std::vector<CalleeSavedInfo>::iterator |
| getSavedReg(std::vector<CalleeSavedInfo> &V, unsigned reg) { |
| for (auto I = V.begin(), E = V.end(); I != E; ++I) { |
| if (reg == I->getReg()) |
| return I; |
| } |
| return V.end(); |
| } |
| |
| bool ARCFrameLowering::assignCalleeSavedSpillSlots( |
| MachineFunction &MF, const TargetRegisterInfo *TRI, |
| std::vector<CalleeSavedInfo> &CSI) const { |
| // Use this opportunity to assign the spill slots for all of the potential |
| // callee save registers (blink, fp, r13->r25) that we care about the |
| // placement for. We can calculate all of that data here. |
| int CurOffset = -4; |
| unsigned Last = determineLastCalleeSave(CSI); |
| MachineFrameInfo &MFI = MF.getFrameInfo(); |
| if (hasFP(MF)) { |
| // Create a fixed slot at for FP |
| int StackObj = MFI.CreateFixedSpillStackObject(4, CurOffset, true); |
| LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj << ") for FP at " |
| << CurOffset << "\n"); |
| (void)StackObj; |
| CurOffset -= 4; |
| } |
| if (MFI.hasCalls() || (UseSaveRestoreFunclet && Last > ARC::R14)) { |
| // Create a fixed slot for BLINK. |
| int StackObj = MFI.CreateFixedSpillStackObject(4, CurOffset, true); |
| LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj |
| << ") for BLINK at " << CurOffset << "\n"); |
| (void)StackObj; |
| CurOffset -= 4; |
| } |
| |
| // Create slots for last down to r13. |
| for (unsigned Which = Last; Which > ARC::R12; Which--) { |
| auto RegI = getSavedReg(CSI, Which); |
| if (RegI == CSI.end() || RegI->getFrameIdx() == 0) { |
| // Always create the stack slot. If for some reason the register isn't in |
| // the save list, then don't worry about it. |
| int FI = MFI.CreateFixedSpillStackObject(4, CurOffset, true); |
| if (RegI != CSI.end()) |
| RegI->setFrameIdx(FI); |
| } else |
| MFI.setObjectOffset(RegI->getFrameIdx(), CurOffset); |
| CurOffset -= 4; |
| } |
| for (auto &I : CSI) { |
| if (I.getReg() > ARC::R12) |
| continue; |
| if (I.getFrameIdx() == 0) { |
| I.setFrameIdx(MFI.CreateFixedSpillStackObject(4, CurOffset, true)); |
| LLVM_DEBUG(dbgs() << "Creating fixed object (" << I.getFrameIdx() |
| << ") for other register at " << CurOffset << "\n"); |
| } else { |
| MFI.setObjectOffset(I.getFrameIdx(), CurOffset); |
| LLVM_DEBUG(dbgs() << "Updating fixed object (" << I.getFrameIdx() |
| << ") for other register at " << CurOffset << "\n"); |
| } |
| CurOffset -= 4; |
| } |
| return true; |
| } |
| |
| bool ARCFrameLowering::spillCalleeSavedRegisters( |
| MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, |
| const std::vector<CalleeSavedInfo> &CSI, |
| const TargetRegisterInfo *TRI) const { |
| LLVM_DEBUG(dbgs() << "Spill callee saved registers: " |
| << MBB.getParent()->getName() << "\n"); |
| // There are routines for saving at least 3 registers (r13 to r15, etc.) |
| unsigned Last = determineLastCalleeSave(CSI); |
| if (UseSaveRestoreFunclet && Last > ARC::R14) { |
| // Use setObjectOffset for these registers. |
| // Needs to be in or before processFunctionBeforeFrameFinalized. |
| // Or, do assignCalleeSaveSpillSlots? |
| // Will be handled in prolog. |
| return true; |
| } |
| return false; |
| } |
| |
| bool ARCFrameLowering::restoreCalleeSavedRegisters( |
| MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, |
| std::vector<CalleeSavedInfo> &CSI, const TargetRegisterInfo *TRI) const { |
| LLVM_DEBUG(dbgs() << "Restore callee saved registers: " |
| << MBB.getParent()->getName() << "\n"); |
| // There are routines for saving at least 3 registers (r13 to r15, etc.) |
| unsigned Last = determineLastCalleeSave(CSI); |
| if (UseSaveRestoreFunclet && Last > ARC::R14) { |
| // Will be handled in epilog. |
| return true; |
| } |
| return false; |
| } |
| |
| // Adjust local variables that are 4-bytes or larger to 4-byte boundary |
| void ARCFrameLowering::processFunctionBeforeFrameFinalized( |
| MachineFunction &MF, RegScavenger *RS) const { |
| const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); |
| LLVM_DEBUG(dbgs() << "Process function before frame finalized: " |
| << MF.getName() << "\n"); |
| MachineFrameInfo &MFI = MF.getFrameInfo(); |
| LLVM_DEBUG(dbgs() << "Current stack size: " << MFI.getStackSize() << "\n"); |
| const TargetRegisterClass *RC = &ARC::GPR32RegClass; |
| if (MFI.hasStackObjects()) { |
| int RegScavFI = MFI.CreateStackObject( |
| RegInfo->getSpillSize(*RC), RegInfo->getSpillAlignment(*RC), false); |
| RS->addScavengingFrameIndex(RegScavFI); |
| LLVM_DEBUG(dbgs() << "Created scavenging index RegScavFI=" << RegScavFI |
| << "\n"); |
| } |
| } |
| |
| static void emitRegUpdate(MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator &MBBI, DebugLoc dl, |
| unsigned Reg, int NumBytes, bool IsAdd, |
| const ARCInstrInfo *TII) { |
| unsigned Opc = IsAdd ? ARC::ADD_rru6 : ARC::SUB_rru6; |
| BuildMI(MBB, MBBI, dl, TII->get(Opc), Reg) |
| .addReg(Reg, RegState::Kill) |
| .addImm(NumBytes); |
| } |
| |
| MachineBasicBlock::iterator ARCFrameLowering::eliminateCallFramePseudoInstr( |
| MachineFunction &MF, MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator I) const { |
| LLVM_DEBUG(dbgs() << "EmitCallFramePseudo: " << MF.getName() << "\n"); |
| const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo(); |
| MachineInstr &Old = *I; |
| DebugLoc dl = Old.getDebugLoc(); |
| unsigned Amt = Old.getOperand(0).getImm(); |
| auto *AFI = MF.getInfo<ARCFunctionInfo>(); |
| if (!hasFP(MF)) { |
| if (Amt > AFI->MaxCallStackReq && Old.getOpcode() == ARC::ADJCALLSTACKDOWN) |
| AFI->MaxCallStackReq = Amt; |
| } else { |
| if (Amt != 0) { |
| assert((Old.getOpcode() == ARC::ADJCALLSTACKDOWN || |
| Old.getOpcode() == ARC::ADJCALLSTACKUP) && |
| "Unknown Frame Pseudo."); |
| bool IsAdd = (Old.getOpcode() == ARC::ADJCALLSTACKUP); |
| emitRegUpdate(MBB, I, dl, ARC::SP, Amt, IsAdd, TII); |
| } |
| } |
| return MBB.erase(I); |
| } |
| |
| bool ARCFrameLowering::hasFP(const MachineFunction &MF) const { |
| const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); |
| bool HasFP = MF.getTarget().Options.DisableFramePointerElim(MF) || |
| MF.getFrameInfo().hasVarSizedObjects() || |
| MF.getFrameInfo().isFrameAddressTaken() || |
| RegInfo->needsStackRealignment(MF); |
| return HasFP; |
| } |