LLVM 19.0.0git
ARMRegisterBankInfo.cpp
Go to the documentation of this file.
1//===- ARMRegisterBankInfo.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 ARM.
10/// \todo This should be generated by TableGen.
11//===----------------------------------------------------------------------===//
12
13#include "ARMRegisterBankInfo.h"
14#include "ARMInstrInfo.h" // For the register classes
15#include "ARMSubtarget.h"
20
21#define GET_TARGET_REGBANK_IMPL
22#include "ARMGenRegisterBank.inc"
23
24using namespace llvm;
25
26// FIXME: TableGen this.
27// If it grows too much and TableGen still isn't ready to do the job, extract it
28// into an ARMGenRegisterBankInfo.def (similar to AArch64).
29namespace llvm {
30namespace ARM {
36};
37
39 // GPR Partial Mapping
40 {0, 32, GPRRegBank},
41 // SPR Partial Mapping
42 {0, 32, FPRRegBank},
43 // DPR Partial Mapping
44 {0, 64, FPRRegBank},
45};
46
47#ifndef NDEBUG
49 unsigned Start, unsigned Length,
50 unsigned RegBankID) {
51 return PM.StartIdx == Start && PM.Length == Length &&
52 PM.RegBank->getID() == RegBankID;
53}
54
55static void checkPartialMappings() {
56 assert(
57 checkPartMapping(PartMappings[PMI_GPR - PMI_Min], 0, 32, GPRRegBankID) &&
58 "Wrong mapping for GPR");
59 assert(
60 checkPartMapping(PartMappings[PMI_SPR - PMI_Min], 0, 32, FPRRegBankID) &&
61 "Wrong mapping for SPR");
62 assert(
63 checkPartMapping(PartMappings[PMI_DPR - PMI_Min], 0, 64, FPRRegBankID) &&
64 "Wrong mapping for DPR");
65}
66#endif
67
73};
74
76 // invalid
77 {nullptr, 0},
78 // 3 ops in GPRs
82 // 3 ops in SPRs
86 // 3 ops in DPRs
90
91#ifndef NDEBUG
92static bool
94 const RegisterBankInfo::PartialMapping *BreakDown) {
95 return VM.NumBreakDowns == 1 && VM.BreakDown == BreakDown;
96}
97
98static void checkValueMappings() {
101 "Wrong value mapping for 3 GPR ops instruction");
104 "Wrong value mapping for 3 GPR ops instruction");
107 "Wrong value mapping for 3 GPR ops instruction");
108
111 "Wrong value mapping for 3 SPR ops instruction");
114 "Wrong value mapping for 3 SPR ops instruction");
117 "Wrong value mapping for 3 SPR ops instruction");
118
121 "Wrong value mapping for 3 DPR ops instruction");
124 "Wrong value mapping for 3 DPR ops instruction");
127 "Wrong value mapping for 3 DPR ops instruction");
128}
129#endif
130} // end namespace arm
131} // end namespace llvm
132
134 // We have only one set of register banks, whatever the subtarget
135 // is. Therefore, the initialization of the RegBanks table should be
136 // done only once. Indeed the table of all register banks
137 // (ARM::RegBanks) is unique in the compiler. At some point, it
138 // will get tablegen'ed and the whole constructor becomes empty.
139 static llvm::once_flag InitializeRegisterBankFlag;
140
141 static auto InitializeRegisterBankOnce = [&]() {
142 const RegisterBank &RBGPR = getRegBank(ARM::GPRRegBankID);
143 (void)RBGPR;
144 assert(&ARM::GPRRegBank == &RBGPR && "The order in RegBanks is messed up");
145
146 // Initialize the GPR bank.
147 assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRRegClassID)) &&
148 "Subclass not added?");
149 assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRwithAPSRRegClassID)) &&
150 "Subclass not added?");
151 assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRnopcRegClassID)) &&
152 "Subclass not added?");
153 assert(RBGPR.covers(*TRI.getRegClass(ARM::rGPRRegClassID)) &&
154 "Subclass not added?");
155 assert(RBGPR.covers(*TRI.getRegClass(ARM::tGPRRegClassID)) &&
156 "Subclass not added?");
157 assert(RBGPR.covers(*TRI.getRegClass(ARM::tcGPRRegClassID)) &&
158 "Subclass not added?");
159 assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRnoip_and_tcGPRRegClassID)) &&
160 "Subclass not added?");
161 assert(RBGPR.covers(*TRI.getRegClass(
162 ARM::tGPREven_and_GPRnoip_and_tcGPRRegClassID)) &&
163 "Subclass not added?");
164 assert(RBGPR.covers(*TRI.getRegClass(ARM::tGPROdd_and_tcGPRRegClassID)) &&
165 "Subclass not added?");
166 assert(getMaximumSize(RBGPR.getID()) == 32 &&
167 "GPRs should hold up to 32-bit");
168
169#ifndef NDEBUG
172#endif
173 };
174
175 llvm::call_once(InitializeRegisterBankFlag, InitializeRegisterBankOnce);
176}
177
178const RegisterBank &
180 LLT) const {
181 using namespace ARM;
182
183 switch (RC.getID()) {
184 case GPRRegClassID:
185 case GPRwithAPSRRegClassID:
186 case GPRnoipRegClassID:
187 case GPRnopcRegClassID:
188 case GPRnoip_and_GPRnopcRegClassID:
189 case rGPRRegClassID:
190 case GPRspRegClassID:
191 case GPRnoip_and_tcGPRRegClassID:
192 case tcGPRRegClassID:
193 case tGPRRegClassID:
194 case tGPREvenRegClassID:
195 case tGPROddRegClassID:
196 case tGPR_and_tGPREvenRegClassID:
197 case tGPR_and_tGPROddRegClassID:
198 case tGPREven_and_tcGPRRegClassID:
199 case tGPREven_and_GPRnoip_and_tcGPRRegClassID:
200 case tGPROdd_and_tcGPRRegClassID:
201 return getRegBank(ARM::GPRRegBankID);
202 case HPRRegClassID:
203 case SPR_8RegClassID:
204 case SPRRegClassID:
205 case DPR_8RegClassID:
206 case DPRRegClassID:
207 case QPRRegClassID:
208 return getRegBank(ARM::FPRRegBankID);
209 default:
210 llvm_unreachable("Unsupported register kind");
211 }
212
213 llvm_unreachable("Switch should handle all register classes");
214}
215
218 auto Opc = MI.getOpcode();
219
220 // Try the default logic for non-generic instructions that are either copies
221 // or already have some operands assigned to banks.
222 if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {
223 const InstructionMapping &Mapping = getInstrMappingImpl(MI);
224 if (Mapping.isValid())
225 return Mapping;
226 }
227
228 using namespace TargetOpcode;
229
230 const MachineFunction &MF = *MI.getParent()->getParent();
231 const MachineRegisterInfo &MRI = MF.getRegInfo();
232 unsigned NumOperands = MI.getNumOperands();
233 const ValueMapping *OperandsMapping = &ARM::ValueMappings[ARM::GPR3OpsIdx];
234
235 switch (Opc) {
236 case G_ADD:
237 case G_SUB: {
238 // Integer operations where the source and destination are in the
239 // same register class.
240 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
241 OperandsMapping = Ty.getSizeInBits() == 64
244 break;
245 }
246 case G_MUL:
247 case G_AND:
248 case G_OR:
249 case G_XOR:
250 case G_LSHR:
251 case G_ASHR:
252 case G_SHL:
253 case G_SDIV:
254 case G_UDIV:
255 case G_SEXT:
256 case G_ZEXT:
257 case G_ANYEXT:
258 case G_PTR_ADD:
259 case G_INTTOPTR:
260 case G_PTRTOINT:
261 case G_CTLZ:
262 // FIXME: We're abusing the fact that everything lives in a GPR for now; in
263 // the real world we would use different mappings.
264 OperandsMapping = &ARM::ValueMappings[ARM::GPR3OpsIdx];
265 break;
266 case G_TRUNC: {
267 // In some cases we may end up with a G_TRUNC from a 64-bit value to a
268 // 32-bit value. This isn't a real floating point trunc (that would be a
269 // G_FPTRUNC). Instead it is an integer trunc in disguise, which can appear
270 // because the legalizer doesn't distinguish between integer and floating
271 // point values so it may leave some 64-bit integers un-narrowed. Until we
272 // have a more principled solution that doesn't let such things sneak all
273 // the way to this point, just map the source to a DPR and the destination
274 // to a GPR.
275 LLT LargeTy = MRI.getType(MI.getOperand(1).getReg());
276 OperandsMapping =
277 LargeTy.getSizeInBits() <= 32
281 break;
282 }
283 case G_LOAD:
284 case G_STORE: {
285 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
286 OperandsMapping =
287 Ty.getSizeInBits() == 64
291 break;
292 }
293 case G_FADD:
294 case G_FSUB:
295 case G_FMUL:
296 case G_FDIV:
297 case G_FNEG: {
298 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
299 OperandsMapping =Ty.getSizeInBits() == 64
302 break;
303 }
304 case G_FMA: {
305 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
306 OperandsMapping =
307 Ty.getSizeInBits() == 64
316 break;
317 }
318 case G_FPEXT: {
319 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
320 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
321 if (ToTy.getSizeInBits() == 64 && FromTy.getSizeInBits() == 32)
322 OperandsMapping =
325 break;
326 }
327 case G_FPTRUNC: {
328 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
329 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
330 if (ToTy.getSizeInBits() == 32 && FromTy.getSizeInBits() == 64)
331 OperandsMapping =
334 break;
335 }
336 case G_FPTOSI:
337 case G_FPTOUI: {
338 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
339 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
340 if ((FromTy.getSizeInBits() == 32 || FromTy.getSizeInBits() == 64) &&
341 ToTy.getSizeInBits() == 32)
342 OperandsMapping =
343 FromTy.getSizeInBits() == 64
348 break;
349 }
350 case G_SITOFP:
351 case G_UITOFP: {
352 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
353 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
354 if (FromTy.getSizeInBits() == 32 &&
355 (ToTy.getSizeInBits() == 32 || ToTy.getSizeInBits() == 64))
356 OperandsMapping =
357 ToTy.getSizeInBits() == 64
362 break;
363 }
364 case G_FCONSTANT: {
365 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
366 OperandsMapping = getOperandsMapping(
369 nullptr});
370 break;
371 }
372 case G_CONSTANT:
373 case G_FRAME_INDEX:
374 case G_GLOBAL_VALUE:
375 OperandsMapping =
377 break;
378 case G_SELECT: {
379 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
380 (void)Ty;
381 LLT Ty2 = MRI.getType(MI.getOperand(1).getReg());
382 (void)Ty2;
383 assert(Ty.getSizeInBits() == 32 && "Unsupported size for G_SELECT");
384 assert(Ty2.getSizeInBits() == 1 && "Unsupported size for G_SELECT");
385 OperandsMapping =
390 break;
391 }
392 case G_ICMP: {
393 LLT Ty2 = MRI.getType(MI.getOperand(2).getReg());
394 (void)Ty2;
395 assert(Ty2.getSizeInBits() == 32 && "Unsupported size for G_ICMP");
396 OperandsMapping =
400 break;
401 }
402 case G_FCMP: {
403 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
404 (void)Ty;
405 LLT Ty1 = MRI.getType(MI.getOperand(2).getReg());
406 LLT Ty2 = MRI.getType(MI.getOperand(3).getReg());
407 (void)Ty2;
408 assert(Ty.getSizeInBits() == 1 && "Unsupported size for G_FCMP");
409 assert(Ty1.getSizeInBits() == Ty2.getSizeInBits() &&
410 "Mismatched operand sizes for G_FCMP");
411
412 unsigned Size = Ty1.getSizeInBits();
413 assert((Size == 32 || Size == 64) && "Unsupported size for G_FCMP");
414
415 auto FPRValueMapping = Size == 32 ? &ARM::ValueMappings[ARM::SPR3OpsIdx]
417 OperandsMapping =
419 FPRValueMapping, FPRValueMapping});
420 break;
421 }
422 case G_MERGE_VALUES: {
423 // We only support G_MERGE_VALUES for creating a double precision floating
424 // point value out of two GPRs.
425 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
426 LLT Ty1 = MRI.getType(MI.getOperand(1).getReg());
427 LLT Ty2 = MRI.getType(MI.getOperand(2).getReg());
428 if (Ty.getSizeInBits() != 64 || Ty1.getSizeInBits() != 32 ||
429 Ty2.getSizeInBits() != 32)
431 OperandsMapping =
435 break;
436 }
437 case G_UNMERGE_VALUES: {
438 // We only support G_UNMERGE_VALUES for splitting a double precision
439 // floating point value into two GPRs.
440 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
441 LLT Ty1 = MRI.getType(MI.getOperand(1).getReg());
442 LLT Ty2 = MRI.getType(MI.getOperand(2).getReg());
443 if (Ty.getSizeInBits() != 32 || Ty1.getSizeInBits() != 32 ||
444 Ty2.getSizeInBits() != 64)
446 OperandsMapping =
450 break;
451 }
452 case G_BR:
453 OperandsMapping = getOperandsMapping({nullptr});
454 break;
455 case G_BRCOND:
456 OperandsMapping =
458 break;
459 case DBG_VALUE: {
460 SmallVector<const ValueMapping *, 4> OperandBanks(NumOperands);
461 const MachineOperand &MaybeReg = MI.getOperand(0);
462 if (MaybeReg.isReg() && MaybeReg.getReg()) {
463 unsigned Size = MRI.getType(MaybeReg.getReg()).getSizeInBits();
464 if (Size > 32 && Size != 64)
466 OperandBanks[0] = Size == 64 ? &ARM::ValueMappings[ARM::DPR3OpsIdx]
468 }
469 OperandsMapping = getOperandsMapping(OperandBanks);
470 break;
471 }
472 case G_GET_FPENV:
473 case G_SET_FPENV:
474 OperandsMapping =
476 break;
477 case G_RESET_FPENV:
478 OperandsMapping = getOperandsMapping({nullptr});
479 break;
480 default:
482 }
483
484#ifndef NDEBUG
485 for (unsigned i = 0; i < NumOperands; i++) {
486 for (const auto &Mapping : OperandsMapping[i]) {
487 assert(
488 (Mapping.RegBank->getID() != ARM::FPRRegBankID ||
490 "Trying to use floating point register bank on target without vfp");
491 }
492 }
493#endif
494
495 return getInstructionMapping(DefaultMappingID, /*Cost=*/1, OperandsMapping,
496 NumOperands);
497}
unsigned const MachineRegisterInfo * MRI
This file declares the targeting of the RegisterBankInfo class for ARM.
uint64_t Size
IRTranslator LLVM IR MI
unsigned const TargetRegisterInfo * TRI
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
const RegisterBank & getRegBankFromRegClass(const TargetRegisterClass &RC, LLT) const override
Get a register bank that covers RC.
ARMRegisterBankInfo(const TargetRegisterInfo &TRI)
const InstructionMapping & getInstrMapping(const MachineInstr &MI) const override
Get the mapping of the different operands of MI on the register bank.
bool hasVFP2Base() const
Definition: ARMSubtarget.h:333
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
Definition: LowLevelType.h:185
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
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
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 InstructionMapping & getInvalidInstructionMapping() const
Method to get a uniquely generated invalid 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
bool covers(const TargetRegisterClass &RC) const
Check whether this register bank covers RC.
unsigned getID() const
Get the identifier of this register bank.
Definition: RegisterBank.h:45
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...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
const RegisterBankInfo::PartialMapping PartMappings[]
static void checkPartialMappings()
static void checkValueMappings()
const RegisterBankInfo::ValueMapping ValueMappings[]
static bool checkValueMapping(const RegisterBankInfo::ValueMapping &VM, const RegisterBankInfo::PartialMapping *BreakDown)
static bool checkPartMapping(const RegisterBankInfo::PartialMapping &PM, unsigned Start, unsigned Length, unsigned RegBankID)
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Length
Definition: DWP.cpp:456
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
void call_once(once_flag &flag, Function &&F, Args &&... ArgList)
Execute the function specified as a parameter once.
Definition: Threading.h:87
Helper struct that represents how a value is partially mapped into a register.
unsigned StartIdx
Number of bits at which this partial mapping starts in the original value.
const RegisterBank * RegBank
Register bank where the partial value lives.
unsigned Length
Length of this mapping in bits.
Helper struct that represents how a value is mapped through different register banks.
unsigned NumBreakDowns
Number of partial mapping to break down this value.
const PartialMapping * BreakDown
How the value is broken down between the different register banks.
The llvm::once_flag structure.
Definition: Threading.h:68