12d1f6d67SPete Couperus //===- ARCFrameLowering.cpp - ARC Frame Information -------------*- C++ -*-===//
22d1f6d67SPete Couperus //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62d1f6d67SPete Couperus //
72d1f6d67SPete Couperus //===----------------------------------------------------------------------===//
82d1f6d67SPete Couperus //
92d1f6d67SPete Couperus // This file contains the ARC implementation of the TargetFrameLowering class.
102d1f6d67SPete Couperus //
112d1f6d67SPete Couperus //===----------------------------------------------------------------------===//
122d1f6d67SPete Couperus 
132d1f6d67SPete Couperus #include "ARCFrameLowering.h"
142d1f6d67SPete Couperus #include "ARCMachineFunctionInfo.h"
152d1f6d67SPete Couperus #include "ARCSubtarget.h"
162d1f6d67SPete Couperus #include "llvm/CodeGen/MachineInstrBuilder.h"
172d1f6d67SPete Couperus #include "llvm/CodeGen/MachineModuleInfo.h"
182d1f6d67SPete Couperus #include "llvm/CodeGen/RegisterScavenging.h"
19b3bde2eaSDavid Blaikie #include "llvm/CodeGen/TargetRegisterInfo.h"
202d1f6d67SPete Couperus #include "llvm/IR/Function.h"
212d1f6d67SPete Couperus #include "llvm/Support/Debug.h"
222d1f6d67SPete Couperus 
232d1f6d67SPete Couperus #define DEBUG_TYPE "arc-frame-lowering"
242d1f6d67SPete Couperus 
252d1f6d67SPete Couperus using namespace llvm;
262d1f6d67SPete Couperus 
272d1f6d67SPete Couperus static cl::opt<bool>
282d1f6d67SPete Couperus     UseSaveRestoreFunclet("arc-save-restore-funclet", cl::Hidden,
292d1f6d67SPete Couperus                           cl::desc("Use arc callee save/restore functions"),
302d1f6d67SPete Couperus                           cl::init(true));
312d1f6d67SPete Couperus 
322d1f6d67SPete Couperus static const char *store_funclet_name[] = {
332d1f6d67SPete Couperus     "__st_r13_to_r15", "__st_r13_to_r16", "__st_r13_to_r17", "__st_r13_to_r18",
342d1f6d67SPete Couperus     "__st_r13_to_r19", "__st_r13_to_r20", "__st_r13_to_r21", "__st_r13_to_r22",
352d1f6d67SPete Couperus     "__st_r13_to_r23", "__st_r13_to_r24", "__st_r13_to_r25",
362d1f6d67SPete Couperus };
372d1f6d67SPete Couperus 
382d1f6d67SPete Couperus static const char *load_funclet_name[] = {
392d1f6d67SPete Couperus     "__ld_r13_to_r15", "__ld_r13_to_r16", "__ld_r13_to_r17", "__ld_r13_to_r18",
402d1f6d67SPete Couperus     "__ld_r13_to_r19", "__ld_r13_to_r20", "__ld_r13_to_r21", "__ld_r13_to_r22",
412d1f6d67SPete Couperus     "__ld_r13_to_r23", "__ld_r13_to_r24", "__ld_r13_to_r25",
422d1f6d67SPete Couperus };
432d1f6d67SPete Couperus 
generateStackAdjustment(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,const ARCInstrInfo & TII,DebugLoc dl,int Amount,int StackPtr)442d1f6d67SPete Couperus static void generateStackAdjustment(MachineBasicBlock &MBB,
452d1f6d67SPete Couperus                                     MachineBasicBlock::iterator MBBI,
462d1f6d67SPete Couperus                                     const ARCInstrInfo &TII, DebugLoc dl,
472d1f6d67SPete Couperus                                     int Amount, int StackPtr) {
482d1f6d67SPete Couperus   unsigned AdjOp;
492d1f6d67SPete Couperus   if (!Amount)
502d1f6d67SPete Couperus     return;
512d1f6d67SPete Couperus   bool Positive;
522d1f6d67SPete Couperus   unsigned AbsAmount;
532d1f6d67SPete Couperus   if (Amount < 0) {
542d1f6d67SPete Couperus     AbsAmount = -Amount;
552d1f6d67SPete Couperus     Positive = false;
562d1f6d67SPete Couperus   } else {
572d1f6d67SPete Couperus     AbsAmount = Amount;
582d1f6d67SPete Couperus     Positive = true;
592d1f6d67SPete Couperus   }
602d1f6d67SPete Couperus 
61d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Internal: adjust stack by: " << Amount << ","
62d34e60caSNicola Zaghen                     << AbsAmount << "\n");
632d1f6d67SPete Couperus 
642d1f6d67SPete Couperus   assert((AbsAmount % 4 == 0) && "Stack adjustments must be 4-byte aligned.");
652d1f6d67SPete Couperus   if (isUInt<6>(AbsAmount))
662d1f6d67SPete Couperus     AdjOp = Positive ? ARC::ADD_rru6 : ARC::SUB_rru6;
67225c0bd6SPete Couperus   else if (isInt<12>(AbsAmount))
68225c0bd6SPete Couperus     AdjOp = Positive ? ARC::ADD_rrs12 : ARC::SUB_rrs12;
692d1f6d67SPete Couperus   else
702d1f6d67SPete Couperus     AdjOp = Positive ? ARC::ADD_rrlimm : ARC::SUB_rrlimm;
712d1f6d67SPete Couperus 
722d1f6d67SPete Couperus   BuildMI(MBB, MBBI, dl, TII.get(AdjOp), StackPtr)
732d1f6d67SPete Couperus       .addReg(StackPtr)
742d1f6d67SPete Couperus       .addImm(AbsAmount);
752d1f6d67SPete Couperus }
762d1f6d67SPete Couperus 
determineLastCalleeSave(ArrayRef<CalleeSavedInfo> CSI)77e4230a9fSBenjamin Kramer static unsigned determineLastCalleeSave(ArrayRef<CalleeSavedInfo> CSI) {
782d1f6d67SPete Couperus   unsigned Last = 0;
792d1f6d67SPete Couperus   for (auto Reg : CSI) {
802d1f6d67SPete Couperus     assert(Reg.getReg() >= ARC::R13 && Reg.getReg() <= ARC::R25 &&
812d1f6d67SPete Couperus            "Unexpected callee saved reg.");
822d1f6d67SPete Couperus     if (Reg.getReg() > Last)
832d1f6d67SPete Couperus       Last = Reg.getReg();
842d1f6d67SPete Couperus   }
852d1f6d67SPete Couperus   return Last;
862d1f6d67SPete Couperus }
872d1f6d67SPete Couperus 
determineCalleeSaves(MachineFunction & MF,BitVector & SavedRegs,RegScavenger * RS) const882d1f6d67SPete Couperus void ARCFrameLowering::determineCalleeSaves(MachineFunction &MF,
892d1f6d67SPete Couperus                                             BitVector &SavedRegs,
902d1f6d67SPete Couperus                                             RegScavenger *RS) const {
91d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Determine Callee Saves: " << MF.getName() << "\n");
922d1f6d67SPete Couperus   TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
932d1f6d67SPete Couperus   SavedRegs.set(ARC::BLINK);
942d1f6d67SPete Couperus }
952d1f6d67SPete Couperus 
adjustStackToMatchRecords(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,bool Allocate) const962d1f6d67SPete Couperus void ARCFrameLowering::adjustStackToMatchRecords(
972d1f6d67SPete Couperus     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
982d1f6d67SPete Couperus     bool Allocate) const {
992d1f6d67SPete Couperus   MachineFunction &MF = *MBB.getParent();
1002d1f6d67SPete Couperus   int ScalarAlloc = MF.getFrameInfo().getStackSize();
1012d1f6d67SPete Couperus 
1022d1f6d67SPete Couperus   if (Allocate) {
1032d1f6d67SPete Couperus     // Allocate by adjusting by the negative of what the record holder tracked
1042d1f6d67SPete Couperus     // it tracked a positive offset in a downward growing stack.
1052d1f6d67SPete Couperus     ScalarAlloc = -ScalarAlloc;
1062d1f6d67SPete Couperus   }
1072d1f6d67SPete Couperus 
1082d1f6d67SPete Couperus   generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), DebugLoc(),
1092d1f6d67SPete Couperus                           ScalarAlloc, ARC::SP);
1102d1f6d67SPete Couperus }
1112d1f6d67SPete Couperus 
1122d1f6d67SPete Couperus /// Insert prolog code into the function.
1132d1f6d67SPete Couperus /// For ARC, this inserts a call to a function that puts required callee saved
1142d1f6d67SPete Couperus /// registers onto the stack, when enough callee saved registers are required.
emitPrologue(MachineFunction & MF,MachineBasicBlock & MBB) const1152d1f6d67SPete Couperus void ARCFrameLowering::emitPrologue(MachineFunction &MF,
1162d1f6d67SPete Couperus                                     MachineBasicBlock &MBB) const {
117d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Emit Prologue: " << MF.getName() << "\n");
1182d1f6d67SPete Couperus   auto *AFI = MF.getInfo<ARCFunctionInfo>();
1192d1f6d67SPete Couperus   MachineModuleInfo &MMI = MF.getMMI();
1202d1f6d67SPete Couperus   MCContext &Context = MMI.getContext();
1212d1f6d67SPete Couperus   const MCRegisterInfo *MRI = Context.getRegisterInfo();
1222d1f6d67SPete Couperus   const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
1232d1f6d67SPete Couperus   MachineBasicBlock::iterator MBBI = MBB.begin();
1242d1f6d67SPete Couperus   // Debug location must be unknown since the first debug location is used
1252d1f6d67SPete Couperus   // to determine the end of the prologue.
1262d1f6d67SPete Couperus   DebugLoc dl;
1272d1f6d67SPete Couperus   MachineFrameInfo &MFI = MF.getFrameInfo();
1282d1f6d67SPete Couperus   const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
1292d1f6d67SPete Couperus   unsigned Last = determineLastCalleeSave(CSI);
1302d1f6d67SPete Couperus   unsigned StackSlotsUsedByFunclet = 0;
1312d1f6d67SPete Couperus   bool SavedBlink = false;
1322d1f6d67SPete Couperus   unsigned AlreadyAdjusted = 0;
133f1caa283SMatthias Braun   if (MF.getFunction().isVarArg()) {
1342d1f6d67SPete Couperus     // Add in the varargs area here first.
135d34e60caSNicola Zaghen     LLVM_DEBUG(dbgs() << "Varargs\n");
1362d1f6d67SPete Couperus     unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex());
137225c0bd6SPete Couperus     unsigned Opc = ARC::SUB_rrlimm;
138225c0bd6SPete Couperus     if (isUInt<6>(VarArgsBytes))
139225c0bd6SPete Couperus       Opc = ARC::SUB_rru6;
140225c0bd6SPete Couperus     else if (isInt<12>(VarArgsBytes))
141225c0bd6SPete Couperus       Opc = ARC::SUB_rrs12;
142225c0bd6SPete Couperus     BuildMI(MBB, MBBI, dl, TII->get(Opc), ARC::SP)
1432d1f6d67SPete Couperus         .addReg(ARC::SP)
1442d1f6d67SPete Couperus         .addImm(VarArgsBytes);
1452d1f6d67SPete Couperus   }
1462d1f6d67SPete Couperus   if (hasFP(MF)) {
147d34e60caSNicola Zaghen     LLVM_DEBUG(dbgs() << "Saving FP\n");
1482d1f6d67SPete Couperus     BuildMI(MBB, MBBI, dl, TII->get(ARC::ST_AW_rs9))
1492d1f6d67SPete Couperus         .addReg(ARC::SP, RegState::Define)
1502d1f6d67SPete Couperus         .addReg(ARC::FP)
1512d1f6d67SPete Couperus         .addReg(ARC::SP)
1522d1f6d67SPete Couperus         .addImm(-4);
1532d1f6d67SPete Couperus     AlreadyAdjusted += 4;
1542d1f6d67SPete Couperus   }
1552d1f6d67SPete Couperus   if (UseSaveRestoreFunclet && Last > ARC::R14) {
156d34e60caSNicola Zaghen     LLVM_DEBUG(dbgs() << "Creating store funclet.\n");
1572d1f6d67SPete Couperus     // BL to __save_r13_to_<TRI->getRegAsmName()>
1582d1f6d67SPete Couperus     StackSlotsUsedByFunclet = Last - ARC::R12;
1592d1f6d67SPete Couperus     BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK));
1602d1f6d67SPete Couperus     BuildMI(MBB, MBBI, dl, TII->get(ARC::SUB_rru6))
1612d1f6d67SPete Couperus         .addReg(ARC::SP)
1622d1f6d67SPete Couperus         .addReg(ARC::SP)
1632d1f6d67SPete Couperus         .addImm(4 * StackSlotsUsedByFunclet);
1642d1f6d67SPete Couperus     BuildMI(MBB, MBBI, dl, TII->get(ARC::BL))
1652d1f6d67SPete Couperus         .addExternalSymbol(store_funclet_name[Last - ARC::R15])
1662d1f6d67SPete Couperus         .addReg(ARC::BLINK, RegState::Implicit | RegState::Kill);
1672d1f6d67SPete Couperus     AlreadyAdjusted += 4 * (StackSlotsUsedByFunclet + 1);
1682d1f6d67SPete Couperus     SavedBlink = true;
1692d1f6d67SPete Couperus   }
1702d1f6d67SPete Couperus   // If we haven't saved BLINK, but we need to...do that now.
1712d1f6d67SPete Couperus   if (MFI.hasCalls() && !SavedBlink) {
172d34e60caSNicola Zaghen     LLVM_DEBUG(dbgs() << "Creating save blink.\n");
1732d1f6d67SPete Couperus     BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK));
1742d1f6d67SPete Couperus     AlreadyAdjusted += 4;
1752d1f6d67SPete Couperus   }
1762d1f6d67SPete Couperus   if (AFI->MaxCallStackReq > 0)
1772d1f6d67SPete Couperus     MFI.setStackSize(MFI.getStackSize() + AFI->MaxCallStackReq);
1782d1f6d67SPete Couperus   // We have already saved some of the stack...
179d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Adjusting stack by: "
1802d1f6d67SPete Couperus                     << (MFI.getStackSize() - AlreadyAdjusted) << "\n");
1812d1f6d67SPete Couperus   generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), dl,
1822d1f6d67SPete Couperus                           -(MFI.getStackSize() - AlreadyAdjusted), ARC::SP);
1832d1f6d67SPete Couperus 
1842d1f6d67SPete Couperus   if (hasFP(MF)) {
185d34e60caSNicola Zaghen     LLVM_DEBUG(dbgs() << "Setting FP from SP.\n");
1862d1f6d67SPete Couperus     BuildMI(MBB, MBBI, dl,
1872d1f6d67SPete Couperus             TII->get(isUInt<6>(MFI.getStackSize()) ? ARC::ADD_rru6
1882d1f6d67SPete Couperus                                                    : ARC::ADD_rrlimm),
1892d1f6d67SPete Couperus             ARC::FP)
1902d1f6d67SPete Couperus         .addReg(ARC::SP)
1912d1f6d67SPete Couperus         .addImm(MFI.getStackSize());
1922d1f6d67SPete Couperus   }
1932d1f6d67SPete Couperus 
1942d1f6d67SPete Couperus   // Emit CFI records:
1952d1f6d67SPete Couperus   // .cfi_def_cfa_offset StackSize
1962d1f6d67SPete Couperus   // .cfi_offset fp, -StackSize
1972d1f6d67SPete Couperus   // .cfi_offset blink, -StackSize+4
1982d1f6d67SPete Couperus   unsigned CFIIndex = MF.addFrameInst(
1990840d725SFangrui Song       MCCFIInstruction::cfiDefCfaOffset(nullptr, MFI.getStackSize()));
2002d1f6d67SPete Couperus   BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
2012d1f6d67SPete Couperus       .addCFIIndex(CFIIndex)
2022d1f6d67SPete Couperus       .setMIFlags(MachineInstr::FrameSetup);
2032d1f6d67SPete Couperus 
2042d1f6d67SPete Couperus   int CurOffset = -4;
2052d1f6d67SPete Couperus   if (hasFP(MF)) {
2062d1f6d67SPete Couperus     CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
2072d1f6d67SPete Couperus         nullptr, MRI->getDwarfRegNum(ARC::FP, true), CurOffset));
2082d1f6d67SPete Couperus     BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
2092d1f6d67SPete Couperus         .addCFIIndex(CFIIndex)
2102d1f6d67SPete Couperus         .setMIFlags(MachineInstr::FrameSetup);
2112d1f6d67SPete Couperus     CurOffset -= 4;
2122d1f6d67SPete Couperus   }
2132d1f6d67SPete Couperus 
2142d1f6d67SPete Couperus   if (MFI.hasCalls()) {
2152d1f6d67SPete Couperus     CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
2162d1f6d67SPete Couperus         nullptr, MRI->getDwarfRegNum(ARC::BLINK, true), CurOffset));
2172d1f6d67SPete Couperus     BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
2182d1f6d67SPete Couperus         .addCFIIndex(CFIIndex)
2192d1f6d67SPete Couperus         .setMIFlags(MachineInstr::FrameSetup);
2202d1f6d67SPete Couperus   }
2212d1f6d67SPete Couperus   // CFI for the rest of the registers.
2222d1f6d67SPete Couperus   for (const auto &Entry : CSI) {
2232d1f6d67SPete Couperus     unsigned Reg = Entry.getReg();
2242d1f6d67SPete Couperus     int FI = Entry.getFrameIdx();
2252d1f6d67SPete Couperus     // Skip BLINK and FP.
2262d1f6d67SPete Couperus     if ((hasFP(MF) && Reg == ARC::FP) || (MFI.hasCalls() && Reg == ARC::BLINK))
2272d1f6d67SPete Couperus       continue;
2282d1f6d67SPete Couperus     CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
2292d1f6d67SPete Couperus         nullptr, MRI->getDwarfRegNum(Reg, true), MFI.getObjectOffset(FI)));
2302d1f6d67SPete Couperus     BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
2312d1f6d67SPete Couperus         .addCFIIndex(CFIIndex)
2322d1f6d67SPete Couperus         .setMIFlags(MachineInstr::FrameSetup);
2332d1f6d67SPete Couperus   }
2342d1f6d67SPete Couperus }
2352d1f6d67SPete Couperus 
2362d1f6d67SPete Couperus /// Insert epilog code into the function.
2372d1f6d67SPete Couperus /// For ARC, this inserts a call to a function that restores callee saved
2382d1f6d67SPete Couperus /// registers onto the stack, when enough callee saved registers are required.
emitEpilogue(MachineFunction & MF,MachineBasicBlock & MBB) const2392d1f6d67SPete Couperus void ARCFrameLowering::emitEpilogue(MachineFunction &MF,
2402d1f6d67SPete Couperus                                     MachineBasicBlock &MBB) const {
241d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Emit Epilogue: " << MF.getName() << "\n");
2422d1f6d67SPete Couperus   auto *AFI = MF.getInfo<ARCFunctionInfo>();
2432d1f6d67SPete Couperus   const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
2442d1f6d67SPete Couperus   MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
2452d1f6d67SPete Couperus   MachineFrameInfo &MFI = MF.getFrameInfo();
2462d1f6d67SPete Couperus   uint64_t StackSize = MF.getFrameInfo().getStackSize();
2472d1f6d67SPete Couperus   bool SavedBlink = false;
2482d1f6d67SPete Couperus   unsigned AmountAboveFunclet = 0;
2492d1f6d67SPete Couperus   // If we have variable sized frame objects, then we have to move
2502d1f6d67SPete Couperus   // the stack pointer to a known spot (fp - StackSize).
2512d1f6d67SPete Couperus   // Then, replace the frame pointer by (new) [sp,StackSize-4].
2522d1f6d67SPete Couperus   // Then, move the stack pointer the rest of the way (sp = sp + StackSize).
2532d1f6d67SPete Couperus   if (hasFP(MF)) {
254225c0bd6SPete Couperus     unsigned Opc = ARC::SUB_rrlimm;
255225c0bd6SPete Couperus     if (isUInt<6>(StackSize))
256225c0bd6SPete Couperus       Opc = ARC::SUB_rru6;
257225c0bd6SPete Couperus     BuildMI(MBB, MBBI, DebugLoc(), TII->get(Opc), ARC::SP)
2582d1f6d67SPete Couperus         .addReg(ARC::FP)
2592d1f6d67SPete Couperus         .addImm(StackSize);
2602d1f6d67SPete Couperus     AmountAboveFunclet += 4;
2612d1f6d67SPete Couperus   }
2622d1f6d67SPete Couperus 
2632d1f6d67SPete Couperus   // Now, move the stack pointer to the bottom of the save area for the funclet.
2642d1f6d67SPete Couperus   const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
2652d1f6d67SPete Couperus   unsigned Last = determineLastCalleeSave(CSI);
2662d1f6d67SPete Couperus   unsigned StackSlotsUsedByFunclet = 0;
2672d1f6d67SPete Couperus   // Now, restore the callee save registers.
2682d1f6d67SPete Couperus   if (UseSaveRestoreFunclet && Last > ARC::R14) {
2692d1f6d67SPete Couperus     // BL to __ld_r13_to_<TRI->getRegAsmName()>
2702d1f6d67SPete Couperus     StackSlotsUsedByFunclet = Last - ARC::R12;
2712d1f6d67SPete Couperus     AmountAboveFunclet += 4 * (StackSlotsUsedByFunclet + 1);
2722d1f6d67SPete Couperus     SavedBlink = true;
2732d1f6d67SPete Couperus   }
2742d1f6d67SPete Couperus 
2752d1f6d67SPete Couperus   if (MFI.hasCalls() && !SavedBlink) {
2762d1f6d67SPete Couperus     AmountAboveFunclet += 4;
2772d1f6d67SPete Couperus     SavedBlink = true;
2782d1f6d67SPete Couperus   }
2792d1f6d67SPete Couperus 
2802d1f6d67SPete Couperus   // Move the stack pointer up to the point of the funclet.
281225c0bd6SPete Couperus   if (unsigned MoveAmount = StackSize - AmountAboveFunclet) {
282225c0bd6SPete Couperus     unsigned Opc = ARC::ADD_rrlimm;
283225c0bd6SPete Couperus     if (isUInt<6>(MoveAmount))
284225c0bd6SPete Couperus       Opc = ARC::ADD_rru6;
285225c0bd6SPete Couperus     else if (isInt<12>(MoveAmount))
286225c0bd6SPete Couperus       Opc = ARC::ADD_rrs12;
287225c0bd6SPete Couperus     BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc), ARC::SP)
2882d1f6d67SPete Couperus         .addReg(ARC::SP)
2892d1f6d67SPete Couperus         .addImm(StackSize - AmountAboveFunclet);
2902d1f6d67SPete Couperus   }
2912d1f6d67SPete Couperus 
2922d1f6d67SPete Couperus   if (StackSlotsUsedByFunclet) {
293225c0bd6SPete Couperus     // This part of the adjustment will always be < 64 bytes.
2942d1f6d67SPete Couperus     BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::BL))
2952d1f6d67SPete Couperus         .addExternalSymbol(load_funclet_name[Last - ARC::R15])
2962d1f6d67SPete Couperus         .addReg(ARC::BLINK, RegState::Implicit | RegState::Kill);
297225c0bd6SPete Couperus     unsigned Opc = ARC::ADD_rrlimm;
298225c0bd6SPete Couperus     if (isUInt<6>(4 * StackSlotsUsedByFunclet))
299225c0bd6SPete Couperus       Opc = ARC::ADD_rru6;
300225c0bd6SPete Couperus     else if (isInt<12>(4 * StackSlotsUsedByFunclet))
301225c0bd6SPete Couperus       Opc = ARC::ADD_rrs12;
302225c0bd6SPete Couperus     BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc), ARC::SP)
3032d1f6d67SPete Couperus         .addReg(ARC::SP)
3042d1f6d67SPete Couperus         .addImm(4 * (StackSlotsUsedByFunclet));
3052d1f6d67SPete Couperus   }
3062d1f6d67SPete Couperus   // Now, pop blink if necessary.
3072d1f6d67SPete Couperus   if (SavedBlink) {
3082d1f6d67SPete Couperus     BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::POP_S_BLINK));
3092d1f6d67SPete Couperus   }
3102d1f6d67SPete Couperus   // Now, pop fp if necessary.
3112d1f6d67SPete Couperus   if (hasFP(MF)) {
3122d1f6d67SPete Couperus     BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::LD_AB_rs9))
3132d1f6d67SPete Couperus         .addReg(ARC::FP, RegState::Define)
314b062239dSPete Couperus         .addReg(ARC::SP, RegState::Define)
3152d1f6d67SPete Couperus         .addReg(ARC::SP)
3162d1f6d67SPete Couperus         .addImm(4);
3172d1f6d67SPete Couperus   }
3182d1f6d67SPete Couperus 
3192d1f6d67SPete Couperus   // Relieve the varargs area if necessary.
320f1caa283SMatthias Braun   if (MF.getFunction().isVarArg()) {
3212d1f6d67SPete Couperus     // Add in the varargs area here first.
322d34e60caSNicola Zaghen     LLVM_DEBUG(dbgs() << "Varargs\n");
3232d1f6d67SPete Couperus     unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex());
324225c0bd6SPete Couperus     unsigned Opc = ARC::ADD_rrlimm;
325225c0bd6SPete Couperus     if (isUInt<6>(VarArgsBytes))
326225c0bd6SPete Couperus       Opc = ARC::ADD_rru6;
327225c0bd6SPete Couperus     else if (isInt<12>(VarArgsBytes))
328225c0bd6SPete Couperus       Opc = ARC::ADD_rrs12;
329225c0bd6SPete Couperus     BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc))
3302d1f6d67SPete Couperus         .addReg(ARC::SP)
3312d1f6d67SPete Couperus         .addReg(ARC::SP)
3322d1f6d67SPete Couperus         .addImm(VarArgsBytes);
3332d1f6d67SPete Couperus   }
3342d1f6d67SPete Couperus }
3352d1f6d67SPete Couperus 
3362d1f6d67SPete Couperus static std::vector<CalleeSavedInfo>::iterator
getSavedReg(std::vector<CalleeSavedInfo> & V,unsigned reg)3372d1f6d67SPete Couperus getSavedReg(std::vector<CalleeSavedInfo> &V, unsigned reg) {
3382d1f6d67SPete Couperus   for (auto I = V.begin(), E = V.end(); I != E; ++I) {
3392d1f6d67SPete Couperus     if (reg == I->getReg())
3402d1f6d67SPete Couperus       return I;
3412d1f6d67SPete Couperus   }
3422d1f6d67SPete Couperus   return V.end();
3432d1f6d67SPete Couperus }
3442d1f6d67SPete Couperus 
assignCalleeSavedSpillSlots(MachineFunction & MF,const TargetRegisterInfo * TRI,std::vector<CalleeSavedInfo> & CSI) const3452d1f6d67SPete Couperus bool ARCFrameLowering::assignCalleeSavedSpillSlots(
3462d1f6d67SPete Couperus     MachineFunction &MF, const TargetRegisterInfo *TRI,
3472d1f6d67SPete Couperus     std::vector<CalleeSavedInfo> &CSI) const {
3482d1f6d67SPete Couperus   // Use this opportunity to assign the spill slots for all of the potential
3492d1f6d67SPete Couperus   // callee save registers (blink, fp, r13->r25) that we care about the
3502d1f6d67SPete Couperus   // placement for.  We can calculate all of that data here.
3512d1f6d67SPete Couperus   int CurOffset = -4;
3522d1f6d67SPete Couperus   unsigned Last = determineLastCalleeSave(CSI);
3532d1f6d67SPete Couperus   MachineFrameInfo &MFI = MF.getFrameInfo();
3542d1f6d67SPete Couperus   if (hasFP(MF)) {
3552d1f6d67SPete Couperus     // Create a fixed slot at for FP
3562d1f6d67SPete Couperus     int StackObj = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
357d34e60caSNicola Zaghen     LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj << ") for FP at "
3582d1f6d67SPete Couperus                       << CurOffset << "\n");
3592d1f6d67SPete Couperus     (void)StackObj;
3602d1f6d67SPete Couperus     CurOffset -= 4;
3612d1f6d67SPete Couperus   }
3622d1f6d67SPete Couperus   if (MFI.hasCalls() || (UseSaveRestoreFunclet && Last > ARC::R14)) {
3632d1f6d67SPete Couperus     // Create a fixed slot for BLINK.
3642d1f6d67SPete Couperus     int StackObj  = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
365d34e60caSNicola Zaghen     LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj
366d34e60caSNicola Zaghen                       << ") for BLINK at " << CurOffset << "\n");
3672d1f6d67SPete Couperus     (void)StackObj;
3682d1f6d67SPete Couperus     CurOffset -= 4;
3692d1f6d67SPete Couperus   }
3702d1f6d67SPete Couperus 
3712d1f6d67SPete Couperus   // Create slots for last down to r13.
3722d1f6d67SPete Couperus   for (unsigned Which = Last; Which > ARC::R12; Which--) {
3732d1f6d67SPete Couperus     auto RegI = getSavedReg(CSI, Which);
3742d1f6d67SPete Couperus     if (RegI == CSI.end() || RegI->getFrameIdx() == 0) {
3752d1f6d67SPete Couperus       // Always create the stack slot.  If for some reason the register isn't in
3762d1f6d67SPete Couperus       // the save list, then don't worry about it.
3772d1f6d67SPete Couperus       int FI = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
3782d1f6d67SPete Couperus       if (RegI != CSI.end())
3792d1f6d67SPete Couperus         RegI->setFrameIdx(FI);
3802d1f6d67SPete Couperus     } else
3812d1f6d67SPete Couperus       MFI.setObjectOffset(RegI->getFrameIdx(), CurOffset);
3822d1f6d67SPete Couperus     CurOffset -= 4;
3832d1f6d67SPete Couperus   }
3842d1f6d67SPete Couperus   for (auto &I : CSI) {
3852d1f6d67SPete Couperus     if (I.getReg() > ARC::R12)
3862d1f6d67SPete Couperus       continue;
3872d1f6d67SPete Couperus     if (I.getFrameIdx() == 0) {
3882d1f6d67SPete Couperus       I.setFrameIdx(MFI.CreateFixedSpillStackObject(4, CurOffset, true));
389d34e60caSNicola Zaghen       LLVM_DEBUG(dbgs() << "Creating fixed object (" << I.getFrameIdx()
3902d1f6d67SPete Couperus                         << ") for other register at " << CurOffset << "\n");
3912d1f6d67SPete Couperus     } else {
3922d1f6d67SPete Couperus       MFI.setObjectOffset(I.getFrameIdx(), CurOffset);
393d34e60caSNicola Zaghen       LLVM_DEBUG(dbgs() << "Updating fixed object (" << I.getFrameIdx()
3942d1f6d67SPete Couperus                         << ") for other register at " << CurOffset << "\n");
3952d1f6d67SPete Couperus     }
3962d1f6d67SPete Couperus     CurOffset -= 4;
3972d1f6d67SPete Couperus   }
3982d1f6d67SPete Couperus   return true;
3992d1f6d67SPete Couperus }
4002d1f6d67SPete Couperus 
spillCalleeSavedRegisters(MachineBasicBlock & MBB,MachineBasicBlock::iterator MI,ArrayRef<CalleeSavedInfo> CSI,const TargetRegisterInfo * TRI) const4012d1f6d67SPete Couperus bool ARCFrameLowering::spillCalleeSavedRegisters(
4022d1f6d67SPete Couperus     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
403e4230a9fSBenjamin Kramer     ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
404d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Spill callee saved registers: "
405f1caa283SMatthias Braun                     << MBB.getParent()->getName() << "\n");
4062d1f6d67SPete Couperus   // There are routines for saving at least 3 registers (r13 to r15, etc.)
4072d1f6d67SPete Couperus   unsigned Last = determineLastCalleeSave(CSI);
4082d1f6d67SPete Couperus   if (UseSaveRestoreFunclet && Last > ARC::R14) {
4092d1f6d67SPete Couperus     // Use setObjectOffset for these registers.
4102d1f6d67SPete Couperus     // Needs to be in or before processFunctionBeforeFrameFinalized.
4112d1f6d67SPete Couperus     // Or, do assignCalleeSaveSpillSlots?
4122d1f6d67SPete Couperus     // Will be handled in prolog.
4132d1f6d67SPete Couperus     return true;
4142d1f6d67SPete Couperus   }
4152d1f6d67SPete Couperus   return false;
4162d1f6d67SPete Couperus }
4172d1f6d67SPete Couperus 
restoreCalleeSavedRegisters(MachineBasicBlock & MBB,MachineBasicBlock::iterator MI,MutableArrayRef<CalleeSavedInfo> CSI,const TargetRegisterInfo * TRI) const4182d1f6d67SPete Couperus bool ARCFrameLowering::restoreCalleeSavedRegisters(
4192d1f6d67SPete Couperus     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
420186dd631SBenjamin Kramer     MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
421d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Restore callee saved registers: "
422f1caa283SMatthias Braun                     << MBB.getParent()->getName() << "\n");
4232d1f6d67SPete Couperus   // There are routines for saving at least 3 registers (r13 to r15, etc.)
4242d1f6d67SPete Couperus   unsigned Last = determineLastCalleeSave(CSI);
4252d1f6d67SPete Couperus   if (UseSaveRestoreFunclet && Last > ARC::R14) {
4262d1f6d67SPete Couperus     // Will be handled in epilog.
4272d1f6d67SPete Couperus     return true;
4282d1f6d67SPete Couperus   }
4292d1f6d67SPete Couperus   return false;
4302d1f6d67SPete Couperus }
4312d1f6d67SPete Couperus 
4322d1f6d67SPete Couperus // Adjust local variables that are 4-bytes or larger to 4-byte boundary
processFunctionBeforeFrameFinalized(MachineFunction & MF,RegScavenger * RS) const4332d1f6d67SPete Couperus void ARCFrameLowering::processFunctionBeforeFrameFinalized(
4342d1f6d67SPete Couperus     MachineFunction &MF, RegScavenger *RS) const {
4352d1f6d67SPete Couperus   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
436d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Process function before frame finalized: "
437f1caa283SMatthias Braun                     << MF.getName() << "\n");
4382d1f6d67SPete Couperus   MachineFrameInfo &MFI = MF.getFrameInfo();
439d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Current stack size: " << MFI.getStackSize() << "\n");
4402d1f6d67SPete Couperus   const TargetRegisterClass *RC = &ARC::GPR32RegClass;
4412d1f6d67SPete Couperus   if (MFI.hasStackObjects()) {
44228de229bSGuillaume Chatelet     int RegScavFI = MFI.CreateStackObject(RegInfo->getSpillSize(*RC),
44328de229bSGuillaume Chatelet                                           RegInfo->getSpillAlign(*RC), false);
4442d1f6d67SPete Couperus     RS->addScavengingFrameIndex(RegScavFI);
445d34e60caSNicola Zaghen     LLVM_DEBUG(dbgs() << "Created scavenging index RegScavFI=" << RegScavFI
446d34e60caSNicola Zaghen                       << "\n");
4472d1f6d67SPete Couperus   }
4482d1f6d67SPete Couperus }
4492d1f6d67SPete Couperus 
emitRegUpdate(MachineBasicBlock & MBB,MachineBasicBlock::iterator & MBBI,DebugLoc dl,unsigned Reg,int NumBytes,bool IsAdd,const ARCInstrInfo * TII)4502d1f6d67SPete Couperus static void emitRegUpdate(MachineBasicBlock &MBB,
4512d1f6d67SPete Couperus                           MachineBasicBlock::iterator &MBBI, DebugLoc dl,
4522d1f6d67SPete Couperus                           unsigned Reg, int NumBytes, bool IsAdd,
4532d1f6d67SPete Couperus                           const ARCInstrInfo *TII) {
454225c0bd6SPete Couperus   unsigned Opc;
455225c0bd6SPete Couperus   if (isUInt<6>(NumBytes))
456225c0bd6SPete Couperus     Opc = IsAdd ? ARC::ADD_rru6 : ARC::SUB_rru6;
457225c0bd6SPete Couperus   else if (isInt<12>(NumBytes))
458225c0bd6SPete Couperus     Opc = IsAdd ? ARC::ADD_rrs12 : ARC::SUB_rrs12;
459225c0bd6SPete Couperus   else
460225c0bd6SPete Couperus     Opc = IsAdd ? ARC::ADD_rrlimm : ARC::SUB_rrlimm;
461225c0bd6SPete Couperus 
4622d1f6d67SPete Couperus   BuildMI(MBB, MBBI, dl, TII->get(Opc), Reg)
4632d1f6d67SPete Couperus       .addReg(Reg, RegState::Kill)
4642d1f6d67SPete Couperus       .addImm(NumBytes);
4652d1f6d67SPete Couperus }
4662d1f6d67SPete Couperus 
eliminateCallFramePseudoInstr(MachineFunction & MF,MachineBasicBlock & MBB,MachineBasicBlock::iterator I) const4672d1f6d67SPete Couperus MachineBasicBlock::iterator ARCFrameLowering::eliminateCallFramePseudoInstr(
4682d1f6d67SPete Couperus     MachineFunction &MF, MachineBasicBlock &MBB,
4692d1f6d67SPete Couperus     MachineBasicBlock::iterator I) const {
470d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "EmitCallFramePseudo: " << MF.getName() << "\n");
4712d1f6d67SPete Couperus   const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
4722d1f6d67SPete Couperus   MachineInstr &Old = *I;
4732d1f6d67SPete Couperus   DebugLoc dl = Old.getDebugLoc();
4742d1f6d67SPete Couperus   unsigned Amt = Old.getOperand(0).getImm();
4752d1f6d67SPete Couperus   auto *AFI = MF.getInfo<ARCFunctionInfo>();
4762d1f6d67SPete Couperus   if (!hasFP(MF)) {
4772d1f6d67SPete Couperus     if (Amt > AFI->MaxCallStackReq && Old.getOpcode() == ARC::ADJCALLSTACKDOWN)
4782d1f6d67SPete Couperus       AFI->MaxCallStackReq = Amt;
4792d1f6d67SPete Couperus   } else {
4802d1f6d67SPete Couperus     if (Amt != 0) {
4812d1f6d67SPete Couperus       assert((Old.getOpcode() == ARC::ADJCALLSTACKDOWN ||
4822d1f6d67SPete Couperus               Old.getOpcode() == ARC::ADJCALLSTACKUP) &&
4832d1f6d67SPete Couperus              "Unknown Frame Pseudo.");
4842d1f6d67SPete Couperus       bool IsAdd = (Old.getOpcode() == ARC::ADJCALLSTACKUP);
4852d1f6d67SPete Couperus       emitRegUpdate(MBB, I, dl, ARC::SP, Amt, IsAdd, TII);
4862d1f6d67SPete Couperus     }
4872d1f6d67SPete Couperus   }
4882d1f6d67SPete Couperus   return MBB.erase(I);
4892d1f6d67SPete Couperus }
4902d1f6d67SPete Couperus 
hasFP(const MachineFunction & MF) const4912d1f6d67SPete Couperus bool ARCFrameLowering::hasFP(const MachineFunction &MF) const {
4922d1f6d67SPete Couperus   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
4932d1f6d67SPete Couperus   bool HasFP = MF.getTarget().Options.DisableFramePointerElim(MF) ||
4942d1f6d67SPete Couperus                MF.getFrameInfo().hasVarSizedObjects() ||
4952d1f6d67SPete Couperus                MF.getFrameInfo().isFrameAddressTaken() ||
496*a9968c0aSTomas Matheson                RegInfo->hasStackRealignment(MF);
4972d1f6d67SPete Couperus   return HasFP;
4982d1f6d67SPete Couperus }
499