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