1*0fca6ea1SDimitry Andric //===- XtensaFrameLowering.cpp - Xtensa Frame Information -----------------===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric //
9*0fca6ea1SDimitry Andric // This file contains the Xtensa implementation of TargetFrameLowering class.
10*0fca6ea1SDimitry Andric //
11*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
12*0fca6ea1SDimitry Andric
13*0fca6ea1SDimitry Andric #include "XtensaFrameLowering.h"
14*0fca6ea1SDimitry Andric #include "XtensaInstrInfo.h"
15*0fca6ea1SDimitry Andric #include "XtensaSubtarget.h"
16*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
17*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
18*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
19*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
20*0fca6ea1SDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h"
21*0fca6ea1SDimitry Andric #include "llvm/IR/Function.h"
22*0fca6ea1SDimitry Andric
23*0fca6ea1SDimitry Andric using namespace llvm;
24*0fca6ea1SDimitry Andric
XtensaFrameLowering(const XtensaSubtarget & STI)25*0fca6ea1SDimitry Andric XtensaFrameLowering::XtensaFrameLowering(const XtensaSubtarget &STI)
26*0fca6ea1SDimitry Andric : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(4), 0,
27*0fca6ea1SDimitry Andric Align(4)),
28*0fca6ea1SDimitry Andric TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) {}
29*0fca6ea1SDimitry Andric
hasFP(const MachineFunction & MF) const30*0fca6ea1SDimitry Andric bool XtensaFrameLowering::hasFP(const MachineFunction &MF) const {
31*0fca6ea1SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo();
32*0fca6ea1SDimitry Andric return MF.getTarget().Options.DisableFramePointerElim(MF) ||
33*0fca6ea1SDimitry Andric MFI.hasVarSizedObjects();
34*0fca6ea1SDimitry Andric }
35*0fca6ea1SDimitry Andric
emitPrologue(MachineFunction & MF,MachineBasicBlock & MBB) const36*0fca6ea1SDimitry Andric void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
37*0fca6ea1SDimitry Andric MachineBasicBlock &MBB) const {
38*0fca6ea1SDimitry Andric assert(&MBB == &MF.front() && "Shrink-wrapping not yet implemented");
39*0fca6ea1SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo();
40*0fca6ea1SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.begin();
41*0fca6ea1SDimitry Andric DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
42*0fca6ea1SDimitry Andric MCRegister SP = Xtensa::SP;
43*0fca6ea1SDimitry Andric MCRegister FP = TRI->getFrameRegister(MF);
44*0fca6ea1SDimitry Andric const MCRegisterInfo *MRI = MF.getContext().getRegisterInfo();
45*0fca6ea1SDimitry Andric
46*0fca6ea1SDimitry Andric // First, compute final stack size.
47*0fca6ea1SDimitry Andric uint64_t StackSize = MFI.getStackSize();
48*0fca6ea1SDimitry Andric uint64_t PrevStackSize = StackSize;
49*0fca6ea1SDimitry Andric
50*0fca6ea1SDimitry Andric // Round up StackSize to 16*N
51*0fca6ea1SDimitry Andric StackSize += (16 - StackSize) & 0xf;
52*0fca6ea1SDimitry Andric
53*0fca6ea1SDimitry Andric // No need to allocate space on the stack.
54*0fca6ea1SDimitry Andric if (StackSize == 0 && !MFI.adjustsStack())
55*0fca6ea1SDimitry Andric return;
56*0fca6ea1SDimitry Andric
57*0fca6ea1SDimitry Andric // Adjust stack.
58*0fca6ea1SDimitry Andric TII.adjustStackPtr(SP, -StackSize, MBB, MBBI);
59*0fca6ea1SDimitry Andric
60*0fca6ea1SDimitry Andric // emit ".cfi_def_cfa_offset StackSize"
61*0fca6ea1SDimitry Andric unsigned CFIIndex =
62*0fca6ea1SDimitry Andric MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));
63*0fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
64*0fca6ea1SDimitry Andric .addCFIIndex(CFIIndex);
65*0fca6ea1SDimitry Andric
66*0fca6ea1SDimitry Andric const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
67*0fca6ea1SDimitry Andric
68*0fca6ea1SDimitry Andric if (!CSI.empty()) {
69*0fca6ea1SDimitry Andric // Find the instruction past the last instruction that saves a
70*0fca6ea1SDimitry Andric // callee-saved register to the stack. The callee-saved store
71*0fca6ea1SDimitry Andric // instructions are placed at the begin of basic block, so
72*0fca6ea1SDimitry Andric // iterate over instruction sequence and check that
73*0fca6ea1SDimitry Andric // save instructions are placed correctly.
74*0fca6ea1SDimitry Andric for (unsigned i = 0, e = CSI.size(); i < e; ++i) {
75*0fca6ea1SDimitry Andric #ifndef NDEBUG
76*0fca6ea1SDimitry Andric const CalleeSavedInfo &Info = CSI[i];
77*0fca6ea1SDimitry Andric int FI = Info.getFrameIdx();
78*0fca6ea1SDimitry Andric int StoreFI = 0;
79*0fca6ea1SDimitry Andric
80*0fca6ea1SDimitry Andric // Checking that the instruction is exactly as expected
81*0fca6ea1SDimitry Andric bool IsStoreInst = false;
82*0fca6ea1SDimitry Andric if (MBBI->getOpcode() == TargetOpcode::COPY && Info.isSpilledToReg()) {
83*0fca6ea1SDimitry Andric Register DstReg = MBBI->getOperand(0).getReg();
84*0fca6ea1SDimitry Andric Register Reg = MBBI->getOperand(1).getReg();
85*0fca6ea1SDimitry Andric IsStoreInst = (Info.getDstReg() == DstReg) && (Info.getReg() == Reg);
86*0fca6ea1SDimitry Andric } else {
87*0fca6ea1SDimitry Andric Register Reg = TII.isStoreToStackSlot(*MBBI, StoreFI);
88*0fca6ea1SDimitry Andric IsStoreInst = (Reg == Info.getReg()) && (StoreFI == FI);
89*0fca6ea1SDimitry Andric }
90*0fca6ea1SDimitry Andric assert(IsStoreInst &&
91*0fca6ea1SDimitry Andric "Unexpected callee-saved register store instruction");
92*0fca6ea1SDimitry Andric #endif
93*0fca6ea1SDimitry Andric ++MBBI;
94*0fca6ea1SDimitry Andric }
95*0fca6ea1SDimitry Andric
96*0fca6ea1SDimitry Andric // Iterate over list of callee-saved registers and emit .cfi_offset
97*0fca6ea1SDimitry Andric // directives.
98*0fca6ea1SDimitry Andric for (const auto &I : CSI) {
99*0fca6ea1SDimitry Andric int64_t Offset = MFI.getObjectOffset(I.getFrameIdx());
100*0fca6ea1SDimitry Andric Register Reg = I.getReg();
101*0fca6ea1SDimitry Andric
102*0fca6ea1SDimitry Andric unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
103*0fca6ea1SDimitry Andric nullptr, MRI->getDwarfRegNum(Reg, 1), Offset));
104*0fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
105*0fca6ea1SDimitry Andric .addCFIIndex(CFIIndex);
106*0fca6ea1SDimitry Andric }
107*0fca6ea1SDimitry Andric }
108*0fca6ea1SDimitry Andric
109*0fca6ea1SDimitry Andric // if framepointer enabled, set it to point to the stack pointer.
110*0fca6ea1SDimitry Andric if (hasFP(MF)) {
111*0fca6ea1SDimitry Andric // Insert instruction "move $fp, $sp" at this location.
112*0fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(Xtensa::OR), FP)
113*0fca6ea1SDimitry Andric .addReg(SP)
114*0fca6ea1SDimitry Andric .addReg(SP)
115*0fca6ea1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup);
116*0fca6ea1SDimitry Andric
117*0fca6ea1SDimitry Andric // emit ".cfi_def_cfa_register $fp"
118*0fca6ea1SDimitry Andric unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(
119*0fca6ea1SDimitry Andric nullptr, MRI->getDwarfRegNum(FP, true)));
120*0fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
121*0fca6ea1SDimitry Andric .addCFIIndex(CFIIndex);
122*0fca6ea1SDimitry Andric }
123*0fca6ea1SDimitry Andric
124*0fca6ea1SDimitry Andric if (StackSize != PrevStackSize) {
125*0fca6ea1SDimitry Andric MFI.setStackSize(StackSize);
126*0fca6ea1SDimitry Andric
127*0fca6ea1SDimitry Andric for (int i = MFI.getObjectIndexBegin(); i < MFI.getObjectIndexEnd(); i++) {
128*0fca6ea1SDimitry Andric if (!MFI.isDeadObjectIndex(i)) {
129*0fca6ea1SDimitry Andric int64_t SPOffset = MFI.getObjectOffset(i);
130*0fca6ea1SDimitry Andric
131*0fca6ea1SDimitry Andric if (SPOffset < 0)
132*0fca6ea1SDimitry Andric MFI.setObjectOffset(i, SPOffset - StackSize + PrevStackSize);
133*0fca6ea1SDimitry Andric }
134*0fca6ea1SDimitry Andric }
135*0fca6ea1SDimitry Andric }
136*0fca6ea1SDimitry Andric }
137*0fca6ea1SDimitry Andric
emitEpilogue(MachineFunction & MF,MachineBasicBlock & MBB) const138*0fca6ea1SDimitry Andric void XtensaFrameLowering::emitEpilogue(MachineFunction &MF,
139*0fca6ea1SDimitry Andric MachineBasicBlock &MBB) const {
140*0fca6ea1SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
141*0fca6ea1SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo();
142*0fca6ea1SDimitry Andric DebugLoc DL = MBBI->getDebugLoc();
143*0fca6ea1SDimitry Andric MCRegister SP = Xtensa::SP;
144*0fca6ea1SDimitry Andric MCRegister FP = TRI->getFrameRegister(MF);
145*0fca6ea1SDimitry Andric
146*0fca6ea1SDimitry Andric // if framepointer enabled, restore the stack pointer.
147*0fca6ea1SDimitry Andric if (hasFP(MF)) {
148*0fca6ea1SDimitry Andric // We should place restore stack pointer instruction just before
149*0fca6ea1SDimitry Andric // sequence of instructions which restores callee-saved registers.
150*0fca6ea1SDimitry Andric // This sequence is placed at the end of the basic block,
151*0fca6ea1SDimitry Andric // so we should find first instruction of the sequence.
152*0fca6ea1SDimitry Andric MachineBasicBlock::iterator I = MBBI;
153*0fca6ea1SDimitry Andric
154*0fca6ea1SDimitry Andric const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
155*0fca6ea1SDimitry Andric
156*0fca6ea1SDimitry Andric // Find the first instruction at the end that restores a callee-saved
157*0fca6ea1SDimitry Andric // register.
158*0fca6ea1SDimitry Andric for (unsigned i = 0, e = CSI.size(); i < e; ++i) {
159*0fca6ea1SDimitry Andric --I;
160*0fca6ea1SDimitry Andric #ifndef NDEBUG
161*0fca6ea1SDimitry Andric const CalleeSavedInfo &Info = CSI[i];
162*0fca6ea1SDimitry Andric int FI = Info.getFrameIdx();
163*0fca6ea1SDimitry Andric int LoadFI = 0;
164*0fca6ea1SDimitry Andric
165*0fca6ea1SDimitry Andric // Checking that the instruction is exactly as expected
166*0fca6ea1SDimitry Andric bool IsRestoreInst = false;
167*0fca6ea1SDimitry Andric if (I->getOpcode() == TargetOpcode::COPY && Info.isSpilledToReg()) {
168*0fca6ea1SDimitry Andric Register Reg = I->getOperand(0).getReg();
169*0fca6ea1SDimitry Andric Register DstReg = I->getOperand(1).getReg();
170*0fca6ea1SDimitry Andric IsRestoreInst = (Info.getDstReg() == DstReg) && (Info.getReg() == Reg);
171*0fca6ea1SDimitry Andric } else {
172*0fca6ea1SDimitry Andric Register Reg = TII.isLoadFromStackSlot(*I, LoadFI);
173*0fca6ea1SDimitry Andric IsRestoreInst = (Info.getReg() == Reg) && (LoadFI == FI);
174*0fca6ea1SDimitry Andric }
175*0fca6ea1SDimitry Andric assert(IsRestoreInst &&
176*0fca6ea1SDimitry Andric "Unexpected callee-saved register restore instruction");
177*0fca6ea1SDimitry Andric #endif
178*0fca6ea1SDimitry Andric }
179*0fca6ea1SDimitry Andric
180*0fca6ea1SDimitry Andric BuildMI(MBB, I, DL, TII.get(Xtensa::OR), SP).addReg(FP).addReg(FP);
181*0fca6ea1SDimitry Andric }
182*0fca6ea1SDimitry Andric
183*0fca6ea1SDimitry Andric // Get the number of bytes from FrameInfo
184*0fca6ea1SDimitry Andric uint64_t StackSize = MFI.getStackSize();
185*0fca6ea1SDimitry Andric
186*0fca6ea1SDimitry Andric if (!StackSize)
187*0fca6ea1SDimitry Andric return;
188*0fca6ea1SDimitry Andric
189*0fca6ea1SDimitry Andric // Adjust stack.
190*0fca6ea1SDimitry Andric TII.adjustStackPtr(SP, StackSize, MBB, MBBI);
191*0fca6ea1SDimitry Andric }
192*0fca6ea1SDimitry Andric
spillCalleeSavedRegisters(MachineBasicBlock & MBB,MachineBasicBlock::iterator MI,ArrayRef<CalleeSavedInfo> CSI,const TargetRegisterInfo * TRI) const193*0fca6ea1SDimitry Andric bool XtensaFrameLowering::spillCalleeSavedRegisters(
194*0fca6ea1SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
195*0fca6ea1SDimitry Andric ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
196*0fca6ea1SDimitry Andric MachineFunction *MF = MBB.getParent();
197*0fca6ea1SDimitry Andric MachineBasicBlock &EntryBlock = *(MF->begin());
198*0fca6ea1SDimitry Andric
199*0fca6ea1SDimitry Andric for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
200*0fca6ea1SDimitry Andric // Add the callee-saved register as live-in. Do not add if the register is
201*0fca6ea1SDimitry Andric // A0 and return address is taken, because it will be implemented in
202*0fca6ea1SDimitry Andric // method XtensaTargetLowering::LowerRETURNADDR.
203*0fca6ea1SDimitry Andric // It's killed at the spill, unless the register is RA and return address
204*0fca6ea1SDimitry Andric // is taken.
205*0fca6ea1SDimitry Andric Register Reg = CSI[i].getReg();
206*0fca6ea1SDimitry Andric bool IsA0AndRetAddrIsTaken =
207*0fca6ea1SDimitry Andric (Reg == Xtensa::A0) && MF->getFrameInfo().isReturnAddressTaken();
208*0fca6ea1SDimitry Andric if (!IsA0AndRetAddrIsTaken)
209*0fca6ea1SDimitry Andric EntryBlock.addLiveIn(Reg);
210*0fca6ea1SDimitry Andric
211*0fca6ea1SDimitry Andric // Insert the spill to the stack frame.
212*0fca6ea1SDimitry Andric bool IsKill = !IsA0AndRetAddrIsTaken;
213*0fca6ea1SDimitry Andric const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
214*0fca6ea1SDimitry Andric TII.storeRegToStackSlot(EntryBlock, MI, Reg, IsKill, CSI[i].getFrameIdx(),
215*0fca6ea1SDimitry Andric RC, TRI, Register());
216*0fca6ea1SDimitry Andric }
217*0fca6ea1SDimitry Andric
218*0fca6ea1SDimitry Andric return true;
219*0fca6ea1SDimitry Andric }
220*0fca6ea1SDimitry Andric
restoreCalleeSavedRegisters(MachineBasicBlock & MBB,MachineBasicBlock::iterator MI,MutableArrayRef<CalleeSavedInfo> CSI,const TargetRegisterInfo * TRI) const221*0fca6ea1SDimitry Andric bool XtensaFrameLowering::restoreCalleeSavedRegisters(
222*0fca6ea1SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
223*0fca6ea1SDimitry Andric MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
224*0fca6ea1SDimitry Andric return TargetFrameLowering::restoreCalleeSavedRegisters(MBB, MI, CSI, TRI);
225*0fca6ea1SDimitry Andric }
226*0fca6ea1SDimitry Andric
227*0fca6ea1SDimitry Andric // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions
eliminateCallFramePseudoInstr(MachineFunction & MF,MachineBasicBlock & MBB,MachineBasicBlock::iterator I) const228*0fca6ea1SDimitry Andric MachineBasicBlock::iterator XtensaFrameLowering::eliminateCallFramePseudoInstr(
229*0fca6ea1SDimitry Andric MachineFunction &MF, MachineBasicBlock &MBB,
230*0fca6ea1SDimitry Andric MachineBasicBlock::iterator I) const {
231*0fca6ea1SDimitry Andric const XtensaInstrInfo &TII =
232*0fca6ea1SDimitry Andric *static_cast<const XtensaInstrInfo *>(MF.getSubtarget().getInstrInfo());
233*0fca6ea1SDimitry Andric
234*0fca6ea1SDimitry Andric if (!hasReservedCallFrame(MF)) {
235*0fca6ea1SDimitry Andric int64_t Amount = I->getOperand(0).getImm();
236*0fca6ea1SDimitry Andric
237*0fca6ea1SDimitry Andric if (I->getOpcode() == Xtensa::ADJCALLSTACKDOWN)
238*0fca6ea1SDimitry Andric Amount = -Amount;
239*0fca6ea1SDimitry Andric
240*0fca6ea1SDimitry Andric TII.adjustStackPtr(Xtensa::SP, Amount, MBB, I);
241*0fca6ea1SDimitry Andric }
242*0fca6ea1SDimitry Andric
243*0fca6ea1SDimitry Andric return MBB.erase(I);
244*0fca6ea1SDimitry Andric }
245*0fca6ea1SDimitry Andric
determineCalleeSaves(MachineFunction & MF,BitVector & SavedRegs,RegScavenger * RS) const246*0fca6ea1SDimitry Andric void XtensaFrameLowering::determineCalleeSaves(MachineFunction &MF,
247*0fca6ea1SDimitry Andric BitVector &SavedRegs,
248*0fca6ea1SDimitry Andric RegScavenger *RS) const {
249*0fca6ea1SDimitry Andric unsigned FP = TRI->getFrameRegister(MF);
250*0fca6ea1SDimitry Andric
251*0fca6ea1SDimitry Andric TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
252*0fca6ea1SDimitry Andric
253*0fca6ea1SDimitry Andric // Mark $fp as used if function has dedicated frame pointer.
254*0fca6ea1SDimitry Andric if (hasFP(MF))
255*0fca6ea1SDimitry Andric SavedRegs.set(FP);
256*0fca6ea1SDimitry Andric }
257*0fca6ea1SDimitry Andric
processFunctionBeforeFrameFinalized(MachineFunction & MF,RegScavenger * RS) const258*0fca6ea1SDimitry Andric void XtensaFrameLowering::processFunctionBeforeFrameFinalized(
259*0fca6ea1SDimitry Andric MachineFunction &MF, RegScavenger *RS) const {
260*0fca6ea1SDimitry Andric // Set scavenging frame index if necessary.
261*0fca6ea1SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo();
262*0fca6ea1SDimitry Andric uint64_t MaxSPOffset = MFI.estimateStackSize(MF);
263*0fca6ea1SDimitry Andric
264*0fca6ea1SDimitry Andric if (isInt<12>(MaxSPOffset))
265*0fca6ea1SDimitry Andric return;
266*0fca6ea1SDimitry Andric
267*0fca6ea1SDimitry Andric const TargetRegisterClass &RC = Xtensa::ARRegClass;
268*0fca6ea1SDimitry Andric unsigned Size = TRI->getSpillSize(RC);
269*0fca6ea1SDimitry Andric Align Alignment = TRI->getSpillAlign(RC);
270*0fca6ea1SDimitry Andric int FI = MF.getFrameInfo().CreateStackObject(Size, Alignment, false);
271*0fca6ea1SDimitry Andric
272*0fca6ea1SDimitry Andric RS->addScavengingFrameIndex(FI);
273*0fca6ea1SDimitry Andric }
274