1326938Sdim//===- ARCFrameLowering.cpp - ARC Frame Information -------------*- C++ -*-===//
2326938Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6326938Sdim//
7326938Sdim//===----------------------------------------------------------------------===//
8326938Sdim//
9326938Sdim// This file contains the ARC implementation of the TargetFrameLowering class.
10326938Sdim//
11326938Sdim//===----------------------------------------------------------------------===//
12326938Sdim
13326938Sdim#include "ARCFrameLowering.h"
14326938Sdim#include "ARCMachineFunctionInfo.h"
15326938Sdim#include "ARCSubtarget.h"
16326938Sdim#include "llvm/CodeGen/MachineInstrBuilder.h"
17326938Sdim#include "llvm/CodeGen/MachineModuleInfo.h"
18326938Sdim#include "llvm/CodeGen/RegisterScavenging.h"
19326938Sdim#include "llvm/CodeGen/TargetRegisterInfo.h"
20326938Sdim#include "llvm/IR/Function.h"
21326938Sdim#include "llvm/Support/Debug.h"
22326938Sdim
23326938Sdim#define DEBUG_TYPE "arc-frame-lowering"
24326938Sdim
25326938Sdimusing namespace llvm;
26326938Sdim
27326938Sdimstatic cl::opt<bool>
28326938Sdim    UseSaveRestoreFunclet("arc-save-restore-funclet", cl::Hidden,
29326938Sdim                          cl::desc("Use arc callee save/restore functions"),
30326938Sdim                          cl::init(true));
31326938Sdim
32326938Sdimstatic const char *store_funclet_name[] = {
33326938Sdim    "__st_r13_to_r15", "__st_r13_to_r16", "__st_r13_to_r17", "__st_r13_to_r18",
34326938Sdim    "__st_r13_to_r19", "__st_r13_to_r20", "__st_r13_to_r21", "__st_r13_to_r22",
35326938Sdim    "__st_r13_to_r23", "__st_r13_to_r24", "__st_r13_to_r25",
36326938Sdim};
37326938Sdim
38326938Sdimstatic const char *load_funclet_name[] = {
39326938Sdim    "__ld_r13_to_r15", "__ld_r13_to_r16", "__ld_r13_to_r17", "__ld_r13_to_r18",
40326938Sdim    "__ld_r13_to_r19", "__ld_r13_to_r20", "__ld_r13_to_r21", "__ld_r13_to_r22",
41326938Sdim    "__ld_r13_to_r23", "__ld_r13_to_r24", "__ld_r13_to_r25",
42326938Sdim};
43326938Sdim
44326938Sdimstatic void generateStackAdjustment(MachineBasicBlock &MBB,
45326938Sdim                                    MachineBasicBlock::iterator MBBI,
46326938Sdim                                    const ARCInstrInfo &TII, DebugLoc dl,
47326938Sdim                                    int Amount, int StackPtr) {
48326938Sdim  unsigned AdjOp;
49326938Sdim  if (!Amount)
50326938Sdim    return;
51326938Sdim  bool Positive;
52326938Sdim  unsigned AbsAmount;
53326938Sdim  if (Amount < 0) {
54326938Sdim    AbsAmount = -Amount;
55326938Sdim    Positive = false;
56326938Sdim  } else {
57326938Sdim    AbsAmount = Amount;
58326938Sdim    Positive = true;
59326938Sdim  }
60326938Sdim
61341825Sdim  LLVM_DEBUG(dbgs() << "Internal: adjust stack by: " << Amount << ","
62341825Sdim                    << AbsAmount << "\n");
63326938Sdim
64326938Sdim  assert((AbsAmount % 4 == 0) && "Stack adjustments must be 4-byte aligned.");
65326938Sdim  if (isUInt<6>(AbsAmount))
66326938Sdim    AdjOp = Positive ? ARC::ADD_rru6 : ARC::SUB_rru6;
67353358Sdim  else if (isInt<12>(AbsAmount))
68353358Sdim    AdjOp = Positive ? ARC::ADD_rrs12 : ARC::SUB_rrs12;
69326938Sdim  else
70326938Sdim    AdjOp = Positive ? ARC::ADD_rrlimm : ARC::SUB_rrlimm;
71326938Sdim
72326938Sdim  BuildMI(MBB, MBBI, dl, TII.get(AdjOp), StackPtr)
73326938Sdim      .addReg(StackPtr)
74326938Sdim      .addImm(AbsAmount);
75326938Sdim}
76326938Sdim
77326938Sdimstatic unsigned
78326938SdimdetermineLastCalleeSave(const std::vector<CalleeSavedInfo> &CSI) {
79326938Sdim  unsigned Last = 0;
80326938Sdim  for (auto Reg : CSI) {
81326938Sdim    assert(Reg.getReg() >= ARC::R13 && Reg.getReg() <= ARC::R25 &&
82326938Sdim           "Unexpected callee saved reg.");
83326938Sdim    if (Reg.getReg() > Last)
84326938Sdim      Last = Reg.getReg();
85326938Sdim  }
86326938Sdim  return Last;
87326938Sdim}
88326938Sdim
89326938Sdimvoid ARCFrameLowering::determineCalleeSaves(MachineFunction &MF,
90326938Sdim                                            BitVector &SavedRegs,
91326938Sdim                                            RegScavenger *RS) const {
92341825Sdim  LLVM_DEBUG(dbgs() << "Determine Callee Saves: " << MF.getName() << "\n");
93326938Sdim  TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
94326938Sdim  SavedRegs.set(ARC::BLINK);
95326938Sdim}
96326938Sdim
97326938Sdimvoid ARCFrameLowering::adjustStackToMatchRecords(
98326938Sdim    MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
99326938Sdim    bool Allocate) const {
100326938Sdim  MachineFunction &MF = *MBB.getParent();
101326938Sdim  int ScalarAlloc = MF.getFrameInfo().getStackSize();
102326938Sdim
103326938Sdim  if (Allocate) {
104326938Sdim    // Allocate by adjusting by the negative of what the record holder tracked
105326938Sdim    // it tracked a positive offset in a downward growing stack.
106326938Sdim    ScalarAlloc = -ScalarAlloc;
107326938Sdim  }
108326938Sdim
109326938Sdim  generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), DebugLoc(),
110326938Sdim                          ScalarAlloc, ARC::SP);
111326938Sdim}
112326938Sdim
113326938Sdim/// Insert prolog code into the function.
114326938Sdim/// For ARC, this inserts a call to a function that puts required callee saved
115326938Sdim/// registers onto the stack, when enough callee saved registers are required.
116326938Sdimvoid ARCFrameLowering::emitPrologue(MachineFunction &MF,
117326938Sdim                                    MachineBasicBlock &MBB) const {
118341825Sdim  LLVM_DEBUG(dbgs() << "Emit Prologue: " << MF.getName() << "\n");
119326938Sdim  auto *AFI = MF.getInfo<ARCFunctionInfo>();
120326938Sdim  MachineModuleInfo &MMI = MF.getMMI();
121326938Sdim  MCContext &Context = MMI.getContext();
122326938Sdim  const MCRegisterInfo *MRI = Context.getRegisterInfo();
123326938Sdim  const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
124326938Sdim  MachineBasicBlock::iterator MBBI = MBB.begin();
125326938Sdim  // Debug location must be unknown since the first debug location is used
126326938Sdim  // to determine the end of the prologue.
127326938Sdim  DebugLoc dl;
128326938Sdim  MachineFrameInfo &MFI = MF.getFrameInfo();
129326938Sdim  const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
130326938Sdim  unsigned Last = determineLastCalleeSave(CSI);
131326938Sdim  unsigned StackSlotsUsedByFunclet = 0;
132326938Sdim  bool SavedBlink = false;
133326938Sdim  unsigned AlreadyAdjusted = 0;
134326938Sdim  if (MF.getFunction().isVarArg()) {
135326938Sdim    // Add in the varargs area here first.
136341825Sdim    LLVM_DEBUG(dbgs() << "Varargs\n");
137326938Sdim    unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex());
138353358Sdim    unsigned Opc = ARC::SUB_rrlimm;
139353358Sdim    if (isUInt<6>(VarArgsBytes))
140353358Sdim      Opc = ARC::SUB_rru6;
141353358Sdim    else if (isInt<12>(VarArgsBytes))
142353358Sdim      Opc = ARC::SUB_rrs12;
143353358Sdim    BuildMI(MBB, MBBI, dl, TII->get(Opc), ARC::SP)
144326938Sdim        .addReg(ARC::SP)
145326938Sdim        .addImm(VarArgsBytes);
146326938Sdim  }
147326938Sdim  if (hasFP(MF)) {
148341825Sdim    LLVM_DEBUG(dbgs() << "Saving FP\n");
149326938Sdim    BuildMI(MBB, MBBI, dl, TII->get(ARC::ST_AW_rs9))
150326938Sdim        .addReg(ARC::SP, RegState::Define)
151326938Sdim        .addReg(ARC::FP)
152326938Sdim        .addReg(ARC::SP)
153326938Sdim        .addImm(-4);
154326938Sdim    AlreadyAdjusted += 4;
155326938Sdim  }
156326938Sdim  if (UseSaveRestoreFunclet && Last > ARC::R14) {
157341825Sdim    LLVM_DEBUG(dbgs() << "Creating store funclet.\n");
158326938Sdim    // BL to __save_r13_to_<TRI->getRegAsmName()>
159326938Sdim    StackSlotsUsedByFunclet = Last - ARC::R12;
160326938Sdim    BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK));
161326938Sdim    BuildMI(MBB, MBBI, dl, TII->get(ARC::SUB_rru6))
162326938Sdim        .addReg(ARC::SP)
163326938Sdim        .addReg(ARC::SP)
164326938Sdim        .addImm(4 * StackSlotsUsedByFunclet);
165326938Sdim    BuildMI(MBB, MBBI, dl, TII->get(ARC::BL))
166326938Sdim        .addExternalSymbol(store_funclet_name[Last - ARC::R15])
167326938Sdim        .addReg(ARC::BLINK, RegState::Implicit | RegState::Kill);
168326938Sdim    AlreadyAdjusted += 4 * (StackSlotsUsedByFunclet + 1);
169326938Sdim    SavedBlink = true;
170326938Sdim  }
171326938Sdim  // If we haven't saved BLINK, but we need to...do that now.
172326938Sdim  if (MFI.hasCalls() && !SavedBlink) {
173341825Sdim    LLVM_DEBUG(dbgs() << "Creating save blink.\n");
174326938Sdim    BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK));
175326938Sdim    AlreadyAdjusted += 4;
176326938Sdim  }
177326938Sdim  if (AFI->MaxCallStackReq > 0)
178326938Sdim    MFI.setStackSize(MFI.getStackSize() + AFI->MaxCallStackReq);
179326938Sdim  // We have already saved some of the stack...
180341825Sdim  LLVM_DEBUG(dbgs() << "Adjusting stack by: "
181341825Sdim                    << (MFI.getStackSize() - AlreadyAdjusted) << "\n");
182326938Sdim  generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), dl,
183326938Sdim                          -(MFI.getStackSize() - AlreadyAdjusted), ARC::SP);
184326938Sdim
185326938Sdim  if (hasFP(MF)) {
186341825Sdim    LLVM_DEBUG(dbgs() << "Setting FP from SP.\n");
187326938Sdim    BuildMI(MBB, MBBI, dl,
188326938Sdim            TII->get(isUInt<6>(MFI.getStackSize()) ? ARC::ADD_rru6
189326938Sdim                                                   : ARC::ADD_rrlimm),
190326938Sdim            ARC::FP)
191326938Sdim        .addReg(ARC::SP)
192326938Sdim        .addImm(MFI.getStackSize());
193326938Sdim  }
194326938Sdim
195326938Sdim  // Emit CFI records:
196326938Sdim  // .cfi_def_cfa_offset StackSize
197326938Sdim  // .cfi_offset fp, -StackSize
198326938Sdim  // .cfi_offset blink, -StackSize+4
199326938Sdim  unsigned CFIIndex = MF.addFrameInst(
200326938Sdim      MCCFIInstruction::createDefCfaOffset(nullptr, -MFI.getStackSize()));
201326938Sdim  BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
202326938Sdim      .addCFIIndex(CFIIndex)
203326938Sdim      .setMIFlags(MachineInstr::FrameSetup);
204326938Sdim
205326938Sdim  int CurOffset = -4;
206326938Sdim  if (hasFP(MF)) {
207326938Sdim    CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
208326938Sdim        nullptr, MRI->getDwarfRegNum(ARC::FP, true), CurOffset));
209326938Sdim    BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
210326938Sdim        .addCFIIndex(CFIIndex)
211326938Sdim        .setMIFlags(MachineInstr::FrameSetup);
212326938Sdim    CurOffset -= 4;
213326938Sdim  }
214326938Sdim
215326938Sdim  if (MFI.hasCalls()) {
216326938Sdim    CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
217326938Sdim        nullptr, MRI->getDwarfRegNum(ARC::BLINK, true), CurOffset));
218326938Sdim    BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
219326938Sdim        .addCFIIndex(CFIIndex)
220326938Sdim        .setMIFlags(MachineInstr::FrameSetup);
221326938Sdim  }
222326938Sdim  // CFI for the rest of the registers.
223326938Sdim  for (const auto &Entry : CSI) {
224326938Sdim    unsigned Reg = Entry.getReg();
225326938Sdim    int FI = Entry.getFrameIdx();
226326938Sdim    // Skip BLINK and FP.
227326938Sdim    if ((hasFP(MF) && Reg == ARC::FP) || (MFI.hasCalls() && Reg == ARC::BLINK))
228326938Sdim      continue;
229326938Sdim    CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
230326938Sdim        nullptr, MRI->getDwarfRegNum(Reg, true), MFI.getObjectOffset(FI)));
231326938Sdim    BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
232326938Sdim        .addCFIIndex(CFIIndex)
233326938Sdim        .setMIFlags(MachineInstr::FrameSetup);
234326938Sdim  }
235326938Sdim}
236326938Sdim
237326938Sdim/// Insert epilog code into the function.
238326938Sdim/// For ARC, this inserts a call to a function that restores callee saved
239326938Sdim/// registers onto the stack, when enough callee saved registers are required.
240326938Sdimvoid ARCFrameLowering::emitEpilogue(MachineFunction &MF,
241326938Sdim                                    MachineBasicBlock &MBB) const {
242341825Sdim  LLVM_DEBUG(dbgs() << "Emit Epilogue: " << MF.getName() << "\n");
243326938Sdim  auto *AFI = MF.getInfo<ARCFunctionInfo>();
244326938Sdim  const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
245326938Sdim  MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
246326938Sdim  MachineFrameInfo &MFI = MF.getFrameInfo();
247326938Sdim  uint64_t StackSize = MF.getFrameInfo().getStackSize();
248326938Sdim  bool SavedBlink = false;
249326938Sdim  unsigned AmountAboveFunclet = 0;
250326938Sdim  // If we have variable sized frame objects, then we have to move
251326938Sdim  // the stack pointer to a known spot (fp - StackSize).
252326938Sdim  // Then, replace the frame pointer by (new) [sp,StackSize-4].
253326938Sdim  // Then, move the stack pointer the rest of the way (sp = sp + StackSize).
254326938Sdim  if (hasFP(MF)) {
255353358Sdim    unsigned Opc = ARC::SUB_rrlimm;
256353358Sdim    if (isUInt<6>(StackSize))
257353358Sdim      Opc = ARC::SUB_rru6;
258353358Sdim    BuildMI(MBB, MBBI, DebugLoc(), TII->get(Opc), ARC::SP)
259326938Sdim        .addReg(ARC::FP)
260326938Sdim        .addImm(StackSize);
261326938Sdim    AmountAboveFunclet += 4;
262326938Sdim  }
263326938Sdim
264326938Sdim  // Now, move the stack pointer to the bottom of the save area for the funclet.
265326938Sdim  const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
266326938Sdim  unsigned Last = determineLastCalleeSave(CSI);
267326938Sdim  unsigned StackSlotsUsedByFunclet = 0;
268326938Sdim  // Now, restore the callee save registers.
269326938Sdim  if (UseSaveRestoreFunclet && Last > ARC::R14) {
270326938Sdim    // BL to __ld_r13_to_<TRI->getRegAsmName()>
271326938Sdim    StackSlotsUsedByFunclet = Last - ARC::R12;
272326938Sdim    AmountAboveFunclet += 4 * (StackSlotsUsedByFunclet + 1);
273326938Sdim    SavedBlink = true;
274326938Sdim  }
275326938Sdim
276326938Sdim  if (MFI.hasCalls() && !SavedBlink) {
277326938Sdim    AmountAboveFunclet += 4;
278326938Sdim    SavedBlink = true;
279326938Sdim  }
280326938Sdim
281326938Sdim  // Move the stack pointer up to the point of the funclet.
282353358Sdim  if (unsigned MoveAmount = StackSize - AmountAboveFunclet) {
283353358Sdim    unsigned Opc = ARC::ADD_rrlimm;
284353358Sdim    if (isUInt<6>(MoveAmount))
285353358Sdim      Opc = ARC::ADD_rru6;
286353358Sdim    else if (isInt<12>(MoveAmount))
287353358Sdim      Opc = ARC::ADD_rrs12;
288353358Sdim    BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc), ARC::SP)
289326938Sdim        .addReg(ARC::SP)
290326938Sdim        .addImm(StackSize - AmountAboveFunclet);
291326938Sdim  }
292326938Sdim
293326938Sdim  if (StackSlotsUsedByFunclet) {
294353358Sdim    // This part of the adjustment will always be < 64 bytes.
295326938Sdim    BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::BL))
296326938Sdim        .addExternalSymbol(load_funclet_name[Last - ARC::R15])
297326938Sdim        .addReg(ARC::BLINK, RegState::Implicit | RegState::Kill);
298353358Sdim    unsigned Opc = ARC::ADD_rrlimm;
299353358Sdim    if (isUInt<6>(4 * StackSlotsUsedByFunclet))
300353358Sdim      Opc = ARC::ADD_rru6;
301353358Sdim    else if (isInt<12>(4 * StackSlotsUsedByFunclet))
302353358Sdim      Opc = ARC::ADD_rrs12;
303353358Sdim    BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc), ARC::SP)
304326938Sdim        .addReg(ARC::SP)
305326938Sdim        .addImm(4 * (StackSlotsUsedByFunclet));
306326938Sdim  }
307326938Sdim  // Now, pop blink if necessary.
308326938Sdim  if (SavedBlink) {
309326938Sdim    BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::POP_S_BLINK));
310326938Sdim  }
311326938Sdim  // Now, pop fp if necessary.
312326938Sdim  if (hasFP(MF)) {
313326938Sdim    BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::LD_AB_rs9))
314353358Sdim        .addReg(ARC::FP, RegState::Define)
315326938Sdim        .addReg(ARC::SP, RegState::Define)
316326938Sdim        .addReg(ARC::SP)
317326938Sdim        .addImm(4);
318326938Sdim  }
319326938Sdim
320326938Sdim  // Relieve the varargs area if necessary.
321326938Sdim  if (MF.getFunction().isVarArg()) {
322326938Sdim    // Add in the varargs area here first.
323341825Sdim    LLVM_DEBUG(dbgs() << "Varargs\n");
324326938Sdim    unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex());
325353358Sdim    unsigned Opc = ARC::ADD_rrlimm;
326353358Sdim    if (isUInt<6>(VarArgsBytes))
327353358Sdim      Opc = ARC::ADD_rru6;
328353358Sdim    else if (isInt<12>(VarArgsBytes))
329353358Sdim      Opc = ARC::ADD_rrs12;
330353358Sdim    BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc))
331326938Sdim        .addReg(ARC::SP)
332326938Sdim        .addReg(ARC::SP)
333326938Sdim        .addImm(VarArgsBytes);
334326938Sdim  }
335326938Sdim}
336326938Sdim
337326938Sdimstatic std::vector<CalleeSavedInfo>::iterator
338326938SdimgetSavedReg(std::vector<CalleeSavedInfo> &V, unsigned reg) {
339326938Sdim  for (auto I = V.begin(), E = V.end(); I != E; ++I) {
340326938Sdim    if (reg == I->getReg())
341326938Sdim      return I;
342326938Sdim  }
343326938Sdim  return V.end();
344326938Sdim}
345326938Sdim
346326938Sdimbool ARCFrameLowering::assignCalleeSavedSpillSlots(
347326938Sdim    MachineFunction &MF, const TargetRegisterInfo *TRI,
348326938Sdim    std::vector<CalleeSavedInfo> &CSI) const {
349326938Sdim  // Use this opportunity to assign the spill slots for all of the potential
350326938Sdim  // callee save registers (blink, fp, r13->r25) that we care about the
351326938Sdim  // placement for.  We can calculate all of that data here.
352326938Sdim  int CurOffset = -4;
353326938Sdim  unsigned Last = determineLastCalleeSave(CSI);
354326938Sdim  MachineFrameInfo &MFI = MF.getFrameInfo();
355326938Sdim  if (hasFP(MF)) {
356326938Sdim    // Create a fixed slot at for FP
357326938Sdim    int StackObj = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
358341825Sdim    LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj << ") for FP at "
359341825Sdim                      << CurOffset << "\n");
360326938Sdim    (void)StackObj;
361326938Sdim    CurOffset -= 4;
362326938Sdim  }
363326938Sdim  if (MFI.hasCalls() || (UseSaveRestoreFunclet && Last > ARC::R14)) {
364326938Sdim    // Create a fixed slot for BLINK.
365326938Sdim    int StackObj  = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
366341825Sdim    LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj
367341825Sdim                      << ") for BLINK at " << CurOffset << "\n");
368326938Sdim    (void)StackObj;
369326938Sdim    CurOffset -= 4;
370326938Sdim  }
371326938Sdim
372326938Sdim  // Create slots for last down to r13.
373326938Sdim  for (unsigned Which = Last; Which > ARC::R12; Which--) {
374326938Sdim    auto RegI = getSavedReg(CSI, Which);
375326938Sdim    if (RegI == CSI.end() || RegI->getFrameIdx() == 0) {
376326938Sdim      // Always create the stack slot.  If for some reason the register isn't in
377326938Sdim      // the save list, then don't worry about it.
378326938Sdim      int FI = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
379326938Sdim      if (RegI != CSI.end())
380326938Sdim        RegI->setFrameIdx(FI);
381326938Sdim    } else
382326938Sdim      MFI.setObjectOffset(RegI->getFrameIdx(), CurOffset);
383326938Sdim    CurOffset -= 4;
384326938Sdim  }
385326938Sdim  for (auto &I : CSI) {
386326938Sdim    if (I.getReg() > ARC::R12)
387326938Sdim      continue;
388326938Sdim    if (I.getFrameIdx() == 0) {
389326938Sdim      I.setFrameIdx(MFI.CreateFixedSpillStackObject(4, CurOffset, true));
390341825Sdim      LLVM_DEBUG(dbgs() << "Creating fixed object (" << I.getFrameIdx()
391341825Sdim                        << ") for other register at " << CurOffset << "\n");
392326938Sdim    } else {
393326938Sdim      MFI.setObjectOffset(I.getFrameIdx(), CurOffset);
394341825Sdim      LLVM_DEBUG(dbgs() << "Updating fixed object (" << I.getFrameIdx()
395341825Sdim                        << ") for other register at " << CurOffset << "\n");
396326938Sdim    }
397326938Sdim    CurOffset -= 4;
398326938Sdim  }
399326938Sdim  return true;
400326938Sdim}
401326938Sdim
402326938Sdimbool ARCFrameLowering::spillCalleeSavedRegisters(
403326938Sdim    MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
404326938Sdim    const std::vector<CalleeSavedInfo> &CSI,
405326938Sdim    const TargetRegisterInfo *TRI) const {
406341825Sdim  LLVM_DEBUG(dbgs() << "Spill callee saved registers: "
407341825Sdim                    << MBB.getParent()->getName() << "\n");
408326938Sdim  // There are routines for saving at least 3 registers (r13 to r15, etc.)
409326938Sdim  unsigned Last = determineLastCalleeSave(CSI);
410326938Sdim  if (UseSaveRestoreFunclet && Last > ARC::R14) {
411326938Sdim    // Use setObjectOffset for these registers.
412326938Sdim    // Needs to be in or before processFunctionBeforeFrameFinalized.
413326938Sdim    // Or, do assignCalleeSaveSpillSlots?
414326938Sdim    // Will be handled in prolog.
415326938Sdim    return true;
416326938Sdim  }
417326938Sdim  return false;
418326938Sdim}
419326938Sdim
420326938Sdimbool ARCFrameLowering::restoreCalleeSavedRegisters(
421326938Sdim    MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
422326938Sdim    std::vector<CalleeSavedInfo> &CSI, const TargetRegisterInfo *TRI) const {
423341825Sdim  LLVM_DEBUG(dbgs() << "Restore callee saved registers: "
424341825Sdim                    << MBB.getParent()->getName() << "\n");
425326938Sdim  // There are routines for saving at least 3 registers (r13 to r15, etc.)
426326938Sdim  unsigned Last = determineLastCalleeSave(CSI);
427326938Sdim  if (UseSaveRestoreFunclet && Last > ARC::R14) {
428326938Sdim    // Will be handled in epilog.
429326938Sdim    return true;
430326938Sdim  }
431326938Sdim  return false;
432326938Sdim}
433326938Sdim
434326938Sdim// Adjust local variables that are 4-bytes or larger to 4-byte boundary
435326938Sdimvoid ARCFrameLowering::processFunctionBeforeFrameFinalized(
436326938Sdim    MachineFunction &MF, RegScavenger *RS) const {
437326938Sdim  const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
438341825Sdim  LLVM_DEBUG(dbgs() << "Process function before frame finalized: "
439341825Sdim                    << MF.getName() << "\n");
440326938Sdim  MachineFrameInfo &MFI = MF.getFrameInfo();
441341825Sdim  LLVM_DEBUG(dbgs() << "Current stack size: " << MFI.getStackSize() << "\n");
442326938Sdim  const TargetRegisterClass *RC = &ARC::GPR32RegClass;
443326938Sdim  if (MFI.hasStackObjects()) {
444326938Sdim    int RegScavFI = MFI.CreateStackObject(
445326938Sdim        RegInfo->getSpillSize(*RC), RegInfo->getSpillAlignment(*RC), false);
446326938Sdim    RS->addScavengingFrameIndex(RegScavFI);
447341825Sdim    LLVM_DEBUG(dbgs() << "Created scavenging index RegScavFI=" << RegScavFI
448341825Sdim                      << "\n");
449326938Sdim  }
450326938Sdim}
451326938Sdim
452326938Sdimstatic void emitRegUpdate(MachineBasicBlock &MBB,
453326938Sdim                          MachineBasicBlock::iterator &MBBI, DebugLoc dl,
454326938Sdim                          unsigned Reg, int NumBytes, bool IsAdd,
455326938Sdim                          const ARCInstrInfo *TII) {
456353358Sdim  unsigned Opc;
457353358Sdim  if (isUInt<6>(NumBytes))
458353358Sdim    Opc = IsAdd ? ARC::ADD_rru6 : ARC::SUB_rru6;
459353358Sdim  else if (isInt<12>(NumBytes))
460353358Sdim    Opc = IsAdd ? ARC::ADD_rrs12 : ARC::SUB_rrs12;
461353358Sdim  else
462353358Sdim    Opc = IsAdd ? ARC::ADD_rrlimm : ARC::SUB_rrlimm;
463353358Sdim
464326938Sdim  BuildMI(MBB, MBBI, dl, TII->get(Opc), Reg)
465326938Sdim      .addReg(Reg, RegState::Kill)
466326938Sdim      .addImm(NumBytes);
467326938Sdim}
468326938Sdim
469326938SdimMachineBasicBlock::iterator ARCFrameLowering::eliminateCallFramePseudoInstr(
470326938Sdim    MachineFunction &MF, MachineBasicBlock &MBB,
471326938Sdim    MachineBasicBlock::iterator I) const {
472341825Sdim  LLVM_DEBUG(dbgs() << "EmitCallFramePseudo: " << MF.getName() << "\n");
473326938Sdim  const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
474326938Sdim  MachineInstr &Old = *I;
475326938Sdim  DebugLoc dl = Old.getDebugLoc();
476326938Sdim  unsigned Amt = Old.getOperand(0).getImm();
477326938Sdim  auto *AFI = MF.getInfo<ARCFunctionInfo>();
478326938Sdim  if (!hasFP(MF)) {
479326938Sdim    if (Amt > AFI->MaxCallStackReq && Old.getOpcode() == ARC::ADJCALLSTACKDOWN)
480326938Sdim      AFI->MaxCallStackReq = Amt;
481326938Sdim  } else {
482326938Sdim    if (Amt != 0) {
483326938Sdim      assert((Old.getOpcode() == ARC::ADJCALLSTACKDOWN ||
484326938Sdim              Old.getOpcode() == ARC::ADJCALLSTACKUP) &&
485326938Sdim             "Unknown Frame Pseudo.");
486326938Sdim      bool IsAdd = (Old.getOpcode() == ARC::ADJCALLSTACKUP);
487326938Sdim      emitRegUpdate(MBB, I, dl, ARC::SP, Amt, IsAdd, TII);
488326938Sdim    }
489326938Sdim  }
490326938Sdim  return MBB.erase(I);
491326938Sdim}
492326938Sdim
493326938Sdimbool ARCFrameLowering::hasFP(const MachineFunction &MF) const {
494326938Sdim  const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
495326938Sdim  bool HasFP = MF.getTarget().Options.DisableFramePointerElim(MF) ||
496326938Sdim               MF.getFrameInfo().hasVarSizedObjects() ||
497326938Sdim               MF.getFrameInfo().isFrameAddressTaken() ||
498326938Sdim               RegInfo->needsStackRealignment(MF);
499326938Sdim  return HasFP;
500326938Sdim}
501