xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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