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(Reg: ScratchOffset); |
103 | TII.loadImmediate(MBB, MI: II, Reg: ScratchOffset, Value: 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(val: 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(B: MI.getOperand(i: 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(Reg: 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(Reg: ScratchOffset); |
182 | TII.loadImmediate(MBB, MI: II, Reg: ScratchOffset, Value: 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: *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(i: 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(ObjectIdx: 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(i: FIOperandNum).ChangeToRegister(Reg: FrameReg, isDef: false /*isDef*/); |
289 | MI.getOperand(i: FIOperandNum + 1).ChangeToImmediate(ImmVal: Offset); |
290 | return false; |
291 | } |
292 | |
293 | // fold constant into offset. |
294 | Offset += MI.getOperand(i: FIOperandNum + 1).getImm(); |
295 | MI.getOperand(i: FIOperandNum + 1).ChangeToImmediate(ImmVal: 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(i: 0).getReg(); |
303 | assert(XCore::GRRegsRegClass.contains(Reg) && "Unexpected register operand" ); |
304 | |
305 | if (TFI->hasFP(MF)) { |
306 | if (isImmUs(val: Offset)) |
307 | InsertFPImmInst(II, TII, Reg, FrameReg, Offset); |
308 | else |
309 | InsertFPConstInst(II, TII, Reg, FrameReg, Offset, RS); |
310 | } else { |
311 | if (isImmU16(val: 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(I: 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 | |