1 | //===-- CSKYRegisterInfo.h - CSKY Register Information Impl ---*- C++ -*---===// |
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 CSKY implementation of the TargetRegisterInfo class. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "CSKYRegisterInfo.h" |
14 | #include "CSKY.h" |
15 | #include "CSKYSubtarget.h" |
16 | #include "llvm/CodeGen/MachineFrameInfo.h" |
17 | #include "llvm/CodeGen/MachineFunction.h" |
18 | #include "llvm/CodeGen/RegisterScavenging.h" |
19 | #include "llvm/MC/MCContext.h" |
20 | |
21 | #define GET_REGINFO_TARGET_DESC |
22 | #include "CSKYGenRegisterInfo.inc" |
23 | |
24 | using namespace llvm; |
25 | |
26 | CSKYRegisterInfo::CSKYRegisterInfo() |
27 | : CSKYGenRegisterInfo(CSKY::R15, 0, 0, 0) {} |
28 | |
29 | const uint32_t * |
30 | CSKYRegisterInfo::getCallPreservedMask(const MachineFunction &MF, |
31 | CallingConv::ID Id) const { |
32 | const CSKYSubtarget &STI = MF.getSubtarget<CSKYSubtarget>(); |
33 | if (STI.hasFPUv2DoubleFloat() || STI.hasFPUv3DoubleFloat()) |
34 | return CSR_GPR_FPR64_RegMask; |
35 | if (STI.hasFPUv2SingleFloat() || STI.hasFPUv3SingleFloat()) |
36 | return CSR_GPR_FPR32_RegMask; |
37 | return CSR_I32_RegMask; |
38 | } |
39 | |
40 | Register CSKYRegisterInfo::getFrameRegister(const MachineFunction &MF) const { |
41 | const TargetFrameLowering *TFI = getFrameLowering(MF); |
42 | return TFI->hasFP(MF) ? CSKY::R8 : CSKY::R14; |
43 | } |
44 | |
45 | BitVector CSKYRegisterInfo::getReservedRegs(const MachineFunction &MF) const { |
46 | const CSKYFrameLowering *TFI = getFrameLowering(MF); |
47 | const CSKYSubtarget &STI = MF.getSubtarget<CSKYSubtarget>(); |
48 | BitVector Reserved(getNumRegs()); |
49 | |
50 | // Reserve the base register if we need to allocate |
51 | // variable-sized objects at runtime. |
52 | if (TFI->hasBP(MF)) |
53 | markSuperRegs(Reserved, CSKY::R7); // bp |
54 | |
55 | if (TFI->hasFP(MF)) |
56 | markSuperRegs(Reserved, CSKY::R8); // fp |
57 | |
58 | if (!STI.hasE2()) { |
59 | for (unsigned i = 0; i < 6; i++) |
60 | markSuperRegs(Reserved, CSKY::R8 + i); // R8 - R13 |
61 | } |
62 | |
63 | markSuperRegs(Reserved, CSKY::R14); // sp |
64 | markSuperRegs(Reserved, CSKY::R15); // lr |
65 | |
66 | if (!STI.hasHighRegisters()) { |
67 | for (unsigned i = 0; i < 10; i++) |
68 | markSuperRegs(Reserved, CSKY::R16 + i); // R16 - R25 |
69 | } |
70 | |
71 | markSuperRegs(Reserved, CSKY::R26); |
72 | markSuperRegs(Reserved, CSKY::R27); |
73 | markSuperRegs(Reserved, CSKY::R28); // gp |
74 | markSuperRegs(Reserved, CSKY::R29); |
75 | markSuperRegs(Reserved, CSKY::R30); |
76 | markSuperRegs(Reserved, CSKY::R31); // tp |
77 | |
78 | assert(checkAllSuperRegsMarked(Reserved)); |
79 | return Reserved; |
80 | } |
81 | |
82 | const uint32_t *CSKYRegisterInfo::getNoPreservedMask() const { |
83 | return CSR_NoRegs_RegMask; |
84 | } |
85 | |
86 | const MCPhysReg * |
87 | CSKYRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { |
88 | const CSKYSubtarget &STI = MF->getSubtarget<CSKYSubtarget>(); |
89 | if (MF->getFunction().hasFnAttribute(Kind: "interrupt" )) { |
90 | if (STI.hasFPUv3DoubleFloat()) |
91 | return CSR_GPR_FPR64v3_ISR_SaveList; |
92 | if (STI.hasFPUv3SingleFloat()) |
93 | return CSR_GPR_FPR32v3_ISR_SaveList; |
94 | if (STI.hasFPUv2DoubleFloat()) |
95 | return CSR_GPR_FPR64_ISR_SaveList; |
96 | if (STI.hasFPUv2SingleFloat()) |
97 | return CSR_GPR_FPR32_ISR_SaveList; |
98 | return CSR_GPR_ISR_SaveList; |
99 | } |
100 | |
101 | if (STI.hasFPUv2DoubleFloat() || STI.hasFPUv3DoubleFloat()) |
102 | return CSR_GPR_FPR64_SaveList; |
103 | if (STI.hasFPUv2SingleFloat() || STI.hasFPUv3SingleFloat()) |
104 | return CSR_GPR_FPR32_SaveList; |
105 | return CSR_I32_SaveList; |
106 | } |
107 | |
108 | static bool IsLegalOffset(const CSKYInstrInfo *TII, MachineInstr *MI, |
109 | int &Offset) { |
110 | const MCInstrDesc &Desc = MI->getDesc(); |
111 | unsigned AddrMode = (Desc.TSFlags & CSKYII::AddrModeMask); |
112 | unsigned i = 0; |
113 | for (; !MI->getOperand(i).isFI(); ++i) { |
114 | assert(i + 1 < MI->getNumOperands() && |
115 | "Instr doesn't have FrameIndex operand!" ); |
116 | } |
117 | |
118 | if (MI->getOpcode() == CSKY::ADDI32) { |
119 | if (!isUInt<12>(x: std::abs(x: Offset) - 1)) |
120 | return false; |
121 | if (Offset < 0) { |
122 | MI->setDesc(TII->get(CSKY::SUBI32)); |
123 | Offset = -Offset; |
124 | } |
125 | |
126 | return true; |
127 | } |
128 | |
129 | if (MI->getOpcode() == CSKY::ADDI16XZ) |
130 | return false; |
131 | |
132 | if (Offset < 0) |
133 | return false; |
134 | |
135 | unsigned NumBits = 0; |
136 | unsigned Scale = 1; |
137 | switch (AddrMode) { |
138 | case CSKYII::AddrMode32B: |
139 | Scale = 1; |
140 | NumBits = 12; |
141 | break; |
142 | case CSKYII::AddrMode32H: |
143 | Scale = 2; |
144 | NumBits = 12; |
145 | break; |
146 | case CSKYII::AddrMode32WD: |
147 | Scale = 4; |
148 | NumBits = 12; |
149 | break; |
150 | case CSKYII::AddrMode16B: |
151 | Scale = 1; |
152 | NumBits = 5; |
153 | break; |
154 | case CSKYII::AddrMode16H: |
155 | Scale = 2; |
156 | NumBits = 5; |
157 | break; |
158 | case CSKYII::AddrMode16W: |
159 | Scale = 4; |
160 | NumBits = 5; |
161 | break; |
162 | case CSKYII::AddrMode32SDF: |
163 | Scale = 4; |
164 | NumBits = 8; |
165 | break; |
166 | default: |
167 | llvm_unreachable("Unsupported addressing mode!" ); |
168 | } |
169 | |
170 | // Cannot encode offset. |
171 | if ((Offset & (Scale - 1)) != 0) |
172 | return false; |
173 | |
174 | unsigned Mask = (1 << NumBits) - 1; |
175 | if ((unsigned)Offset <= Mask * Scale) |
176 | return true; |
177 | |
178 | // Offset out of range. |
179 | return false; |
180 | } |
181 | |
182 | bool CSKYRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, |
183 | int SPAdj, unsigned FIOperandNum, |
184 | RegScavenger *RS) const { |
185 | assert(SPAdj == 0 && "Unexpected non-zero SPAdj value" ); |
186 | |
187 | MachineInstr *MI = &*II; |
188 | MachineBasicBlock &MBB = *MI->getParent(); |
189 | MachineFunction &MF = *MI->getParent()->getParent(); |
190 | MachineRegisterInfo &MRI = MF.getRegInfo(); |
191 | const CSKYInstrInfo *TII = MF.getSubtarget<CSKYSubtarget>().getInstrInfo(); |
192 | DebugLoc DL = MI->getDebugLoc(); |
193 | const CSKYSubtarget &STI = MF.getSubtarget<CSKYSubtarget>(); |
194 | |
195 | switch (MI->getOpcode()) { |
196 | default: |
197 | break; |
198 | case CSKY::RESTORE_CARRY: { |
199 | Register NewReg = STI.hasE2() |
200 | ? MRI.createVirtualRegister(&CSKY::GPRRegClass) |
201 | : MRI.createVirtualRegister(&CSKY::mGPRRegClass); |
202 | |
203 | auto *Temp = BuildMI(MBB, II, DL, TII->get(CSKY::LD32W), NewReg) |
204 | .add(MI->getOperand(1)) |
205 | .add(MI->getOperand(2)) |
206 | .getInstr(); |
207 | |
208 | BuildMI(MBB, II, DL, TII->get(STI.hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16), |
209 | MI->getOperand(0).getReg()) |
210 | .addReg(NewReg, getKillRegState(true)) |
211 | .addImm(0); |
212 | |
213 | MI = Temp; |
214 | |
215 | MBB.erase(I: II); |
216 | break; |
217 | } |
218 | case CSKY::SPILL_CARRY: { |
219 | Register NewReg; |
220 | if (STI.hasE2()) { |
221 | NewReg = MRI.createVirtualRegister(&CSKY::GPRRegClass); |
222 | BuildMI(MBB, II, DL, TII->get(CSKY::MVC32), NewReg) |
223 | .add(MI->getOperand(0)); |
224 | } else { |
225 | NewReg = MRI.createVirtualRegister(&CSKY::mGPRRegClass); |
226 | BuildMI(MBB, II, DL, TII->get(CSKY::MOVI16), NewReg).addImm(0); |
227 | BuildMI(MBB, II, DL, TII->get(CSKY::ADDC16)) |
228 | .addReg(NewReg, RegState::Define) |
229 | .addReg(MI->getOperand(0).getReg(), RegState::Define) |
230 | .addReg(NewReg, getKillRegState(true)) |
231 | .addReg(NewReg, getKillRegState(true)) |
232 | .addReg(MI->getOperand(0).getReg()); |
233 | |
234 | BuildMI(MBB, II, DL, TII->get(CSKY::BTSTI16), MI->getOperand(0).getReg()) |
235 | .addReg(NewReg) |
236 | .addImm(0); |
237 | } |
238 | |
239 | MI = BuildMI(MBB, II, DL, TII->get(CSKY::ST32W)) |
240 | .addReg(NewReg, getKillRegState(true)) |
241 | .add(MI->getOperand(1)) |
242 | .add(MI->getOperand(2)) |
243 | .getInstr(); |
244 | |
245 | MBB.erase(I: II); |
246 | |
247 | break; |
248 | } |
249 | } |
250 | |
251 | int FrameIndex = MI->getOperand(i: FIOperandNum).getIndex(); |
252 | Register FrameReg; |
253 | int Offset = getFrameLowering(MF) |
254 | ->getFrameIndexReference(MF, FrameIndex, FrameReg) |
255 | .getFixed() + |
256 | MI->getOperand(i: FIOperandNum + 1).getImm(); |
257 | |
258 | if (!isInt<32>(x: Offset)) |
259 | report_fatal_error( |
260 | reason: "Frame offsets outside of the signed 32-bit range not supported" ); |
261 | |
262 | bool FrameRegIsKill = false; |
263 | MachineBasicBlock::iterator NewII(MI); |
264 | if (!IsLegalOffset(TII, MI, Offset)) { |
265 | assert(isInt<32>(Offset) && "Int32 expected" ); |
266 | // The offset won't fit in an immediate, so use a scratch register instead |
267 | // Modify Offset and FrameReg appropriately |
268 | Register ScratchReg = TII->movImm(MBB, MBBI: NewII, DL, Val: Offset); |
269 | BuildMI(MBB, NewII, DL, |
270 | TII->get(STI.hasE2() ? CSKY::ADDU32 : CSKY::ADDU16XZ), ScratchReg) |
271 | .addReg(ScratchReg, RegState::Kill) |
272 | .addReg(FrameReg); |
273 | |
274 | Offset = 0; |
275 | FrameReg = ScratchReg; |
276 | FrameRegIsKill = true; |
277 | } |
278 | |
279 | if (Offset == 0 && |
280 | (MI->getOpcode() == CSKY::ADDI32 || MI->getOpcode() == CSKY::ADDI16XZ)) { |
281 | MI->setDesc(TII->get(TargetOpcode::COPY)); |
282 | MI->getOperand(i: FIOperandNum) |
283 | .ChangeToRegister(Reg: FrameReg, isDef: false, isImp: false, isKill: FrameRegIsKill); |
284 | MI->removeOperand(OpNo: FIOperandNum + 1); |
285 | } else { |
286 | MI->getOperand(i: FIOperandNum) |
287 | .ChangeToRegister(Reg: FrameReg, isDef: false, isImp: false, isKill: FrameRegIsKill); |
288 | MI->getOperand(i: FIOperandNum + 1).ChangeToImmediate(ImmVal: Offset); |
289 | } |
290 | return false; |
291 | } |
292 | |