1//===-- XCoreFrameLowering.cpp - Frame info for XCore Target -----*- C++ -*-==//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file contains XCore frame information that doesn't fit anywhere else
11// cleanly...
12//
13//===----------------------------------------------------------------------===//
14
15#include "XCore.h"
16#include "XCoreFrameLowering.h"
17#include "XCoreInstrInfo.h"
18#include "XCoreMachineFunctionInfo.h"
19#include "llvm/Function.h"
20#include "llvm/CodeGen/MachineFrameInfo.h"
21#include "llvm/CodeGen/MachineFunction.h"
22#include "llvm/CodeGen/MachineInstrBuilder.h"
23#include "llvm/CodeGen/MachineModuleInfo.h"
24#include "llvm/CodeGen/MachineRegisterInfo.h"
25#include "llvm/CodeGen/RegisterScavenging.h"
26#include "llvm/Target/TargetData.h"
27#include "llvm/Target/TargetOptions.h"
28#include "llvm/Support/ErrorHandling.h"
29
30using namespace llvm;
31
32// helper functions. FIXME: Eliminate.
33static inline bool isImmUs(unsigned val) {
34  return val <= 11;
35}
36
37static inline bool isImmU6(unsigned val) {
38  return val < (1 << 6);
39}
40
41static inline bool isImmU16(unsigned val) {
42  return val < (1 << 16);
43}
44
45static void loadFromStack(MachineBasicBlock &MBB,
46                          MachineBasicBlock::iterator I,
47                          unsigned DstReg, int Offset, DebugLoc dl,
48                          const TargetInstrInfo &TII) {
49  assert(Offset%4 == 0 && "Misaligned stack offset");
50  Offset/=4;
51  bool isU6 = isImmU6(Offset);
52  if (!isU6 && !isImmU16(Offset))
53    report_fatal_error("loadFromStack offset too big " + Twine(Offset));
54  int Opcode = isU6 ? XCore::LDWSP_ru6 : XCore::LDWSP_lru6;
55  BuildMI(MBB, I, dl, TII.get(Opcode), DstReg)
56    .addImm(Offset);
57}
58
59
60static void storeToStack(MachineBasicBlock &MBB,
61                         MachineBasicBlock::iterator I,
62                         unsigned SrcReg, int Offset, DebugLoc dl,
63                         const TargetInstrInfo &TII) {
64  assert(Offset%4 == 0 && "Misaligned stack offset");
65  Offset/=4;
66  bool isU6 = isImmU6(Offset);
67  if (!isU6 && !isImmU16(Offset))
68    report_fatal_error("storeToStack offset too big " + Twine(Offset));
69  int Opcode = isU6 ? XCore::STWSP_ru6 : XCore::STWSP_lru6;
70  BuildMI(MBB, I, dl, TII.get(Opcode))
71    .addReg(SrcReg)
72    .addImm(Offset);
73}
74
75
76//===----------------------------------------------------------------------===//
77// XCoreFrameLowering:
78//===----------------------------------------------------------------------===//
79
80XCoreFrameLowering::XCoreFrameLowering(const XCoreSubtarget &sti)
81  : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 4, 0),
82    STI(sti) {
83  // Do nothing
84}
85
86bool XCoreFrameLowering::hasFP(const MachineFunction &MF) const {
87  return DisableFramePointerElim(MF) || MF.getFrameInfo()->hasVarSizedObjects();
88}
89
90void XCoreFrameLowering::emitPrologue(MachineFunction &MF) const {
91  MachineBasicBlock &MBB = MF.front();   // Prolog goes in entry BB
92  MachineBasicBlock::iterator MBBI = MBB.begin();
93  MachineFrameInfo *MFI = MF.getFrameInfo();
94  MachineModuleInfo *MMI = &MF.getMMI();
95  const XCoreRegisterInfo *RegInfo =
96    static_cast<const XCoreRegisterInfo*>(MF.getTarget().getRegisterInfo());
97  const XCoreInstrInfo &TII =
98    *static_cast<const XCoreInstrInfo*>(MF.getTarget().getInstrInfo());
99  XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>();
100  DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
101
102  bool FP = hasFP(MF);
103  bool Nested = MF.getFunction()->
104                getAttributes().hasAttrSomewhere(Attribute::Nest);
105
106  if (Nested) {
107    loadFromStack(MBB, MBBI, XCore::R11, 0, dl, TII);
108  }
109
110  // Work out frame sizes.
111  int FrameSize = MFI->getStackSize();
112  assert(FrameSize%4 == 0 && "Misaligned frame size");
113  FrameSize/=4;
114
115  bool isU6 = isImmU6(FrameSize);
116
117  if (!isU6 && !isImmU16(FrameSize)) {
118    // FIXME could emit multiple instructions.
119    report_fatal_error("emitPrologue Frame size too big: " + Twine(FrameSize));
120  }
121  bool emitFrameMoves = RegInfo->needsFrameMoves(MF);
122
123  // Do we need to allocate space on the stack?
124  if (FrameSize) {
125    bool saveLR = XFI->getUsesLR();
126    bool LRSavedOnEntry = false;
127    int Opcode;
128    if (saveLR && (MFI->getObjectOffset(XFI->getLRSpillSlot()) == 0)) {
129      Opcode = (isU6) ? XCore::ENTSP_u6 : XCore::ENTSP_lu6;
130      MBB.addLiveIn(XCore::LR);
131      saveLR = false;
132      LRSavedOnEntry = true;
133    } else {
134      Opcode = (isU6) ? XCore::EXTSP_u6 : XCore::EXTSP_lu6;
135    }
136    BuildMI(MBB, MBBI, dl, TII.get(Opcode)).addImm(FrameSize);
137
138    if (emitFrameMoves) {
139      std::vector<MachineMove> &Moves = MMI->getFrameMoves();
140
141      // Show update of SP.
142      MCSymbol *FrameLabel = MMI->getContext().CreateTempSymbol();
143      BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(FrameLabel);
144
145      MachineLocation SPDst(MachineLocation::VirtualFP);
146      MachineLocation SPSrc(MachineLocation::VirtualFP, -FrameSize * 4);
147      Moves.push_back(MachineMove(FrameLabel, SPDst, SPSrc));
148
149      if (LRSavedOnEntry) {
150        MachineLocation CSDst(MachineLocation::VirtualFP, 0);
151        MachineLocation CSSrc(XCore::LR);
152        Moves.push_back(MachineMove(FrameLabel, CSDst, CSSrc));
153      }
154    }
155    if (saveLR) {
156      int LRSpillOffset = MFI->getObjectOffset(XFI->getLRSpillSlot());
157      storeToStack(MBB, MBBI, XCore::LR, LRSpillOffset + FrameSize*4, dl, TII);
158      MBB.addLiveIn(XCore::LR);
159
160      if (emitFrameMoves) {
161        MCSymbol *SaveLRLabel = MMI->getContext().CreateTempSymbol();
162        BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(SaveLRLabel);
163        MachineLocation CSDst(MachineLocation::VirtualFP, LRSpillOffset);
164        MachineLocation CSSrc(XCore::LR);
165        MMI->getFrameMoves().push_back(MachineMove(SaveLRLabel, CSDst, CSSrc));
166      }
167    }
168  }
169
170  if (FP) {
171    // Save R10 to the stack.
172    int FPSpillOffset = MFI->getObjectOffset(XFI->getFPSpillSlot());
173    storeToStack(MBB, MBBI, XCore::R10, FPSpillOffset + FrameSize*4, dl, TII);
174    // R10 is live-in. It is killed at the spill.
175    MBB.addLiveIn(XCore::R10);
176    if (emitFrameMoves) {
177      MCSymbol *SaveR10Label = MMI->getContext().CreateTempSymbol();
178      BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(SaveR10Label);
179      MachineLocation CSDst(MachineLocation::VirtualFP, FPSpillOffset);
180      MachineLocation CSSrc(XCore::R10);
181      MMI->getFrameMoves().push_back(MachineMove(SaveR10Label, CSDst, CSSrc));
182    }
183    // Set the FP from the SP.
184    unsigned FramePtr = XCore::R10;
185    BuildMI(MBB, MBBI, dl, TII.get(XCore::LDAWSP_ru6), FramePtr)
186      .addImm(0);
187    if (emitFrameMoves) {
188      // Show FP is now valid.
189      MCSymbol *FrameLabel = MMI->getContext().CreateTempSymbol();
190      BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(FrameLabel);
191      MachineLocation SPDst(FramePtr);
192      MachineLocation SPSrc(MachineLocation::VirtualFP);
193      MMI->getFrameMoves().push_back(MachineMove(FrameLabel, SPDst, SPSrc));
194    }
195  }
196
197  if (emitFrameMoves) {
198    // Frame moves for callee saved.
199    std::vector<MachineMove> &Moves = MMI->getFrameMoves();
200    std::vector<std::pair<MCSymbol*, CalleeSavedInfo> >&SpillLabels =
201        XFI->getSpillLabels();
202    for (unsigned I = 0, E = SpillLabels.size(); I != E; ++I) {
203      MCSymbol *SpillLabel = SpillLabels[I].first;
204      CalleeSavedInfo &CSI = SpillLabels[I].second;
205      int Offset = MFI->getObjectOffset(CSI.getFrameIdx());
206      unsigned Reg = CSI.getReg();
207      MachineLocation CSDst(MachineLocation::VirtualFP, Offset);
208      MachineLocation CSSrc(Reg);
209      Moves.push_back(MachineMove(SpillLabel, CSDst, CSSrc));
210    }
211  }
212}
213
214void XCoreFrameLowering::emitEpilogue(MachineFunction &MF,
215                                     MachineBasicBlock &MBB) const {
216  MachineFrameInfo *MFI            = MF.getFrameInfo();
217  MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
218  const XCoreInstrInfo &TII =
219    *static_cast<const XCoreInstrInfo*>(MF.getTarget().getInstrInfo());
220  DebugLoc dl = MBBI->getDebugLoc();
221
222  bool FP = hasFP(MF);
223  if (FP) {
224    // Restore the stack pointer.
225    unsigned FramePtr = XCore::R10;
226    BuildMI(MBB, MBBI, dl, TII.get(XCore::SETSP_1r))
227      .addReg(FramePtr);
228  }
229
230  // Work out frame sizes.
231  int FrameSize = MFI->getStackSize();
232
233  assert(FrameSize%4 == 0 && "Misaligned frame size");
234
235  FrameSize/=4;
236
237  bool isU6 = isImmU6(FrameSize);
238
239  if (!isU6 && !isImmU16(FrameSize)) {
240    // FIXME could emit multiple instructions.
241    report_fatal_error("emitEpilogue Frame size too big: " + Twine(FrameSize));
242  }
243
244  if (FrameSize) {
245    XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>();
246
247    if (FP) {
248      // Restore R10
249      int FPSpillOffset = MFI->getObjectOffset(XFI->getFPSpillSlot());
250      FPSpillOffset += FrameSize*4;
251      loadFromStack(MBB, MBBI, XCore::R10, FPSpillOffset, dl, TII);
252    }
253    bool restoreLR = XFI->getUsesLR();
254    if (restoreLR && MFI->getObjectOffset(XFI->getLRSpillSlot()) != 0) {
255      int LRSpillOffset = MFI->getObjectOffset(XFI->getLRSpillSlot());
256      LRSpillOffset += FrameSize*4;
257      loadFromStack(MBB, MBBI, XCore::LR, LRSpillOffset, dl, TII);
258      restoreLR = false;
259    }
260    if (restoreLR) {
261      // Fold prologue into return instruction
262      assert(MBBI->getOpcode() == XCore::RETSP_u6
263        || MBBI->getOpcode() == XCore::RETSP_lu6);
264      int Opcode = (isU6) ? XCore::RETSP_u6 : XCore::RETSP_lu6;
265      BuildMI(MBB, MBBI, dl, TII.get(Opcode)).addImm(FrameSize);
266      MBB.erase(MBBI);
267    } else {
268      int Opcode = (isU6) ? XCore::LDAWSP_ru6_RRegs : XCore::LDAWSP_lru6_RRegs;
269      BuildMI(MBB, MBBI, dl, TII.get(Opcode), XCore::SP).addImm(FrameSize);
270    }
271  }
272}
273
274bool XCoreFrameLowering::spillCalleeSavedRegisters(MachineBasicBlock &MBB,
275                                               MachineBasicBlock::iterator MI,
276                                        const std::vector<CalleeSavedInfo> &CSI,
277                                          const TargetRegisterInfo *TRI) const {
278  if (CSI.empty())
279    return true;
280
281  MachineFunction *MF = MBB.getParent();
282  const TargetInstrInfo &TII = *MF->getTarget().getInstrInfo();
283
284  XCoreFunctionInfo *XFI = MF->getInfo<XCoreFunctionInfo>();
285  bool emitFrameMoves = XCoreRegisterInfo::needsFrameMoves(*MF);
286
287  DebugLoc DL;
288  if (MI != MBB.end()) DL = MI->getDebugLoc();
289
290  for (std::vector<CalleeSavedInfo>::const_iterator it = CSI.begin();
291                                                    it != CSI.end(); ++it) {
292    // Add the callee-saved register as live-in. It's killed at the spill.
293    MBB.addLiveIn(it->getReg());
294
295    unsigned Reg = it->getReg();
296    const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
297    TII.storeRegToStackSlot(MBB, MI, Reg, true,
298                            it->getFrameIdx(), RC, TRI);
299    if (emitFrameMoves) {
300      MCSymbol *SaveLabel = MF->getContext().CreateTempSymbol();
301      BuildMI(MBB, MI, DL, TII.get(XCore::PROLOG_LABEL)).addSym(SaveLabel);
302      XFI->getSpillLabels().push_back(std::make_pair(SaveLabel, *it));
303    }
304  }
305  return true;
306}
307
308bool XCoreFrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
309                                                 MachineBasicBlock::iterator MI,
310                                        const std::vector<CalleeSavedInfo> &CSI,
311                                            const TargetRegisterInfo *TRI) const{
312  MachineFunction *MF = MBB.getParent();
313  const TargetInstrInfo &TII = *MF->getTarget().getInstrInfo();
314
315  bool AtStart = MI == MBB.begin();
316  MachineBasicBlock::iterator BeforeI = MI;
317  if (!AtStart)
318    --BeforeI;
319  for (std::vector<CalleeSavedInfo>::const_iterator it = CSI.begin();
320                                                    it != CSI.end(); ++it) {
321    unsigned Reg = it->getReg();
322    const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
323    TII.loadRegFromStackSlot(MBB, MI, it->getReg(), it->getFrameIdx(),
324                             RC, TRI);
325    assert(MI != MBB.begin() &&
326           "loadRegFromStackSlot didn't insert any code!");
327    // Insert in reverse order.  loadRegFromStackSlot can insert multiple
328    // instructions.
329    if (AtStart)
330      MI = MBB.begin();
331    else {
332      MI = BeforeI;
333      ++MI;
334    }
335  }
336  return true;
337}
338
339void
340XCoreFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
341                                                     RegScavenger *RS) const {
342  MachineFrameInfo *MFI = MF.getFrameInfo();
343  const TargetRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo();
344  bool LRUsed = MF.getRegInfo().isPhysRegUsed(XCore::LR);
345  const TargetRegisterClass *RC = XCore::GRRegsRegisterClass;
346  XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>();
347  if (LRUsed) {
348    MF.getRegInfo().setPhysRegUnused(XCore::LR);
349
350    bool isVarArg = MF.getFunction()->isVarArg();
351    int FrameIdx;
352    if (! isVarArg) {
353      // A fixed offset of 0 allows us to save / restore LR using entsp / retsp.
354      FrameIdx = MFI->CreateFixedObject(RC->getSize(), 0, true);
355    } else {
356      FrameIdx = MFI->CreateStackObject(RC->getSize(), RC->getAlignment(),
357                                        false);
358    }
359    XFI->setUsesLR(FrameIdx);
360    XFI->setLRSpillSlot(FrameIdx);
361  }
362  if (RegInfo->requiresRegisterScavenging(MF)) {
363    // Reserve a slot close to SP or frame pointer.
364    RS->setScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(),
365                                                       RC->getAlignment(),
366                                                       false));
367  }
368  if (hasFP(MF)) {
369    // A callee save register is used to hold the FP.
370    // This needs saving / restoring in the epilogue / prologue.
371    XFI->setFPSpillSlot(MFI->CreateStackObject(RC->getSize(),
372                                               RC->getAlignment(),
373                                               false));
374  }
375}
376
377void XCoreFrameLowering::
378processFunctionBeforeFrameFinalized(MachineFunction &MF) const {
379
380}
381