1 //===-- XCoreRegisterInfo.cpp - XCore Register Information ----------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains the XCore implementation of the MRegisterInfo class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "XCoreRegisterInfo.h"
14 #include "XCore.h"
15 #include "XCoreInstrInfo.h"
16 #include "XCoreMachineFunctionInfo.h"
17 #include "XCoreSubtarget.h"
18 #include "llvm/ADT/BitVector.h"
19 #include "llvm/ADT/STLExtras.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/IR/Function.h"
27 #include "llvm/IR/Type.h"
28 #include "llvm/Support/Debug.h"
29 #include "llvm/Support/ErrorHandling.h"
30 #include "llvm/Support/MathExtras.h"
31 #include "llvm/Support/raw_ostream.h"
32 #include "llvm/CodeGen/TargetFrameLowering.h"
33 #include "llvm/Target/TargetMachine.h"
34 #include "llvm/Target/TargetOptions.h"
35 
36 using namespace llvm;
37 
38 #define DEBUG_TYPE "xcore-reg-info"
39 
40 #define GET_REGINFO_TARGET_DESC
41 #include "XCoreGenRegisterInfo.inc"
42 
43 XCoreRegisterInfo::XCoreRegisterInfo()
44   : XCoreGenRegisterInfo(XCore::LR) {
45 }
46 
47 // helper functions
48 static inline bool isImmUs(unsigned val) {
49   return val <= 11;
50 }
51 
52 static inline bool isImmU6(unsigned val) {
53   return val < (1 << 6);
54 }
55 
56 static inline bool isImmU16(unsigned val) {
57   return val < (1 << 16);
58 }
59 
60 
61 static void InsertFPImmInst(MachineBasicBlock::iterator II,
62                             const XCoreInstrInfo &TII,
63                             unsigned Reg, unsigned FrameReg, int Offset ) {
64   MachineInstr &MI = *II;
65   MachineBasicBlock &MBB = *MI.getParent();
66   DebugLoc dl = MI.getDebugLoc();
67 
68   switch (MI.getOpcode()) {
69   case XCore::LDWFI:
70     BuildMI(MBB, II, dl, TII.get(XCore::LDW_2rus), Reg)
71           .addReg(FrameReg)
72           .addImm(Offset)
73           .addMemOperand(*MI.memoperands_begin());
74     break;
75   case XCore::STWFI:
76     BuildMI(MBB, II, dl, TII.get(XCore::STW_2rus))
77           .addReg(Reg, getKillRegState(MI.getOperand(0).isKill()))
78           .addReg(FrameReg)
79           .addImm(Offset)
80           .addMemOperand(*MI.memoperands_begin());
81     break;
82   case XCore::LDAWFI:
83     BuildMI(MBB, II, dl, TII.get(XCore::LDAWF_l2rus), Reg)
84           .addReg(FrameReg)
85           .addImm(Offset);
86     break;
87   default:
88     llvm_unreachable("Unexpected Opcode");
89   }
90 }
91 
92 static void InsertFPConstInst(MachineBasicBlock::iterator II,
93                               const XCoreInstrInfo &TII,
94                               unsigned Reg, unsigned FrameReg,
95                               int Offset, RegScavenger *RS ) {
96   assert(RS && "requiresRegisterScavenging failed");
97   MachineInstr &MI = *II;
98   MachineBasicBlock &MBB = *MI.getParent();
99   DebugLoc dl = MI.getDebugLoc();
100   Register ScratchOffset =
101       RS->scavengeRegisterBackwards(XCore::GRRegsRegClass, II, false, 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 
129 static 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 
162 static 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 =
174         RS->scavengeRegisterBackwards(XCore::GRRegsRegClass, II, false, 0);
175     RS->setRegUsed(ScratchBase);
176   } else
177     ScratchBase = Reg;
178   BuildMI(MBB, II, dl, TII.get(XCore::LDAWSP_ru6), ScratchBase).addImm(0);
179   Register ScratchOffset =
180       RS->scavengeRegisterBackwards(XCore::GRRegsRegClass, II, false, 0);
181   RS->setRegUsed(ScratchOffset);
182   TII.loadImmediate(MBB, II, ScratchOffset, Offset);
183 
184   switch (OpCode) {
185   case XCore::LDWFI:
186     BuildMI(MBB, II, dl, TII.get(XCore::LDW_3r), Reg)
187           .addReg(ScratchBase, RegState::Kill)
188           .addReg(ScratchOffset, RegState::Kill)
189           .addMemOperand(*MI.memoperands_begin());
190     break;
191   case XCore::STWFI:
192     BuildMI(MBB, II, dl, TII.get(XCore::STW_l3r))
193           .addReg(Reg, getKillRegState(MI.getOperand(0).isKill()))
194           .addReg(ScratchBase, RegState::Kill)
195           .addReg(ScratchOffset, RegState::Kill)
196           .addMemOperand(*MI.memoperands_begin());
197     break;
198   case XCore::LDAWFI:
199     BuildMI(MBB, II, dl, TII.get(XCore::LDAWF_l3r), Reg)
200           .addReg(ScratchBase, RegState::Kill)
201           .addReg(ScratchOffset, RegState::Kill);
202     break;
203   default:
204     llvm_unreachable("Unexpected Opcode");
205   }
206 }
207 
208 bool XCoreRegisterInfo::needsFrameMoves(const MachineFunction &MF) {
209   return MF.needsFrameMoves();
210 }
211 
212 const MCPhysReg *
213 XCoreRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
214   // The callee saved registers LR & FP are explicitly handled during
215   // emitPrologue & emitEpilogue and related functions.
216   static const MCPhysReg CalleeSavedRegs[] = {
217     XCore::R4, XCore::R5, XCore::R6, XCore::R7,
218     XCore::R8, XCore::R9, XCore::R10,
219     0
220   };
221   static const MCPhysReg CalleeSavedRegsFP[] = {
222     XCore::R4, XCore::R5, XCore::R6, XCore::R7,
223     XCore::R8, XCore::R9,
224     0
225   };
226   const XCoreFrameLowering *TFI = getFrameLowering(*MF);
227   if (TFI->hasFP(*MF))
228     return CalleeSavedRegsFP;
229   return CalleeSavedRegs;
230 }
231 
232 BitVector XCoreRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
233   BitVector Reserved(getNumRegs());
234   const XCoreFrameLowering *TFI = getFrameLowering(MF);
235 
236   Reserved.set(XCore::CP);
237   Reserved.set(XCore::DP);
238   Reserved.set(XCore::SP);
239   Reserved.set(XCore::LR);
240   if (TFI->hasFP(MF)) {
241     Reserved.set(XCore::R10);
242   }
243   return Reserved;
244 }
245 
246 bool
247 XCoreRegisterInfo::requiresRegisterScavenging(const MachineFunction &MF) const {
248   return true;
249 }
250 
251 bool
252 XCoreRegisterInfo::useFPForScavengingIndex(const MachineFunction &MF) const {
253   return false;
254 }
255 
256 bool
257 XCoreRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
258                                        int SPAdj, unsigned FIOperandNum,
259                                        RegScavenger *RS) const {
260   assert(SPAdj == 0 && "Unexpected");
261   MachineInstr &MI = *II;
262   MachineOperand &FrameOp = MI.getOperand(FIOperandNum);
263   int FrameIndex = FrameOp.getIndex();
264 
265   MachineFunction &MF = *MI.getParent()->getParent();
266   const XCoreInstrInfo &TII =
267       *static_cast<const XCoreInstrInfo *>(MF.getSubtarget().getInstrInfo());
268 
269   const XCoreFrameLowering *TFI = getFrameLowering(MF);
270   int Offset = MF.getFrameInfo().getObjectOffset(FrameIndex);
271   int StackSize = MF.getFrameInfo().getStackSize();
272 
273   #ifndef NDEBUG
274   LLVM_DEBUG(errs() << "\nFunction         : " << MF.getName() << "\n");
275   LLVM_DEBUG(errs() << "<--------->\n");
276   LLVM_DEBUG(MI.print(errs()));
277   LLVM_DEBUG(errs() << "FrameIndex         : " << FrameIndex << "\n");
278   LLVM_DEBUG(errs() << "FrameOffset        : " << Offset << "\n");
279   LLVM_DEBUG(errs() << "StackSize          : " << StackSize << "\n");
280 #endif
281 
282   Offset += StackSize;
283 
284   Register FrameReg = getFrameRegister(MF);
285 
286   // Special handling of DBG_VALUE instructions.
287   if (MI.isDebugValue()) {
288     MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false /*isDef*/);
289     MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
290     return false;
291   }
292 
293   // fold constant into offset.
294   Offset += MI.getOperand(FIOperandNum + 1).getImm();
295   MI.getOperand(FIOperandNum + 1).ChangeToImmediate(0);
296 
297   assert(Offset%4 == 0 && "Misaligned stack offset");
298   LLVM_DEBUG(errs() << "Offset             : " << Offset << "\n"
299                     << "<--------->\n");
300   Offset/=4;
301 
302   Register Reg = MI.getOperand(0).getReg();
303   assert(XCore::GRRegsRegClass.contains(Reg) && "Unexpected register operand");
304 
305   if (TFI->hasFP(MF)) {
306     if (isImmUs(Offset))
307       InsertFPImmInst(II, TII, Reg, FrameReg, Offset);
308     else
309       InsertFPConstInst(II, TII, Reg, FrameReg, Offset, RS);
310   } else {
311     if (isImmU16(Offset))
312       InsertSPImmInst(II, TII, Reg, Offset);
313     else
314       InsertSPConstInst(II, TII, Reg, Offset, RS);
315   }
316   // Erase old instruction.
317   MachineBasicBlock &MBB = *MI.getParent();
318   MBB.erase(II);
319   return true;
320 }
321 
322 
323 Register XCoreRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
324   const XCoreFrameLowering *TFI = getFrameLowering(MF);
325 
326   return TFI->hasFP(MF) ? XCore::R10 : XCore::SP;
327 }
328