LLVM 22.0.0git
RISCVRegisterBankInfo.cpp
Go to the documentation of this file.
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
15#include "RISCVSubtarget.h"
21
22#define GET_TARGET_REGBANK_IMPL
23#include "RISCVGenRegisterBank.inc"
24
25namespace llvm {
26namespace RISCV {
27
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
53
55 // Invalid value mapping.
56 {nullptr, 0},
57 // Maximum 3 GPR operands; 32 bit.
61 // Maximum 3 GPR operands; 64 bit.
65 // Maximum 3 FPR operands; 16 bit.
69 // Maximum 3 FPR operands; 32 bit.
73 // Maximum 3 FPR operands; 64 bit.
77 // Maximum 3 VR LMUL={1, MF2, MF4, MF8} operands.
81 // Maximum 3 VR LMUL=2 operands.
85 // Maximum 3 VR LMUL=4 operands.
89 // Maximum 3 VR LMUL=8 operands.
93};
94
107} // namespace RISCV
108} // namespace llvm
109
110using namespace llvm;
111
114
116 unsigned Idx;
117 switch (Size) {
118 default:
119 llvm_unreachable("Unexpected size");
120 case 16:
121 Idx = RISCV::FPRB16Idx;
122 break;
123 case 32:
124 Idx = RISCV::FPRB32Idx;
125 break;
126 case 64:
127 Idx = RISCV::FPRB64Idx;
128 break;
129 }
130 return &RISCV::ValueMappings[Idx];
131}
132
133// TODO: Make this more like AArch64?
134bool RISCVRegisterBankInfo::hasFPConstraints(
135 const MachineInstr &MI, const MachineRegisterInfo &MRI,
136 const TargetRegisterInfo &TRI) const {
138 return true;
139
140 // If we have a copy instruction, we could be feeding floating point
141 // instructions.
142 if (MI.getOpcode() != TargetOpcode::COPY)
143 return false;
144
145 return getRegBank(MI.getOperand(0).getReg(), MRI, TRI) == &RISCV::FPRBRegBank;
146}
147
148bool RISCVRegisterBankInfo::onlyUsesFP(const MachineInstr &MI,
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:
158 return true;
159 default:
160 break;
161 }
162
163 return hasFPConstraints(MI, MRI, TRI);
164}
165
166bool RISCVRegisterBankInfo::onlyDefinesFP(const MachineInstr &MI,
168 const TargetRegisterInfo &TRI) const {
169 switch (MI.getOpcode()) {
170 case TargetOpcode::G_SITOFP:
171 case TargetOpcode::G_UITOFP:
172 return true;
173 default:
174 break;
175 }
176
177 return hasFPConstraints(MI, MRI, TRI);
178}
179
180bool RISCVRegisterBankInfo::anyUseOnlyUseFP(
181 Register Def, const MachineRegisterInfo &MRI,
182 const TargetRegisterInfo &TRI) const {
183 return any_of(
184 MRI.use_nodbg_instructions(Def),
185 [&](const MachineInstr &UseMI) { return onlyUsesFP(UseMI, MRI, TRI); });
186}
187
189 unsigned Idx;
190
191 if (Size <= 64)
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;
199 else
200 llvm::report_fatal_error("Invalid Size");
201
202 return &RISCV::ValueMappings[Idx];
203}
204
207 const unsigned Opc = MI.getOpcode();
208
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())
214 return Mapping;
215 }
216
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();
221
222 unsigned GPRSize = getMaximumSize(RISCV::GPRBRegBankID);
223 assert((GPRSize == 32 || GPRSize == 64) && "Unexpected GPR size");
224
225 unsigned NumOperands = MI.getNumOperands();
226 const ValueMapping *GPRValueMapping =
229
230 switch (Opc) {
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();
264
265 const ValueMapping *Mapping;
266 if (Ty.isVector())
267 Mapping = getVRBValueMapping(Size.getKnownMinValue());
269 Mapping = getFPValueMapping(Size.getFixedValue());
270 else
271 Mapping = GPRValueMapping;
272
273#ifndef NDEBUG
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.
281 assert(Size == OpTy.getSizeInBits() && "Operand has incompatible size");
282 }
283#endif // End NDEBUG
284
285 return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands);
286 }
287 case TargetOpcode::G_SEXTLOAD:
288 case TargetOpcode::G_ZEXTLOAD:
289 return getInstructionMapping(DefaultMappingID, /*Cost=*/1, GPRValueMapping,
290 NumOperands);
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);
305
306 return getInstructionMapping(DefaultMappingID, /*Cost=*/1, Mapping,
307 NumOperands);
308 }
309 }
310
311 SmallVector<const ValueMapping *, 4> OpdsMapping(NumOperands);
312
313 switch (Opc) {
314 case TargetOpcode::G_LOAD: {
315 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
316 TypeSize Size = Ty.getSizeInBits();
317
318 OpdsMapping[1] = GPRValueMapping;
319
320 if (Ty.isVector()) {
321 OpdsMapping[0] = getVRBValueMapping(Size.getKnownMinValue());
322 break;
323 }
324
325 OpdsMapping[0] = GPRValueMapping;
326
327 // Atomics always use GPR destinations. Don't refine any further.
328 if (cast<GLoad>(MI).isAtomic())
329 break;
330
331 // Use FPR64 for s64 loads on rv32.
332 if (GPRSize == 32 && Size.getFixedValue() == 64) {
333 assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
334 OpdsMapping[0] = getFPValueMapping(Size);
335 break;
336 }
337
338 // Check if that load feeds fp instructions.
339 // In that case, we want the default mapping to be on FPR
340 // instead of blind map every scalar to GPR.
341 if (anyUseOnlyUseFP(MI.getOperand(0).getReg(), MRI, TRI)) {
342 // If we have at least one direct use in a FP instruction,
343 // assume this was a floating point load in the IR. If it was
344 // not, we would have had a bitcast before reaching that
345 // instruction.
346 OpdsMapping[0] = getFPValueMapping(Size);
347 break;
348 }
349
350 break;
351 }
352 case TargetOpcode::G_STORE: {
353 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
354 TypeSize Size = Ty.getSizeInBits();
355
356 OpdsMapping[1] = GPRValueMapping;
357
358 if (Ty.isVector()) {
359 OpdsMapping[0] = getVRBValueMapping(Size.getKnownMinValue());
360 break;
361 }
362
363 OpdsMapping[0] = GPRValueMapping;
364
365 // Atomics always use GPR sources. Don't refine any further.
366 if (cast<GStore>(MI).isAtomic())
367 break;
368
369 // Use FPR64 for s64 stores on rv32.
370 if (GPRSize == 32 && Size.getFixedValue() == 64) {
371 assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
372 OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
373 break;
374 }
375
376 MachineInstr *DefMI = MRI.getVRegDef(MI.getOperand(0).getReg());
377 if (onlyDefinesFP(*DefMI, MRI, TRI))
378 OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
379 break;
380 }
381 case TargetOpcode::G_SELECT: {
382 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
383
384 if (Ty.isVector()) {
385 auto &Sel = cast<GSelect>(MI);
386 LLT TestTy = MRI.getType(Sel.getCondReg());
387 assert(TestTy.isVector() && "Unexpected condition argument type");
388 OpdsMapping[0] = OpdsMapping[2] = OpdsMapping[3] =
389 getVRBValueMapping(Ty.getSizeInBits().getKnownMinValue());
390 OpdsMapping[1] =
392 break;
393 }
394
395 // Try to minimize the number of copies. If we have more floating point
396 // constrained values than not, then we'll put everything on FPR. Otherwise,
397 // everything has to be on GPR.
398 unsigned NumFP = 0;
399
400 // Use FPR64 for s64 select on rv32.
401 if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
402 NumFP = 3;
403 } else {
404 // Check if the uses of the result always produce floating point values.
405 //
406 // For example:
407 //
408 // %z = G_SELECT %cond %x %y
409 // fpr = G_FOO %z ...
410 if (any_of(MRI.use_nodbg_instructions(MI.getOperand(0).getReg()),
411 [&](const MachineInstr &UseMI) {
412 return onlyUsesFP(UseMI, MRI, TRI);
413 }))
414 ++NumFP;
415
416 // Check if the defs of the source values always produce floating point
417 // values.
418 //
419 // For example:
420 //
421 // %x = G_SOMETHING_ALWAYS_FLOAT %a ...
422 // %z = G_SELECT %cond %x %y
423 //
424 // Also check whether or not the sources have already been decided to be
425 // FPR. Keep track of this.
426 //
427 // This doesn't check the condition, since the condition is always an
428 // integer.
429 for (unsigned Idx = 2; Idx < 4; ++Idx) {
430 Register VReg = MI.getOperand(Idx).getReg();
431 MachineInstr *DefMI = MRI.getVRegDef(VReg);
432 if (getRegBank(VReg, MRI, TRI) == &RISCV::FPRBRegBank ||
433 onlyDefinesFP(*DefMI, MRI, TRI))
434 ++NumFP;
435 }
436 }
437
438 // Condition operand is always GPR.
439 OpdsMapping[1] = GPRValueMapping;
440
441 const ValueMapping *Mapping = GPRValueMapping;
442 if (NumFP >= 2)
443 Mapping = getFPValueMapping(Ty.getSizeInBits());
444
445 OpdsMapping[0] = OpdsMapping[2] = OpdsMapping[3] = Mapping;
446 break;
447 }
448 case RISCV::G_FCVT_W_RV64:
449 case RISCV::G_FCVT_WU_RV64:
450 case TargetOpcode::G_FPTOSI:
451 case TargetOpcode::G_FPTOUI:
452 case RISCV::G_FCLASS: {
453 LLT Ty = MRI.getType(MI.getOperand(1).getReg());
454 OpdsMapping[0] = GPRValueMapping;
455 OpdsMapping[1] = getFPValueMapping(Ty.getSizeInBits());
456 break;
457 }
458 case TargetOpcode::G_SITOFP:
459 case TargetOpcode::G_UITOFP: {
460 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
461 OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
462 OpdsMapping[1] = GPRValueMapping;
463 break;
464 }
465 case TargetOpcode::G_FCMP: {
466 LLT Ty = MRI.getType(MI.getOperand(2).getReg());
467
468 unsigned Size = Ty.getSizeInBits();
469
470 OpdsMapping[0] = GPRValueMapping;
471 OpdsMapping[2] = OpdsMapping[3] = getFPValueMapping(Size);
472 break;
473 }
474 case TargetOpcode::G_MERGE_VALUES: {
475 // Use FPR64 for s64 merge on rv32.
476 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
477 if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
478 assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
479 OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
480 OpdsMapping[1] = GPRValueMapping;
481 OpdsMapping[2] = GPRValueMapping;
482 }
483 break;
484 }
485 case TargetOpcode::G_UNMERGE_VALUES: {
486 // Use FPR64 for s64 unmerge on rv32.
487 LLT Ty = MRI.getType(MI.getOperand(2).getReg());
488 if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
489 assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
490 OpdsMapping[0] = GPRValueMapping;
491 OpdsMapping[1] = GPRValueMapping;
492 OpdsMapping[2] = getFPValueMapping(Ty.getSizeInBits());
493 }
494 break;
495 }
496 case TargetOpcode::G_SPLAT_VECTOR: {
497 OpdsMapping[0] = getVRBValueMapping(MRI.getType(MI.getOperand(0).getReg())
498 .getSizeInBits()
499 .getKnownMinValue());
500
501 LLT ScalarTy = MRI.getType(MI.getOperand(1).getReg());
502 MachineInstr *DefMI = MRI.getVRegDef(MI.getOperand(1).getReg());
503 if ((GPRSize == 32 && ScalarTy.getSizeInBits() == 64) ||
504 onlyDefinesFP(*DefMI, MRI, TRI)) {
505 assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
506 OpdsMapping[1] = getFPValueMapping(ScalarTy.getSizeInBits());
507 } else
508 OpdsMapping[1] = GPRValueMapping;
509 break;
510 }
511 case TargetOpcode::G_INTRINSIC: {
512 Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID();
513
515 RISCVVIntrinsicsTable::getRISCVVIntrinsicInfo(IntrinsicID)) {
516 unsigned ScalarIdx = -1;
517 if (II->hasScalarOperand()) {
518 ScalarIdx = II->ScalarOperand + 2;
519 }
520 for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
521 const MachineOperand &MO = MI.getOperand(Idx);
522 if (!MO.isReg())
523 continue;
524 LLT Ty = MRI.getType(MO.getReg());
525 if (Ty.isVector()) {
526 OpdsMapping[Idx] =
527 getVRBValueMapping(Ty.getSizeInBits().getKnownMinValue());
528 } else if (II->IsFPIntrinsic && ScalarIdx == Idx) {
529 // Chose the right FPR for scalar operand of RVV intrinsics.
530 OpdsMapping[Idx] = getFPValueMapping(Ty.getSizeInBits());
531 } else {
532 OpdsMapping[Idx] = GPRValueMapping;
533 }
534 }
535 }
536 break;
537 }
538 default:
539 // By default map all scalars to GPR.
540 for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
541 auto &MO = MI.getOperand(Idx);
542 if (!MO.isReg() || !MO.getReg())
543 continue;
544 LLT Ty = MRI.getType(MO.getReg());
545 if (!Ty.isValid())
546 continue;
547
548 if (Ty.isVector())
549 OpdsMapping[Idx] =
550 getVRBValueMapping(Ty.getSizeInBits().getKnownMinValue());
552 OpdsMapping[Idx] = getFPValueMapping(Ty.getSizeInBits());
553 else
554 OpdsMapping[Idx] = GPRValueMapping;
555 }
556 break;
557 }
558
559 return getInstructionMapping(DefaultMappingID, /*Cost=*/1,
560 getOperandsMapping(OpdsMapping), NumOperands);
561}
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
IRTranslator LLVM IR MI
Register const TargetRegisterInfo * TRI
uint64_t IntrinsicInst * II
static const RegisterBankInfo::ValueMapping * getFPValueMapping(unsigned Size)
static const RegisterBankInfo::ValueMapping * getVRBValueMapping(unsigned Size)
This file declares the targeting of the RegisterBankInfo class for RISC-V.
constexpr bool isVector() const
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Representation of each machine instruction.
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
const InstructionMapping & getInstrMapping(const MachineInstr &MI) const override
Get the mapping of the different operands of MI on the register bank.
Helper class that represents how the value of an instruction may be mapped and what is the related co...
bool isValid() const
Check whether this object is valid.
const InstructionMapping & getInstructionMapping(unsigned ID, unsigned Cost, const ValueMapping *OperandsMapping, unsigned NumOperands) const
Method to get a uniquely generated InstructionMapping.
const RegisterBank & getRegBank(unsigned ID)
Get the register bank identified by ID.
unsigned getMaximumSize(unsigned RegBankID) const
Get the maximum size in bits that fits in the given register bank.
const ValueMapping * getOperandsMapping(Iterator Begin, Iterator End) const
Get the uniquely generated array of ValueMapping for the elements of between Begin and End.
static const unsigned DefaultMappingID
Identifier used when the related instruction mapping instance is generated by target independent code...
unsigned HwMode
Current HwMode for the target.
const InstructionMapping & getInstrMappingImpl(const MachineInstr &MI) const
Try to get the mapping of MI.
Wrapper class representing virtual and physical registers.
Definition Register.h:19
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
TargetSubtargetInfo - Generic base class for all target subtargets.
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition TypeSize.h:166
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
const RegisterBankInfo::PartialMapping PartMappings[]
const RegisterBankInfo::ValueMapping ValueMappings[]
This is an optimization pass for GlobalISel generic memory operations.
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1734
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:167
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:560
LLVM_ABI bool isPreISelGenericFloatingPointOpcode(unsigned Opc)
Returns whether opcode Opc is a pre-isel generic floating-point opcode, having only floating-point op...
Definition Utils.cpp:1744
Helper struct that represents how a value is partially mapped into a register.
Helper struct that represents how a value is mapped through different register banks.