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