xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/ARC/ARCFrameLowering.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- ARCFrameLowering.cpp - ARC Frame Information -------------*- C++ -*-===//
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 ARC implementation of the TargetFrameLowering class.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "ARCFrameLowering.h"
140b57cec5SDimitry Andric #include "ARCMachineFunctionInfo.h"
150b57cec5SDimitry Andric #include "ARCSubtarget.h"
160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
200b57cec5SDimitry Andric #include "llvm/IR/Function.h"
210b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric #define DEBUG_TYPE "arc-frame-lowering"
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric using namespace llvm;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric static cl::opt<bool>
280b57cec5SDimitry Andric     UseSaveRestoreFunclet("arc-save-restore-funclet", cl::Hidden,
290b57cec5SDimitry Andric                           cl::desc("Use arc callee save/restore functions"),
300b57cec5SDimitry Andric                           cl::init(true));
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric static const char *store_funclet_name[] = {
330b57cec5SDimitry Andric     "__st_r13_to_r15", "__st_r13_to_r16", "__st_r13_to_r17", "__st_r13_to_r18",
340b57cec5SDimitry Andric     "__st_r13_to_r19", "__st_r13_to_r20", "__st_r13_to_r21", "__st_r13_to_r22",
350b57cec5SDimitry Andric     "__st_r13_to_r23", "__st_r13_to_r24", "__st_r13_to_r25",
360b57cec5SDimitry Andric };
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric static const char *load_funclet_name[] = {
390b57cec5SDimitry Andric     "__ld_r13_to_r15", "__ld_r13_to_r16", "__ld_r13_to_r17", "__ld_r13_to_r18",
400b57cec5SDimitry Andric     "__ld_r13_to_r19", "__ld_r13_to_r20", "__ld_r13_to_r21", "__ld_r13_to_r22",
410b57cec5SDimitry Andric     "__ld_r13_to_r23", "__ld_r13_to_r24", "__ld_r13_to_r25",
420b57cec5SDimitry Andric };
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric static void generateStackAdjustment(MachineBasicBlock &MBB,
450b57cec5SDimitry Andric                                     MachineBasicBlock::iterator MBBI,
460b57cec5SDimitry Andric                                     const ARCInstrInfo &TII, DebugLoc dl,
470b57cec5SDimitry Andric                                     int Amount, int StackPtr) {
480b57cec5SDimitry Andric   unsigned AdjOp;
490b57cec5SDimitry Andric   if (!Amount)
500b57cec5SDimitry Andric     return;
510b57cec5SDimitry Andric   bool Positive;
520b57cec5SDimitry Andric   unsigned AbsAmount;
530b57cec5SDimitry Andric   if (Amount < 0) {
540b57cec5SDimitry Andric     AbsAmount = -Amount;
550b57cec5SDimitry Andric     Positive = false;
560b57cec5SDimitry Andric   } else {
570b57cec5SDimitry Andric     AbsAmount = Amount;
580b57cec5SDimitry Andric     Positive = true;
590b57cec5SDimitry Andric   }
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Internal: adjust stack by: " << Amount << ","
620b57cec5SDimitry Andric                     << AbsAmount << "\n");
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   assert((AbsAmount % 4 == 0) && "Stack adjustments must be 4-byte aligned.");
650b57cec5SDimitry Andric   if (isUInt<6>(AbsAmount))
660b57cec5SDimitry Andric     AdjOp = Positive ? ARC::ADD_rru6 : ARC::SUB_rru6;
670b57cec5SDimitry Andric   else if (isInt<12>(AbsAmount))
680b57cec5SDimitry Andric     AdjOp = Positive ? ARC::ADD_rrs12 : ARC::SUB_rrs12;
690b57cec5SDimitry Andric   else
700b57cec5SDimitry Andric     AdjOp = Positive ? ARC::ADD_rrlimm : ARC::SUB_rrlimm;
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   BuildMI(MBB, MBBI, dl, TII.get(AdjOp), StackPtr)
730b57cec5SDimitry Andric       .addReg(StackPtr)
740b57cec5SDimitry Andric       .addImm(AbsAmount);
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric 
775ffd83dbSDimitry Andric static unsigned determineLastCalleeSave(ArrayRef<CalleeSavedInfo> CSI) {
780b57cec5SDimitry Andric   unsigned Last = 0;
790b57cec5SDimitry Andric   for (auto Reg : CSI) {
800b57cec5SDimitry Andric     assert(Reg.getReg() >= ARC::R13 && Reg.getReg() <= ARC::R25 &&
810b57cec5SDimitry Andric            "Unexpected callee saved reg.");
820b57cec5SDimitry Andric     if (Reg.getReg() > Last)
830b57cec5SDimitry Andric       Last = Reg.getReg();
840b57cec5SDimitry Andric   }
850b57cec5SDimitry Andric   return Last;
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric void ARCFrameLowering::determineCalleeSaves(MachineFunction &MF,
890b57cec5SDimitry Andric                                             BitVector &SavedRegs,
900b57cec5SDimitry Andric                                             RegScavenger *RS) const {
910b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Determine Callee Saves: " << MF.getName() << "\n");
920b57cec5SDimitry Andric   TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
930b57cec5SDimitry Andric   SavedRegs.set(ARC::BLINK);
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric void ARCFrameLowering::adjustStackToMatchRecords(
970b57cec5SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
980b57cec5SDimitry Andric     bool Allocate) const {
990b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
1000b57cec5SDimitry Andric   int ScalarAlloc = MF.getFrameInfo().getStackSize();
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   if (Allocate) {
1030b57cec5SDimitry Andric     // Allocate by adjusting by the negative of what the record holder tracked
1040b57cec5SDimitry Andric     // it tracked a positive offset in a downward growing stack.
1050b57cec5SDimitry Andric     ScalarAlloc = -ScalarAlloc;
1060b57cec5SDimitry Andric   }
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric   generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), DebugLoc(),
1090b57cec5SDimitry Andric                           ScalarAlloc, ARC::SP);
1100b57cec5SDimitry Andric }
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric /// Insert prolog code into the function.
1130b57cec5SDimitry Andric /// For ARC, this inserts a call to a function that puts required callee saved
1140b57cec5SDimitry Andric /// registers onto the stack, when enough callee saved registers are required.
1150b57cec5SDimitry Andric void ARCFrameLowering::emitPrologue(MachineFunction &MF,
1160b57cec5SDimitry Andric                                     MachineBasicBlock &MBB) const {
1170b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Emit Prologue: " << MF.getName() << "\n");
1180b57cec5SDimitry Andric   auto *AFI = MF.getInfo<ARCFunctionInfo>();
119*0fca6ea1SDimitry Andric   MCContext &Context = MF.getContext();
1200b57cec5SDimitry Andric   const MCRegisterInfo *MRI = Context.getRegisterInfo();
1210b57cec5SDimitry Andric   const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
1220b57cec5SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.begin();
1230b57cec5SDimitry Andric   // Debug location must be unknown since the first debug location is used
1240b57cec5SDimitry Andric   // to determine the end of the prologue.
1250b57cec5SDimitry Andric   DebugLoc dl;
1260b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
1270b57cec5SDimitry Andric   const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
1280b57cec5SDimitry Andric   unsigned Last = determineLastCalleeSave(CSI);
1290b57cec5SDimitry Andric   unsigned StackSlotsUsedByFunclet = 0;
1300b57cec5SDimitry Andric   bool SavedBlink = false;
1310b57cec5SDimitry Andric   unsigned AlreadyAdjusted = 0;
1320b57cec5SDimitry Andric   if (MF.getFunction().isVarArg()) {
1330b57cec5SDimitry Andric     // Add in the varargs area here first.
1340b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Varargs\n");
1350b57cec5SDimitry Andric     unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex());
1360b57cec5SDimitry Andric     unsigned Opc = ARC::SUB_rrlimm;
1370b57cec5SDimitry Andric     if (isUInt<6>(VarArgsBytes))
1380b57cec5SDimitry Andric       Opc = ARC::SUB_rru6;
1390b57cec5SDimitry Andric     else if (isInt<12>(VarArgsBytes))
1400b57cec5SDimitry Andric       Opc = ARC::SUB_rrs12;
1410b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII->get(Opc), ARC::SP)
1420b57cec5SDimitry Andric         .addReg(ARC::SP)
1430b57cec5SDimitry Andric         .addImm(VarArgsBytes);
1440b57cec5SDimitry Andric   }
1450b57cec5SDimitry Andric   if (hasFP(MF)) {
1460b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Saving FP\n");
1470b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII->get(ARC::ST_AW_rs9))
1480b57cec5SDimitry Andric         .addReg(ARC::SP, RegState::Define)
1490b57cec5SDimitry Andric         .addReg(ARC::FP)
1500b57cec5SDimitry Andric         .addReg(ARC::SP)
1510b57cec5SDimitry Andric         .addImm(-4);
1520b57cec5SDimitry Andric     AlreadyAdjusted += 4;
1530b57cec5SDimitry Andric   }
1540b57cec5SDimitry Andric   if (UseSaveRestoreFunclet && Last > ARC::R14) {
1550b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Creating store funclet.\n");
1560b57cec5SDimitry Andric     // BL to __save_r13_to_<TRI->getRegAsmName()>
1570b57cec5SDimitry Andric     StackSlotsUsedByFunclet = Last - ARC::R12;
1580b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK));
1590b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII->get(ARC::SUB_rru6))
1600b57cec5SDimitry Andric         .addReg(ARC::SP)
1610b57cec5SDimitry Andric         .addReg(ARC::SP)
1620b57cec5SDimitry Andric         .addImm(4 * StackSlotsUsedByFunclet);
1630b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII->get(ARC::BL))
1640b57cec5SDimitry Andric         .addExternalSymbol(store_funclet_name[Last - ARC::R15])
1650b57cec5SDimitry Andric         .addReg(ARC::BLINK, RegState::Implicit | RegState::Kill);
1660b57cec5SDimitry Andric     AlreadyAdjusted += 4 * (StackSlotsUsedByFunclet + 1);
1670b57cec5SDimitry Andric     SavedBlink = true;
1680b57cec5SDimitry Andric   }
1690b57cec5SDimitry Andric   // If we haven't saved BLINK, but we need to...do that now.
1700b57cec5SDimitry Andric   if (MFI.hasCalls() && !SavedBlink) {
1710b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Creating save blink.\n");
1720b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK));
1730b57cec5SDimitry Andric     AlreadyAdjusted += 4;
1740b57cec5SDimitry Andric   }
1750b57cec5SDimitry Andric   if (AFI->MaxCallStackReq > 0)
1760b57cec5SDimitry Andric     MFI.setStackSize(MFI.getStackSize() + AFI->MaxCallStackReq);
1770b57cec5SDimitry Andric   // We have already saved some of the stack...
1780b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Adjusting stack by: "
1790b57cec5SDimitry Andric                     << (MFI.getStackSize() - AlreadyAdjusted) << "\n");
1800b57cec5SDimitry Andric   generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), dl,
1810b57cec5SDimitry Andric                           -(MFI.getStackSize() - AlreadyAdjusted), ARC::SP);
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric   if (hasFP(MF)) {
1840b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Setting FP from SP.\n");
1850b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl,
1860b57cec5SDimitry Andric             TII->get(isUInt<6>(MFI.getStackSize()) ? ARC::ADD_rru6
1870b57cec5SDimitry Andric                                                    : ARC::ADD_rrlimm),
1880b57cec5SDimitry Andric             ARC::FP)
1890b57cec5SDimitry Andric         .addReg(ARC::SP)
1900b57cec5SDimitry Andric         .addImm(MFI.getStackSize());
1910b57cec5SDimitry Andric   }
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric   // Emit CFI records:
1940b57cec5SDimitry Andric   // .cfi_def_cfa_offset StackSize
1950b57cec5SDimitry Andric   // .cfi_offset fp, -StackSize
1960b57cec5SDimitry Andric   // .cfi_offset blink, -StackSize+4
1970b57cec5SDimitry Andric   unsigned CFIIndex = MF.addFrameInst(
1985ffd83dbSDimitry Andric       MCCFIInstruction::cfiDefCfaOffset(nullptr, MFI.getStackSize()));
1990b57cec5SDimitry Andric   BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
2000b57cec5SDimitry Andric       .addCFIIndex(CFIIndex)
2010b57cec5SDimitry Andric       .setMIFlags(MachineInstr::FrameSetup);
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric   int CurOffset = -4;
2040b57cec5SDimitry Andric   if (hasFP(MF)) {
2050b57cec5SDimitry Andric     CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
2060b57cec5SDimitry Andric         nullptr, MRI->getDwarfRegNum(ARC::FP, true), CurOffset));
2070b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
2080b57cec5SDimitry Andric         .addCFIIndex(CFIIndex)
2090b57cec5SDimitry Andric         .setMIFlags(MachineInstr::FrameSetup);
2100b57cec5SDimitry Andric     CurOffset -= 4;
2110b57cec5SDimitry Andric   }
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric   if (MFI.hasCalls()) {
2140b57cec5SDimitry Andric     CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
2150b57cec5SDimitry Andric         nullptr, MRI->getDwarfRegNum(ARC::BLINK, true), CurOffset));
2160b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
2170b57cec5SDimitry Andric         .addCFIIndex(CFIIndex)
2180b57cec5SDimitry Andric         .setMIFlags(MachineInstr::FrameSetup);
2190b57cec5SDimitry Andric   }
2200b57cec5SDimitry Andric   // CFI for the rest of the registers.
2210b57cec5SDimitry Andric   for (const auto &Entry : CSI) {
2220b57cec5SDimitry Andric     unsigned Reg = Entry.getReg();
2230b57cec5SDimitry Andric     int FI = Entry.getFrameIdx();
2240b57cec5SDimitry Andric     // Skip BLINK and FP.
2250b57cec5SDimitry Andric     if ((hasFP(MF) && Reg == ARC::FP) || (MFI.hasCalls() && Reg == ARC::BLINK))
2260b57cec5SDimitry Andric       continue;
2270b57cec5SDimitry Andric     CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
2280b57cec5SDimitry Andric         nullptr, MRI->getDwarfRegNum(Reg, true), MFI.getObjectOffset(FI)));
2290b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
2300b57cec5SDimitry Andric         .addCFIIndex(CFIIndex)
2310b57cec5SDimitry Andric         .setMIFlags(MachineInstr::FrameSetup);
2320b57cec5SDimitry Andric   }
2330b57cec5SDimitry Andric }
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric /// Insert epilog code into the function.
2360b57cec5SDimitry Andric /// For ARC, this inserts a call to a function that restores callee saved
2370b57cec5SDimitry Andric /// registers onto the stack, when enough callee saved registers are required.
2380b57cec5SDimitry Andric void ARCFrameLowering::emitEpilogue(MachineFunction &MF,
2390b57cec5SDimitry Andric                                     MachineBasicBlock &MBB) const {
2400b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Emit Epilogue: " << MF.getName() << "\n");
2410b57cec5SDimitry Andric   auto *AFI = MF.getInfo<ARCFunctionInfo>();
2420b57cec5SDimitry Andric   const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
2430b57cec5SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
2440b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
2450b57cec5SDimitry Andric   uint64_t StackSize = MF.getFrameInfo().getStackSize();
2460b57cec5SDimitry Andric   bool SavedBlink = false;
2470b57cec5SDimitry Andric   unsigned AmountAboveFunclet = 0;
2480b57cec5SDimitry Andric   // If we have variable sized frame objects, then we have to move
2490b57cec5SDimitry Andric   // the stack pointer to a known spot (fp - StackSize).
2500b57cec5SDimitry Andric   // Then, replace the frame pointer by (new) [sp,StackSize-4].
2510b57cec5SDimitry Andric   // Then, move the stack pointer the rest of the way (sp = sp + StackSize).
2520b57cec5SDimitry Andric   if (hasFP(MF)) {
2530b57cec5SDimitry Andric     unsigned Opc = ARC::SUB_rrlimm;
2540b57cec5SDimitry Andric     if (isUInt<6>(StackSize))
2550b57cec5SDimitry Andric       Opc = ARC::SUB_rru6;
2560b57cec5SDimitry Andric     BuildMI(MBB, MBBI, DebugLoc(), TII->get(Opc), ARC::SP)
2570b57cec5SDimitry Andric         .addReg(ARC::FP)
2580b57cec5SDimitry Andric         .addImm(StackSize);
2590b57cec5SDimitry Andric     AmountAboveFunclet += 4;
2600b57cec5SDimitry Andric   }
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric   // Now, move the stack pointer to the bottom of the save area for the funclet.
2630b57cec5SDimitry Andric   const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
2640b57cec5SDimitry Andric   unsigned Last = determineLastCalleeSave(CSI);
2650b57cec5SDimitry Andric   unsigned StackSlotsUsedByFunclet = 0;
2660b57cec5SDimitry Andric   // Now, restore the callee save registers.
2670b57cec5SDimitry Andric   if (UseSaveRestoreFunclet && Last > ARC::R14) {
2680b57cec5SDimitry Andric     // BL to __ld_r13_to_<TRI->getRegAsmName()>
2690b57cec5SDimitry Andric     StackSlotsUsedByFunclet = Last - ARC::R12;
2700b57cec5SDimitry Andric     AmountAboveFunclet += 4 * (StackSlotsUsedByFunclet + 1);
2710b57cec5SDimitry Andric     SavedBlink = true;
2720b57cec5SDimitry Andric   }
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric   if (MFI.hasCalls() && !SavedBlink) {
2750b57cec5SDimitry Andric     AmountAboveFunclet += 4;
2760b57cec5SDimitry Andric     SavedBlink = true;
2770b57cec5SDimitry Andric   }
2780b57cec5SDimitry Andric 
2790b57cec5SDimitry Andric   // Move the stack pointer up to the point of the funclet.
2800b57cec5SDimitry Andric   if (unsigned MoveAmount = StackSize - AmountAboveFunclet) {
2810b57cec5SDimitry Andric     unsigned Opc = ARC::ADD_rrlimm;
2820b57cec5SDimitry Andric     if (isUInt<6>(MoveAmount))
2830b57cec5SDimitry Andric       Opc = ARC::ADD_rru6;
2840b57cec5SDimitry Andric     else if (isInt<12>(MoveAmount))
2850b57cec5SDimitry Andric       Opc = ARC::ADD_rrs12;
2860b57cec5SDimitry Andric     BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc), ARC::SP)
2870b57cec5SDimitry Andric         .addReg(ARC::SP)
2880b57cec5SDimitry Andric         .addImm(StackSize - AmountAboveFunclet);
2890b57cec5SDimitry Andric   }
2900b57cec5SDimitry Andric 
2910b57cec5SDimitry Andric   if (StackSlotsUsedByFunclet) {
2920b57cec5SDimitry Andric     // This part of the adjustment will always be < 64 bytes.
2930b57cec5SDimitry Andric     BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::BL))
2940b57cec5SDimitry Andric         .addExternalSymbol(load_funclet_name[Last - ARC::R15])
2950b57cec5SDimitry Andric         .addReg(ARC::BLINK, RegState::Implicit | RegState::Kill);
2960b57cec5SDimitry Andric     unsigned Opc = ARC::ADD_rrlimm;
2970b57cec5SDimitry Andric     if (isUInt<6>(4 * StackSlotsUsedByFunclet))
2980b57cec5SDimitry Andric       Opc = ARC::ADD_rru6;
2990b57cec5SDimitry Andric     else if (isInt<12>(4 * StackSlotsUsedByFunclet))
3000b57cec5SDimitry Andric       Opc = ARC::ADD_rrs12;
3010b57cec5SDimitry Andric     BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc), ARC::SP)
3020b57cec5SDimitry Andric         .addReg(ARC::SP)
3030b57cec5SDimitry Andric         .addImm(4 * (StackSlotsUsedByFunclet));
3040b57cec5SDimitry Andric   }
3050b57cec5SDimitry Andric   // Now, pop blink if necessary.
3060b57cec5SDimitry Andric   if (SavedBlink) {
3070b57cec5SDimitry Andric     BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::POP_S_BLINK));
3080b57cec5SDimitry Andric   }
3090b57cec5SDimitry Andric   // Now, pop fp if necessary.
3100b57cec5SDimitry Andric   if (hasFP(MF)) {
3110b57cec5SDimitry Andric     BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::LD_AB_rs9))
3120b57cec5SDimitry Andric         .addReg(ARC::FP, RegState::Define)
3130b57cec5SDimitry Andric         .addReg(ARC::SP, RegState::Define)
3140b57cec5SDimitry Andric         .addReg(ARC::SP)
3150b57cec5SDimitry Andric         .addImm(4);
3160b57cec5SDimitry Andric   }
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric   // Relieve the varargs area if necessary.
3190b57cec5SDimitry Andric   if (MF.getFunction().isVarArg()) {
3200b57cec5SDimitry Andric     // Add in the varargs area here first.
3210b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Varargs\n");
3220b57cec5SDimitry Andric     unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex());
3230b57cec5SDimitry Andric     unsigned Opc = ARC::ADD_rrlimm;
3240b57cec5SDimitry Andric     if (isUInt<6>(VarArgsBytes))
3250b57cec5SDimitry Andric       Opc = ARC::ADD_rru6;
3260b57cec5SDimitry Andric     else if (isInt<12>(VarArgsBytes))
3270b57cec5SDimitry Andric       Opc = ARC::ADD_rrs12;
3280b57cec5SDimitry Andric     BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc))
3290b57cec5SDimitry Andric         .addReg(ARC::SP)
3300b57cec5SDimitry Andric         .addReg(ARC::SP)
3310b57cec5SDimitry Andric         .addImm(VarArgsBytes);
3320b57cec5SDimitry Andric   }
3330b57cec5SDimitry Andric }
3340b57cec5SDimitry Andric 
3350b57cec5SDimitry Andric static std::vector<CalleeSavedInfo>::iterator
3360b57cec5SDimitry Andric getSavedReg(std::vector<CalleeSavedInfo> &V, unsigned reg) {
3370b57cec5SDimitry Andric   for (auto I = V.begin(), E = V.end(); I != E; ++I) {
3380b57cec5SDimitry Andric     if (reg == I->getReg())
3390b57cec5SDimitry Andric       return I;
3400b57cec5SDimitry Andric   }
3410b57cec5SDimitry Andric   return V.end();
3420b57cec5SDimitry Andric }
3430b57cec5SDimitry Andric 
3440b57cec5SDimitry Andric bool ARCFrameLowering::assignCalleeSavedSpillSlots(
3450b57cec5SDimitry Andric     MachineFunction &MF, const TargetRegisterInfo *TRI,
3460b57cec5SDimitry Andric     std::vector<CalleeSavedInfo> &CSI) const {
3470b57cec5SDimitry Andric   // Use this opportunity to assign the spill slots for all of the potential
3480b57cec5SDimitry Andric   // callee save registers (blink, fp, r13->r25) that we care about the
3490b57cec5SDimitry Andric   // placement for.  We can calculate all of that data here.
3500b57cec5SDimitry Andric   int CurOffset = -4;
3510b57cec5SDimitry Andric   unsigned Last = determineLastCalleeSave(CSI);
3520b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
3530b57cec5SDimitry Andric   if (hasFP(MF)) {
3540b57cec5SDimitry Andric     // Create a fixed slot at for FP
3550b57cec5SDimitry Andric     int StackObj = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
3560b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj << ") for FP at "
3570b57cec5SDimitry Andric                       << CurOffset << "\n");
3580b57cec5SDimitry Andric     (void)StackObj;
3590b57cec5SDimitry Andric     CurOffset -= 4;
3600b57cec5SDimitry Andric   }
3610b57cec5SDimitry Andric   if (MFI.hasCalls() || (UseSaveRestoreFunclet && Last > ARC::R14)) {
3620b57cec5SDimitry Andric     // Create a fixed slot for BLINK.
3630b57cec5SDimitry Andric     int StackObj  = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
3640b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj
3650b57cec5SDimitry Andric                       << ") for BLINK at " << CurOffset << "\n");
3660b57cec5SDimitry Andric     (void)StackObj;
3670b57cec5SDimitry Andric     CurOffset -= 4;
3680b57cec5SDimitry Andric   }
3690b57cec5SDimitry Andric 
3700b57cec5SDimitry Andric   // Create slots for last down to r13.
3710b57cec5SDimitry Andric   for (unsigned Which = Last; Which > ARC::R12; Which--) {
3720b57cec5SDimitry Andric     auto RegI = getSavedReg(CSI, Which);
3730b57cec5SDimitry Andric     if (RegI == CSI.end() || RegI->getFrameIdx() == 0) {
3740b57cec5SDimitry Andric       // Always create the stack slot.  If for some reason the register isn't in
3750b57cec5SDimitry Andric       // the save list, then don't worry about it.
3760b57cec5SDimitry Andric       int FI = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
3770b57cec5SDimitry Andric       if (RegI != CSI.end())
3780b57cec5SDimitry Andric         RegI->setFrameIdx(FI);
3790b57cec5SDimitry Andric     } else
3800b57cec5SDimitry Andric       MFI.setObjectOffset(RegI->getFrameIdx(), CurOffset);
3810b57cec5SDimitry Andric     CurOffset -= 4;
3820b57cec5SDimitry Andric   }
3830b57cec5SDimitry Andric   for (auto &I : CSI) {
3840b57cec5SDimitry Andric     if (I.getReg() > ARC::R12)
3850b57cec5SDimitry Andric       continue;
3860b57cec5SDimitry Andric     if (I.getFrameIdx() == 0) {
3870b57cec5SDimitry Andric       I.setFrameIdx(MFI.CreateFixedSpillStackObject(4, CurOffset, true));
3880b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "Creating fixed object (" << I.getFrameIdx()
3890b57cec5SDimitry Andric                         << ") for other register at " << CurOffset << "\n");
3900b57cec5SDimitry Andric     } else {
3910b57cec5SDimitry Andric       MFI.setObjectOffset(I.getFrameIdx(), CurOffset);
3920b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "Updating fixed object (" << I.getFrameIdx()
3930b57cec5SDimitry Andric                         << ") for other register at " << CurOffset << "\n");
3940b57cec5SDimitry Andric     }
3950b57cec5SDimitry Andric     CurOffset -= 4;
3960b57cec5SDimitry Andric   }
3970b57cec5SDimitry Andric   return true;
3980b57cec5SDimitry Andric }
3990b57cec5SDimitry Andric 
4000b57cec5SDimitry Andric bool ARCFrameLowering::spillCalleeSavedRegisters(
4010b57cec5SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
4025ffd83dbSDimitry Andric     ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
4030b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Spill callee saved registers: "
4040b57cec5SDimitry Andric                     << MBB.getParent()->getName() << "\n");
4050b57cec5SDimitry Andric   // There are routines for saving at least 3 registers (r13 to r15, etc.)
4060b57cec5SDimitry Andric   unsigned Last = determineLastCalleeSave(CSI);
4070b57cec5SDimitry Andric   if (UseSaveRestoreFunclet && Last > ARC::R14) {
4080b57cec5SDimitry Andric     // Use setObjectOffset for these registers.
4090b57cec5SDimitry Andric     // Needs to be in or before processFunctionBeforeFrameFinalized.
4100b57cec5SDimitry Andric     // Or, do assignCalleeSaveSpillSlots?
4110b57cec5SDimitry Andric     // Will be handled in prolog.
4120b57cec5SDimitry Andric     return true;
4130b57cec5SDimitry Andric   }
4140b57cec5SDimitry Andric   return false;
4150b57cec5SDimitry Andric }
4160b57cec5SDimitry Andric 
4170b57cec5SDimitry Andric bool ARCFrameLowering::restoreCalleeSavedRegisters(
4180b57cec5SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
4195ffd83dbSDimitry Andric     MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
4200b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Restore callee saved registers: "
4210b57cec5SDimitry Andric                     << MBB.getParent()->getName() << "\n");
4220b57cec5SDimitry Andric   // There are routines for saving at least 3 registers (r13 to r15, etc.)
4230b57cec5SDimitry Andric   unsigned Last = determineLastCalleeSave(CSI);
4240b57cec5SDimitry Andric   if (UseSaveRestoreFunclet && Last > ARC::R14) {
4250b57cec5SDimitry Andric     // Will be handled in epilog.
4260b57cec5SDimitry Andric     return true;
4270b57cec5SDimitry Andric   }
4280b57cec5SDimitry Andric   return false;
4290b57cec5SDimitry Andric }
4300b57cec5SDimitry Andric 
4310b57cec5SDimitry Andric // Adjust local variables that are 4-bytes or larger to 4-byte boundary
4320b57cec5SDimitry Andric void ARCFrameLowering::processFunctionBeforeFrameFinalized(
4330b57cec5SDimitry Andric     MachineFunction &MF, RegScavenger *RS) const {
4340b57cec5SDimitry Andric   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
4350b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Process function before frame finalized: "
4360b57cec5SDimitry Andric                     << MF.getName() << "\n");
4370b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
4380b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Current stack size: " << MFI.getStackSize() << "\n");
4390b57cec5SDimitry Andric   const TargetRegisterClass *RC = &ARC::GPR32RegClass;
4400b57cec5SDimitry Andric   if (MFI.hasStackObjects()) {
4415ffd83dbSDimitry Andric     int RegScavFI = MFI.CreateStackObject(RegInfo->getSpillSize(*RC),
4425ffd83dbSDimitry Andric                                           RegInfo->getSpillAlign(*RC), false);
4430b57cec5SDimitry Andric     RS->addScavengingFrameIndex(RegScavFI);
4440b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Created scavenging index RegScavFI=" << RegScavFI
4450b57cec5SDimitry Andric                       << "\n");
4460b57cec5SDimitry Andric   }
4470b57cec5SDimitry Andric }
4480b57cec5SDimitry Andric 
4490b57cec5SDimitry Andric static void emitRegUpdate(MachineBasicBlock &MBB,
4500b57cec5SDimitry Andric                           MachineBasicBlock::iterator &MBBI, DebugLoc dl,
4510b57cec5SDimitry Andric                           unsigned Reg, int NumBytes, bool IsAdd,
4520b57cec5SDimitry Andric                           const ARCInstrInfo *TII) {
4530b57cec5SDimitry Andric   unsigned Opc;
4540b57cec5SDimitry Andric   if (isUInt<6>(NumBytes))
4550b57cec5SDimitry Andric     Opc = IsAdd ? ARC::ADD_rru6 : ARC::SUB_rru6;
4560b57cec5SDimitry Andric   else if (isInt<12>(NumBytes))
4570b57cec5SDimitry Andric     Opc = IsAdd ? ARC::ADD_rrs12 : ARC::SUB_rrs12;
4580b57cec5SDimitry Andric   else
4590b57cec5SDimitry Andric     Opc = IsAdd ? ARC::ADD_rrlimm : ARC::SUB_rrlimm;
4600b57cec5SDimitry Andric 
4610b57cec5SDimitry Andric   BuildMI(MBB, MBBI, dl, TII->get(Opc), Reg)
4620b57cec5SDimitry Andric       .addReg(Reg, RegState::Kill)
4630b57cec5SDimitry Andric       .addImm(NumBytes);
4640b57cec5SDimitry Andric }
4650b57cec5SDimitry Andric 
4660b57cec5SDimitry Andric MachineBasicBlock::iterator ARCFrameLowering::eliminateCallFramePseudoInstr(
4670b57cec5SDimitry Andric     MachineFunction &MF, MachineBasicBlock &MBB,
4680b57cec5SDimitry Andric     MachineBasicBlock::iterator I) const {
4690b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "EmitCallFramePseudo: " << MF.getName() << "\n");
4700b57cec5SDimitry Andric   const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
4710b57cec5SDimitry Andric   MachineInstr &Old = *I;
4720b57cec5SDimitry Andric   DebugLoc dl = Old.getDebugLoc();
4730b57cec5SDimitry Andric   unsigned Amt = Old.getOperand(0).getImm();
4740b57cec5SDimitry Andric   auto *AFI = MF.getInfo<ARCFunctionInfo>();
4750b57cec5SDimitry Andric   if (!hasFP(MF)) {
4760b57cec5SDimitry Andric     if (Amt > AFI->MaxCallStackReq && Old.getOpcode() == ARC::ADJCALLSTACKDOWN)
4770b57cec5SDimitry Andric       AFI->MaxCallStackReq = Amt;
4780b57cec5SDimitry Andric   } else {
4790b57cec5SDimitry Andric     if (Amt != 0) {
4800b57cec5SDimitry Andric       assert((Old.getOpcode() == ARC::ADJCALLSTACKDOWN ||
4810b57cec5SDimitry Andric               Old.getOpcode() == ARC::ADJCALLSTACKUP) &&
4820b57cec5SDimitry Andric              "Unknown Frame Pseudo.");
4830b57cec5SDimitry Andric       bool IsAdd = (Old.getOpcode() == ARC::ADJCALLSTACKUP);
4840b57cec5SDimitry Andric       emitRegUpdate(MBB, I, dl, ARC::SP, Amt, IsAdd, TII);
4850b57cec5SDimitry Andric     }
4860b57cec5SDimitry Andric   }
4870b57cec5SDimitry Andric   return MBB.erase(I);
4880b57cec5SDimitry Andric }
4890b57cec5SDimitry Andric 
4900b57cec5SDimitry Andric bool ARCFrameLowering::hasFP(const MachineFunction &MF) const {
4910b57cec5SDimitry Andric   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
4920b57cec5SDimitry Andric   bool HasFP = MF.getTarget().Options.DisableFramePointerElim(MF) ||
4930b57cec5SDimitry Andric                MF.getFrameInfo().hasVarSizedObjects() ||
4940b57cec5SDimitry Andric                MF.getFrameInfo().isFrameAddressTaken() ||
495fe6060f1SDimitry Andric                RegInfo->hasStackRealignment(MF);
4960b57cec5SDimitry Andric   return HasFP;
4970b57cec5SDimitry Andric }
498