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, 32, FPRBRegBank},
33 {0, 64, FPRBRegBank},
34 {0, 64, VRBRegBank},
35 {0, 128, VRBRegBank},
36 {0, 256, VRBRegBank},
37 {0, 512, VRBRegBank},
38 // clang-format on
39};
40
50};
51
53 // Invalid value mapping.
54 {nullptr, 0},
55 // Maximum 3 GPR operands; 32 bit.
59 // Maximum 3 GPR operands; 64 bit.
63 // Maximum 3 FPR operands; 32 bit.
67 // Maximum 3 FPR operands; 64 bit.
71 // Maximum 3 VR LMUL={1, MF2, MF4, MF8} operands.
75 // Maximum 3 VR LMUL=2 operands.
79 // Maximum 3 VR LMUL=4 operands.
83 // Maximum 3 VR LMUL=8 operands.
87};
88
99};
100} // namespace RISCV
101} // namespace llvm
102
103using namespace llvm;
104
106 : RISCVGenRegisterBankInfo(HwMode) {}
107
108const RegisterBank &
110 LLT Ty) const {
111 switch (RC.getID()) {
112 default:
113 llvm_unreachable("Register class not supported");
114 case RISCV::GPRRegClassID:
115 case RISCV::GPRF16RegClassID:
116 case RISCV::GPRF32RegClassID:
117 case RISCV::GPRNoX0RegClassID:
118 case RISCV::GPRNoX0X2RegClassID:
119 case RISCV::GPRJALRRegClassID:
120 case RISCV::GPRTCRegClassID:
121 case RISCV::GPRC_and_GPRTCRegClassID:
122 case RISCV::GPRCRegClassID:
123 case RISCV::GPRC_and_SR07RegClassID:
124 case RISCV::SR07RegClassID:
125 case RISCV::SPRegClassID:
126 case RISCV::GPRX0RegClassID:
127 return getRegBank(RISCV::GPRBRegBankID);
128 case RISCV::FPR64RegClassID:
129 case RISCV::FPR16RegClassID:
130 case RISCV::FPR32RegClassID:
131 case RISCV::FPR64CRegClassID:
132 case RISCV::FPR32CRegClassID:
133 return getRegBank(RISCV::FPRBRegBankID);
134 case RISCV::VMRegClassID:
135 case RISCV::VRRegClassID:
136 case RISCV::VRNoV0RegClassID:
137 case RISCV::VRM2RegClassID:
138 case RISCV::VRM2NoV0RegClassID:
139 case RISCV::VRM4RegClassID:
140 case RISCV::VRM4NoV0RegClassID:
141 case RISCV::VMV0RegClassID:
142 case RISCV::VRM2_with_sub_vrm1_0_in_VMV0RegClassID:
143 case RISCV::VRM4_with_sub_vrm1_0_in_VMV0RegClassID:
144 case RISCV::VRM8RegClassID:
145 case RISCV::VRM8NoV0RegClassID:
146 case RISCV::VRM8_with_sub_vrm1_0_in_VMV0RegClassID:
147 return getRegBank(RISCV::VRBRegBankID);
148 }
149}
150
152 assert(Size == 32 || Size == 64);
153 unsigned Idx = Size == 64 ? RISCV::FPRB64Idx : RISCV::FPRB32Idx;
154 return &RISCV::ValueMappings[Idx];
155}
156
157// TODO: Make this more like AArch64?
158bool RISCVRegisterBankInfo::hasFPConstraints(
159 const MachineInstr &MI, const MachineRegisterInfo &MRI,
160 const TargetRegisterInfo &TRI) const {
162 return true;
163
164 // If we have a copy instruction, we could be feeding floating point
165 // instructions.
166 if (MI.getOpcode() != TargetOpcode::COPY)
167 return false;
168
169 return getRegBank(MI.getOperand(0).getReg(), MRI, TRI) == &RISCV::FPRBRegBank;
170}
171
172bool RISCVRegisterBankInfo::onlyUsesFP(const MachineInstr &MI,
174 const TargetRegisterInfo &TRI) const {
175 switch (MI.getOpcode()) {
176 case TargetOpcode::G_FPTOSI:
177 case TargetOpcode::G_FPTOUI:
178 case TargetOpcode::G_FCMP:
179 return true;
180 default:
181 break;
182 }
183
184 return hasFPConstraints(MI, MRI, TRI);
185}
186
187bool RISCVRegisterBankInfo::onlyDefinesFP(const MachineInstr &MI,
189 const TargetRegisterInfo &TRI) const {
190 switch (MI.getOpcode()) {
191 case TargetOpcode::G_SITOFP:
192 case TargetOpcode::G_UITOFP:
193 return true;
194 default:
195 break;
196 }
197
198 return hasFPConstraints(MI, MRI, TRI);
199}
200
201bool RISCVRegisterBankInfo::anyUseOnlyUseFP(
202 Register Def, const MachineRegisterInfo &MRI,
203 const TargetRegisterInfo &TRI) const {
204 return any_of(
205 MRI.use_nodbg_instructions(Def),
206 [&](const MachineInstr &UseMI) { return onlyUsesFP(UseMI, MRI, TRI); });
207}
208
210 unsigned Idx;
211
212 if (Size <= 64)
214 else if (Size == 128)
216 else if (Size == 256)
218 else if (Size == 512)
220 else
221 llvm::report_fatal_error("Invalid Size");
222
223 return &RISCV::ValueMappings[Idx];
224}
225
228 const unsigned Opc = MI.getOpcode();
229
230 // Try the default logic for non-generic instructions that are either copies
231 // or already have some operands assigned to banks.
232 if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {
233 const InstructionMapping &Mapping = getInstrMappingImpl(MI);
234 if (Mapping.isValid())
235 return Mapping;
236 }
237
238 const MachineFunction &MF = *MI.getParent()->getParent();
239 const MachineRegisterInfo &MRI = MF.getRegInfo();
240 const TargetSubtargetInfo &STI = MF.getSubtarget();
241 const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
242
243 unsigned GPRSize = getMaximumSize(RISCV::GPRBRegBankID);
244 assert((GPRSize == 32 || GPRSize == 64) && "Unexpected GPR size");
245
246 unsigned NumOperands = MI.getNumOperands();
247 const ValueMapping *GPRValueMapping =
250
251 switch (Opc) {
252 case TargetOpcode::G_ADD:
253 case TargetOpcode::G_SUB:
254 case TargetOpcode::G_SHL:
255 case TargetOpcode::G_ASHR:
256 case TargetOpcode::G_LSHR:
257 case TargetOpcode::G_AND:
258 case TargetOpcode::G_OR:
259 case TargetOpcode::G_XOR:
260 case TargetOpcode::G_MUL:
261 case TargetOpcode::G_SDIV:
262 case TargetOpcode::G_SREM:
263 case TargetOpcode::G_SMULH:
264 case TargetOpcode::G_SMAX:
265 case TargetOpcode::G_SMIN:
266 case TargetOpcode::G_UDIV:
267 case TargetOpcode::G_UREM:
268 case TargetOpcode::G_UMULH:
269 case TargetOpcode::G_UMAX:
270 case TargetOpcode::G_UMIN:
271 case TargetOpcode::G_PTR_ADD:
272 case TargetOpcode::G_PTRTOINT:
273 case TargetOpcode::G_INTTOPTR:
274 case TargetOpcode::G_FADD:
275 case TargetOpcode::G_FSUB:
276 case TargetOpcode::G_FMUL:
277 case TargetOpcode::G_FDIV:
278 case TargetOpcode::G_FABS:
279 case TargetOpcode::G_FNEG:
280 case TargetOpcode::G_FSQRT:
281 case TargetOpcode::G_FMAXNUM:
282 case TargetOpcode::G_FMINNUM: {
283 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
285
286 const ValueMapping *Mapping;
287 if (Ty.isVector())
288 Mapping = getVRBValueMapping(Size.getKnownMinValue());
290 Mapping = getFPValueMapping(Size.getFixedValue());
291 else
292 Mapping = GPRValueMapping;
293
294#ifndef NDEBUG
295 // Make sure all the operands are using similar size and type.
296 for (unsigned Idx = 1; Idx != NumOperands; ++Idx) {
297 LLT OpTy = MRI.getType(MI.getOperand(Idx).getReg());
298 assert(Ty.isVector() == OpTy.isVector() &&
299 "Operand has incompatible type");
300 // Don't check size for GPR.
302 assert(Size == OpTy.getSizeInBits() && "Operand has incompatible size");
303 }
304#endif // End NDEBUG
305
306 return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands);
307 }
308 case TargetOpcode::G_SEXTLOAD:
309 case TargetOpcode::G_ZEXTLOAD:
310 return getInstructionMapping(DefaultMappingID, /*Cost=*/1, GPRValueMapping,
311 NumOperands);
312 case TargetOpcode::G_IMPLICIT_DEF: {
313 Register Dst = MI.getOperand(0).getReg();
314 LLT DstTy = MRI.getType(Dst);
315 unsigned DstMinSize = DstTy.getSizeInBits().getKnownMinValue();
316 auto Mapping = GPRValueMapping;
317 // FIXME: May need to do a better job determining when to use FPRB.
318 // For example, the look through COPY case:
319 // %0:_(s32) = G_IMPLICIT_DEF
320 // %1:_(s32) = COPY %0
321 // $f10_d = COPY %1(s32)
322 if (DstTy.isVector())
323 Mapping = getVRBValueMapping(DstMinSize);
324 else if (anyUseOnlyUseFP(Dst, MRI, TRI))
325 Mapping = getFPValueMapping(DstMinSize);
326
327 return getInstructionMapping(DefaultMappingID, /*Cost=*/1, Mapping,
328 NumOperands);
329 }
330 }
331
332 SmallVector<const ValueMapping *, 4> OpdsMapping(NumOperands);
333
334 switch (Opc) {
335 case TargetOpcode::G_LOAD: {
336 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
337 OpdsMapping[0] = GPRValueMapping;
338 OpdsMapping[1] = GPRValueMapping;
339 // Use FPR64 for s64 loads on rv32.
340 if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
341 assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
342 OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
343 break;
344 }
345
346 // Check if that load feeds fp instructions.
347 // In that case, we want the default mapping to be on FPR
348 // instead of blind map every scalar to GPR.
349 if (anyUseOnlyUseFP(MI.getOperand(0).getReg(), MRI, TRI))
350 // If we have at least one direct use in a FP instruction,
351 // assume this was a floating point load in the IR. If it was
352 // not, we would have had a bitcast before reaching that
353 // instruction.
354 OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
355
356 break;
357 }
358 case TargetOpcode::G_STORE: {
359 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
360 OpdsMapping[0] = GPRValueMapping;
361 OpdsMapping[1] = GPRValueMapping;
362 // Use FPR64 for s64 stores on rv32.
363 if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
364 assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
365 OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
366 break;
367 }
368
369 MachineInstr *DefMI = MRI.getVRegDef(MI.getOperand(0).getReg());
370 if (onlyDefinesFP(*DefMI, MRI, TRI))
371 OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
372 break;
373 }
374 case TargetOpcode::G_SELECT: {
375 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
376
377 if (Ty.isVector()) {
378 auto &Sel = cast<GSelect>(MI);
379 LLT TestTy = MRI.getType(Sel.getCondReg());
380 assert(TestTy.isVector() && "Unexpected condition argument type");
381 OpdsMapping[0] = OpdsMapping[2] = OpdsMapping[3] =
383 OpdsMapping[1] =
385 break;
386 }
387
388 // Try to minimize the number of copies. If we have more floating point
389 // constrained values than not, then we'll put everything on FPR. Otherwise,
390 // everything has to be on GPR.
391 unsigned NumFP = 0;
392
393 // Use FPR64 for s64 select on rv32.
394 if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
395 NumFP = 3;
396 } else {
397 // Check if the uses of the result always produce floating point values.
398 //
399 // For example:
400 //
401 // %z = G_SELECT %cond %x %y
402 // fpr = G_FOO %z ...
403 if (any_of(MRI.use_nodbg_instructions(MI.getOperand(0).getReg()),
404 [&](const MachineInstr &UseMI) {
405 return onlyUsesFP(UseMI, MRI, TRI);
406 }))
407 ++NumFP;
408
409 // Check if the defs of the source values always produce floating point
410 // values.
411 //
412 // For example:
413 //
414 // %x = G_SOMETHING_ALWAYS_FLOAT %a ...
415 // %z = G_SELECT %cond %x %y
416 //
417 // Also check whether or not the sources have already been decided to be
418 // FPR. Keep track of this.
419 //
420 // This doesn't check the condition, since the condition is always an
421 // integer.
422 for (unsigned Idx = 2; Idx < 4; ++Idx) {
423 Register VReg = MI.getOperand(Idx).getReg();
424 MachineInstr *DefMI = MRI.getVRegDef(VReg);
425 if (getRegBank(VReg, MRI, TRI) == &RISCV::FPRBRegBank ||
426 onlyDefinesFP(*DefMI, MRI, TRI))
427 ++NumFP;
428 }
429 }
430
431 // Condition operand is always GPR.
432 OpdsMapping[1] = GPRValueMapping;
433
434 const ValueMapping *Mapping = GPRValueMapping;
435 if (NumFP >= 2)
436 Mapping = getFPValueMapping(Ty.getSizeInBits());
437
438 OpdsMapping[0] = OpdsMapping[2] = OpdsMapping[3] = Mapping;
439 break;
440 }
441 case TargetOpcode::G_FPTOSI:
442 case TargetOpcode::G_FPTOUI:
443 case RISCV::G_FCLASS: {
444 LLT Ty = MRI.getType(MI.getOperand(1).getReg());
445 OpdsMapping[0] = GPRValueMapping;
446 OpdsMapping[1] = getFPValueMapping(Ty.getSizeInBits());
447 break;
448 }
449 case TargetOpcode::G_SITOFP:
450 case TargetOpcode::G_UITOFP: {
451 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
452 OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
453 OpdsMapping[1] = GPRValueMapping;
454 break;
455 }
456 case TargetOpcode::G_FCMP: {
457 LLT Ty = MRI.getType(MI.getOperand(2).getReg());
458
459 unsigned Size = Ty.getSizeInBits();
460 assert((Size == 32 || Size == 64) && "Unsupported size for G_FCMP");
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 default:
489 // By default map all scalars to GPR.
490 for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
491 auto &MO = MI.getOperand(Idx);
492 if (!MO.isReg() || !MO.getReg())
493 continue;
494 LLT Ty = MRI.getType(MO.getReg());
495 if (!Ty.isValid())
496 continue;
497
498 if (Ty.isVector())
499 OpdsMapping[Idx] =
502 OpdsMapping[Idx] = getFPValueMapping(Ty.getSizeInBits());
503 else
504 OpdsMapping[Idx] = GPRValueMapping;
505 }
506 break;
507 }
508
509 return getInstructionMapping(DefaultMappingID, /*Cost=*/1,
510 getOperandsMapping(OpdsMapping), NumOperands);
511}
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:156
bool isPreISelGenericFloatingPointOpcode(unsigned Opc)
Returns whether opcode Opc is a pre-isel generic floating-point opcode, having only floating-point op...
Definition: Utils.cpp:1669
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.