LLVM 18.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"
20
21#define GET_TARGET_REGBANK_IMPL
22#include "RISCVGenRegisterBank.inc"
23
24namespace llvm {
25namespace RISCV {
26
28 {0, 32, GPRBRegBank},
29 {0, 64, GPRBRegBank},
30 {0, 32, FPRBRegBank},
31 {0, 64, FPRBRegBank},
32};
33
39};
40
42 // Invalid value mapping.
43 {nullptr, 0},
44 // Maximum 3 GPR operands; 32 bit.
48 // Maximum 3 GPR operands; 64 bit.
52 // Maximum 3 FPR operands; 32 bit.
56 // Maximum 3 FPR operands; 64 bit.
60};
61
68};
69} // namespace RISCV
70} // namespace llvm
71
72using namespace llvm;
73
75 : RISCVGenRegisterBankInfo(HwMode) {}
76
77const RegisterBank &
79 LLT Ty) const {
80 switch (RC.getID()) {
81 default:
82 llvm_unreachable("Register class not supported");
83 case RISCV::GPRRegClassID:
84 case RISCV::GPRF16RegClassID:
85 case RISCV::GPRF32RegClassID:
86 case RISCV::GPRNoX0RegClassID:
87 case RISCV::GPRNoX0X2RegClassID:
88 case RISCV::GPRJALRRegClassID:
89 case RISCV::GPRTCRegClassID:
90 case RISCV::GPRC_and_GPRTCRegClassID:
91 case RISCV::GPRCRegClassID:
92 case RISCV::GPRC_and_SR07RegClassID:
93 case RISCV::SR07RegClassID:
94 case RISCV::SPRegClassID:
95 case RISCV::GPRX0RegClassID:
96 return getRegBank(RISCV::GPRBRegBankID);
97 case RISCV::FPR64RegClassID:
98 case RISCV::FPR16RegClassID:
99 case RISCV::FPR32RegClassID:
100 case RISCV::FPR64CRegClassID:
101 case RISCV::FPR32CRegClassID:
102 return getRegBank(RISCV::FPRBRegBankID);
103 case RISCV::VMRegClassID:
104 case RISCV::VRRegClassID:
105 case RISCV::VRNoV0RegClassID:
106 case RISCV::VRM2RegClassID:
107 case RISCV::VRM2NoV0RegClassID:
108 case RISCV::VRM4RegClassID:
109 case RISCV::VRM4NoV0RegClassID:
110 case RISCV::VMV0RegClassID:
111 case RISCV::VRM2_with_sub_vrm1_0_in_VMV0RegClassID:
112 case RISCV::VRM4_with_sub_vrm1_0_in_VMV0RegClassID:
113 case RISCV::VRM8RegClassID:
114 case RISCV::VRM8NoV0RegClassID:
115 case RISCV::VRM8_with_sub_vrm1_0_in_VMV0RegClassID:
116 return getRegBank(RISCV::VRBRegBankID);
117 }
118}
119
121 assert(Size == 32 || Size == 64);
122 unsigned Idx = Size == 64 ? RISCV::FPRB64Idx : RISCV::FPRB32Idx;
123 return &RISCV::ValueMappings[Idx];
124}
125
126/// Returns whether opcode \p Opc is a pre-isel generic floating-point opcode,
127/// having only floating-point operands.
128/// FIXME: this is copied from target AArch64. Needs some code refactor here to
129/// put this function in GlobalISel/Utils.cpp.
130static bool isPreISelGenericFloatingPointOpcode(unsigned Opc) {
131 switch (Opc) {
132 case TargetOpcode::G_FADD:
133 case TargetOpcode::G_FSUB:
134 case TargetOpcode::G_FMUL:
135 case TargetOpcode::G_FMA:
136 case TargetOpcode::G_FDIV:
137 case TargetOpcode::G_FCONSTANT:
138 case TargetOpcode::G_FPEXT:
139 case TargetOpcode::G_FPTRUNC:
140 case TargetOpcode::G_FCEIL:
141 case TargetOpcode::G_FFLOOR:
142 case TargetOpcode::G_FNEARBYINT:
143 case TargetOpcode::G_FNEG:
144 case TargetOpcode::G_FCOPYSIGN:
145 case TargetOpcode::G_FCOS:
146 case TargetOpcode::G_FSIN:
147 case TargetOpcode::G_FLOG10:
148 case TargetOpcode::G_FLOG:
149 case TargetOpcode::G_FLOG2:
150 case TargetOpcode::G_FSQRT:
151 case TargetOpcode::G_FABS:
152 case TargetOpcode::G_FEXP:
153 case TargetOpcode::G_FRINT:
154 case TargetOpcode::G_INTRINSIC_TRUNC:
155 case TargetOpcode::G_INTRINSIC_ROUND:
156 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
157 case TargetOpcode::G_FMAXNUM:
158 case TargetOpcode::G_FMINNUM:
159 case TargetOpcode::G_FMAXIMUM:
160 case TargetOpcode::G_FMINIMUM:
161 return true;
162 }
163 return false;
164}
165
166// TODO: Make this more like AArch64?
167bool RISCVRegisterBankInfo::hasFPConstraints(
168 const MachineInstr &MI, const MachineRegisterInfo &MRI,
169 const TargetRegisterInfo &TRI) const {
171 return true;
172
173 // If we have a copy instruction, we could be feeding floating point
174 // instructions.
175 if (MI.getOpcode() != TargetOpcode::COPY)
176 return false;
177
178 return getRegBank(MI.getOperand(0).getReg(), MRI, TRI) == &RISCV::FPRBRegBank;
179}
180
181bool RISCVRegisterBankInfo::onlyUsesFP(const MachineInstr &MI,
183 const TargetRegisterInfo &TRI) const {
184 switch (MI.getOpcode()) {
185 case TargetOpcode::G_FPTOSI:
186 case TargetOpcode::G_FPTOUI:
187 case TargetOpcode::G_FCMP:
188 return true;
189 default:
190 break;
191 }
192
193 return hasFPConstraints(MI, MRI, TRI);
194}
195
196bool RISCVRegisterBankInfo::onlyDefinesFP(const MachineInstr &MI,
198 const TargetRegisterInfo &TRI) const {
199 switch (MI.getOpcode()) {
200 case TargetOpcode::G_SITOFP:
201 case TargetOpcode::G_UITOFP:
202 return true;
203 default:
204 break;
205 }
206
207 return hasFPConstraints(MI, MRI, TRI);
208}
209
210bool RISCVRegisterBankInfo::anyUseOnlyUseFP(
211 Register Def, const MachineRegisterInfo &MRI,
212 const TargetRegisterInfo &TRI) const {
213 return any_of(
214 MRI.use_nodbg_instructions(Def),
215 [&](const MachineInstr &UseMI) { return onlyUsesFP(UseMI, MRI, TRI); });
216}
217
220 const unsigned Opc = MI.getOpcode();
221
222 // Try the default logic for non-generic instructions that are either copies
223 // or already have some operands assigned to banks.
224 if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {
225 const InstructionMapping &Mapping = getInstrMappingImpl(MI);
226 if (Mapping.isValid())
227 return Mapping;
228 }
229
230 const MachineFunction &MF = *MI.getParent()->getParent();
231 const MachineRegisterInfo &MRI = MF.getRegInfo();
232 const TargetSubtargetInfo &STI = MF.getSubtarget();
233 const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
234
235 unsigned GPRSize = getMaximumSize(RISCV::GPRBRegBankID);
236 assert((GPRSize == 32 || GPRSize == 64) && "Unexpected GPR size");
237
238 unsigned NumOperands = MI.getNumOperands();
239 const ValueMapping *GPRValueMapping =
242
243 switch (Opc) {
244 case TargetOpcode::G_ADD:
245 case TargetOpcode::G_SUB:
246 case TargetOpcode::G_SHL:
247 case TargetOpcode::G_ASHR:
248 case TargetOpcode::G_LSHR:
249 case TargetOpcode::G_AND:
250 case TargetOpcode::G_OR:
251 case TargetOpcode::G_XOR:
252 case TargetOpcode::G_MUL:
253 case TargetOpcode::G_SDIV:
254 case TargetOpcode::G_SREM:
255 case TargetOpcode::G_SMULH:
256 case TargetOpcode::G_SMAX:
257 case TargetOpcode::G_SMIN:
258 case TargetOpcode::G_UDIV:
259 case TargetOpcode::G_UREM:
260 case TargetOpcode::G_UMULH:
261 case TargetOpcode::G_UMAX:
262 case TargetOpcode::G_UMIN:
263 case TargetOpcode::G_PTR_ADD:
264 case TargetOpcode::G_PTRTOINT:
265 case TargetOpcode::G_INTTOPTR:
266 case TargetOpcode::G_TRUNC:
267 case TargetOpcode::G_ANYEXT:
268 case TargetOpcode::G_SEXT:
269 case TargetOpcode::G_ZEXT:
270 case TargetOpcode::G_SEXTLOAD:
271 case TargetOpcode::G_ZEXTLOAD:
272 return getInstructionMapping(DefaultMappingID, /*Cost=*/1, GPRValueMapping,
273 NumOperands);
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());
284 return getInstructionMapping(DefaultMappingID, /*Cost=*/1,
286 NumOperands);
287 }
288 case TargetOpcode::G_IMPLICIT_DEF: {
289 Register Dst = MI.getOperand(0).getReg();
290 auto Mapping = GPRValueMapping;
291 // FIXME: May need to do a better job determining when to use FPRB.
292 // For example, the look through COPY case:
293 // %0:_(s32) = G_IMPLICIT_DEF
294 // %1:_(s32) = COPY %0
295 // $f10_d = COPY %1(s32)
296 if (anyUseOnlyUseFP(Dst, MRI, TRI))
297 Mapping = getFPValueMapping(MRI.getType(Dst).getSizeInBits());
298 return getInstructionMapping(DefaultMappingID, /*Cost=*/1, Mapping,
299 NumOperands);
300 }
301 }
302
303 SmallVector<const ValueMapping *, 4> OpdsMapping(NumOperands);
304
305 switch (Opc) {
306 case TargetOpcode::G_LOAD: {
307 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
308 OpdsMapping[0] = GPRValueMapping;
309 OpdsMapping[1] = GPRValueMapping;
310 // Use FPR64 for s64 loads on rv32.
311 if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
312 assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
313 OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
314 break;
315 }
316
317 // Check if that load feeds fp instructions.
318 // In that case, we want the default mapping to be on FPR
319 // instead of blind map every scalar to GPR.
320 if (anyUseOnlyUseFP(MI.getOperand(0).getReg(), MRI, TRI))
321 // If we have at least one direct use in a FP instruction,
322 // assume this was a floating point load in the IR. If it was
323 // not, we would have had a bitcast before reaching that
324 // instruction.
325 OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
326
327 break;
328 }
329 case TargetOpcode::G_STORE: {
330 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
331 OpdsMapping[0] = GPRValueMapping;
332 OpdsMapping[1] = GPRValueMapping;
333 // Use FPR64 for s64 stores on rv32.
334 if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
335 assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
336 OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
337 break;
338 }
339
340 MachineInstr *DefMI = MRI.getVRegDef(MI.getOperand(0).getReg());
341 if (onlyDefinesFP(*DefMI, MRI, TRI))
342 OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
343 break;
344 }
345 case TargetOpcode::G_SELECT: {
346 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
347
348 // Try to minimize the number of copies. If we have more floating point
349 // constrained values than not, then we'll put everything on FPR. Otherwise,
350 // everything has to be on GPR.
351 unsigned NumFP = 0;
352
353 // Use FPR64 for s64 select on rv32.
354 if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
355 NumFP = 3;
356 } else {
357 // Check if the uses of the result always produce floating point values.
358 //
359 // For example:
360 //
361 // %z = G_SELECT %cond %x %y
362 // fpr = G_FOO %z ...
363 if (any_of(MRI.use_nodbg_instructions(MI.getOperand(0).getReg()),
364 [&](const MachineInstr &UseMI) {
365 return onlyUsesFP(UseMI, MRI, TRI);
366 }))
367 ++NumFP;
368
369 // Check if the defs of the source values always produce floating point
370 // values.
371 //
372 // For example:
373 //
374 // %x = G_SOMETHING_ALWAYS_FLOAT %a ...
375 // %z = G_SELECT %cond %x %y
376 //
377 // Also check whether or not the sources have already been decided to be
378 // FPR. Keep track of this.
379 //
380 // This doesn't check the condition, since the condition is always an
381 // integer.
382 for (unsigned Idx = 2; Idx < 4; ++Idx) {
383 Register VReg = MI.getOperand(Idx).getReg();
384 MachineInstr *DefMI = MRI.getVRegDef(VReg);
385 if (getRegBank(VReg, MRI, TRI) == &RISCV::FPRBRegBank ||
386 onlyDefinesFP(*DefMI, MRI, TRI))
387 ++NumFP;
388 }
389 }
390
391 // Condition operand is always GPR.
392 OpdsMapping[1] = GPRValueMapping;
393
394 const ValueMapping *Mapping = GPRValueMapping;
395 if (NumFP >= 2)
396 Mapping = getFPValueMapping(Ty.getSizeInBits());
397
398 OpdsMapping[0] = OpdsMapping[2] = OpdsMapping[3] = Mapping;
399 break;
400 }
401 case TargetOpcode::G_FPTOSI:
402 case TargetOpcode::G_FPTOUI:
403 case RISCV::G_FCLASS: {
404 LLT Ty = MRI.getType(MI.getOperand(1).getReg());
405 OpdsMapping[0] = GPRValueMapping;
406 OpdsMapping[1] = getFPValueMapping(Ty.getSizeInBits());
407 break;
408 }
409 case TargetOpcode::G_SITOFP:
410 case TargetOpcode::G_UITOFP: {
411 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
412 OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
413 OpdsMapping[1] = GPRValueMapping;
414 break;
415 }
416 case TargetOpcode::G_FCMP: {
417 LLT Ty = MRI.getType(MI.getOperand(2).getReg());
418
419 unsigned Size = Ty.getSizeInBits();
420 assert((Size == 32 || Size == 64) && "Unsupported size for G_FCMP");
421
422 OpdsMapping[0] = GPRValueMapping;
423 OpdsMapping[2] = OpdsMapping[3] = getFPValueMapping(Size);
424 break;
425 }
426 case TargetOpcode::G_MERGE_VALUES: {
427 // Use FPR64 for s64 merge on rv32.
428 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
429 if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
430 assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
431 OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
432 OpdsMapping[1] = GPRValueMapping;
433 OpdsMapping[2] = GPRValueMapping;
434 }
435 break;
436 }
437 case TargetOpcode::G_UNMERGE_VALUES: {
438 // Use FPR64 for s64 unmerge on rv32.
439 LLT Ty = MRI.getType(MI.getOperand(2).getReg());
440 if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
441 assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
442 OpdsMapping[0] = GPRValueMapping;
443 OpdsMapping[1] = GPRValueMapping;
444 OpdsMapping[2] = getFPValueMapping(Ty.getSizeInBits());
445 }
446 break;
447 }
448 default:
449 // By default map all scalars to GPR.
450 for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
451 auto &MO = MI.getOperand(Idx);
452 if (!MO.isReg() || !MO.getReg())
453 continue;
454 LLT Ty = MRI.getType(MO.getReg());
455 if (!Ty.isValid())
456 continue;
457
459 OpdsMapping[Idx] = getFPValueMapping(Ty.getSizeInBits());
460 else
461 OpdsMapping[Idx] = GPRValueMapping;
462 }
463 break;
464 }
465
466 return getInstructionMapping(DefaultMappingID, /*Cost=*/1,
467 getOperandsMapping(OpdsMapping), NumOperands);
468}
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
static bool isPreISelGenericFloatingPointOpcode(unsigned Opc)
Returns whether opcode Opc is a pre-isel generic floating-point opcode, having only floating-point op...
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
IRTranslator LLVM IR MI
unsigned const TargetRegisterInfo * TRI
static const RegisterBankInfo::ValueMapping * getFPValueMapping(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:137
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
Definition: LowLevelType.h:183
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:68
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:1200
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.
#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:1733
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.