106f32e7eSjoerg //===- ARCFrameLowering.cpp - ARC Frame Information -------------*- C++ -*-===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg // This file contains the ARC implementation of the TargetFrameLowering class.
1006f32e7eSjoerg //
1106f32e7eSjoerg //===----------------------------------------------------------------------===//
1206f32e7eSjoerg 
1306f32e7eSjoerg #include "ARCFrameLowering.h"
1406f32e7eSjoerg #include "ARCMachineFunctionInfo.h"
1506f32e7eSjoerg #include "ARCSubtarget.h"
1606f32e7eSjoerg #include "llvm/CodeGen/MachineInstrBuilder.h"
1706f32e7eSjoerg #include "llvm/CodeGen/MachineModuleInfo.h"
1806f32e7eSjoerg #include "llvm/CodeGen/RegisterScavenging.h"
1906f32e7eSjoerg #include "llvm/CodeGen/TargetRegisterInfo.h"
2006f32e7eSjoerg #include "llvm/IR/Function.h"
2106f32e7eSjoerg #include "llvm/Support/Debug.h"
2206f32e7eSjoerg 
2306f32e7eSjoerg #define DEBUG_TYPE "arc-frame-lowering"
2406f32e7eSjoerg 
2506f32e7eSjoerg using namespace llvm;
2606f32e7eSjoerg 
2706f32e7eSjoerg static cl::opt<bool>
2806f32e7eSjoerg     UseSaveRestoreFunclet("arc-save-restore-funclet", cl::Hidden,
2906f32e7eSjoerg                           cl::desc("Use arc callee save/restore functions"),
3006f32e7eSjoerg                           cl::init(true));
3106f32e7eSjoerg 
3206f32e7eSjoerg static const char *store_funclet_name[] = {
3306f32e7eSjoerg     "__st_r13_to_r15", "__st_r13_to_r16", "__st_r13_to_r17", "__st_r13_to_r18",
3406f32e7eSjoerg     "__st_r13_to_r19", "__st_r13_to_r20", "__st_r13_to_r21", "__st_r13_to_r22",
3506f32e7eSjoerg     "__st_r13_to_r23", "__st_r13_to_r24", "__st_r13_to_r25",
3606f32e7eSjoerg };
3706f32e7eSjoerg 
3806f32e7eSjoerg static const char *load_funclet_name[] = {
3906f32e7eSjoerg     "__ld_r13_to_r15", "__ld_r13_to_r16", "__ld_r13_to_r17", "__ld_r13_to_r18",
4006f32e7eSjoerg     "__ld_r13_to_r19", "__ld_r13_to_r20", "__ld_r13_to_r21", "__ld_r13_to_r22",
4106f32e7eSjoerg     "__ld_r13_to_r23", "__ld_r13_to_r24", "__ld_r13_to_r25",
4206f32e7eSjoerg };
4306f32e7eSjoerg 
generateStackAdjustment(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,const ARCInstrInfo & TII,DebugLoc dl,int Amount,int StackPtr)4406f32e7eSjoerg static void generateStackAdjustment(MachineBasicBlock &MBB,
4506f32e7eSjoerg                                     MachineBasicBlock::iterator MBBI,
4606f32e7eSjoerg                                     const ARCInstrInfo &TII, DebugLoc dl,
4706f32e7eSjoerg                                     int Amount, int StackPtr) {
4806f32e7eSjoerg   unsigned AdjOp;
4906f32e7eSjoerg   if (!Amount)
5006f32e7eSjoerg     return;
5106f32e7eSjoerg   bool Positive;
5206f32e7eSjoerg   unsigned AbsAmount;
5306f32e7eSjoerg   if (Amount < 0) {
5406f32e7eSjoerg     AbsAmount = -Amount;
5506f32e7eSjoerg     Positive = false;
5606f32e7eSjoerg   } else {
5706f32e7eSjoerg     AbsAmount = Amount;
5806f32e7eSjoerg     Positive = true;
5906f32e7eSjoerg   }
6006f32e7eSjoerg 
6106f32e7eSjoerg   LLVM_DEBUG(dbgs() << "Internal: adjust stack by: " << Amount << ","
6206f32e7eSjoerg                     << AbsAmount << "\n");
6306f32e7eSjoerg 
6406f32e7eSjoerg   assert((AbsAmount % 4 == 0) && "Stack adjustments must be 4-byte aligned.");
6506f32e7eSjoerg   if (isUInt<6>(AbsAmount))
6606f32e7eSjoerg     AdjOp = Positive ? ARC::ADD_rru6 : ARC::SUB_rru6;
6706f32e7eSjoerg   else if (isInt<12>(AbsAmount))
6806f32e7eSjoerg     AdjOp = Positive ? ARC::ADD_rrs12 : ARC::SUB_rrs12;
6906f32e7eSjoerg   else
7006f32e7eSjoerg     AdjOp = Positive ? ARC::ADD_rrlimm : ARC::SUB_rrlimm;
7106f32e7eSjoerg 
7206f32e7eSjoerg   BuildMI(MBB, MBBI, dl, TII.get(AdjOp), StackPtr)
7306f32e7eSjoerg       .addReg(StackPtr)
7406f32e7eSjoerg       .addImm(AbsAmount);
7506f32e7eSjoerg }
7606f32e7eSjoerg 
determineLastCalleeSave(ArrayRef<CalleeSavedInfo> CSI)77*da58b97aSjoerg static unsigned determineLastCalleeSave(ArrayRef<CalleeSavedInfo> CSI) {
7806f32e7eSjoerg   unsigned Last = 0;
7906f32e7eSjoerg   for (auto Reg : CSI) {
8006f32e7eSjoerg     assert(Reg.getReg() >= ARC::R13 && Reg.getReg() <= ARC::R25 &&
8106f32e7eSjoerg            "Unexpected callee saved reg.");
8206f32e7eSjoerg     if (Reg.getReg() > Last)
8306f32e7eSjoerg       Last = Reg.getReg();
8406f32e7eSjoerg   }
8506f32e7eSjoerg   return Last;
8606f32e7eSjoerg }
8706f32e7eSjoerg 
determineCalleeSaves(MachineFunction & MF,BitVector & SavedRegs,RegScavenger * RS) const8806f32e7eSjoerg void ARCFrameLowering::determineCalleeSaves(MachineFunction &MF,
8906f32e7eSjoerg                                             BitVector &SavedRegs,
9006f32e7eSjoerg                                             RegScavenger *RS) const {
9106f32e7eSjoerg   LLVM_DEBUG(dbgs() << "Determine Callee Saves: " << MF.getName() << "\n");
9206f32e7eSjoerg   TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
9306f32e7eSjoerg   SavedRegs.set(ARC::BLINK);
9406f32e7eSjoerg }
9506f32e7eSjoerg 
adjustStackToMatchRecords(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,bool Allocate) const9606f32e7eSjoerg void ARCFrameLowering::adjustStackToMatchRecords(
9706f32e7eSjoerg     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
9806f32e7eSjoerg     bool Allocate) const {
9906f32e7eSjoerg   MachineFunction &MF = *MBB.getParent();
10006f32e7eSjoerg   int ScalarAlloc = MF.getFrameInfo().getStackSize();
10106f32e7eSjoerg 
10206f32e7eSjoerg   if (Allocate) {
10306f32e7eSjoerg     // Allocate by adjusting by the negative of what the record holder tracked
10406f32e7eSjoerg     // it tracked a positive offset in a downward growing stack.
10506f32e7eSjoerg     ScalarAlloc = -ScalarAlloc;
10606f32e7eSjoerg   }
10706f32e7eSjoerg 
10806f32e7eSjoerg   generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), DebugLoc(),
10906f32e7eSjoerg                           ScalarAlloc, ARC::SP);
11006f32e7eSjoerg }
11106f32e7eSjoerg 
11206f32e7eSjoerg /// Insert prolog code into the function.
11306f32e7eSjoerg /// For ARC, this inserts a call to a function that puts required callee saved
11406f32e7eSjoerg /// registers onto the stack, when enough callee saved registers are required.
emitPrologue(MachineFunction & MF,MachineBasicBlock & MBB) const11506f32e7eSjoerg void ARCFrameLowering::emitPrologue(MachineFunction &MF,
11606f32e7eSjoerg                                     MachineBasicBlock &MBB) const {
11706f32e7eSjoerg   LLVM_DEBUG(dbgs() << "Emit Prologue: " << MF.getName() << "\n");
11806f32e7eSjoerg   auto *AFI = MF.getInfo<ARCFunctionInfo>();
11906f32e7eSjoerg   MachineModuleInfo &MMI = MF.getMMI();
12006f32e7eSjoerg   MCContext &Context = MMI.getContext();
12106f32e7eSjoerg   const MCRegisterInfo *MRI = Context.getRegisterInfo();
12206f32e7eSjoerg   const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
12306f32e7eSjoerg   MachineBasicBlock::iterator MBBI = MBB.begin();
12406f32e7eSjoerg   // Debug location must be unknown since the first debug location is used
12506f32e7eSjoerg   // to determine the end of the prologue.
12606f32e7eSjoerg   DebugLoc dl;
12706f32e7eSjoerg   MachineFrameInfo &MFI = MF.getFrameInfo();
12806f32e7eSjoerg   const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
12906f32e7eSjoerg   unsigned Last = determineLastCalleeSave(CSI);
13006f32e7eSjoerg   unsigned StackSlotsUsedByFunclet = 0;
13106f32e7eSjoerg   bool SavedBlink = false;
13206f32e7eSjoerg   unsigned AlreadyAdjusted = 0;
13306f32e7eSjoerg   if (MF.getFunction().isVarArg()) {
13406f32e7eSjoerg     // Add in the varargs area here first.
13506f32e7eSjoerg     LLVM_DEBUG(dbgs() << "Varargs\n");
13606f32e7eSjoerg     unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex());
13706f32e7eSjoerg     unsigned Opc = ARC::SUB_rrlimm;
13806f32e7eSjoerg     if (isUInt<6>(VarArgsBytes))
13906f32e7eSjoerg       Opc = ARC::SUB_rru6;
14006f32e7eSjoerg     else if (isInt<12>(VarArgsBytes))
14106f32e7eSjoerg       Opc = ARC::SUB_rrs12;
14206f32e7eSjoerg     BuildMI(MBB, MBBI, dl, TII->get(Opc), ARC::SP)
14306f32e7eSjoerg         .addReg(ARC::SP)
14406f32e7eSjoerg         .addImm(VarArgsBytes);
14506f32e7eSjoerg   }
14606f32e7eSjoerg   if (hasFP(MF)) {
14706f32e7eSjoerg     LLVM_DEBUG(dbgs() << "Saving FP\n");
14806f32e7eSjoerg     BuildMI(MBB, MBBI, dl, TII->get(ARC::ST_AW_rs9))
14906f32e7eSjoerg         .addReg(ARC::SP, RegState::Define)
15006f32e7eSjoerg         .addReg(ARC::FP)
15106f32e7eSjoerg         .addReg(ARC::SP)
15206f32e7eSjoerg         .addImm(-4);
15306f32e7eSjoerg     AlreadyAdjusted += 4;
15406f32e7eSjoerg   }
15506f32e7eSjoerg   if (UseSaveRestoreFunclet && Last > ARC::R14) {
15606f32e7eSjoerg     LLVM_DEBUG(dbgs() << "Creating store funclet.\n");
15706f32e7eSjoerg     // BL to __save_r13_to_<TRI->getRegAsmName()>
15806f32e7eSjoerg     StackSlotsUsedByFunclet = Last - ARC::R12;
15906f32e7eSjoerg     BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK));
16006f32e7eSjoerg     BuildMI(MBB, MBBI, dl, TII->get(ARC::SUB_rru6))
16106f32e7eSjoerg         .addReg(ARC::SP)
16206f32e7eSjoerg         .addReg(ARC::SP)
16306f32e7eSjoerg         .addImm(4 * StackSlotsUsedByFunclet);
16406f32e7eSjoerg     BuildMI(MBB, MBBI, dl, TII->get(ARC::BL))
16506f32e7eSjoerg         .addExternalSymbol(store_funclet_name[Last - ARC::R15])
16606f32e7eSjoerg         .addReg(ARC::BLINK, RegState::Implicit | RegState::Kill);
16706f32e7eSjoerg     AlreadyAdjusted += 4 * (StackSlotsUsedByFunclet + 1);
16806f32e7eSjoerg     SavedBlink = true;
16906f32e7eSjoerg   }
17006f32e7eSjoerg   // If we haven't saved BLINK, but we need to...do that now.
17106f32e7eSjoerg   if (MFI.hasCalls() && !SavedBlink) {
17206f32e7eSjoerg     LLVM_DEBUG(dbgs() << "Creating save blink.\n");
17306f32e7eSjoerg     BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK));
17406f32e7eSjoerg     AlreadyAdjusted += 4;
17506f32e7eSjoerg   }
17606f32e7eSjoerg   if (AFI->MaxCallStackReq > 0)
17706f32e7eSjoerg     MFI.setStackSize(MFI.getStackSize() + AFI->MaxCallStackReq);
17806f32e7eSjoerg   // We have already saved some of the stack...
17906f32e7eSjoerg   LLVM_DEBUG(dbgs() << "Adjusting stack by: "
18006f32e7eSjoerg                     << (MFI.getStackSize() - AlreadyAdjusted) << "\n");
18106f32e7eSjoerg   generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), dl,
18206f32e7eSjoerg                           -(MFI.getStackSize() - AlreadyAdjusted), ARC::SP);
18306f32e7eSjoerg 
18406f32e7eSjoerg   if (hasFP(MF)) {
18506f32e7eSjoerg     LLVM_DEBUG(dbgs() << "Setting FP from SP.\n");
18606f32e7eSjoerg     BuildMI(MBB, MBBI, dl,
18706f32e7eSjoerg             TII->get(isUInt<6>(MFI.getStackSize()) ? ARC::ADD_rru6
18806f32e7eSjoerg                                                    : ARC::ADD_rrlimm),
18906f32e7eSjoerg             ARC::FP)
19006f32e7eSjoerg         .addReg(ARC::SP)
19106f32e7eSjoerg         .addImm(MFI.getStackSize());
19206f32e7eSjoerg   }
19306f32e7eSjoerg 
19406f32e7eSjoerg   // Emit CFI records:
19506f32e7eSjoerg   // .cfi_def_cfa_offset StackSize
19606f32e7eSjoerg   // .cfi_offset fp, -StackSize
19706f32e7eSjoerg   // .cfi_offset blink, -StackSize+4
19806f32e7eSjoerg   unsigned CFIIndex = MF.addFrameInst(
199*da58b97aSjoerg       MCCFIInstruction::cfiDefCfaOffset(nullptr, MFI.getStackSize()));
20006f32e7eSjoerg   BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
20106f32e7eSjoerg       .addCFIIndex(CFIIndex)
20206f32e7eSjoerg       .setMIFlags(MachineInstr::FrameSetup);
20306f32e7eSjoerg 
20406f32e7eSjoerg   int CurOffset = -4;
20506f32e7eSjoerg   if (hasFP(MF)) {
20606f32e7eSjoerg     CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
20706f32e7eSjoerg         nullptr, MRI->getDwarfRegNum(ARC::FP, true), CurOffset));
20806f32e7eSjoerg     BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
20906f32e7eSjoerg         .addCFIIndex(CFIIndex)
21006f32e7eSjoerg         .setMIFlags(MachineInstr::FrameSetup);
21106f32e7eSjoerg     CurOffset -= 4;
21206f32e7eSjoerg   }
21306f32e7eSjoerg 
21406f32e7eSjoerg   if (MFI.hasCalls()) {
21506f32e7eSjoerg     CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
21606f32e7eSjoerg         nullptr, MRI->getDwarfRegNum(ARC::BLINK, true), CurOffset));
21706f32e7eSjoerg     BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
21806f32e7eSjoerg         .addCFIIndex(CFIIndex)
21906f32e7eSjoerg         .setMIFlags(MachineInstr::FrameSetup);
22006f32e7eSjoerg   }
22106f32e7eSjoerg   // CFI for the rest of the registers.
22206f32e7eSjoerg   for (const auto &Entry : CSI) {
22306f32e7eSjoerg     unsigned Reg = Entry.getReg();
22406f32e7eSjoerg     int FI = Entry.getFrameIdx();
22506f32e7eSjoerg     // Skip BLINK and FP.
22606f32e7eSjoerg     if ((hasFP(MF) && Reg == ARC::FP) || (MFI.hasCalls() && Reg == ARC::BLINK))
22706f32e7eSjoerg       continue;
22806f32e7eSjoerg     CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
22906f32e7eSjoerg         nullptr, MRI->getDwarfRegNum(Reg, true), MFI.getObjectOffset(FI)));
23006f32e7eSjoerg     BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
23106f32e7eSjoerg         .addCFIIndex(CFIIndex)
23206f32e7eSjoerg         .setMIFlags(MachineInstr::FrameSetup);
23306f32e7eSjoerg   }
23406f32e7eSjoerg }
23506f32e7eSjoerg 
23606f32e7eSjoerg /// Insert epilog code into the function.
23706f32e7eSjoerg /// For ARC, this inserts a call to a function that restores callee saved
23806f32e7eSjoerg /// registers onto the stack, when enough callee saved registers are required.
emitEpilogue(MachineFunction & MF,MachineBasicBlock & MBB) const23906f32e7eSjoerg void ARCFrameLowering::emitEpilogue(MachineFunction &MF,
24006f32e7eSjoerg                                     MachineBasicBlock &MBB) const {
24106f32e7eSjoerg   LLVM_DEBUG(dbgs() << "Emit Epilogue: " << MF.getName() << "\n");
24206f32e7eSjoerg   auto *AFI = MF.getInfo<ARCFunctionInfo>();
24306f32e7eSjoerg   const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
24406f32e7eSjoerg   MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
24506f32e7eSjoerg   MachineFrameInfo &MFI = MF.getFrameInfo();
24606f32e7eSjoerg   uint64_t StackSize = MF.getFrameInfo().getStackSize();
24706f32e7eSjoerg   bool SavedBlink = false;
24806f32e7eSjoerg   unsigned AmountAboveFunclet = 0;
24906f32e7eSjoerg   // If we have variable sized frame objects, then we have to move
25006f32e7eSjoerg   // the stack pointer to a known spot (fp - StackSize).
25106f32e7eSjoerg   // Then, replace the frame pointer by (new) [sp,StackSize-4].
25206f32e7eSjoerg   // Then, move the stack pointer the rest of the way (sp = sp + StackSize).
25306f32e7eSjoerg   if (hasFP(MF)) {
25406f32e7eSjoerg     unsigned Opc = ARC::SUB_rrlimm;
25506f32e7eSjoerg     if (isUInt<6>(StackSize))
25606f32e7eSjoerg       Opc = ARC::SUB_rru6;
25706f32e7eSjoerg     BuildMI(MBB, MBBI, DebugLoc(), TII->get(Opc), ARC::SP)
25806f32e7eSjoerg         .addReg(ARC::FP)
25906f32e7eSjoerg         .addImm(StackSize);
26006f32e7eSjoerg     AmountAboveFunclet += 4;
26106f32e7eSjoerg   }
26206f32e7eSjoerg 
26306f32e7eSjoerg   // Now, move the stack pointer to the bottom of the save area for the funclet.
26406f32e7eSjoerg   const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
26506f32e7eSjoerg   unsigned Last = determineLastCalleeSave(CSI);
26606f32e7eSjoerg   unsigned StackSlotsUsedByFunclet = 0;
26706f32e7eSjoerg   // Now, restore the callee save registers.
26806f32e7eSjoerg   if (UseSaveRestoreFunclet && Last > ARC::R14) {
26906f32e7eSjoerg     // BL to __ld_r13_to_<TRI->getRegAsmName()>
27006f32e7eSjoerg     StackSlotsUsedByFunclet = Last - ARC::R12;
27106f32e7eSjoerg     AmountAboveFunclet += 4 * (StackSlotsUsedByFunclet + 1);
27206f32e7eSjoerg     SavedBlink = true;
27306f32e7eSjoerg   }
27406f32e7eSjoerg 
27506f32e7eSjoerg   if (MFI.hasCalls() && !SavedBlink) {
27606f32e7eSjoerg     AmountAboveFunclet += 4;
27706f32e7eSjoerg     SavedBlink = true;
27806f32e7eSjoerg   }
27906f32e7eSjoerg 
28006f32e7eSjoerg   // Move the stack pointer up to the point of the funclet.
28106f32e7eSjoerg   if (unsigned MoveAmount = StackSize - AmountAboveFunclet) {
28206f32e7eSjoerg     unsigned Opc = ARC::ADD_rrlimm;
28306f32e7eSjoerg     if (isUInt<6>(MoveAmount))
28406f32e7eSjoerg       Opc = ARC::ADD_rru6;
28506f32e7eSjoerg     else if (isInt<12>(MoveAmount))
28606f32e7eSjoerg       Opc = ARC::ADD_rrs12;
28706f32e7eSjoerg     BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc), ARC::SP)
28806f32e7eSjoerg         .addReg(ARC::SP)
28906f32e7eSjoerg         .addImm(StackSize - AmountAboveFunclet);
29006f32e7eSjoerg   }
29106f32e7eSjoerg 
29206f32e7eSjoerg   if (StackSlotsUsedByFunclet) {
29306f32e7eSjoerg     // This part of the adjustment will always be < 64 bytes.
29406f32e7eSjoerg     BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::BL))
29506f32e7eSjoerg         .addExternalSymbol(load_funclet_name[Last - ARC::R15])
29606f32e7eSjoerg         .addReg(ARC::BLINK, RegState::Implicit | RegState::Kill);
29706f32e7eSjoerg     unsigned Opc = ARC::ADD_rrlimm;
29806f32e7eSjoerg     if (isUInt<6>(4 * StackSlotsUsedByFunclet))
29906f32e7eSjoerg       Opc = ARC::ADD_rru6;
30006f32e7eSjoerg     else if (isInt<12>(4 * StackSlotsUsedByFunclet))
30106f32e7eSjoerg       Opc = ARC::ADD_rrs12;
30206f32e7eSjoerg     BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc), ARC::SP)
30306f32e7eSjoerg         .addReg(ARC::SP)
30406f32e7eSjoerg         .addImm(4 * (StackSlotsUsedByFunclet));
30506f32e7eSjoerg   }
30606f32e7eSjoerg   // Now, pop blink if necessary.
30706f32e7eSjoerg   if (SavedBlink) {
30806f32e7eSjoerg     BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::POP_S_BLINK));
30906f32e7eSjoerg   }
31006f32e7eSjoerg   // Now, pop fp if necessary.
31106f32e7eSjoerg   if (hasFP(MF)) {
31206f32e7eSjoerg     BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::LD_AB_rs9))
31306f32e7eSjoerg         .addReg(ARC::FP, RegState::Define)
31406f32e7eSjoerg         .addReg(ARC::SP, RegState::Define)
31506f32e7eSjoerg         .addReg(ARC::SP)
31606f32e7eSjoerg         .addImm(4);
31706f32e7eSjoerg   }
31806f32e7eSjoerg 
31906f32e7eSjoerg   // Relieve the varargs area if necessary.
32006f32e7eSjoerg   if (MF.getFunction().isVarArg()) {
32106f32e7eSjoerg     // Add in the varargs area here first.
32206f32e7eSjoerg     LLVM_DEBUG(dbgs() << "Varargs\n");
32306f32e7eSjoerg     unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex());
32406f32e7eSjoerg     unsigned Opc = ARC::ADD_rrlimm;
32506f32e7eSjoerg     if (isUInt<6>(VarArgsBytes))
32606f32e7eSjoerg       Opc = ARC::ADD_rru6;
32706f32e7eSjoerg     else if (isInt<12>(VarArgsBytes))
32806f32e7eSjoerg       Opc = ARC::ADD_rrs12;
32906f32e7eSjoerg     BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc))
33006f32e7eSjoerg         .addReg(ARC::SP)
33106f32e7eSjoerg         .addReg(ARC::SP)
33206f32e7eSjoerg         .addImm(VarArgsBytes);
33306f32e7eSjoerg   }
33406f32e7eSjoerg }
33506f32e7eSjoerg 
33606f32e7eSjoerg static std::vector<CalleeSavedInfo>::iterator
getSavedReg(std::vector<CalleeSavedInfo> & V,unsigned reg)33706f32e7eSjoerg getSavedReg(std::vector<CalleeSavedInfo> &V, unsigned reg) {
33806f32e7eSjoerg   for (auto I = V.begin(), E = V.end(); I != E; ++I) {
33906f32e7eSjoerg     if (reg == I->getReg())
34006f32e7eSjoerg       return I;
34106f32e7eSjoerg   }
34206f32e7eSjoerg   return V.end();
34306f32e7eSjoerg }
34406f32e7eSjoerg 
assignCalleeSavedSpillSlots(MachineFunction & MF,const TargetRegisterInfo * TRI,std::vector<CalleeSavedInfo> & CSI) const34506f32e7eSjoerg bool ARCFrameLowering::assignCalleeSavedSpillSlots(
34606f32e7eSjoerg     MachineFunction &MF, const TargetRegisterInfo *TRI,
34706f32e7eSjoerg     std::vector<CalleeSavedInfo> &CSI) const {
34806f32e7eSjoerg   // Use this opportunity to assign the spill slots for all of the potential
34906f32e7eSjoerg   // callee save registers (blink, fp, r13->r25) that we care about the
35006f32e7eSjoerg   // placement for.  We can calculate all of that data here.
35106f32e7eSjoerg   int CurOffset = -4;
35206f32e7eSjoerg   unsigned Last = determineLastCalleeSave(CSI);
35306f32e7eSjoerg   MachineFrameInfo &MFI = MF.getFrameInfo();
35406f32e7eSjoerg   if (hasFP(MF)) {
35506f32e7eSjoerg     // Create a fixed slot at for FP
35606f32e7eSjoerg     int StackObj = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
35706f32e7eSjoerg     LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj << ") for FP at "
35806f32e7eSjoerg                       << CurOffset << "\n");
35906f32e7eSjoerg     (void)StackObj;
36006f32e7eSjoerg     CurOffset -= 4;
36106f32e7eSjoerg   }
36206f32e7eSjoerg   if (MFI.hasCalls() || (UseSaveRestoreFunclet && Last > ARC::R14)) {
36306f32e7eSjoerg     // Create a fixed slot for BLINK.
36406f32e7eSjoerg     int StackObj  = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
36506f32e7eSjoerg     LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj
36606f32e7eSjoerg                       << ") for BLINK at " << CurOffset << "\n");
36706f32e7eSjoerg     (void)StackObj;
36806f32e7eSjoerg     CurOffset -= 4;
36906f32e7eSjoerg   }
37006f32e7eSjoerg 
37106f32e7eSjoerg   // Create slots for last down to r13.
37206f32e7eSjoerg   for (unsigned Which = Last; Which > ARC::R12; Which--) {
37306f32e7eSjoerg     auto RegI = getSavedReg(CSI, Which);
37406f32e7eSjoerg     if (RegI == CSI.end() || RegI->getFrameIdx() == 0) {
37506f32e7eSjoerg       // Always create the stack slot.  If for some reason the register isn't in
37606f32e7eSjoerg       // the save list, then don't worry about it.
37706f32e7eSjoerg       int FI = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
37806f32e7eSjoerg       if (RegI != CSI.end())
37906f32e7eSjoerg         RegI->setFrameIdx(FI);
38006f32e7eSjoerg     } else
38106f32e7eSjoerg       MFI.setObjectOffset(RegI->getFrameIdx(), CurOffset);
38206f32e7eSjoerg     CurOffset -= 4;
38306f32e7eSjoerg   }
38406f32e7eSjoerg   for (auto &I : CSI) {
38506f32e7eSjoerg     if (I.getReg() > ARC::R12)
38606f32e7eSjoerg       continue;
38706f32e7eSjoerg     if (I.getFrameIdx() == 0) {
38806f32e7eSjoerg       I.setFrameIdx(MFI.CreateFixedSpillStackObject(4, CurOffset, true));
38906f32e7eSjoerg       LLVM_DEBUG(dbgs() << "Creating fixed object (" << I.getFrameIdx()
39006f32e7eSjoerg                         << ") for other register at " << CurOffset << "\n");
39106f32e7eSjoerg     } else {
39206f32e7eSjoerg       MFI.setObjectOffset(I.getFrameIdx(), CurOffset);
39306f32e7eSjoerg       LLVM_DEBUG(dbgs() << "Updating fixed object (" << I.getFrameIdx()
39406f32e7eSjoerg                         << ") for other register at " << CurOffset << "\n");
39506f32e7eSjoerg     }
39606f32e7eSjoerg     CurOffset -= 4;
39706f32e7eSjoerg   }
39806f32e7eSjoerg   return true;
39906f32e7eSjoerg }
40006f32e7eSjoerg 
spillCalleeSavedRegisters(MachineBasicBlock & MBB,MachineBasicBlock::iterator MI,ArrayRef<CalleeSavedInfo> CSI,const TargetRegisterInfo * TRI) const40106f32e7eSjoerg bool ARCFrameLowering::spillCalleeSavedRegisters(
40206f32e7eSjoerg     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
403*da58b97aSjoerg     ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
40406f32e7eSjoerg   LLVM_DEBUG(dbgs() << "Spill callee saved registers: "
40506f32e7eSjoerg                     << MBB.getParent()->getName() << "\n");
40606f32e7eSjoerg   // There are routines for saving at least 3 registers (r13 to r15, etc.)
40706f32e7eSjoerg   unsigned Last = determineLastCalleeSave(CSI);
40806f32e7eSjoerg   if (UseSaveRestoreFunclet && Last > ARC::R14) {
40906f32e7eSjoerg     // Use setObjectOffset for these registers.
41006f32e7eSjoerg     // Needs to be in or before processFunctionBeforeFrameFinalized.
41106f32e7eSjoerg     // Or, do assignCalleeSaveSpillSlots?
41206f32e7eSjoerg     // Will be handled in prolog.
41306f32e7eSjoerg     return true;
41406f32e7eSjoerg   }
41506f32e7eSjoerg   return false;
41606f32e7eSjoerg }
41706f32e7eSjoerg 
restoreCalleeSavedRegisters(MachineBasicBlock & MBB,MachineBasicBlock::iterator MI,MutableArrayRef<CalleeSavedInfo> CSI,const TargetRegisterInfo * TRI) const41806f32e7eSjoerg bool ARCFrameLowering::restoreCalleeSavedRegisters(
41906f32e7eSjoerg     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
420*da58b97aSjoerg     MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
42106f32e7eSjoerg   LLVM_DEBUG(dbgs() << "Restore callee saved registers: "
42206f32e7eSjoerg                     << MBB.getParent()->getName() << "\n");
42306f32e7eSjoerg   // There are routines for saving at least 3 registers (r13 to r15, etc.)
42406f32e7eSjoerg   unsigned Last = determineLastCalleeSave(CSI);
42506f32e7eSjoerg   if (UseSaveRestoreFunclet && Last > ARC::R14) {
42606f32e7eSjoerg     // Will be handled in epilog.
42706f32e7eSjoerg     return true;
42806f32e7eSjoerg   }
42906f32e7eSjoerg   return false;
43006f32e7eSjoerg }
43106f32e7eSjoerg 
43206f32e7eSjoerg // Adjust local variables that are 4-bytes or larger to 4-byte boundary
processFunctionBeforeFrameFinalized(MachineFunction & MF,RegScavenger * RS) const43306f32e7eSjoerg void ARCFrameLowering::processFunctionBeforeFrameFinalized(
43406f32e7eSjoerg     MachineFunction &MF, RegScavenger *RS) const {
43506f32e7eSjoerg   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
43606f32e7eSjoerg   LLVM_DEBUG(dbgs() << "Process function before frame finalized: "
43706f32e7eSjoerg                     << MF.getName() << "\n");
43806f32e7eSjoerg   MachineFrameInfo &MFI = MF.getFrameInfo();
43906f32e7eSjoerg   LLVM_DEBUG(dbgs() << "Current stack size: " << MFI.getStackSize() << "\n");
44006f32e7eSjoerg   const TargetRegisterClass *RC = &ARC::GPR32RegClass;
44106f32e7eSjoerg   if (MFI.hasStackObjects()) {
442*da58b97aSjoerg     int RegScavFI = MFI.CreateStackObject(RegInfo->getSpillSize(*RC),
443*da58b97aSjoerg                                           RegInfo->getSpillAlign(*RC), false);
44406f32e7eSjoerg     RS->addScavengingFrameIndex(RegScavFI);
44506f32e7eSjoerg     LLVM_DEBUG(dbgs() << "Created scavenging index RegScavFI=" << RegScavFI
44606f32e7eSjoerg                       << "\n");
44706f32e7eSjoerg   }
44806f32e7eSjoerg }
44906f32e7eSjoerg 
emitRegUpdate(MachineBasicBlock & MBB,MachineBasicBlock::iterator & MBBI,DebugLoc dl,unsigned Reg,int NumBytes,bool IsAdd,const ARCInstrInfo * TII)45006f32e7eSjoerg static void emitRegUpdate(MachineBasicBlock &MBB,
45106f32e7eSjoerg                           MachineBasicBlock::iterator &MBBI, DebugLoc dl,
45206f32e7eSjoerg                           unsigned Reg, int NumBytes, bool IsAdd,
45306f32e7eSjoerg                           const ARCInstrInfo *TII) {
45406f32e7eSjoerg   unsigned Opc;
45506f32e7eSjoerg   if (isUInt<6>(NumBytes))
45606f32e7eSjoerg     Opc = IsAdd ? ARC::ADD_rru6 : ARC::SUB_rru6;
45706f32e7eSjoerg   else if (isInt<12>(NumBytes))
45806f32e7eSjoerg     Opc = IsAdd ? ARC::ADD_rrs12 : ARC::SUB_rrs12;
45906f32e7eSjoerg   else
46006f32e7eSjoerg     Opc = IsAdd ? ARC::ADD_rrlimm : ARC::SUB_rrlimm;
46106f32e7eSjoerg 
46206f32e7eSjoerg   BuildMI(MBB, MBBI, dl, TII->get(Opc), Reg)
46306f32e7eSjoerg       .addReg(Reg, RegState::Kill)
46406f32e7eSjoerg       .addImm(NumBytes);
46506f32e7eSjoerg }
46606f32e7eSjoerg 
eliminateCallFramePseudoInstr(MachineFunction & MF,MachineBasicBlock & MBB,MachineBasicBlock::iterator I) const46706f32e7eSjoerg MachineBasicBlock::iterator ARCFrameLowering::eliminateCallFramePseudoInstr(
46806f32e7eSjoerg     MachineFunction &MF, MachineBasicBlock &MBB,
46906f32e7eSjoerg     MachineBasicBlock::iterator I) const {
47006f32e7eSjoerg   LLVM_DEBUG(dbgs() << "EmitCallFramePseudo: " << MF.getName() << "\n");
47106f32e7eSjoerg   const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
47206f32e7eSjoerg   MachineInstr &Old = *I;
47306f32e7eSjoerg   DebugLoc dl = Old.getDebugLoc();
47406f32e7eSjoerg   unsigned Amt = Old.getOperand(0).getImm();
47506f32e7eSjoerg   auto *AFI = MF.getInfo<ARCFunctionInfo>();
47606f32e7eSjoerg   if (!hasFP(MF)) {
47706f32e7eSjoerg     if (Amt > AFI->MaxCallStackReq && Old.getOpcode() == ARC::ADJCALLSTACKDOWN)
47806f32e7eSjoerg       AFI->MaxCallStackReq = Amt;
47906f32e7eSjoerg   } else {
48006f32e7eSjoerg     if (Amt != 0) {
48106f32e7eSjoerg       assert((Old.getOpcode() == ARC::ADJCALLSTACKDOWN ||
48206f32e7eSjoerg               Old.getOpcode() == ARC::ADJCALLSTACKUP) &&
48306f32e7eSjoerg              "Unknown Frame Pseudo.");
48406f32e7eSjoerg       bool IsAdd = (Old.getOpcode() == ARC::ADJCALLSTACKUP);
48506f32e7eSjoerg       emitRegUpdate(MBB, I, dl, ARC::SP, Amt, IsAdd, TII);
48606f32e7eSjoerg     }
48706f32e7eSjoerg   }
48806f32e7eSjoerg   return MBB.erase(I);
48906f32e7eSjoerg }
49006f32e7eSjoerg 
hasFP(const MachineFunction & MF) const49106f32e7eSjoerg bool ARCFrameLowering::hasFP(const MachineFunction &MF) const {
49206f32e7eSjoerg   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
49306f32e7eSjoerg   bool HasFP = MF.getTarget().Options.DisableFramePointerElim(MF) ||
49406f32e7eSjoerg                MF.getFrameInfo().hasVarSizedObjects() ||
49506f32e7eSjoerg                MF.getFrameInfo().isFrameAddressTaken() ||
496*da58b97aSjoerg                RegInfo->hasStackRealignment(MF);
49706f32e7eSjoerg   return HasFP;
49806f32e7eSjoerg }
499