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 "XCore.h"
16#include "XCoreInstrInfo.h"
17#include "XCoreMachineFunctionInfo.h"
18#include "XCoreSubtarget.h"
19#include "llvm/ADT/BitVector.h"
20#include "llvm/ADT/STLExtras.h"
21#include "llvm/CodeGen/MachineFrameInfo.h"
22#include "llvm/CodeGen/MachineFunction.h"
23#include "llvm/CodeGen/MachineInstrBuilder.h"
24#include "llvm/CodeGen/MachineModuleInfo.h"
25#include "llvm/CodeGen/MachineRegisterInfo.h"
26#include "llvm/CodeGen/RegisterScavenging.h"
27#include "llvm/IR/Function.h"
28#include "llvm/IR/Type.h"
29#include "llvm/Support/Debug.h"
30#include "llvm/Support/ErrorHandling.h"
31#include "llvm/Support/MathExtras.h"
32#include "llvm/Support/raw_ostream.h"
33#include "llvm/Target/TargetFrameLowering.h"
34#include "llvm/Target/TargetMachine.h"
35#include "llvm/Target/TargetOptions.h"
36
37using namespace llvm;
38
39#define DEBUG_TYPE "xcore-reg-info"
40
41#define GET_REGINFO_TARGET_DESC
42#include "XCoreGenRegisterInfo.inc"
43
44XCoreRegisterInfo::XCoreRegisterInfo()
45  : XCoreGenRegisterInfo(XCore::LR) {
46}
47
48// helper functions
49static inline bool isImmUs(unsigned val) {
50  return val <= 11;
51}
52
53static inline bool isImmU6(unsigned val) {
54  return val < (1 << 6);
55}
56
57static inline bool isImmU16(unsigned val) {
58  return val < (1 << 16);
59}
60
61
62static void InsertFPImmInst(MachineBasicBlock::iterator II,
63                            const XCoreInstrInfo &TII,
64                            unsigned Reg, unsigned FrameReg, int Offset ) {
65  MachineInstr &MI = *II;
66  MachineBasicBlock &MBB = *MI.getParent();
67  DebugLoc dl = MI.getDebugLoc();
68
69  switch (MI.getOpcode()) {
70  case XCore::LDWFI:
71    BuildMI(MBB, II, dl, TII.get(XCore::LDW_2rus), Reg)
72          .addReg(FrameReg)
73          .addImm(Offset)
74          .addMemOperand(*MI.memoperands_begin());
75    break;
76  case XCore::STWFI:
77    BuildMI(MBB, II, dl, TII.get(XCore::STW_2rus))
78          .addReg(Reg, getKillRegState(MI.getOperand(0).isKill()))
79          .addReg(FrameReg)
80          .addImm(Offset)
81          .addMemOperand(*MI.memoperands_begin());
82    break;
83  case XCore::LDAWFI:
84    BuildMI(MBB, II, dl, TII.get(XCore::LDAWF_l2rus), Reg)
85          .addReg(FrameReg)
86          .addImm(Offset);
87    break;
88  default:
89    llvm_unreachable("Unexpected Opcode");
90  }
91}
92
93static void InsertFPConstInst(MachineBasicBlock::iterator II,
94                              const XCoreInstrInfo &TII,
95                              unsigned Reg, unsigned FrameReg,
96                              int Offset, RegScavenger *RS ) {
97  assert(RS && "requiresRegisterScavenging failed");
98  MachineInstr &MI = *II;
99  MachineBasicBlock &MBB = *MI.getParent();
100  DebugLoc dl = MI.getDebugLoc();
101  unsigned ScratchOffset = RS->scavengeRegister(&XCore::GRRegsRegClass, II, 0);
102  RS->setRegUsed(ScratchOffset);
103  TII.loadImmediate(MBB, II, ScratchOffset, Offset);
104
105  switch (MI.getOpcode()) {
106  case XCore::LDWFI:
107    BuildMI(MBB, II, dl, TII.get(XCore::LDW_3r), Reg)
108          .addReg(FrameReg)
109          .addReg(ScratchOffset, RegState::Kill)
110          .addMemOperand(*MI.memoperands_begin());
111    break;
112  case XCore::STWFI:
113    BuildMI(MBB, II, dl, TII.get(XCore::STW_l3r))
114          .addReg(Reg, getKillRegState(MI.getOperand(0).isKill()))
115          .addReg(FrameReg)
116          .addReg(ScratchOffset, RegState::Kill)
117          .addMemOperand(*MI.memoperands_begin());
118    break;
119  case XCore::LDAWFI:
120    BuildMI(MBB, II, dl, TII.get(XCore::LDAWF_l3r), Reg)
121          .addReg(FrameReg)
122          .addReg(ScratchOffset, RegState::Kill);
123    break;
124  default:
125    llvm_unreachable("Unexpected Opcode");
126  }
127}
128
129static void InsertSPImmInst(MachineBasicBlock::iterator II,
130                            const XCoreInstrInfo &TII,
131                            unsigned Reg, int Offset) {
132  MachineInstr &MI = *II;
133  MachineBasicBlock &MBB = *MI.getParent();
134  DebugLoc dl = MI.getDebugLoc();
135  bool isU6 = isImmU6(Offset);
136
137  switch (MI.getOpcode()) {
138  int NewOpcode;
139  case XCore::LDWFI:
140    NewOpcode = (isU6) ? XCore::LDWSP_ru6 : XCore::LDWSP_lru6;
141    BuildMI(MBB, II, dl, TII.get(NewOpcode), Reg)
142          .addImm(Offset)
143          .addMemOperand(*MI.memoperands_begin());
144    break;
145  case XCore::STWFI:
146    NewOpcode = (isU6) ? XCore::STWSP_ru6 : XCore::STWSP_lru6;
147    BuildMI(MBB, II, dl, TII.get(NewOpcode))
148          .addReg(Reg, getKillRegState(MI.getOperand(0).isKill()))
149          .addImm(Offset)
150          .addMemOperand(*MI.memoperands_begin());
151    break;
152  case XCore::LDAWFI:
153    NewOpcode = (isU6) ? XCore::LDAWSP_ru6 : XCore::LDAWSP_lru6;
154    BuildMI(MBB, II, dl, TII.get(NewOpcode), Reg)
155          .addImm(Offset);
156    break;
157  default:
158    llvm_unreachable("Unexpected Opcode");
159  }
160}
161
162static void InsertSPConstInst(MachineBasicBlock::iterator II,
163                                const XCoreInstrInfo &TII,
164                                unsigned Reg, int Offset, RegScavenger *RS ) {
165  assert(RS && "requiresRegisterScavenging failed");
166  MachineInstr &MI = *II;
167  MachineBasicBlock &MBB = *MI.getParent();
168  DebugLoc dl = MI.getDebugLoc();
169  unsigned OpCode = MI.getOpcode();
170
171  unsigned ScratchBase;
172  if (OpCode==XCore::STWFI) {
173    ScratchBase = RS->scavengeRegister(&XCore::GRRegsRegClass, II, 0);
174    RS->setRegUsed(ScratchBase);
175  } else
176    ScratchBase = Reg;
177  BuildMI(MBB, II, dl, TII.get(XCore::LDAWSP_ru6), ScratchBase).addImm(0);
178  unsigned ScratchOffset = RS->scavengeRegister(&XCore::GRRegsRegClass, II, 0);
179  RS->setRegUsed(ScratchOffset);
180  TII.loadImmediate(MBB, II, ScratchOffset, Offset);
181
182  switch (OpCode) {
183  case XCore::LDWFI:
184    BuildMI(MBB, II, dl, TII.get(XCore::LDW_3r), Reg)
185          .addReg(ScratchBase, RegState::Kill)
186          .addReg(ScratchOffset, RegState::Kill)
187          .addMemOperand(*MI.memoperands_begin());
188    break;
189  case XCore::STWFI:
190    BuildMI(MBB, II, dl, TII.get(XCore::STW_l3r))
191          .addReg(Reg, getKillRegState(MI.getOperand(0).isKill()))
192          .addReg(ScratchBase, RegState::Kill)
193          .addReg(ScratchOffset, RegState::Kill)
194          .addMemOperand(*MI.memoperands_begin());
195    break;
196  case XCore::LDAWFI:
197    BuildMI(MBB, II, dl, TII.get(XCore::LDAWF_l3r), Reg)
198          .addReg(ScratchBase, RegState::Kill)
199          .addReg(ScratchOffset, RegState::Kill);
200    break;
201  default:
202    llvm_unreachable("Unexpected Opcode");
203  }
204}
205
206bool XCoreRegisterInfo::needsFrameMoves(const MachineFunction &MF) {
207  return MF.getMMI().hasDebugInfo() ||
208    MF.getFunction()->needsUnwindTableEntry();
209}
210
211const MCPhysReg *
212XCoreRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
213  // The callee saved registers LR & FP are explicitly handled during
214  // emitPrologue & emitEpilogue and related functions.
215  static const MCPhysReg CalleeSavedRegs[] = {
216    XCore::R4, XCore::R5, XCore::R6, XCore::R7,
217    XCore::R8, XCore::R9, XCore::R10,
218    0
219  };
220  static const MCPhysReg CalleeSavedRegsFP[] = {
221    XCore::R4, XCore::R5, XCore::R6, XCore::R7,
222    XCore::R8, XCore::R9,
223    0
224  };
225  const XCoreFrameLowering *TFI = getFrameLowering(*MF);
226  if (TFI->hasFP(*MF))
227    return CalleeSavedRegsFP;
228  return CalleeSavedRegs;
229}
230
231BitVector XCoreRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
232  BitVector Reserved(getNumRegs());
233  const XCoreFrameLowering *TFI = getFrameLowering(MF);
234
235  Reserved.set(XCore::CP);
236  Reserved.set(XCore::DP);
237  Reserved.set(XCore::SP);
238  Reserved.set(XCore::LR);
239  if (TFI->hasFP(MF)) {
240    Reserved.set(XCore::R10);
241  }
242  return Reserved;
243}
244
245bool
246XCoreRegisterInfo::requiresRegisterScavenging(const MachineFunction &MF) const {
247  return true;
248}
249
250bool
251XCoreRegisterInfo::trackLivenessAfterRegAlloc(const MachineFunction &MF) const {
252  return true;
253}
254
255bool
256XCoreRegisterInfo::useFPForScavengingIndex(const MachineFunction &MF) const {
257  return false;
258}
259
260void
261XCoreRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
262                                       int SPAdj, unsigned FIOperandNum,
263                                       RegScavenger *RS) const {
264  assert(SPAdj == 0 && "Unexpected");
265  MachineInstr &MI = *II;
266  MachineOperand &FrameOp = MI.getOperand(FIOperandNum);
267  int FrameIndex = FrameOp.getIndex();
268
269  MachineFunction &MF = *MI.getParent()->getParent();
270  const XCoreInstrInfo &TII =
271      *static_cast<const XCoreInstrInfo *>(MF.getSubtarget().getInstrInfo());
272
273  const XCoreFrameLowering *TFI = getFrameLowering(MF);
274  int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex);
275  int StackSize = MF.getFrameInfo()->getStackSize();
276
277  #ifndef NDEBUG
278  DEBUG(errs() << "\nFunction         : "
279        << MF.getName() << "\n");
280  DEBUG(errs() << "<--------->\n");
281  DEBUG(MI.print(errs()));
282  DEBUG(errs() << "FrameIndex         : " << FrameIndex << "\n");
283  DEBUG(errs() << "FrameOffset        : " << Offset << "\n");
284  DEBUG(errs() << "StackSize          : " << StackSize << "\n");
285  #endif
286
287  Offset += StackSize;
288
289  unsigned FrameReg = getFrameRegister(MF);
290
291  // Special handling of DBG_VALUE instructions.
292  if (MI.isDebugValue()) {
293    MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false /*isDef*/);
294    MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
295    return;
296  }
297
298  // fold constant into offset.
299  Offset += MI.getOperand(FIOperandNum + 1).getImm();
300  MI.getOperand(FIOperandNum + 1).ChangeToImmediate(0);
301
302  assert(Offset%4 == 0 && "Misaligned stack offset");
303  DEBUG(errs() << "Offset             : " << Offset << "\n" << "<--------->\n");
304  Offset/=4;
305
306  unsigned Reg = MI.getOperand(0).getReg();
307  assert(XCore::GRRegsRegClass.contains(Reg) && "Unexpected register operand");
308
309  if (TFI->hasFP(MF)) {
310    if (isImmUs(Offset))
311      InsertFPImmInst(II, TII, Reg, FrameReg, Offset);
312    else
313      InsertFPConstInst(II, TII, Reg, FrameReg, Offset, RS);
314  } else {
315    if (isImmU16(Offset))
316      InsertSPImmInst(II, TII, Reg, Offset);
317    else
318      InsertSPConstInst(II, TII, Reg, Offset, RS);
319  }
320  // Erase old instruction.
321  MachineBasicBlock &MBB = *MI.getParent();
322  MBB.erase(II);
323}
324
325
326unsigned XCoreRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
327  const XCoreFrameLowering *TFI = getFrameLowering(MF);
328
329  return TFI->hasFP(MF) ? XCore::R10 : XCore::SP;
330}
331