1 //===-- RISCVRegisterBankInfo.cpp -------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 /// This file implements the targeting of the RegisterBankInfo class for RISC-V.
10 /// \todo This should be generated by TableGen.
11 //===----------------------------------------------------------------------===//
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"
22 #define GET_TARGET_REGBANK_IMPL
23 #include "RISCVGenRegisterBank.inc"
28 const RegisterBankInfo::PartialMapping PartMappings
[] = {
42 enum PartialMappingIdx
{
54 const RegisterBankInfo::ValueMapping ValueMappings
[] = {
55 // Invalid value mapping.
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},
95 enum ValueMappingIdx
{
110 using namespace llvm
;
112 RISCVRegisterBankInfo::RISCVRegisterBankInfo(unsigned HwMode
)
113 : RISCVGenRegisterBankInfo(HwMode
) {}
115 static const RegisterBankInfo::ValueMapping
*getFPValueMapping(unsigned Size
) {
119 llvm_unreachable("Unexpected size");
121 Idx
= RISCV::FPRB16Idx
;
124 Idx
= RISCV::FPRB32Idx
;
127 Idx
= RISCV::FPRB64Idx
;
130 return &RISCV::ValueMappings
[Idx
];
133 // TODO: Make this more like AArch64?
134 bool RISCVRegisterBankInfo::hasFPConstraints(
135 const MachineInstr
&MI
, const MachineRegisterInfo
&MRI
,
136 const TargetRegisterInfo
&TRI
) const {
137 if (isPreISelGenericFloatingPointOpcode(MI
.getOpcode()))
140 // If we have a copy instruction, we could be feeding floating point
142 if (MI
.getOpcode() != TargetOpcode::COPY
)
145 return getRegBank(MI
.getOperand(0).getReg(), MRI
, TRI
) == &RISCV::FPRBRegBank
;
148 bool RISCVRegisterBankInfo::onlyUsesFP(const MachineInstr
&MI
,
149 const MachineRegisterInfo
&MRI
,
150 const TargetRegisterInfo
&TRI
) const {
151 switch (MI
.getOpcode()) {
152 case RISCV::G_FCVT_W_RV64
:
153 case RISCV::G_FCVT_WU_RV64
:
154 case RISCV::G_FCLASS
:
155 case TargetOpcode::G_FPTOSI
:
156 case TargetOpcode::G_FPTOUI
:
157 case TargetOpcode::G_FCMP
:
163 return hasFPConstraints(MI
, MRI
, TRI
);
166 bool RISCVRegisterBankInfo::onlyDefinesFP(const MachineInstr
&MI
,
167 const MachineRegisterInfo
&MRI
,
168 const TargetRegisterInfo
&TRI
) const {
169 switch (MI
.getOpcode()) {
170 case TargetOpcode::G_SITOFP
:
171 case TargetOpcode::G_UITOFP
:
177 return hasFPConstraints(MI
, MRI
, TRI
);
180 bool RISCVRegisterBankInfo::anyUseOnlyUseFP(
181 Register Def
, const MachineRegisterInfo
&MRI
,
182 const TargetRegisterInfo
&TRI
) const {
184 MRI
.use_nodbg_instructions(Def
),
185 [&](const MachineInstr
&UseMI
) { return onlyUsesFP(UseMI
, MRI
, TRI
); });
188 static const RegisterBankInfo::ValueMapping
*getVRBValueMapping(unsigned Size
) {
192 Idx
= RISCV::VRB64Idx
;
193 else if (Size
== 128)
194 Idx
= RISCV::VRB128Idx
;
195 else if (Size
== 256)
196 Idx
= RISCV::VRB256Idx
;
197 else if (Size
== 512)
198 Idx
= RISCV::VRB512Idx
;
200 llvm::report_fatal_error("Invalid Size");
202 return &RISCV::ValueMappings
[Idx
];
205 const RegisterBankInfo::InstructionMapping
&
206 RISCVRegisterBankInfo::getInstrMapping(const MachineInstr
&MI
) const {
207 const unsigned Opc
= MI
.getOpcode();
209 // Try the default logic for non-generic instructions that are either copies
210 // or already have some operands assigned to banks.
211 if (!isPreISelGenericOpcode(Opc
) || Opc
== TargetOpcode::G_PHI
) {
212 const InstructionMapping
&Mapping
= getInstrMappingImpl(MI
);
213 if (Mapping
.isValid())
217 const MachineFunction
&MF
= *MI
.getParent()->getParent();
218 const MachineRegisterInfo
&MRI
= MF
.getRegInfo();
219 const TargetSubtargetInfo
&STI
= MF
.getSubtarget();
220 const TargetRegisterInfo
&TRI
= *STI
.getRegisterInfo();
222 unsigned GPRSize
= getMaximumSize(RISCV::GPRBRegBankID
);
223 assert((GPRSize
== 32 || GPRSize
== 64) && "Unexpected GPR size");
225 unsigned NumOperands
= MI
.getNumOperands();
226 const ValueMapping
*GPRValueMapping
=
227 &RISCV::ValueMappings
[GPRSize
== 64 ? RISCV::GPRB64Idx
231 case TargetOpcode::G_ADD
:
232 case TargetOpcode::G_SUB
:
233 case TargetOpcode::G_SHL
:
234 case TargetOpcode::G_ASHR
:
235 case TargetOpcode::G_LSHR
:
236 case TargetOpcode::G_AND
:
237 case TargetOpcode::G_OR
:
238 case TargetOpcode::G_XOR
:
239 case TargetOpcode::G_MUL
:
240 case TargetOpcode::G_SDIV
:
241 case TargetOpcode::G_SREM
:
242 case TargetOpcode::G_SMULH
:
243 case TargetOpcode::G_SMAX
:
244 case TargetOpcode::G_SMIN
:
245 case TargetOpcode::G_UDIV
:
246 case TargetOpcode::G_UREM
:
247 case TargetOpcode::G_UMULH
:
248 case TargetOpcode::G_UMAX
:
249 case TargetOpcode::G_UMIN
:
250 case TargetOpcode::G_PTR_ADD
:
251 case TargetOpcode::G_PTRTOINT
:
252 case TargetOpcode::G_INTTOPTR
:
253 case TargetOpcode::G_FADD
:
254 case TargetOpcode::G_FSUB
:
255 case TargetOpcode::G_FMUL
:
256 case TargetOpcode::G_FDIV
:
257 case TargetOpcode::G_FABS
:
258 case TargetOpcode::G_FNEG
:
259 case TargetOpcode::G_FSQRT
:
260 case TargetOpcode::G_FMAXNUM
:
261 case TargetOpcode::G_FMINNUM
: {
262 LLT Ty
= MRI
.getType(MI
.getOperand(0).getReg());
263 TypeSize Size
= Ty
.getSizeInBits();
265 const ValueMapping
*Mapping
;
267 Mapping
= getVRBValueMapping(Size
.getKnownMinValue());
268 else if (isPreISelGenericFloatingPointOpcode(Opc
))
269 Mapping
= getFPValueMapping(Size
.getFixedValue());
271 Mapping
= GPRValueMapping
;
274 // Make sure all the operands are using similar size and type.
275 for (unsigned Idx
= 1; Idx
!= NumOperands
; ++Idx
) {
276 LLT OpTy
= MRI
.getType(MI
.getOperand(Idx
).getReg());
277 assert(Ty
.isVector() == OpTy
.isVector() &&
278 "Operand has incompatible type");
279 // Don't check size for GPR.
280 if (OpTy
.isVector() || isPreISelGenericFloatingPointOpcode(Opc
))
281 assert(Size
== OpTy
.getSizeInBits() && "Operand has incompatible size");
285 return getInstructionMapping(DefaultMappingID
, 1, Mapping
, NumOperands
);
287 case TargetOpcode::G_SEXTLOAD
:
288 case TargetOpcode::G_ZEXTLOAD
:
289 return getInstructionMapping(DefaultMappingID
, /*Cost=*/1, GPRValueMapping
,
291 case TargetOpcode::G_IMPLICIT_DEF
: {
292 Register Dst
= MI
.getOperand(0).getReg();
293 LLT DstTy
= MRI
.getType(Dst
);
294 unsigned DstMinSize
= DstTy
.getSizeInBits().getKnownMinValue();
295 auto Mapping
= GPRValueMapping
;
296 // FIXME: May need to do a better job determining when to use FPRB.
297 // For example, the look through COPY case:
298 // %0:_(s32) = G_IMPLICIT_DEF
299 // %1:_(s32) = COPY %0
300 // $f10_d = COPY %1(s32)
301 if (DstTy
.isVector())
302 Mapping
= getVRBValueMapping(DstMinSize
);
303 else if (anyUseOnlyUseFP(Dst
, MRI
, TRI
))
304 Mapping
= getFPValueMapping(DstMinSize
);
306 return getInstructionMapping(DefaultMappingID
, /*Cost=*/1, Mapping
,
311 SmallVector
<const ValueMapping
*, 4> OpdsMapping(NumOperands
);
314 case TargetOpcode::G_LOAD
: {
315 LLT Ty
= MRI
.getType(MI
.getOperand(0).getReg());
316 TypeSize Size
= Ty
.getSizeInBits();
318 OpdsMapping
[1] = GPRValueMapping
;
321 OpdsMapping
[0] = getVRBValueMapping(Size
.getKnownMinValue());
325 OpdsMapping
[0] = GPRValueMapping
;
327 // Use FPR64 for s64 loads on rv32.
328 if (GPRSize
== 32 && Size
.getFixedValue() == 64) {
329 assert(MF
.getSubtarget
<RISCVSubtarget
>().hasStdExtD());
330 OpdsMapping
[0] = getFPValueMapping(Size
);
334 // Check if that load feeds fp instructions.
335 // In that case, we want the default mapping to be on FPR
336 // instead of blind map every scalar to GPR.
337 if (anyUseOnlyUseFP(MI
.getOperand(0).getReg(), MRI
, TRI
)) {
338 // If we have at least one direct use in a FP instruction,
339 // assume this was a floating point load in the IR. If it was
340 // not, we would have had a bitcast before reaching that
342 OpdsMapping
[0] = getFPValueMapping(Size
);
348 case TargetOpcode::G_STORE
: {
349 LLT Ty
= MRI
.getType(MI
.getOperand(0).getReg());
350 TypeSize Size
= Ty
.getSizeInBits();
352 OpdsMapping
[1] = GPRValueMapping
;
355 OpdsMapping
[0] = getVRBValueMapping(Size
.getKnownMinValue());
359 OpdsMapping
[0] = GPRValueMapping
;
361 // Use FPR64 for s64 stores on rv32.
362 if (GPRSize
== 32 && Size
.getFixedValue() == 64) {
363 assert(MF
.getSubtarget
<RISCVSubtarget
>().hasStdExtD());
364 OpdsMapping
[0] = getFPValueMapping(Ty
.getSizeInBits());
368 MachineInstr
*DefMI
= MRI
.getVRegDef(MI
.getOperand(0).getReg());
369 if (onlyDefinesFP(*DefMI
, MRI
, TRI
))
370 OpdsMapping
[0] = getFPValueMapping(Ty
.getSizeInBits());
373 case TargetOpcode::G_SELECT
: {
374 LLT Ty
= MRI
.getType(MI
.getOperand(0).getReg());
377 auto &Sel
= cast
<GSelect
>(MI
);
378 LLT TestTy
= MRI
.getType(Sel
.getCondReg());
379 assert(TestTy
.isVector() && "Unexpected condition argument type");
380 OpdsMapping
[0] = OpdsMapping
[2] = OpdsMapping
[3] =
381 getVRBValueMapping(Ty
.getSizeInBits().getKnownMinValue());
383 getVRBValueMapping(TestTy
.getSizeInBits().getKnownMinValue());
387 // Try to minimize the number of copies. If we have more floating point
388 // constrained values than not, then we'll put everything on FPR. Otherwise,
389 // everything has to be on GPR.
392 // Use FPR64 for s64 select on rv32.
393 if (GPRSize
== 32 && Ty
.getSizeInBits() == 64) {
396 // Check if the uses of the result always produce floating point values.
400 // %z = G_SELECT %cond %x %y
401 // fpr = G_FOO %z ...
402 if (any_of(MRI
.use_nodbg_instructions(MI
.getOperand(0).getReg()),
403 [&](const MachineInstr
&UseMI
) {
404 return onlyUsesFP(UseMI
, MRI
, TRI
);
408 // Check if the defs of the source values always produce floating point
413 // %x = G_SOMETHING_ALWAYS_FLOAT %a ...
414 // %z = G_SELECT %cond %x %y
416 // Also check whether or not the sources have already been decided to be
417 // FPR. Keep track of this.
419 // This doesn't check the condition, since the condition is always an
421 for (unsigned Idx
= 2; Idx
< 4; ++Idx
) {
422 Register VReg
= MI
.getOperand(Idx
).getReg();
423 MachineInstr
*DefMI
= MRI
.getVRegDef(VReg
);
424 if (getRegBank(VReg
, MRI
, TRI
) == &RISCV::FPRBRegBank
||
425 onlyDefinesFP(*DefMI
, MRI
, TRI
))
430 // Condition operand is always GPR.
431 OpdsMapping
[1] = GPRValueMapping
;
433 const ValueMapping
*Mapping
= GPRValueMapping
;
435 Mapping
= getFPValueMapping(Ty
.getSizeInBits());
437 OpdsMapping
[0] = OpdsMapping
[2] = OpdsMapping
[3] = Mapping
;
440 case RISCV::G_FCVT_W_RV64
:
441 case RISCV::G_FCVT_WU_RV64
:
442 case TargetOpcode::G_FPTOSI
:
443 case TargetOpcode::G_FPTOUI
:
444 case RISCV::G_FCLASS
: {
445 LLT Ty
= MRI
.getType(MI
.getOperand(1).getReg());
446 OpdsMapping
[0] = GPRValueMapping
;
447 OpdsMapping
[1] = getFPValueMapping(Ty
.getSizeInBits());
450 case TargetOpcode::G_SITOFP
:
451 case TargetOpcode::G_UITOFP
: {
452 LLT Ty
= MRI
.getType(MI
.getOperand(0).getReg());
453 OpdsMapping
[0] = getFPValueMapping(Ty
.getSizeInBits());
454 OpdsMapping
[1] = GPRValueMapping
;
457 case TargetOpcode::G_FCMP
: {
458 LLT Ty
= MRI
.getType(MI
.getOperand(2).getReg());
460 unsigned Size
= Ty
.getSizeInBits();
462 OpdsMapping
[0] = GPRValueMapping
;
463 OpdsMapping
[2] = OpdsMapping
[3] = getFPValueMapping(Size
);
466 case TargetOpcode::G_MERGE_VALUES
: {
467 // Use FPR64 for s64 merge on rv32.
468 LLT Ty
= MRI
.getType(MI
.getOperand(0).getReg());
469 if (GPRSize
== 32 && Ty
.getSizeInBits() == 64) {
470 assert(MF
.getSubtarget
<RISCVSubtarget
>().hasStdExtD());
471 OpdsMapping
[0] = getFPValueMapping(Ty
.getSizeInBits());
472 OpdsMapping
[1] = GPRValueMapping
;
473 OpdsMapping
[2] = GPRValueMapping
;
477 case TargetOpcode::G_UNMERGE_VALUES
: {
478 // Use FPR64 for s64 unmerge on rv32.
479 LLT Ty
= MRI
.getType(MI
.getOperand(2).getReg());
480 if (GPRSize
== 32 && Ty
.getSizeInBits() == 64) {
481 assert(MF
.getSubtarget
<RISCVSubtarget
>().hasStdExtD());
482 OpdsMapping
[0] = GPRValueMapping
;
483 OpdsMapping
[1] = GPRValueMapping
;
484 OpdsMapping
[2] = getFPValueMapping(Ty
.getSizeInBits());
488 case TargetOpcode::G_SPLAT_VECTOR
: {
489 OpdsMapping
[0] = getVRBValueMapping(MRI
.getType(MI
.getOperand(0).getReg())
491 .getKnownMinValue());
493 LLT ScalarTy
= MRI
.getType(MI
.getOperand(1).getReg());
494 MachineInstr
*DefMI
= MRI
.getVRegDef(MI
.getOperand(1).getReg());
495 if ((GPRSize
== 32 && ScalarTy
.getSizeInBits() == 64) ||
496 onlyDefinesFP(*DefMI
, MRI
, TRI
)) {
497 assert(MF
.getSubtarget
<RISCVSubtarget
>().hasStdExtD());
498 OpdsMapping
[1] = getFPValueMapping(ScalarTy
.getSizeInBits());
500 OpdsMapping
[1] = GPRValueMapping
;
504 // By default map all scalars to GPR.
505 for (unsigned Idx
= 0; Idx
< NumOperands
; ++Idx
) {
506 auto &MO
= MI
.getOperand(Idx
);
507 if (!MO
.isReg() || !MO
.getReg())
509 LLT Ty
= MRI
.getType(MO
.getReg());
515 getVRBValueMapping(Ty
.getSizeInBits().getKnownMinValue());
516 else if (isPreISelGenericFloatingPointOpcode(Opc
))
517 OpdsMapping
[Idx
] = getFPValueMapping(Ty
.getSizeInBits());
519 OpdsMapping
[Idx
] = GPRValueMapping
;
524 return getInstructionMapping(DefaultMappingID
, /*Cost=*/1,
525 getOperandsMapping(OpdsMapping
), NumOperands
);