xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Sparc/SparcFrameLowering.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===-- SparcFrameLowering.cpp - Sparc Frame Information ------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This file contains the Sparc implementation of TargetFrameLowering class.
10*0b57cec5SDimitry Andric //
11*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
12*0b57cec5SDimitry Andric 
13*0b57cec5SDimitry Andric #include "SparcFrameLowering.h"
14*0b57cec5SDimitry Andric #include "SparcInstrInfo.h"
15*0b57cec5SDimitry Andric #include "SparcMachineFunctionInfo.h"
16*0b57cec5SDimitry Andric #include "SparcSubtarget.h"
17*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
18*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
19*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
20*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
21*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
22*0b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h"
23*0b57cec5SDimitry Andric #include "llvm/IR/Function.h"
24*0b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
25*0b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h"
26*0b57cec5SDimitry Andric 
27*0b57cec5SDimitry Andric using namespace llvm;
28*0b57cec5SDimitry Andric 
29*0b57cec5SDimitry Andric static cl::opt<bool>
30*0b57cec5SDimitry Andric DisableLeafProc("disable-sparc-leaf-proc",
31*0b57cec5SDimitry Andric                 cl::init(false),
32*0b57cec5SDimitry Andric                 cl::desc("Disable Sparc leaf procedure optimization."),
33*0b57cec5SDimitry Andric                 cl::Hidden);
34*0b57cec5SDimitry Andric 
35*0b57cec5SDimitry Andric SparcFrameLowering::SparcFrameLowering(const SparcSubtarget &ST)
36*0b57cec5SDimitry Andric     : TargetFrameLowering(TargetFrameLowering::StackGrowsDown,
37*0b57cec5SDimitry Andric                           ST.is64Bit() ? 16 : 8, 0, ST.is64Bit() ? 16 : 8) {}
38*0b57cec5SDimitry Andric 
39*0b57cec5SDimitry Andric void SparcFrameLowering::emitSPAdjustment(MachineFunction &MF,
40*0b57cec5SDimitry Andric                                           MachineBasicBlock &MBB,
41*0b57cec5SDimitry Andric                                           MachineBasicBlock::iterator MBBI,
42*0b57cec5SDimitry Andric                                           int NumBytes,
43*0b57cec5SDimitry Andric                                           unsigned ADDrr,
44*0b57cec5SDimitry Andric                                           unsigned ADDri) const {
45*0b57cec5SDimitry Andric 
46*0b57cec5SDimitry Andric   DebugLoc dl;
47*0b57cec5SDimitry Andric   const SparcInstrInfo &TII =
48*0b57cec5SDimitry Andric       *static_cast<const SparcInstrInfo *>(MF.getSubtarget().getInstrInfo());
49*0b57cec5SDimitry Andric 
50*0b57cec5SDimitry Andric   if (NumBytes >= -4096 && NumBytes < 4096) {
51*0b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII.get(ADDri), SP::O6)
52*0b57cec5SDimitry Andric       .addReg(SP::O6).addImm(NumBytes);
53*0b57cec5SDimitry Andric     return;
54*0b57cec5SDimitry Andric   }
55*0b57cec5SDimitry Andric 
56*0b57cec5SDimitry Andric   // Emit this the hard way.  This clobbers G1 which we always know is
57*0b57cec5SDimitry Andric   // available here.
58*0b57cec5SDimitry Andric   if (NumBytes >= 0) {
59*0b57cec5SDimitry Andric     // Emit nonnegative numbers with sethi + or.
60*0b57cec5SDimitry Andric     // sethi %hi(NumBytes), %g1
61*0b57cec5SDimitry Andric     // or %g1, %lo(NumBytes), %g1
62*0b57cec5SDimitry Andric     // add %sp, %g1, %sp
63*0b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII.get(SP::SETHIi), SP::G1)
64*0b57cec5SDimitry Andric       .addImm(HI22(NumBytes));
65*0b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII.get(SP::ORri), SP::G1)
66*0b57cec5SDimitry Andric       .addReg(SP::G1).addImm(LO10(NumBytes));
67*0b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII.get(ADDrr), SP::O6)
68*0b57cec5SDimitry Andric       .addReg(SP::O6).addReg(SP::G1);
69*0b57cec5SDimitry Andric     return ;
70*0b57cec5SDimitry Andric   }
71*0b57cec5SDimitry Andric 
72*0b57cec5SDimitry Andric   // Emit negative numbers with sethi + xor.
73*0b57cec5SDimitry Andric   // sethi %hix(NumBytes), %g1
74*0b57cec5SDimitry Andric   // xor %g1, %lox(NumBytes), %g1
75*0b57cec5SDimitry Andric   // add %sp, %g1, %sp
76*0b57cec5SDimitry Andric   BuildMI(MBB, MBBI, dl, TII.get(SP::SETHIi), SP::G1)
77*0b57cec5SDimitry Andric     .addImm(HIX22(NumBytes));
78*0b57cec5SDimitry Andric   BuildMI(MBB, MBBI, dl, TII.get(SP::XORri), SP::G1)
79*0b57cec5SDimitry Andric     .addReg(SP::G1).addImm(LOX10(NumBytes));
80*0b57cec5SDimitry Andric   BuildMI(MBB, MBBI, dl, TII.get(ADDrr), SP::O6)
81*0b57cec5SDimitry Andric     .addReg(SP::O6).addReg(SP::G1);
82*0b57cec5SDimitry Andric }
83*0b57cec5SDimitry Andric 
84*0b57cec5SDimitry Andric void SparcFrameLowering::emitPrologue(MachineFunction &MF,
85*0b57cec5SDimitry Andric                                       MachineBasicBlock &MBB) const {
86*0b57cec5SDimitry Andric   SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
87*0b57cec5SDimitry Andric 
88*0b57cec5SDimitry Andric   assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");
89*0b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
90*0b57cec5SDimitry Andric   const SparcSubtarget &Subtarget = MF.getSubtarget<SparcSubtarget>();
91*0b57cec5SDimitry Andric   const SparcInstrInfo &TII =
92*0b57cec5SDimitry Andric       *static_cast<const SparcInstrInfo *>(Subtarget.getInstrInfo());
93*0b57cec5SDimitry Andric   const SparcRegisterInfo &RegInfo =
94*0b57cec5SDimitry Andric       *static_cast<const SparcRegisterInfo *>(Subtarget.getRegisterInfo());
95*0b57cec5SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.begin();
96*0b57cec5SDimitry Andric   // Debug location must be unknown since the first debug location is used
97*0b57cec5SDimitry Andric   // to determine the end of the prologue.
98*0b57cec5SDimitry Andric   DebugLoc dl;
99*0b57cec5SDimitry Andric   bool NeedsStackRealignment = RegInfo.needsStackRealignment(MF);
100*0b57cec5SDimitry Andric 
101*0b57cec5SDimitry Andric   // FIXME: unfortunately, returning false from canRealignStack
102*0b57cec5SDimitry Andric   // actually just causes needsStackRealignment to return false,
103*0b57cec5SDimitry Andric   // rather than reporting an error, as would be sensible. This is
104*0b57cec5SDimitry Andric   // poor, but fixing that bogosity is going to be a large project.
105*0b57cec5SDimitry Andric   // For now, just see if it's lied, and report an error here.
106*0b57cec5SDimitry Andric   if (!NeedsStackRealignment && MFI.getMaxAlignment() > getStackAlignment())
107*0b57cec5SDimitry Andric     report_fatal_error("Function \"" + Twine(MF.getName()) + "\" required "
108*0b57cec5SDimitry Andric                        "stack re-alignment, but LLVM couldn't handle it "
109*0b57cec5SDimitry Andric                        "(probably because it has a dynamic alloca).");
110*0b57cec5SDimitry Andric 
111*0b57cec5SDimitry Andric   // Get the number of bytes to allocate from the FrameInfo
112*0b57cec5SDimitry Andric   int NumBytes = (int) MFI.getStackSize();
113*0b57cec5SDimitry Andric 
114*0b57cec5SDimitry Andric   unsigned SAVEri = SP::SAVEri;
115*0b57cec5SDimitry Andric   unsigned SAVErr = SP::SAVErr;
116*0b57cec5SDimitry Andric   if (FuncInfo->isLeafProc()) {
117*0b57cec5SDimitry Andric     if (NumBytes == 0)
118*0b57cec5SDimitry Andric       return;
119*0b57cec5SDimitry Andric     SAVEri = SP::ADDri;
120*0b57cec5SDimitry Andric     SAVErr = SP::ADDrr;
121*0b57cec5SDimitry Andric   }
122*0b57cec5SDimitry Andric 
123*0b57cec5SDimitry Andric   // The SPARC ABI is a bit odd in that it requires a reserved 92-byte
124*0b57cec5SDimitry Andric   // (128 in v9) area in the user's stack, starting at %sp. Thus, the
125*0b57cec5SDimitry Andric   // first part of the stack that can actually be used is located at
126*0b57cec5SDimitry Andric   // %sp + 92.
127*0b57cec5SDimitry Andric   //
128*0b57cec5SDimitry Andric   // We therefore need to add that offset to the total stack size
129*0b57cec5SDimitry Andric   // after all the stack objects are placed by
130*0b57cec5SDimitry Andric   // PrologEpilogInserter calculateFrameObjectOffsets. However, since the stack needs to be
131*0b57cec5SDimitry Andric   // aligned *after* the extra size is added, we need to disable
132*0b57cec5SDimitry Andric   // calculateFrameObjectOffsets's built-in stack alignment, by having
133*0b57cec5SDimitry Andric   // targetHandlesStackFrameRounding return true.
134*0b57cec5SDimitry Andric 
135*0b57cec5SDimitry Andric 
136*0b57cec5SDimitry Andric   // Add the extra call frame stack size, if needed. (This is the same
137*0b57cec5SDimitry Andric   // code as in PrologEpilogInserter, but also gets disabled by
138*0b57cec5SDimitry Andric   // targetHandlesStackFrameRounding)
139*0b57cec5SDimitry Andric   if (MFI.adjustsStack() && hasReservedCallFrame(MF))
140*0b57cec5SDimitry Andric     NumBytes += MFI.getMaxCallFrameSize();
141*0b57cec5SDimitry Andric 
142*0b57cec5SDimitry Andric   // Adds the SPARC subtarget-specific spill area to the stack
143*0b57cec5SDimitry Andric   // size. Also ensures target-required alignment.
144*0b57cec5SDimitry Andric   NumBytes = Subtarget.getAdjustedFrameSize(NumBytes);
145*0b57cec5SDimitry Andric 
146*0b57cec5SDimitry Andric   // Finally, ensure that the size is sufficiently aligned for the
147*0b57cec5SDimitry Andric   // data on the stack.
148*0b57cec5SDimitry Andric   if (MFI.getMaxAlignment() > 0) {
149*0b57cec5SDimitry Andric     NumBytes = alignTo(NumBytes, MFI.getMaxAlignment());
150*0b57cec5SDimitry Andric   }
151*0b57cec5SDimitry Andric 
152*0b57cec5SDimitry Andric   // Update stack size with corrected value.
153*0b57cec5SDimitry Andric   MFI.setStackSize(NumBytes);
154*0b57cec5SDimitry Andric 
155*0b57cec5SDimitry Andric   emitSPAdjustment(MF, MBB, MBBI, -NumBytes, SAVErr, SAVEri);
156*0b57cec5SDimitry Andric 
157*0b57cec5SDimitry Andric   unsigned regFP = RegInfo.getDwarfRegNum(SP::I6, true);
158*0b57cec5SDimitry Andric 
159*0b57cec5SDimitry Andric   // Emit ".cfi_def_cfa_register 30".
160*0b57cec5SDimitry Andric   unsigned CFIIndex =
161*0b57cec5SDimitry Andric       MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(nullptr, regFP));
162*0b57cec5SDimitry Andric   BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
163*0b57cec5SDimitry Andric       .addCFIIndex(CFIIndex);
164*0b57cec5SDimitry Andric 
165*0b57cec5SDimitry Andric   // Emit ".cfi_window_save".
166*0b57cec5SDimitry Andric   CFIIndex = MF.addFrameInst(MCCFIInstruction::createWindowSave(nullptr));
167*0b57cec5SDimitry Andric   BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
168*0b57cec5SDimitry Andric       .addCFIIndex(CFIIndex);
169*0b57cec5SDimitry Andric 
170*0b57cec5SDimitry Andric   unsigned regInRA = RegInfo.getDwarfRegNum(SP::I7, true);
171*0b57cec5SDimitry Andric   unsigned regOutRA = RegInfo.getDwarfRegNum(SP::O7, true);
172*0b57cec5SDimitry Andric   // Emit ".cfi_register 15, 31".
173*0b57cec5SDimitry Andric   CFIIndex = MF.addFrameInst(
174*0b57cec5SDimitry Andric       MCCFIInstruction::createRegister(nullptr, regOutRA, regInRA));
175*0b57cec5SDimitry Andric   BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
176*0b57cec5SDimitry Andric       .addCFIIndex(CFIIndex);
177*0b57cec5SDimitry Andric 
178*0b57cec5SDimitry Andric   if (NeedsStackRealignment) {
179*0b57cec5SDimitry Andric     int64_t Bias = Subtarget.getStackPointerBias();
180*0b57cec5SDimitry Andric     unsigned regUnbiased;
181*0b57cec5SDimitry Andric     if (Bias) {
182*0b57cec5SDimitry Andric       // This clobbers G1 which we always know is available here.
183*0b57cec5SDimitry Andric       regUnbiased = SP::G1;
184*0b57cec5SDimitry Andric       // add %o6, BIAS, %g1
185*0b57cec5SDimitry Andric       BuildMI(MBB, MBBI, dl, TII.get(SP::ADDri), regUnbiased)
186*0b57cec5SDimitry Andric         .addReg(SP::O6).addImm(Bias);
187*0b57cec5SDimitry Andric     } else
188*0b57cec5SDimitry Andric       regUnbiased = SP::O6;
189*0b57cec5SDimitry Andric 
190*0b57cec5SDimitry Andric     // andn %regUnbiased, MaxAlign-1, %regUnbiased
191*0b57cec5SDimitry Andric     int MaxAlign = MFI.getMaxAlignment();
192*0b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII.get(SP::ANDNri), regUnbiased)
193*0b57cec5SDimitry Andric       .addReg(regUnbiased).addImm(MaxAlign - 1);
194*0b57cec5SDimitry Andric 
195*0b57cec5SDimitry Andric     if (Bias) {
196*0b57cec5SDimitry Andric       // add %g1, -BIAS, %o6
197*0b57cec5SDimitry Andric       BuildMI(MBB, MBBI, dl, TII.get(SP::ADDri), SP::O6)
198*0b57cec5SDimitry Andric         .addReg(regUnbiased).addImm(-Bias);
199*0b57cec5SDimitry Andric     }
200*0b57cec5SDimitry Andric   }
201*0b57cec5SDimitry Andric }
202*0b57cec5SDimitry Andric 
203*0b57cec5SDimitry Andric MachineBasicBlock::iterator SparcFrameLowering::
204*0b57cec5SDimitry Andric eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
205*0b57cec5SDimitry Andric                               MachineBasicBlock::iterator I) const {
206*0b57cec5SDimitry Andric   if (!hasReservedCallFrame(MF)) {
207*0b57cec5SDimitry Andric     MachineInstr &MI = *I;
208*0b57cec5SDimitry Andric     int Size = MI.getOperand(0).getImm();
209*0b57cec5SDimitry Andric     if (MI.getOpcode() == SP::ADJCALLSTACKDOWN)
210*0b57cec5SDimitry Andric       Size = -Size;
211*0b57cec5SDimitry Andric 
212*0b57cec5SDimitry Andric     if (Size)
213*0b57cec5SDimitry Andric       emitSPAdjustment(MF, MBB, I, Size, SP::ADDrr, SP::ADDri);
214*0b57cec5SDimitry Andric   }
215*0b57cec5SDimitry Andric   return MBB.erase(I);
216*0b57cec5SDimitry Andric }
217*0b57cec5SDimitry Andric 
218*0b57cec5SDimitry Andric 
219*0b57cec5SDimitry Andric void SparcFrameLowering::emitEpilogue(MachineFunction &MF,
220*0b57cec5SDimitry Andric                                   MachineBasicBlock &MBB) const {
221*0b57cec5SDimitry Andric   SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
222*0b57cec5SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
223*0b57cec5SDimitry Andric   const SparcInstrInfo &TII =
224*0b57cec5SDimitry Andric       *static_cast<const SparcInstrInfo *>(MF.getSubtarget().getInstrInfo());
225*0b57cec5SDimitry Andric   DebugLoc dl = MBBI->getDebugLoc();
226*0b57cec5SDimitry Andric   assert(MBBI->getOpcode() == SP::RETL &&
227*0b57cec5SDimitry Andric          "Can only put epilog before 'retl' instruction!");
228*0b57cec5SDimitry Andric   if (!FuncInfo->isLeafProc()) {
229*0b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII.get(SP::RESTORErr), SP::G0).addReg(SP::G0)
230*0b57cec5SDimitry Andric       .addReg(SP::G0);
231*0b57cec5SDimitry Andric     return;
232*0b57cec5SDimitry Andric   }
233*0b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
234*0b57cec5SDimitry Andric 
235*0b57cec5SDimitry Andric   int NumBytes = (int) MFI.getStackSize();
236*0b57cec5SDimitry Andric   if (NumBytes == 0)
237*0b57cec5SDimitry Andric     return;
238*0b57cec5SDimitry Andric 
239*0b57cec5SDimitry Andric   emitSPAdjustment(MF, MBB, MBBI, NumBytes, SP::ADDrr, SP::ADDri);
240*0b57cec5SDimitry Andric }
241*0b57cec5SDimitry Andric 
242*0b57cec5SDimitry Andric bool SparcFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
243*0b57cec5SDimitry Andric   // Reserve call frame if there are no variable sized objects on the stack.
244*0b57cec5SDimitry Andric   return !MF.getFrameInfo().hasVarSizedObjects();
245*0b57cec5SDimitry Andric }
246*0b57cec5SDimitry Andric 
247*0b57cec5SDimitry Andric // hasFP - Return true if the specified function should have a dedicated frame
248*0b57cec5SDimitry Andric // pointer register.  This is true if the function has variable sized allocas or
249*0b57cec5SDimitry Andric // if frame pointer elimination is disabled.
250*0b57cec5SDimitry Andric bool SparcFrameLowering::hasFP(const MachineFunction &MF) const {
251*0b57cec5SDimitry Andric   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
252*0b57cec5SDimitry Andric 
253*0b57cec5SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
254*0b57cec5SDimitry Andric   return MF.getTarget().Options.DisableFramePointerElim(MF) ||
255*0b57cec5SDimitry Andric       RegInfo->needsStackRealignment(MF) ||
256*0b57cec5SDimitry Andric       MFI.hasVarSizedObjects() ||
257*0b57cec5SDimitry Andric       MFI.isFrameAddressTaken();
258*0b57cec5SDimitry Andric }
259*0b57cec5SDimitry Andric 
260*0b57cec5SDimitry Andric 
261*0b57cec5SDimitry Andric int SparcFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
262*0b57cec5SDimitry Andric                                                unsigned &FrameReg) const {
263*0b57cec5SDimitry Andric   const SparcSubtarget &Subtarget = MF.getSubtarget<SparcSubtarget>();
264*0b57cec5SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
265*0b57cec5SDimitry Andric   const SparcRegisterInfo *RegInfo = Subtarget.getRegisterInfo();
266*0b57cec5SDimitry Andric   const SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
267*0b57cec5SDimitry Andric   bool isFixed = MFI.isFixedObjectIndex(FI);
268*0b57cec5SDimitry Andric 
269*0b57cec5SDimitry Andric   // Addressable stack objects are accessed using neg. offsets from
270*0b57cec5SDimitry Andric   // %fp, or positive offsets from %sp.
271*0b57cec5SDimitry Andric   bool UseFP;
272*0b57cec5SDimitry Andric 
273*0b57cec5SDimitry Andric   // Sparc uses FP-based references in general, even when "hasFP" is
274*0b57cec5SDimitry Andric   // false. That function is rather a misnomer, because %fp is
275*0b57cec5SDimitry Andric   // actually always available, unless isLeafProc.
276*0b57cec5SDimitry Andric   if (FuncInfo->isLeafProc()) {
277*0b57cec5SDimitry Andric     // If there's a leaf proc, all offsets need to be %sp-based,
278*0b57cec5SDimitry Andric     // because we haven't caused %fp to actually point to our frame.
279*0b57cec5SDimitry Andric     UseFP = false;
280*0b57cec5SDimitry Andric   } else if (isFixed) {
281*0b57cec5SDimitry Andric     // Otherwise, argument access should always use %fp.
282*0b57cec5SDimitry Andric     UseFP = true;
283*0b57cec5SDimitry Andric   } else if (RegInfo->needsStackRealignment(MF)) {
284*0b57cec5SDimitry Andric     // If there is dynamic stack realignment, all local object
285*0b57cec5SDimitry Andric     // references need to be via %sp, to take account of the
286*0b57cec5SDimitry Andric     // re-alignment.
287*0b57cec5SDimitry Andric     UseFP = false;
288*0b57cec5SDimitry Andric   } else {
289*0b57cec5SDimitry Andric     // Finally, default to using %fp.
290*0b57cec5SDimitry Andric     UseFP = true;
291*0b57cec5SDimitry Andric   }
292*0b57cec5SDimitry Andric 
293*0b57cec5SDimitry Andric   int64_t FrameOffset = MF.getFrameInfo().getObjectOffset(FI) +
294*0b57cec5SDimitry Andric       Subtarget.getStackPointerBias();
295*0b57cec5SDimitry Andric 
296*0b57cec5SDimitry Andric   if (UseFP) {
297*0b57cec5SDimitry Andric     FrameReg = RegInfo->getFrameRegister(MF);
298*0b57cec5SDimitry Andric     return FrameOffset;
299*0b57cec5SDimitry Andric   } else {
300*0b57cec5SDimitry Andric     FrameReg = SP::O6; // %sp
301*0b57cec5SDimitry Andric     return FrameOffset + MF.getFrameInfo().getStackSize();
302*0b57cec5SDimitry Andric   }
303*0b57cec5SDimitry Andric }
304*0b57cec5SDimitry Andric 
305*0b57cec5SDimitry Andric static bool LLVM_ATTRIBUTE_UNUSED verifyLeafProcRegUse(MachineRegisterInfo *MRI)
306*0b57cec5SDimitry Andric {
307*0b57cec5SDimitry Andric 
308*0b57cec5SDimitry Andric   for (unsigned reg = SP::I0; reg <= SP::I7; ++reg)
309*0b57cec5SDimitry Andric     if (MRI->isPhysRegUsed(reg))
310*0b57cec5SDimitry Andric       return false;
311*0b57cec5SDimitry Andric 
312*0b57cec5SDimitry Andric   for (unsigned reg = SP::L0; reg <= SP::L7; ++reg)
313*0b57cec5SDimitry Andric     if (MRI->isPhysRegUsed(reg))
314*0b57cec5SDimitry Andric       return false;
315*0b57cec5SDimitry Andric 
316*0b57cec5SDimitry Andric   return true;
317*0b57cec5SDimitry Andric }
318*0b57cec5SDimitry Andric 
319*0b57cec5SDimitry Andric bool SparcFrameLowering::isLeafProc(MachineFunction &MF) const
320*0b57cec5SDimitry Andric {
321*0b57cec5SDimitry Andric 
322*0b57cec5SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
323*0b57cec5SDimitry Andric   MachineFrameInfo    &MFI = MF.getFrameInfo();
324*0b57cec5SDimitry Andric 
325*0b57cec5SDimitry Andric   return !(MFI.hasCalls()                  // has calls
326*0b57cec5SDimitry Andric            || MRI.isPhysRegUsed(SP::L0)    // Too many registers needed
327*0b57cec5SDimitry Andric            || MRI.isPhysRegUsed(SP::O6)    // %sp is used
328*0b57cec5SDimitry Andric            || hasFP(MF));                  // need %fp
329*0b57cec5SDimitry Andric }
330*0b57cec5SDimitry Andric 
331*0b57cec5SDimitry Andric void SparcFrameLowering::remapRegsForLeafProc(MachineFunction &MF) const {
332*0b57cec5SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
333*0b57cec5SDimitry Andric   // Remap %i[0-7] to %o[0-7].
334*0b57cec5SDimitry Andric   for (unsigned reg = SP::I0; reg <= SP::I7; ++reg) {
335*0b57cec5SDimitry Andric     if (!MRI.isPhysRegUsed(reg))
336*0b57cec5SDimitry Andric       continue;
337*0b57cec5SDimitry Andric 
338*0b57cec5SDimitry Andric     unsigned mapped_reg = reg - SP::I0 + SP::O0;
339*0b57cec5SDimitry Andric 
340*0b57cec5SDimitry Andric     // Replace I register with O register.
341*0b57cec5SDimitry Andric     MRI.replaceRegWith(reg, mapped_reg);
342*0b57cec5SDimitry Andric 
343*0b57cec5SDimitry Andric     // Also replace register pair super-registers.
344*0b57cec5SDimitry Andric     if ((reg - SP::I0) % 2 == 0) {
345*0b57cec5SDimitry Andric       unsigned preg = (reg - SP::I0) / 2 + SP::I0_I1;
346*0b57cec5SDimitry Andric       unsigned mapped_preg = preg - SP::I0_I1 + SP::O0_O1;
347*0b57cec5SDimitry Andric       MRI.replaceRegWith(preg, mapped_preg);
348*0b57cec5SDimitry Andric     }
349*0b57cec5SDimitry Andric   }
350*0b57cec5SDimitry Andric 
351*0b57cec5SDimitry Andric   // Rewrite MBB's Live-ins.
352*0b57cec5SDimitry Andric   for (MachineFunction::iterator MBB = MF.begin(), E = MF.end();
353*0b57cec5SDimitry Andric        MBB != E; ++MBB) {
354*0b57cec5SDimitry Andric     for (unsigned reg = SP::I0_I1; reg <= SP::I6_I7; ++reg) {
355*0b57cec5SDimitry Andric       if (!MBB->isLiveIn(reg))
356*0b57cec5SDimitry Andric         continue;
357*0b57cec5SDimitry Andric       MBB->removeLiveIn(reg);
358*0b57cec5SDimitry Andric       MBB->addLiveIn(reg - SP::I0_I1 + SP::O0_O1);
359*0b57cec5SDimitry Andric     }
360*0b57cec5SDimitry Andric     for (unsigned reg = SP::I0; reg <= SP::I7; ++reg) {
361*0b57cec5SDimitry Andric       if (!MBB->isLiveIn(reg))
362*0b57cec5SDimitry Andric         continue;
363*0b57cec5SDimitry Andric       MBB->removeLiveIn(reg);
364*0b57cec5SDimitry Andric       MBB->addLiveIn(reg - SP::I0 + SP::O0);
365*0b57cec5SDimitry Andric     }
366*0b57cec5SDimitry Andric   }
367*0b57cec5SDimitry Andric 
368*0b57cec5SDimitry Andric   assert(verifyLeafProcRegUse(&MRI));
369*0b57cec5SDimitry Andric #ifdef EXPENSIVE_CHECKS
370*0b57cec5SDimitry Andric   MF.verify(0, "After LeafProc Remapping");
371*0b57cec5SDimitry Andric #endif
372*0b57cec5SDimitry Andric }
373*0b57cec5SDimitry Andric 
374*0b57cec5SDimitry Andric void SparcFrameLowering::determineCalleeSaves(MachineFunction &MF,
375*0b57cec5SDimitry Andric                                               BitVector &SavedRegs,
376*0b57cec5SDimitry Andric                                               RegScavenger *RS) const {
377*0b57cec5SDimitry Andric   TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
378*0b57cec5SDimitry Andric   if (!DisableLeafProc && isLeafProc(MF)) {
379*0b57cec5SDimitry Andric     SparcMachineFunctionInfo *MFI = MF.getInfo<SparcMachineFunctionInfo>();
380*0b57cec5SDimitry Andric     MFI->setLeafProc(true);
381*0b57cec5SDimitry Andric 
382*0b57cec5SDimitry Andric     remapRegsForLeafProc(MF);
383*0b57cec5SDimitry Andric   }
384*0b57cec5SDimitry Andric 
385*0b57cec5SDimitry Andric }
386