LLVM 19.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
52};
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
106};
107} // namespace RISCV
108} // namespace llvm
109
110using namespace llvm;
111
113 : RISCVGenRegisterBankInfo(HwMode) {}
114
115const RegisterBank &
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(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(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(RISCV::VRBRegBankID);
157 }
158}
159
161 unsigned Idx;
162 switch (Size) {
163 default:
164 llvm_unreachable("Unexpected size");
165 case 16:
167 break;
168 case 32:
170 break;
171 case 64:
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 {
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(MI.getOperand(0).getReg(), MRI, TRI) == &RISCV::FPRBRegBank;
191}
192
193bool RISCVRegisterBankInfo::onlyUsesFP(const MachineInstr &MI,
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,
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 MRI.use_nodbg_instructions(Def),
227 [&](const MachineInstr &UseMI) { return onlyUsesFP(UseMI, MRI, TRI); });
228}
229
231 unsigned Idx;
232
233 if (Size <= 64)
235 else if (Size == 128)
237 else if (Size == 256)
239 else if (Size == 512)
241 else
242 llvm::report_fatal_error("Invalid Size");
243
244 return &RISCV::ValueMappings[Idx];
245}
246
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(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(RISCV::GPRBRegBankID);
265 assert((GPRSize == 32 || GPRSize == 64) && "Unexpected GPR size");
266
267 unsigned NumOperands = MI.getNumOperands();
268 const ValueMapping *GPRValueMapping =
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(MI.getOperand(0).getReg());
306
307 const ValueMapping *Mapping;
308 if (Ty.isVector())
309 Mapping = getVRBValueMapping(Size.getKnownMinValue());
311 Mapping = getFPValueMapping(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.
323 assert(Size == OpTy.getSizeInBits() && "Operand has incompatible size");
324 }
325#endif // End NDEBUG
326
327 return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands);
328 }
329 case TargetOpcode::G_SEXTLOAD:
330 case TargetOpcode::G_ZEXTLOAD:
331 return getInstructionMapping(DefaultMappingID, /*Cost=*/1, GPRValueMapping,
332 NumOperands);
333 case TargetOpcode::G_IMPLICIT_DEF: {
334 Register Dst = MI.getOperand(0).getReg();
335 LLT DstTy = MRI.getType(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(DstMinSize);
345 else if (anyUseOnlyUseFP(Dst, MRI, TRI))
346 Mapping = getFPValueMapping(DstMinSize);
347
348 return getInstructionMapping(DefaultMappingID, /*Cost=*/1, 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(MI.getOperand(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(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(MI.getOperand(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(Ty.getSizeInBits());
376
377 break;
378 }
379 case TargetOpcode::G_STORE: {
380 LLT Ty = MRI.getType(MI.getOperand(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(Ty.getSizeInBits());
387 break;
388 }
389
390 MachineInstr *DefMI = MRI.getVRegDef(MI.getOperand(0).getReg());
391 if (onlyDefinesFP(*DefMI, MRI, TRI))
392 OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
393 break;
394 }
395 case TargetOpcode::G_SELECT: {
396 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
397
398 if (Ty.isVector()) {
399 auto &Sel = cast<GSelect>(MI);
400 LLT TestTy = MRI.getType(Sel.getCondReg());
401 assert(TestTy.isVector() && "Unexpected condition argument type");
402 OpdsMapping[0] = OpdsMapping[2] = OpdsMapping[3] =
404 OpdsMapping[1] =
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(MRI.use_nodbg_instructions(MI.getOperand(0).getReg()),
425 [&](const MachineInstr &UseMI) {
426 return onlyUsesFP(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(Idx).getReg();
445 MachineInstr *DefMI = MRI.getVRegDef(VReg);
446 if (getRegBank(VReg, MRI, TRI) == &RISCV::FPRBRegBank ||
447 onlyDefinesFP(*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(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(MI.getOperand(1).getReg());
466 OpdsMapping[0] = GPRValueMapping;
467 OpdsMapping[1] = getFPValueMapping(Ty.getSizeInBits());
468 break;
469 }
470 case TargetOpcode::G_SITOFP:
471 case TargetOpcode::G_UITOFP: {
472 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
473 OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
474 OpdsMapping[1] = GPRValueMapping;
475 break;
476 }
477 case TargetOpcode::G_FCMP: {
478 LLT Ty = MRI.getType(MI.getOperand(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(MI.getOperand(0).getReg());
489 if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
490 assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
491 OpdsMapping[0] = getFPValueMapping(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(MI.getOperand(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(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(Idx);
512 if (!MO.isReg() || !MO.getReg())
513 continue;
514 LLT Ty = MRI.getType(MO.getReg());
515 if (!Ty.isValid())
516 continue;
517
518 if (Ty.isVector())
519 OpdsMapping[Idx] =
522 OpdsMapping[Idx] = getFPValueMapping(Ty.getSizeInBits());
523 else
524 OpdsMapping[Idx] = GPRValueMapping;
525 }
526 break;
527 }
528
529 return getInstructionMapping(DefaultMappingID, /*Cost=*/1,
530 getOperandsMapping(OpdsMapping), NumOperands);
531}
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
uint64_t Size
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
IRTranslator LLVM IR MI
unsigned const TargetRegisterInfo * TRI
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.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
constexpr bool isValid() const
Definition: LowLevelType.h:145
constexpr bool isVector() const
Definition: LowLevelType.h:148
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
Definition: LowLevelType.h:193
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.
Definition: MachineInstr.h:69
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
const RegisterBank & getRegBankFromRegClass(const TargetRegisterClass &RC, LLT Ty) const override
Get a register bank that covers RC.
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...
const InstructionMapping & getInstrMappingImpl(const MachineInstr &MI) const
Try to get the mapping of MI.
This class implements the register bank concept.
Definition: RegisterBank.h:28
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.
Definition: SmallVector.h:1209
unsigned getID() const
Return the register class ID number.
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
getRegisterInfo - If register information is available, return it.
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition: TypeSize.h:168
#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.
Definition: AddressRanges.h:18
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
Definition: TargetOpcodes.h:30
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:1729
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:167
bool isPreISelGenericFloatingPointOpcode(unsigned Opc)
Returns whether opcode Opc is a pre-isel generic floating-point opcode, having only floating-point op...
Definition: Utils.cpp:1690
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.