LLVM 20.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
116 unsigned Idx;
117 switch (Size) {
118 default:
119 llvm_unreachable("Unexpected size");
120 case 16:
122 break;
123 case 32:
125 break;
126 case 64:
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)
193 else if (Size == 128)
195 else if (Size == 256)
197 else if (Size == 512)
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());
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());
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 // 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);
331 break;
332 }
333
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
341 // instruction.
342 OpdsMapping[0] = getFPValueMapping(Size);
343 break;
344 }
345
346 break;
347 }
348 case TargetOpcode::G_STORE: {
349 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
351
352 OpdsMapping[1] = GPRValueMapping;
353
354 if (Ty.isVector()) {
355 OpdsMapping[0] = getVRBValueMapping(Size.getKnownMinValue());
356 break;
357 }
358
359 OpdsMapping[0] = GPRValueMapping;
360
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());
365 break;
366 }
367
368 MachineInstr *DefMI = MRI.getVRegDef(MI.getOperand(0).getReg());
369 if (onlyDefinesFP(*DefMI, MRI, TRI))
370 OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
371 break;
372 }
373 case TargetOpcode::G_SELECT: {
374 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
375
376 if (Ty.isVector()) {
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] =
382 OpdsMapping[1] =
384 break;
385 }
386
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.
390 unsigned NumFP = 0;
391
392 // Use FPR64 for s64 select on rv32.
393 if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
394 NumFP = 3;
395 } else {
396 // Check if the uses of the result always produce floating point values.
397 //
398 // For example:
399 //
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);
405 }))
406 ++NumFP;
407
408 // Check if the defs of the source values always produce floating point
409 // values.
410 //
411 // For example:
412 //
413 // %x = G_SOMETHING_ALWAYS_FLOAT %a ...
414 // %z = G_SELECT %cond %x %y
415 //
416 // Also check whether or not the sources have already been decided to be
417 // FPR. Keep track of this.
418 //
419 // This doesn't check the condition, since the condition is always an
420 // integer.
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))
426 ++NumFP;
427 }
428 }
429
430 // Condition operand is always GPR.
431 OpdsMapping[1] = GPRValueMapping;
432
433 const ValueMapping *Mapping = GPRValueMapping;
434 if (NumFP >= 2)
435 Mapping = getFPValueMapping(Ty.getSizeInBits());
436
437 OpdsMapping[0] = OpdsMapping[2] = OpdsMapping[3] = Mapping;
438 break;
439 }
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());
448 break;
449 }
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;
455 break;
456 }
457 case TargetOpcode::G_FCMP: {
458 LLT Ty = MRI.getType(MI.getOperand(2).getReg());
459
460 unsigned Size = Ty.getSizeInBits();
461
462 OpdsMapping[0] = GPRValueMapping;
463 OpdsMapping[2] = OpdsMapping[3] = getFPValueMapping(Size);
464 break;
465 }
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;
474 }
475 break;
476 }
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());
485 }
486 break;
487 }
488 case TargetOpcode::G_SPLAT_VECTOR: {
489 OpdsMapping[0] = getVRBValueMapping(MRI.getType(MI.getOperand(0).getReg())
490 .getSizeInBits()
491 .getKnownMinValue());
492
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());
499 } else
500 OpdsMapping[1] = GPRValueMapping;
501 break;
502 }
503 default:
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())
508 continue;
509 LLT Ty = MRI.getType(MO.getReg());
510 if (!Ty.isValid())
511 continue;
512
513 if (Ty.isVector())
514 OpdsMapping[Idx] =
517 OpdsMapping[Idx] = getFPValueMapping(Ty.getSizeInBits());
518 else
519 OpdsMapping[Idx] = GPRValueMapping;
520 }
521 break;
522 }
523
524 return getInstructionMapping(DefaultMappingID, /*Cost=*/1,
525 getOperandsMapping(OpdsMapping), NumOperands);
526}
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:190
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 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.
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:1196
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:1746
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:1675
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.