1//===-- XCoreRegisterInfo.cpp - XCore Register Information ----------------===//
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 the XCore implementation of the MRegisterInfo class.
11//
12//===----------------------------------------------------------------------===//
13
14#include "XCoreRegisterInfo.h"
15#include "XCoreMachineFunctionInfo.h"
16#include "XCore.h"
17#include "llvm/Type.h"
18#include "llvm/Function.h"
19#include "llvm/CodeGen/MachineInstrBuilder.h"
20#include "llvm/CodeGen/MachineFunction.h"
21#include "llvm/CodeGen/MachineFrameInfo.h"
22#include "llvm/CodeGen/MachineModuleInfo.h"
23#include "llvm/CodeGen/MachineRegisterInfo.h"
24#include "llvm/CodeGen/RegisterScavenging.h"
25#include "llvm/Target/TargetFrameLowering.h"
26#include "llvm/Target/TargetMachine.h"
27#include "llvm/Target/TargetOptions.h"
28#include "llvm/Target/TargetInstrInfo.h"
29#include "llvm/ADT/BitVector.h"
30#include "llvm/ADT/STLExtras.h"
31#include "llvm/Support/Debug.h"
32#include "llvm/Support/ErrorHandling.h"
33#include "llvm/Support/raw_ostream.h"
34
35#define GET_REGINFO_TARGET_DESC
36#include "XCoreGenRegisterInfo.inc"
37
38using namespace llvm;
39
40XCoreRegisterInfo::XCoreRegisterInfo(const TargetInstrInfo &tii)
41  : XCoreGenRegisterInfo(XCore::LR), TII(tii) {
42}
43
44// helper functions
45static inline bool isImmUs(unsigned val) {
46  return val <= 11;
47}
48
49static inline bool isImmU6(unsigned val) {
50  return val < (1 << 6);
51}
52
53static inline bool isImmU16(unsigned val) {
54  return val < (1 << 16);
55}
56
57bool XCoreRegisterInfo::needsFrameMoves(const MachineFunction &MF) {
58  return MF.getMMI().hasDebugInfo() ||
59    MF.getFunction()->needsUnwindTableEntry();
60}
61
62const uint16_t* XCoreRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF)
63                                                                         const {
64  static const uint16_t CalleeSavedRegs[] = {
65    XCore::R4, XCore::R5, XCore::R6, XCore::R7,
66    XCore::R8, XCore::R9, XCore::R10, XCore::LR,
67    0
68  };
69  return CalleeSavedRegs;
70}
71
72BitVector XCoreRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
73  BitVector Reserved(getNumRegs());
74  const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering();
75
76  Reserved.set(XCore::CP);
77  Reserved.set(XCore::DP);
78  Reserved.set(XCore::SP);
79  Reserved.set(XCore::LR);
80  if (TFI->hasFP(MF)) {
81    Reserved.set(XCore::R10);
82  }
83  return Reserved;
84}
85
86bool
87XCoreRegisterInfo::requiresRegisterScavenging(const MachineFunction &MF) const {
88  const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering();
89
90  // TODO can we estimate stack size?
91  return TFI->hasFP(MF);
92}
93
94bool
95XCoreRegisterInfo::trackLivenessAfterRegAlloc(const MachineFunction &MF) const {
96  return requiresRegisterScavenging(MF);
97}
98
99bool
100XCoreRegisterInfo::useFPForScavengingIndex(const MachineFunction &MF) const {
101  return false;
102}
103
104// This function eliminates ADJCALLSTACKDOWN,
105// ADJCALLSTACKUP pseudo instructions
106void XCoreRegisterInfo::
107eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
108                              MachineBasicBlock::iterator I) const {
109  const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering();
110
111  if (!TFI->hasReservedCallFrame(MF)) {
112    // Turn the adjcallstackdown instruction into 'extsp <amt>' and the
113    // adjcallstackup instruction into 'ldaw sp, sp[<amt>]'
114    MachineInstr *Old = I;
115    uint64_t Amount = Old->getOperand(0).getImm();
116    if (Amount != 0) {
117      // We need to keep the stack aligned properly.  To do this, we round the
118      // amount of space needed for the outgoing arguments up to the next
119      // alignment boundary.
120      unsigned Align = TFI->getStackAlignment();
121      Amount = (Amount+Align-1)/Align*Align;
122
123      assert(Amount%4 == 0);
124      Amount /= 4;
125
126      bool isU6 = isImmU6(Amount);
127      if (!isU6 && !isImmU16(Amount)) {
128        // FIX could emit multiple instructions in this case.
129#ifndef NDEBUG
130        errs() << "eliminateCallFramePseudoInstr size too big: "
131               << Amount << "\n";
132#endif
133        llvm_unreachable(0);
134      }
135
136      MachineInstr *New;
137      if (Old->getOpcode() == XCore::ADJCALLSTACKDOWN) {
138        int Opcode = isU6 ? XCore::EXTSP_u6 : XCore::EXTSP_lu6;
139        New=BuildMI(MF, Old->getDebugLoc(), TII.get(Opcode))
140          .addImm(Amount);
141      } else {
142        assert(Old->getOpcode() == XCore::ADJCALLSTACKUP);
143        int Opcode = isU6 ? XCore::LDAWSP_ru6_RRegs : XCore::LDAWSP_lru6_RRegs;
144        New=BuildMI(MF, Old->getDebugLoc(), TII.get(Opcode), XCore::SP)
145          .addImm(Amount);
146      }
147
148      // Replace the pseudo instruction with a new instruction...
149      MBB.insert(I, New);
150    }
151  }
152
153  MBB.erase(I);
154}
155
156void
157XCoreRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
158                                       int SPAdj, RegScavenger *RS) const {
159  assert(SPAdj == 0 && "Unexpected");
160  MachineInstr &MI = *II;
161  DebugLoc dl = MI.getDebugLoc();
162  unsigned i = 0;
163
164  while (!MI.getOperand(i).isFI()) {
165    ++i;
166    assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!");
167  }
168
169  MachineOperand &FrameOp = MI.getOperand(i);
170  int FrameIndex = FrameOp.getIndex();
171
172  MachineFunction &MF = *MI.getParent()->getParent();
173  const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering();
174  int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex);
175  int StackSize = MF.getFrameInfo()->getStackSize();
176
177  #ifndef NDEBUG
178  DEBUG(errs() << "\nFunction         : "
179        << MF.getName() << "\n");
180  DEBUG(errs() << "<--------->\n");
181  DEBUG(MI.print(errs()));
182  DEBUG(errs() << "FrameIndex         : " << FrameIndex << "\n");
183  DEBUG(errs() << "FrameOffset        : " << Offset << "\n");
184  DEBUG(errs() << "StackSize          : " << StackSize << "\n");
185  #endif
186
187  Offset += StackSize;
188
189  unsigned FrameReg = getFrameRegister(MF);
190
191  // Special handling of DBG_VALUE instructions.
192  if (MI.isDebugValue()) {
193    MI.getOperand(i).ChangeToRegister(FrameReg, false /*isDef*/);
194    MI.getOperand(i+1).ChangeToImmediate(Offset);
195    return;
196  }
197
198  // fold constant into offset.
199  Offset += MI.getOperand(i + 1).getImm();
200  MI.getOperand(i + 1).ChangeToImmediate(0);
201
202  assert(Offset%4 == 0 && "Misaligned stack offset");
203
204  DEBUG(errs() << "Offset             : " << Offset << "\n" << "<--------->\n");
205
206  Offset/=4;
207
208  bool FP = TFI->hasFP(MF);
209
210  unsigned Reg = MI.getOperand(0).getReg();
211  bool isKill = MI.getOpcode() == XCore::STWFI && MI.getOperand(0).isKill();
212
213  assert(XCore::GRRegsRegClass.contains(Reg) && "Unexpected register operand");
214
215  MachineBasicBlock &MBB = *MI.getParent();
216
217  if (FP) {
218    bool isUs = isImmUs(Offset);
219
220    if (!isUs) {
221      if (!RS)
222        report_fatal_error("eliminateFrameIndex Frame size too big: " +
223                           Twine(Offset));
224      unsigned ScratchReg = RS->scavengeRegister(&XCore::GRRegsRegClass, II,
225                                                 SPAdj);
226      loadConstant(MBB, II, ScratchReg, Offset, dl);
227      switch (MI.getOpcode()) {
228      case XCore::LDWFI:
229        BuildMI(MBB, II, dl, TII.get(XCore::LDW_3r), Reg)
230              .addReg(FrameReg)
231              .addReg(ScratchReg, RegState::Kill);
232        break;
233      case XCore::STWFI:
234        BuildMI(MBB, II, dl, TII.get(XCore::STW_3r))
235              .addReg(Reg, getKillRegState(isKill))
236              .addReg(FrameReg)
237              .addReg(ScratchReg, RegState::Kill);
238        break;
239      case XCore::LDAWFI:
240        BuildMI(MBB, II, dl, TII.get(XCore::LDAWF_l3r), Reg)
241              .addReg(FrameReg)
242              .addReg(ScratchReg, RegState::Kill);
243        break;
244      default:
245        llvm_unreachable("Unexpected Opcode");
246      }
247    } else {
248      switch (MI.getOpcode()) {
249      case XCore::LDWFI:
250        BuildMI(MBB, II, dl, TII.get(XCore::LDW_2rus), Reg)
251              .addReg(FrameReg)
252              .addImm(Offset);
253        break;
254      case XCore::STWFI:
255        BuildMI(MBB, II, dl, TII.get(XCore::STW_2rus))
256              .addReg(Reg, getKillRegState(isKill))
257              .addReg(FrameReg)
258              .addImm(Offset);
259        break;
260      case XCore::LDAWFI:
261        BuildMI(MBB, II, dl, TII.get(XCore::LDAWF_l2rus), Reg)
262              .addReg(FrameReg)
263              .addImm(Offset);
264        break;
265      default:
266        llvm_unreachable("Unexpected Opcode");
267      }
268    }
269  } else {
270    bool isU6 = isImmU6(Offset);
271    if (!isU6 && !isImmU16(Offset))
272      report_fatal_error("eliminateFrameIndex Frame size too big: " +
273                         Twine(Offset));
274
275    switch (MI.getOpcode()) {
276    int NewOpcode;
277    case XCore::LDWFI:
278      NewOpcode = (isU6) ? XCore::LDWSP_ru6 : XCore::LDWSP_lru6;
279      BuildMI(MBB, II, dl, TII.get(NewOpcode), Reg)
280            .addImm(Offset);
281      break;
282    case XCore::STWFI:
283      NewOpcode = (isU6) ? XCore::STWSP_ru6 : XCore::STWSP_lru6;
284      BuildMI(MBB, II, dl, TII.get(NewOpcode))
285            .addReg(Reg, getKillRegState(isKill))
286            .addImm(Offset);
287      break;
288    case XCore::LDAWFI:
289      NewOpcode = (isU6) ? XCore::LDAWSP_ru6 : XCore::LDAWSP_lru6;
290      BuildMI(MBB, II, dl, TII.get(NewOpcode), Reg)
291            .addImm(Offset);
292      break;
293    default:
294      llvm_unreachable("Unexpected Opcode");
295    }
296  }
297  // Erase old instruction.
298  MBB.erase(II);
299}
300
301void XCoreRegisterInfo::
302loadConstant(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
303            unsigned DstReg, int64_t Value, DebugLoc dl) const {
304  // TODO use mkmsk if possible.
305  if (!isImmU16(Value)) {
306    // TODO use constant pool.
307    report_fatal_error("loadConstant value too big " + Twine(Value));
308  }
309  int Opcode = isImmU6(Value) ? XCore::LDC_ru6 : XCore::LDC_lru6;
310  BuildMI(MBB, I, dl, TII.get(Opcode), DstReg).addImm(Value);
311}
312
313unsigned XCoreRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
314  const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering();
315
316  return TFI->hasFP(MF) ? XCore::R10 : XCore::SP;
317}
318