1 //===- ARCFrameLowering.cpp - ARC Frame Information -------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file contains the ARC implementation of the TargetFrameLowering class.
11 //===----------------------------------------------------------------------===//
13 #include "ARCFrameLowering.h"
14 #include "ARCMachineFunctionInfo.h"
15 #include "ARCSubtarget.h"
16 #include "llvm/CodeGen/MachineInstrBuilder.h"
17 #include "llvm/CodeGen/MachineModuleInfo.h"
18 #include "llvm/CodeGen/RegisterScavenging.h"
19 #include "llvm/CodeGen/TargetRegisterInfo.h"
20 #include "llvm/IR/Function.h"
21 #include "llvm/Support/Debug.h"
23 #define DEBUG_TYPE "arc-frame-lowering"
28 UseSaveRestoreFunclet("arc-save-restore-funclet", cl::Hidden
,
29 cl::desc("Use arc callee save/restore functions"),
32 static const char *store_funclet_name
[] = {
33 "__st_r13_to_r15", "__st_r13_to_r16", "__st_r13_to_r17", "__st_r13_to_r18",
34 "__st_r13_to_r19", "__st_r13_to_r20", "__st_r13_to_r21", "__st_r13_to_r22",
35 "__st_r13_to_r23", "__st_r13_to_r24", "__st_r13_to_r25",
38 static const char *load_funclet_name
[] = {
39 "__ld_r13_to_r15", "__ld_r13_to_r16", "__ld_r13_to_r17", "__ld_r13_to_r18",
40 "__ld_r13_to_r19", "__ld_r13_to_r20", "__ld_r13_to_r21", "__ld_r13_to_r22",
41 "__ld_r13_to_r23", "__ld_r13_to_r24", "__ld_r13_to_r25",
44 static void generateStackAdjustment(MachineBasicBlock
&MBB
,
45 MachineBasicBlock::iterator MBBI
,
46 const ARCInstrInfo
&TII
, DebugLoc dl
,
47 int Amount
, int StackPtr
) {
61 LLVM_DEBUG(dbgs() << "Internal: adjust stack by: " << Amount
<< ","
62 << AbsAmount
<< "\n");
64 assert((AbsAmount
% 4 == 0) && "Stack adjustments must be 4-byte aligned.");
65 if (isUInt
<6>(AbsAmount
))
66 AdjOp
= Positive
? ARC::ADD_rru6
: ARC::SUB_rru6
;
68 AdjOp
= Positive
? ARC::ADD_rrlimm
: ARC::SUB_rrlimm
;
70 BuildMI(MBB
, MBBI
, dl
, TII
.get(AdjOp
), StackPtr
)
76 determineLastCalleeSave(const std::vector
<CalleeSavedInfo
> &CSI
) {
78 for (auto Reg
: CSI
) {
79 assert(Reg
.getReg() >= ARC::R13
&& Reg
.getReg() <= ARC::R25
&&
80 "Unexpected callee saved reg.");
81 if (Reg
.getReg() > Last
)
87 void ARCFrameLowering::determineCalleeSaves(MachineFunction
&MF
,
89 RegScavenger
*RS
) const {
90 LLVM_DEBUG(dbgs() << "Determine Callee Saves: " << MF
.getName() << "\n");
91 TargetFrameLowering::determineCalleeSaves(MF
, SavedRegs
, RS
);
92 SavedRegs
.set(ARC::BLINK
);
95 void ARCFrameLowering::adjustStackToMatchRecords(
96 MachineBasicBlock
&MBB
, MachineBasicBlock::iterator MBBI
,
97 bool Allocate
) const {
98 MachineFunction
&MF
= *MBB
.getParent();
99 int ScalarAlloc
= MF
.getFrameInfo().getStackSize();
102 // Allocate by adjusting by the negative of what the record holder tracked
103 // it tracked a positive offset in a downward growing stack.
104 ScalarAlloc
= -ScalarAlloc
;
107 generateStackAdjustment(MBB
, MBBI
, *ST
.getInstrInfo(), DebugLoc(),
108 ScalarAlloc
, ARC::SP
);
111 /// Insert prolog code into the function.
112 /// For ARC, this inserts a call to a function that puts required callee saved
113 /// registers onto the stack, when enough callee saved registers are required.
114 void ARCFrameLowering::emitPrologue(MachineFunction
&MF
,
115 MachineBasicBlock
&MBB
) const {
116 LLVM_DEBUG(dbgs() << "Emit Prologue: " << MF
.getName() << "\n");
117 auto *AFI
= MF
.getInfo
<ARCFunctionInfo
>();
118 MachineModuleInfo
&MMI
= MF
.getMMI();
119 MCContext
&Context
= MMI
.getContext();
120 const MCRegisterInfo
*MRI
= Context
.getRegisterInfo();
121 const ARCInstrInfo
*TII
= MF
.getSubtarget
<ARCSubtarget
>().getInstrInfo();
122 MachineBasicBlock::iterator MBBI
= MBB
.begin();
123 // Debug location must be unknown since the first debug location is used
124 // to determine the end of the prologue.
126 MachineFrameInfo
&MFI
= MF
.getFrameInfo();
127 const std::vector
<CalleeSavedInfo
> &CSI
= MFI
.getCalleeSavedInfo();
128 unsigned Last
= determineLastCalleeSave(CSI
);
129 unsigned StackSlotsUsedByFunclet
= 0;
130 bool SavedBlink
= false;
131 unsigned AlreadyAdjusted
= 0;
132 if (MF
.getFunction().isVarArg()) {
133 // Add in the varargs area here first.
134 LLVM_DEBUG(dbgs() << "Varargs\n");
135 unsigned VarArgsBytes
= MFI
.getObjectSize(AFI
->getVarArgsFrameIndex());
136 BuildMI(MBB
, MBBI
, dl
, TII
->get(ARC::SUB_rru6
))
139 .addImm(VarArgsBytes
);
142 LLVM_DEBUG(dbgs() << "Saving FP\n");
143 BuildMI(MBB
, MBBI
, dl
, TII
->get(ARC::ST_AW_rs9
))
144 .addReg(ARC::SP
, RegState::Define
)
148 AlreadyAdjusted
+= 4;
150 if (UseSaveRestoreFunclet
&& Last
> ARC::R14
) {
151 LLVM_DEBUG(dbgs() << "Creating store funclet.\n");
152 // BL to __save_r13_to_<TRI->getRegAsmName()>
153 StackSlotsUsedByFunclet
= Last
- ARC::R12
;
154 BuildMI(MBB
, MBBI
, dl
, TII
->get(ARC::PUSH_S_BLINK
));
155 BuildMI(MBB
, MBBI
, dl
, TII
->get(ARC::SUB_rru6
))
158 .addImm(4 * StackSlotsUsedByFunclet
);
159 BuildMI(MBB
, MBBI
, dl
, TII
->get(ARC::BL
))
160 .addExternalSymbol(store_funclet_name
[Last
- ARC::R15
])
161 .addReg(ARC::BLINK
, RegState::Implicit
| RegState::Kill
);
162 AlreadyAdjusted
+= 4 * (StackSlotsUsedByFunclet
+ 1);
165 // If we haven't saved BLINK, but we need to...do that now.
166 if (MFI
.hasCalls() && !SavedBlink
) {
167 LLVM_DEBUG(dbgs() << "Creating save blink.\n");
168 BuildMI(MBB
, MBBI
, dl
, TII
->get(ARC::PUSH_S_BLINK
));
169 AlreadyAdjusted
+= 4;
171 if (AFI
->MaxCallStackReq
> 0)
172 MFI
.setStackSize(MFI
.getStackSize() + AFI
->MaxCallStackReq
);
173 // We have already saved some of the stack...
174 LLVM_DEBUG(dbgs() << "Adjusting stack by: "
175 << (MFI
.getStackSize() - AlreadyAdjusted
) << "\n");
176 generateStackAdjustment(MBB
, MBBI
, *ST
.getInstrInfo(), dl
,
177 -(MFI
.getStackSize() - AlreadyAdjusted
), ARC::SP
);
180 LLVM_DEBUG(dbgs() << "Setting FP from SP.\n");
181 BuildMI(MBB
, MBBI
, dl
,
182 TII
->get(isUInt
<6>(MFI
.getStackSize()) ? ARC::ADD_rru6
186 .addImm(MFI
.getStackSize());
190 // .cfi_def_cfa_offset StackSize
191 // .cfi_offset fp, -StackSize
192 // .cfi_offset blink, -StackSize+4
193 unsigned CFIIndex
= MF
.addFrameInst(
194 MCCFIInstruction::createDefCfaOffset(nullptr, -MFI
.getStackSize()));
195 BuildMI(MBB
, MBBI
, dl
, TII
->get(TargetOpcode::CFI_INSTRUCTION
))
196 .addCFIIndex(CFIIndex
)
197 .setMIFlags(MachineInstr::FrameSetup
);
201 CFIIndex
= MF
.addFrameInst(MCCFIInstruction::createOffset(
202 nullptr, MRI
->getDwarfRegNum(ARC::FP
, true), CurOffset
));
203 BuildMI(MBB
, MBBI
, dl
, TII
->get(TargetOpcode::CFI_INSTRUCTION
))
204 .addCFIIndex(CFIIndex
)
205 .setMIFlags(MachineInstr::FrameSetup
);
209 if (MFI
.hasCalls()) {
210 CFIIndex
= MF
.addFrameInst(MCCFIInstruction::createOffset(
211 nullptr, MRI
->getDwarfRegNum(ARC::BLINK
, true), CurOffset
));
212 BuildMI(MBB
, MBBI
, dl
, TII
->get(TargetOpcode::CFI_INSTRUCTION
))
213 .addCFIIndex(CFIIndex
)
214 .setMIFlags(MachineInstr::FrameSetup
);
216 // CFI for the rest of the registers.
217 for (const auto &Entry
: CSI
) {
218 unsigned Reg
= Entry
.getReg();
219 int FI
= Entry
.getFrameIdx();
220 // Skip BLINK and FP.
221 if ((hasFP(MF
) && Reg
== ARC::FP
) || (MFI
.hasCalls() && Reg
== ARC::BLINK
))
223 CFIIndex
= MF
.addFrameInst(MCCFIInstruction::createOffset(
224 nullptr, MRI
->getDwarfRegNum(Reg
, true), MFI
.getObjectOffset(FI
)));
225 BuildMI(MBB
, MBBI
, dl
, TII
->get(TargetOpcode::CFI_INSTRUCTION
))
226 .addCFIIndex(CFIIndex
)
227 .setMIFlags(MachineInstr::FrameSetup
);
231 /// Insert epilog code into the function.
232 /// For ARC, this inserts a call to a function that restores callee saved
233 /// registers onto the stack, when enough callee saved registers are required.
234 void ARCFrameLowering::emitEpilogue(MachineFunction
&MF
,
235 MachineBasicBlock
&MBB
) const {
236 LLVM_DEBUG(dbgs() << "Emit Epilogue: " << MF
.getName() << "\n");
237 auto *AFI
= MF
.getInfo
<ARCFunctionInfo
>();
238 const ARCInstrInfo
*TII
= MF
.getSubtarget
<ARCSubtarget
>().getInstrInfo();
239 MachineBasicBlock::iterator MBBI
= MBB
.getFirstTerminator();
240 MachineFrameInfo
&MFI
= MF
.getFrameInfo();
241 uint64_t StackSize
= MF
.getFrameInfo().getStackSize();
242 bool SavedBlink
= false;
243 unsigned AmountAboveFunclet
= 0;
244 // If we have variable sized frame objects, then we have to move
245 // the stack pointer to a known spot (fp - StackSize).
246 // Then, replace the frame pointer by (new) [sp,StackSize-4].
247 // Then, move the stack pointer the rest of the way (sp = sp + StackSize).
249 BuildMI(MBB
, MBBI
, DebugLoc(), TII
->get(ARC::SUB_rru6
), ARC::SP
)
252 AmountAboveFunclet
+= 4;
255 // Now, move the stack pointer to the bottom of the save area for the funclet.
256 const std::vector
<CalleeSavedInfo
> &CSI
= MFI
.getCalleeSavedInfo();
257 unsigned Last
= determineLastCalleeSave(CSI
);
258 unsigned StackSlotsUsedByFunclet
= 0;
259 // Now, restore the callee save registers.
260 if (UseSaveRestoreFunclet
&& Last
> ARC::R14
) {
261 // BL to __ld_r13_to_<TRI->getRegAsmName()>
262 StackSlotsUsedByFunclet
= Last
- ARC::R12
;
263 AmountAboveFunclet
+= 4 * (StackSlotsUsedByFunclet
+ 1);
267 if (MFI
.hasCalls() && !SavedBlink
) {
268 AmountAboveFunclet
+= 4;
272 // Move the stack pointer up to the point of the funclet.
273 if (StackSize
- AmountAboveFunclet
) {
274 BuildMI(MBB
, MBBI
, MBB
.findDebugLoc(MBBI
), TII
->get(ARC::ADD_rru6
))
277 .addImm(StackSize
- AmountAboveFunclet
);
280 if (StackSlotsUsedByFunclet
) {
281 BuildMI(MBB
, MBBI
, MBB
.findDebugLoc(MBBI
), TII
->get(ARC::BL
))
282 .addExternalSymbol(load_funclet_name
[Last
- ARC::R15
])
283 .addReg(ARC::BLINK
, RegState::Implicit
| RegState::Kill
);
284 BuildMI(MBB
, MBBI
, MBB
.findDebugLoc(MBBI
), TII
->get(ARC::ADD_rru6
))
287 .addImm(4 * (StackSlotsUsedByFunclet
));
289 // Now, pop blink if necessary.
291 BuildMI(MBB
, MBBI
, MBB
.findDebugLoc(MBBI
), TII
->get(ARC::POP_S_BLINK
));
293 // Now, pop fp if necessary.
295 BuildMI(MBB
, MBBI
, MBB
.findDebugLoc(MBBI
), TII
->get(ARC::LD_AB_rs9
))
296 .addReg(ARC::SP
, RegState::Define
)
297 .addReg(ARC::FP
, RegState::Define
)
302 // Relieve the varargs area if necessary.
303 if (MF
.getFunction().isVarArg()) {
304 // Add in the varargs area here first.
305 LLVM_DEBUG(dbgs() << "Varargs\n");
306 unsigned VarArgsBytes
= MFI
.getObjectSize(AFI
->getVarArgsFrameIndex());
307 BuildMI(MBB
, MBBI
, MBB
.findDebugLoc(MBBI
), TII
->get(ARC::ADD_rru6
))
310 .addImm(VarArgsBytes
);
314 static std::vector
<CalleeSavedInfo
>::iterator
315 getSavedReg(std::vector
<CalleeSavedInfo
> &V
, unsigned reg
) {
316 for (auto I
= V
.begin(), E
= V
.end(); I
!= E
; ++I
) {
317 if (reg
== I
->getReg())
323 bool ARCFrameLowering::assignCalleeSavedSpillSlots(
324 MachineFunction
&MF
, const TargetRegisterInfo
*TRI
,
325 std::vector
<CalleeSavedInfo
> &CSI
) const {
326 // Use this opportunity to assign the spill slots for all of the potential
327 // callee save registers (blink, fp, r13->r25) that we care about the
328 // placement for. We can calculate all of that data here.
330 unsigned Last
= determineLastCalleeSave(CSI
);
331 MachineFrameInfo
&MFI
= MF
.getFrameInfo();
333 // Create a fixed slot at for FP
334 int StackObj
= MFI
.CreateFixedSpillStackObject(4, CurOffset
, true);
335 LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj
<< ") for FP at "
336 << CurOffset
<< "\n");
340 if (MFI
.hasCalls() || (UseSaveRestoreFunclet
&& Last
> ARC::R14
)) {
341 // Create a fixed slot for BLINK.
342 int StackObj
= MFI
.CreateFixedSpillStackObject(4, CurOffset
, true);
343 LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj
344 << ") for BLINK at " << CurOffset
<< "\n");
349 // Create slots for last down to r13.
350 for (unsigned Which
= Last
; Which
> ARC::R12
; Which
--) {
351 auto RegI
= getSavedReg(CSI
, Which
);
352 if (RegI
== CSI
.end() || RegI
->getFrameIdx() == 0) {
353 // Always create the stack slot. If for some reason the register isn't in
354 // the save list, then don't worry about it.
355 int FI
= MFI
.CreateFixedSpillStackObject(4, CurOffset
, true);
356 if (RegI
!= CSI
.end())
357 RegI
->setFrameIdx(FI
);
359 MFI
.setObjectOffset(RegI
->getFrameIdx(), CurOffset
);
362 for (auto &I
: CSI
) {
363 if (I
.getReg() > ARC::R12
)
365 if (I
.getFrameIdx() == 0) {
366 I
.setFrameIdx(MFI
.CreateFixedSpillStackObject(4, CurOffset
, true));
367 LLVM_DEBUG(dbgs() << "Creating fixed object (" << I
.getFrameIdx()
368 << ") for other register at " << CurOffset
<< "\n");
370 MFI
.setObjectOffset(I
.getFrameIdx(), CurOffset
);
371 LLVM_DEBUG(dbgs() << "Updating fixed object (" << I
.getFrameIdx()
372 << ") for other register at " << CurOffset
<< "\n");
379 bool ARCFrameLowering::spillCalleeSavedRegisters(
380 MachineBasicBlock
&MBB
, MachineBasicBlock::iterator MI
,
381 const std::vector
<CalleeSavedInfo
> &CSI
,
382 const TargetRegisterInfo
*TRI
) const {
383 LLVM_DEBUG(dbgs() << "Spill callee saved registers: "
384 << MBB
.getParent()->getName() << "\n");
385 // There are routines for saving at least 3 registers (r13 to r15, etc.)
386 unsigned Last
= determineLastCalleeSave(CSI
);
387 if (UseSaveRestoreFunclet
&& Last
> ARC::R14
) {
388 // Use setObjectOffset for these registers.
389 // Needs to be in or before processFunctionBeforeFrameFinalized.
390 // Or, do assignCalleeSaveSpillSlots?
391 // Will be handled in prolog.
397 bool ARCFrameLowering::restoreCalleeSavedRegisters(
398 MachineBasicBlock
&MBB
, MachineBasicBlock::iterator MI
,
399 std::vector
<CalleeSavedInfo
> &CSI
, const TargetRegisterInfo
*TRI
) const {
400 LLVM_DEBUG(dbgs() << "Restore callee saved registers: "
401 << MBB
.getParent()->getName() << "\n");
402 // There are routines for saving at least 3 registers (r13 to r15, etc.)
403 unsigned Last
= determineLastCalleeSave(CSI
);
404 if (UseSaveRestoreFunclet
&& Last
> ARC::R14
) {
405 // Will be handled in epilog.
411 // Adjust local variables that are 4-bytes or larger to 4-byte boundary
412 void ARCFrameLowering::processFunctionBeforeFrameFinalized(
413 MachineFunction
&MF
, RegScavenger
*RS
) const {
414 const TargetRegisterInfo
*RegInfo
= MF
.getSubtarget().getRegisterInfo();
415 LLVM_DEBUG(dbgs() << "Process function before frame finalized: "
416 << MF
.getName() << "\n");
417 MachineFrameInfo
&MFI
= MF
.getFrameInfo();
418 LLVM_DEBUG(dbgs() << "Current stack size: " << MFI
.getStackSize() << "\n");
419 const TargetRegisterClass
*RC
= &ARC::GPR32RegClass
;
420 if (MFI
.hasStackObjects()) {
421 int RegScavFI
= MFI
.CreateStackObject(
422 RegInfo
->getSpillSize(*RC
), RegInfo
->getSpillAlignment(*RC
), false);
423 RS
->addScavengingFrameIndex(RegScavFI
);
424 LLVM_DEBUG(dbgs() << "Created scavenging index RegScavFI=" << RegScavFI
429 static void emitRegUpdate(MachineBasicBlock
&MBB
,
430 MachineBasicBlock::iterator
&MBBI
, DebugLoc dl
,
431 unsigned Reg
, int NumBytes
, bool IsAdd
,
432 const ARCInstrInfo
*TII
) {
433 unsigned Opc
= IsAdd
? ARC::ADD_rru6
: ARC::SUB_rru6
;
434 BuildMI(MBB
, MBBI
, dl
, TII
->get(Opc
), Reg
)
435 .addReg(Reg
, RegState::Kill
)
439 MachineBasicBlock::iterator
ARCFrameLowering::eliminateCallFramePseudoInstr(
440 MachineFunction
&MF
, MachineBasicBlock
&MBB
,
441 MachineBasicBlock::iterator I
) const {
442 LLVM_DEBUG(dbgs() << "EmitCallFramePseudo: " << MF
.getName() << "\n");
443 const ARCInstrInfo
*TII
= MF
.getSubtarget
<ARCSubtarget
>().getInstrInfo();
444 MachineInstr
&Old
= *I
;
445 DebugLoc dl
= Old
.getDebugLoc();
446 unsigned Amt
= Old
.getOperand(0).getImm();
447 auto *AFI
= MF
.getInfo
<ARCFunctionInfo
>();
449 if (Amt
> AFI
->MaxCallStackReq
&& Old
.getOpcode() == ARC::ADJCALLSTACKDOWN
)
450 AFI
->MaxCallStackReq
= Amt
;
453 assert((Old
.getOpcode() == ARC::ADJCALLSTACKDOWN
||
454 Old
.getOpcode() == ARC::ADJCALLSTACKUP
) &&
455 "Unknown Frame Pseudo.");
456 bool IsAdd
= (Old
.getOpcode() == ARC::ADJCALLSTACKUP
);
457 emitRegUpdate(MBB
, I
, dl
, ARC::SP
, Amt
, IsAdd
, TII
);
463 bool ARCFrameLowering::hasFP(const MachineFunction
&MF
) const {
464 const TargetRegisterInfo
*RegInfo
= MF
.getSubtarget().getRegisterInfo();
465 bool HasFP
= MF
.getTarget().Options
.DisableFramePointerElim(MF
) ||
466 MF
.getFrameInfo().hasVarSizedObjects() ||
467 MF
.getFrameInfo().isFrameAddressTaken() ||
468 RegInfo
->needsStackRealignment(MF
);