1//===-- RISCVRegisterBankInfo.cpp -------------------------------*- 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/// \file
9/// This file implements the targeting of the RegisterBankInfo class for RISC-V.
10/// \todo This should be generated by TableGen.
11//===----------------------------------------------------------------------===//
12
13#include "RISCVRegisterBankInfo.h"
14#include "MCTargetDesc/RISCVMCTargetDesc.h"
15#include "RISCVSubtarget.h"
16#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
17#include "llvm/CodeGen/MachineRegisterInfo.h"
18#include "llvm/CodeGen/RegisterBank.h"
19#include "llvm/CodeGen/RegisterBankInfo.h"
20#include "llvm/CodeGen/TargetRegisterInfo.h"
21
22#define GET_TARGET_REGBANK_IMPL
23#include "RISCVGenRegisterBank.inc"
24
25namespace llvm {
26namespace RISCV {
27
28const RegisterBankInfo::PartialMapping PartMappings[] = {
29 // clang-format off
30 {0, 32, GPRBRegBank},
31 {0, 64, GPRBRegBank},
32 {0, 16, FPRBRegBank},
33 {0, 32, FPRBRegBank},
34 {0, 64, FPRBRegBank},
35 {0, 64, VRBRegBank},
36 {0, 128, VRBRegBank},
37 {0, 256, VRBRegBank},
38 {0, 512, VRBRegBank},
39 // clang-format on
40};
41
42enum PartialMappingIdx {
43 PMI_GPRB32 = 0,
44 PMI_GPRB64 = 1,
45 PMI_FPRB16 = 2,
46 PMI_FPRB32 = 3,
47 PMI_FPRB64 = 4,
48 PMI_VRB64 = 5,
49 PMI_VRB128 = 6,
50 PMI_VRB256 = 7,
51 PMI_VRB512 = 8,
52};
53
54const RegisterBankInfo::ValueMapping ValueMappings[] = {
55 // Invalid value mapping.
56 {nullptr, 0},
57 // Maximum 3 GPR operands; 32 bit.
58 {&PartMappings[PMI_GPRB32], 1},
59 {&PartMappings[PMI_GPRB32], 1},
60 {&PartMappings[PMI_GPRB32], 1},
61 // Maximum 3 GPR operands; 64 bit.
62 {&PartMappings[PMI_GPRB64], 1},
63 {&PartMappings[PMI_GPRB64], 1},
64 {&PartMappings[PMI_GPRB64], 1},
65 // Maximum 3 FPR operands; 16 bit.
66 {&PartMappings[PMI_FPRB16], 1},
67 {&PartMappings[PMI_FPRB16], 1},
68 {&PartMappings[PMI_FPRB16], 1},
69 // Maximum 3 FPR operands; 32 bit.
70 {&PartMappings[PMI_FPRB32], 1},
71 {&PartMappings[PMI_FPRB32], 1},
72 {&PartMappings[PMI_FPRB32], 1},
73 // Maximum 3 FPR operands; 64 bit.
74 {&PartMappings[PMI_FPRB64], 1},
75 {&PartMappings[PMI_FPRB64], 1},
76 {&PartMappings[PMI_FPRB64], 1},
77 // Maximum 3 VR LMUL={1, MF2, MF4, MF8} operands.
78 {&PartMappings[PMI_VRB64], 1},
79 {&PartMappings[PMI_VRB64], 1},
80 {&PartMappings[PMI_VRB64], 1},
81 // Maximum 3 VR LMUL=2 operands.
82 {&PartMappings[PMI_VRB128], 1},
83 {&PartMappings[PMI_VRB128], 1},
84 {&PartMappings[PMI_VRB128], 1},
85 // Maximum 3 VR LMUL=4 operands.
86 {&PartMappings[PMI_VRB256], 1},
87 {&PartMappings[PMI_VRB256], 1},
88 {&PartMappings[PMI_VRB256], 1},
89 // Maximum 3 VR LMUL=8 operands.
90 {&PartMappings[PMI_VRB512], 1},
91 {&PartMappings[PMI_VRB512], 1},
92 {&PartMappings[PMI_VRB512], 1},
93};
94
95enum ValueMappingIdx {
96 InvalidIdx = 0,
97 GPRB32Idx = 1,
98 GPRB64Idx = 4,
99 FPRB16Idx = 7,
100 FPRB32Idx = 10,
101 FPRB64Idx = 13,
102 VRB64Idx = 16,
103 VRB128Idx = 19,
104 VRB256Idx = 22,
105 VRB512Idx = 25,
106};
107} // namespace RISCV
108} // namespace llvm
109
110using namespace llvm;
111
112RISCVRegisterBankInfo::RISCVRegisterBankInfo(unsigned HwMode)
113 : RISCVGenRegisterBankInfo(HwMode) {}
114
115const RegisterBank &
116RISCVRegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC,
117 LLT Ty) const {
118 switch (RC.getID()) {
119 default:
120 llvm_unreachable("Register class not supported");
121 case RISCV::GPRRegClassID:
122 case RISCV::GPRF16RegClassID:
123 case RISCV::GPRF32RegClassID:
124 case RISCV::GPRNoX0RegClassID:
125 case RISCV::GPRNoX0X2RegClassID:
126 case RISCV::GPRJALRRegClassID:
127 case RISCV::GPRJALRNonX7RegClassID:
128 case RISCV::GPRTCRegClassID:
129 case RISCV::GPRTCNonX7RegClassID:
130 case RISCV::GPRC_and_GPRTCRegClassID:
131 case RISCV::GPRCRegClassID:
132 case RISCV::GPRC_and_SR07RegClassID:
133 case RISCV::SR07RegClassID:
134 case RISCV::SPRegClassID:
135 case RISCV::GPRX0RegClassID:
136 return getRegBank(ID: RISCV::GPRBRegBankID);
137 case RISCV::FPR64RegClassID:
138 case RISCV::FPR16RegClassID:
139 case RISCV::FPR32RegClassID:
140 case RISCV::FPR64CRegClassID:
141 case RISCV::FPR32CRegClassID:
142 return getRegBank(ID: RISCV::FPRBRegBankID);
143 case RISCV::VMRegClassID:
144 case RISCV::VRRegClassID:
145 case RISCV::VRNoV0RegClassID:
146 case RISCV::VRM2RegClassID:
147 case RISCV::VRM2NoV0RegClassID:
148 case RISCV::VRM4RegClassID:
149 case RISCV::VRM4NoV0RegClassID:
150 case RISCV::VMV0RegClassID:
151 case RISCV::VRM2_with_sub_vrm1_0_in_VMV0RegClassID:
152 case RISCV::VRM4_with_sub_vrm1_0_in_VMV0RegClassID:
153 case RISCV::VRM8RegClassID:
154 case RISCV::VRM8NoV0RegClassID:
155 case RISCV::VRM8_with_sub_vrm1_0_in_VMV0RegClassID:
156 return getRegBank(ID: RISCV::VRBRegBankID);
157 }
158}
159
160static const RegisterBankInfo::ValueMapping *getFPValueMapping(unsigned Size) {
161 unsigned Idx;
162 switch (Size) {
163 default:
164 llvm_unreachable("Unexpected size");
165 case 16:
166 Idx = RISCV::FPRB16Idx;
167 break;
168 case 32:
169 Idx = RISCV::FPRB32Idx;
170 break;
171 case 64:
172 Idx = RISCV::FPRB64Idx;
173 break;
174 }
175 return &RISCV::ValueMappings[Idx];
176}
177
178// TODO: Make this more like AArch64?
179bool RISCVRegisterBankInfo::hasFPConstraints(
180 const MachineInstr &MI, const MachineRegisterInfo &MRI,
181 const TargetRegisterInfo &TRI) const {
182 if (isPreISelGenericFloatingPointOpcode(Opc: MI.getOpcode()))
183 return true;
184
185 // If we have a copy instruction, we could be feeding floating point
186 // instructions.
187 if (MI.getOpcode() != TargetOpcode::COPY)
188 return false;
189
190 return getRegBank(Reg: MI.getOperand(i: 0).getReg(), MRI, TRI) == &RISCV::FPRBRegBank;
191}
192
193bool RISCVRegisterBankInfo::onlyUsesFP(const MachineInstr &MI,
194 const MachineRegisterInfo &MRI,
195 const TargetRegisterInfo &TRI) const {
196 switch (MI.getOpcode()) {
197 case TargetOpcode::G_FPTOSI:
198 case TargetOpcode::G_FPTOUI:
199 case TargetOpcode::G_FCMP:
200 return true;
201 default:
202 break;
203 }
204
205 return hasFPConstraints(MI, MRI, TRI);
206}
207
208bool RISCVRegisterBankInfo::onlyDefinesFP(const MachineInstr &MI,
209 const MachineRegisterInfo &MRI,
210 const TargetRegisterInfo &TRI) const {
211 switch (MI.getOpcode()) {
212 case TargetOpcode::G_SITOFP:
213 case TargetOpcode::G_UITOFP:
214 return true;
215 default:
216 break;
217 }
218
219 return hasFPConstraints(MI, MRI, TRI);
220}
221
222bool RISCVRegisterBankInfo::anyUseOnlyUseFP(
223 Register Def, const MachineRegisterInfo &MRI,
224 const TargetRegisterInfo &TRI) const {
225 return any_of(
226 Range: MRI.use_nodbg_instructions(Reg: Def),
227 P: [&](const MachineInstr &UseMI) { return onlyUsesFP(MI: UseMI, MRI, TRI); });
228}
229
230static const RegisterBankInfo::ValueMapping *getVRBValueMapping(unsigned Size) {
231 unsigned Idx;
232
233 if (Size <= 64)
234 Idx = RISCV::VRB64Idx;
235 else if (Size == 128)
236 Idx = RISCV::VRB128Idx;
237 else if (Size == 256)
238 Idx = RISCV::VRB256Idx;
239 else if (Size == 512)
240 Idx = RISCV::VRB512Idx;
241 else
242 llvm::report_fatal_error(reason: "Invalid Size");
243
244 return &RISCV::ValueMappings[Idx];
245}
246
247const RegisterBankInfo::InstructionMapping &
248RISCVRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
249 const unsigned Opc = MI.getOpcode();
250
251 // Try the default logic for non-generic instructions that are either copies
252 // or already have some operands assigned to banks.
253 if (!isPreISelGenericOpcode(Opcode: Opc) || Opc == TargetOpcode::G_PHI) {
254 const InstructionMapping &Mapping = getInstrMappingImpl(MI);
255 if (Mapping.isValid())
256 return Mapping;
257 }
258
259 const MachineFunction &MF = *MI.getParent()->getParent();
260 const MachineRegisterInfo &MRI = MF.getRegInfo();
261 const TargetSubtargetInfo &STI = MF.getSubtarget();
262 const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
263
264 unsigned GPRSize = getMaximumSize(RegBankID: RISCV::GPRBRegBankID);
265 assert((GPRSize == 32 || GPRSize == 64) && "Unexpected GPR size");
266
267 unsigned NumOperands = MI.getNumOperands();
268 const ValueMapping *GPRValueMapping =
269 &RISCV::ValueMappings[GPRSize == 64 ? RISCV::GPRB64Idx
270 : RISCV::GPRB32Idx];
271
272 switch (Opc) {
273 case TargetOpcode::G_ADD:
274 case TargetOpcode::G_SUB:
275 case TargetOpcode::G_SHL:
276 case TargetOpcode::G_ASHR:
277 case TargetOpcode::G_LSHR:
278 case TargetOpcode::G_AND:
279 case TargetOpcode::G_OR:
280 case TargetOpcode::G_XOR:
281 case TargetOpcode::G_MUL:
282 case TargetOpcode::G_SDIV:
283 case TargetOpcode::G_SREM:
284 case TargetOpcode::G_SMULH:
285 case TargetOpcode::G_SMAX:
286 case TargetOpcode::G_SMIN:
287 case TargetOpcode::G_UDIV:
288 case TargetOpcode::G_UREM:
289 case TargetOpcode::G_UMULH:
290 case TargetOpcode::G_UMAX:
291 case TargetOpcode::G_UMIN:
292 case TargetOpcode::G_PTR_ADD:
293 case TargetOpcode::G_PTRTOINT:
294 case TargetOpcode::G_INTTOPTR:
295 case TargetOpcode::G_FADD:
296 case TargetOpcode::G_FSUB:
297 case TargetOpcode::G_FMUL:
298 case TargetOpcode::G_FDIV:
299 case TargetOpcode::G_FABS:
300 case TargetOpcode::G_FNEG:
301 case TargetOpcode::G_FSQRT:
302 case TargetOpcode::G_FMAXNUM:
303 case TargetOpcode::G_FMINNUM: {
304 LLT Ty = MRI.getType(Reg: MI.getOperand(i: 0).getReg());
305 TypeSize Size = Ty.getSizeInBits();
306
307 const ValueMapping *Mapping;
308 if (Ty.isVector())
309 Mapping = getVRBValueMapping(Size: Size.getKnownMinValue());
310 else if (isPreISelGenericFloatingPointOpcode(Opc))
311 Mapping = getFPValueMapping(Size: Size.getFixedValue());
312 else
313 Mapping = GPRValueMapping;
314
315#ifndef NDEBUG
316 // Make sure all the operands are using similar size and type.
317 for (unsigned Idx = 1; Idx != NumOperands; ++Idx) {
318 LLT OpTy = MRI.getType(MI.getOperand(Idx).getReg());
319 assert(Ty.isVector() == OpTy.isVector() &&
320 "Operand has incompatible type");
321 // Don't check size for GPR.
322 if (OpTy.isVector() || isPreISelGenericFloatingPointOpcode(Opc))
323 assert(Size == OpTy.getSizeInBits() && "Operand has incompatible size");
324 }
325#endif // End NDEBUG
326
327 return getInstructionMapping(ID: DefaultMappingID, Cost: 1, OperandsMapping: Mapping, NumOperands);
328 }
329 case TargetOpcode::G_SEXTLOAD:
330 case TargetOpcode::G_ZEXTLOAD:
331 return getInstructionMapping(ID: DefaultMappingID, /*Cost=*/1, OperandsMapping: GPRValueMapping,
332 NumOperands);
333 case TargetOpcode::G_IMPLICIT_DEF: {
334 Register Dst = MI.getOperand(i: 0).getReg();
335 LLT DstTy = MRI.getType(Reg: Dst);
336 unsigned DstMinSize = DstTy.getSizeInBits().getKnownMinValue();
337 auto Mapping = GPRValueMapping;
338 // FIXME: May need to do a better job determining when to use FPRB.
339 // For example, the look through COPY case:
340 // %0:_(s32) = G_IMPLICIT_DEF
341 // %1:_(s32) = COPY %0
342 // $f10_d = COPY %1(s32)
343 if (DstTy.isVector())
344 Mapping = getVRBValueMapping(Size: DstMinSize);
345 else if (anyUseOnlyUseFP(Def: Dst, MRI, TRI))
346 Mapping = getFPValueMapping(Size: DstMinSize);
347
348 return getInstructionMapping(ID: DefaultMappingID, /*Cost=*/1, OperandsMapping: Mapping,
349 NumOperands);
350 }
351 }
352
353 SmallVector<const ValueMapping *, 4> OpdsMapping(NumOperands);
354
355 switch (Opc) {
356 case TargetOpcode::G_LOAD: {
357 LLT Ty = MRI.getType(Reg: MI.getOperand(i: 0).getReg());
358 OpdsMapping[0] = GPRValueMapping;
359 OpdsMapping[1] = GPRValueMapping;
360 // Use FPR64 for s64 loads on rv32.
361 if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
362 assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
363 OpdsMapping[0] = getFPValueMapping(Size: Ty.getSizeInBits());
364 break;
365 }
366
367 // Check if that load feeds fp instructions.
368 // In that case, we want the default mapping to be on FPR
369 // instead of blind map every scalar to GPR.
370 if (anyUseOnlyUseFP(Def: MI.getOperand(i: 0).getReg(), MRI, TRI))
371 // If we have at least one direct use in a FP instruction,
372 // assume this was a floating point load in the IR. If it was
373 // not, we would have had a bitcast before reaching that
374 // instruction.
375 OpdsMapping[0] = getFPValueMapping(Size: Ty.getSizeInBits());
376
377 break;
378 }
379 case TargetOpcode::G_STORE: {
380 LLT Ty = MRI.getType(Reg: MI.getOperand(i: 0).getReg());
381 OpdsMapping[0] = GPRValueMapping;
382 OpdsMapping[1] = GPRValueMapping;
383 // Use FPR64 for s64 stores on rv32.
384 if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
385 assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
386 OpdsMapping[0] = getFPValueMapping(Size: Ty.getSizeInBits());
387 break;
388 }
389
390 MachineInstr *DefMI = MRI.getVRegDef(Reg: MI.getOperand(i: 0).getReg());
391 if (onlyDefinesFP(MI: *DefMI, MRI, TRI))
392 OpdsMapping[0] = getFPValueMapping(Size: Ty.getSizeInBits());
393 break;
394 }
395 case TargetOpcode::G_SELECT: {
396 LLT Ty = MRI.getType(Reg: MI.getOperand(i: 0).getReg());
397
398 if (Ty.isVector()) {
399 auto &Sel = cast<GSelect>(Val: MI);
400 LLT TestTy = MRI.getType(Reg: Sel.getCondReg());
401 assert(TestTy.isVector() && "Unexpected condition argument type");
402 OpdsMapping[0] = OpdsMapping[2] = OpdsMapping[3] =
403 getVRBValueMapping(Size: Ty.getSizeInBits().getKnownMinValue());
404 OpdsMapping[1] =
405 getVRBValueMapping(Size: TestTy.getSizeInBits().getKnownMinValue());
406 break;
407 }
408
409 // Try to minimize the number of copies. If we have more floating point
410 // constrained values than not, then we'll put everything on FPR. Otherwise,
411 // everything has to be on GPR.
412 unsigned NumFP = 0;
413
414 // Use FPR64 for s64 select on rv32.
415 if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
416 NumFP = 3;
417 } else {
418 // Check if the uses of the result always produce floating point values.
419 //
420 // For example:
421 //
422 // %z = G_SELECT %cond %x %y
423 // fpr = G_FOO %z ...
424 if (any_of(Range: MRI.use_nodbg_instructions(Reg: MI.getOperand(i: 0).getReg()),
425 P: [&](const MachineInstr &UseMI) {
426 return onlyUsesFP(MI: UseMI, MRI, TRI);
427 }))
428 ++NumFP;
429
430 // Check if the defs of the source values always produce floating point
431 // values.
432 //
433 // For example:
434 //
435 // %x = G_SOMETHING_ALWAYS_FLOAT %a ...
436 // %z = G_SELECT %cond %x %y
437 //
438 // Also check whether or not the sources have already been decided to be
439 // FPR. Keep track of this.
440 //
441 // This doesn't check the condition, since the condition is always an
442 // integer.
443 for (unsigned Idx = 2; Idx < 4; ++Idx) {
444 Register VReg = MI.getOperand(i: Idx).getReg();
445 MachineInstr *DefMI = MRI.getVRegDef(Reg: VReg);
446 if (getRegBank(Reg: VReg, MRI, TRI) == &RISCV::FPRBRegBank ||
447 onlyDefinesFP(MI: *DefMI, MRI, TRI))
448 ++NumFP;
449 }
450 }
451
452 // Condition operand is always GPR.
453 OpdsMapping[1] = GPRValueMapping;
454
455 const ValueMapping *Mapping = GPRValueMapping;
456 if (NumFP >= 2)
457 Mapping = getFPValueMapping(Size: Ty.getSizeInBits());
458
459 OpdsMapping[0] = OpdsMapping[2] = OpdsMapping[3] = Mapping;
460 break;
461 }
462 case TargetOpcode::G_FPTOSI:
463 case TargetOpcode::G_FPTOUI:
464 case RISCV::G_FCLASS: {
465 LLT Ty = MRI.getType(Reg: MI.getOperand(i: 1).getReg());
466 OpdsMapping[0] = GPRValueMapping;
467 OpdsMapping[1] = getFPValueMapping(Size: Ty.getSizeInBits());
468 break;
469 }
470 case TargetOpcode::G_SITOFP:
471 case TargetOpcode::G_UITOFP: {
472 LLT Ty = MRI.getType(Reg: MI.getOperand(i: 0).getReg());
473 OpdsMapping[0] = getFPValueMapping(Size: Ty.getSizeInBits());
474 OpdsMapping[1] = GPRValueMapping;
475 break;
476 }
477 case TargetOpcode::G_FCMP: {
478 LLT Ty = MRI.getType(Reg: MI.getOperand(i: 2).getReg());
479
480 unsigned Size = Ty.getSizeInBits();
481
482 OpdsMapping[0] = GPRValueMapping;
483 OpdsMapping[2] = OpdsMapping[3] = getFPValueMapping(Size);
484 break;
485 }
486 case TargetOpcode::G_MERGE_VALUES: {
487 // Use FPR64 for s64 merge on rv32.
488 LLT Ty = MRI.getType(Reg: MI.getOperand(i: 0).getReg());
489 if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
490 assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
491 OpdsMapping[0] = getFPValueMapping(Size: Ty.getSizeInBits());
492 OpdsMapping[1] = GPRValueMapping;
493 OpdsMapping[2] = GPRValueMapping;
494 }
495 break;
496 }
497 case TargetOpcode::G_UNMERGE_VALUES: {
498 // Use FPR64 for s64 unmerge on rv32.
499 LLT Ty = MRI.getType(Reg: MI.getOperand(i: 2).getReg());
500 if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
501 assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
502 OpdsMapping[0] = GPRValueMapping;
503 OpdsMapping[1] = GPRValueMapping;
504 OpdsMapping[2] = getFPValueMapping(Size: Ty.getSizeInBits());
505 }
506 break;
507 }
508 default:
509 // By default map all scalars to GPR.
510 for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
511 auto &MO = MI.getOperand(i: Idx);
512 if (!MO.isReg() || !MO.getReg())
513 continue;
514 LLT Ty = MRI.getType(Reg: MO.getReg());
515 if (!Ty.isValid())
516 continue;
517
518 if (Ty.isVector())
519 OpdsMapping[Idx] =
520 getVRBValueMapping(Size: Ty.getSizeInBits().getKnownMinValue());
521 else if (isPreISelGenericFloatingPointOpcode(Opc))
522 OpdsMapping[Idx] = getFPValueMapping(Size: Ty.getSizeInBits());
523 else
524 OpdsMapping[Idx] = GPRValueMapping;
525 }
526 break;
527 }
528
529 return getInstructionMapping(ID: DefaultMappingID, /*Cost=*/1,
530 OperandsMapping: getOperandsMapping(OpdsMapping), NumOperands);
531}
532