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::tGPROdd_and_tcGPRRegClassID)) &&
160 "Subclass not added?");
161 assert(getMaximumSize(RBGPR.getID()) == 32 &&
162 "GPRs should hold up to 32-bit");
163
164#ifndef NDEBUG
167#endif
168 };
169
170 llvm::call_once(InitializeRegisterBankFlag, InitializeRegisterBankOnce);
171}
172
173const RegisterBank &
175 LLT) const {
176 using namespace ARM;
177
178 switch (RC.getID()) {
179 case GPRRegClassID:
180 case GPRwithAPSRRegClassID:
181 case GPRnoipRegClassID:
182 case GPRnopcRegClassID:
183 case GPRnoip_and_GPRnopcRegClassID:
184 case rGPRRegClassID:
185 case GPRspRegClassID:
186 case tcGPRRegClassID:
187 case tcGPRnotr12RegClassID:
188 case tGPRRegClassID:
189 case tGPREvenRegClassID:
190 case tGPROddRegClassID:
191 case tGPR_and_tGPREvenRegClassID:
192 case tGPR_and_tGPROddRegClassID:
193 case tGPREven_and_tcGPRRegClassID:
194 case tGPROdd_and_tcGPRRegClassID:
195 case tGPREven_and_tcGPRnotr12RegClassID:
196 return getRegBank(ARM::GPRRegBankID);
197 case HPRRegClassID:
198 case SPR_8RegClassID:
199 case SPRRegClassID:
200 case DPR_8RegClassID:
201 case DPRRegClassID:
202 case QPRRegClassID:
203 return getRegBank(ARM::FPRRegBankID);
204 default:
205 llvm_unreachable("Unsupported register kind");
206 }
207
208 llvm_unreachable("Switch should handle all register classes");
209}
210
213 auto Opc = MI.getOpcode();
214
215 // Try the default logic for non-generic instructions that are either copies
216 // or already have some operands assigned to banks.
217 if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {
218 const InstructionMapping &Mapping = getInstrMappingImpl(MI);
219 if (Mapping.isValid())
220 return Mapping;
221 }
222
223 using namespace TargetOpcode;
224
225 const MachineFunction &MF = *MI.getParent()->getParent();
226 const MachineRegisterInfo &MRI = MF.getRegInfo();
227 unsigned NumOperands = MI.getNumOperands();
228 const ValueMapping *OperandsMapping = &ARM::ValueMappings[ARM::GPR3OpsIdx];
229
230 switch (Opc) {
231 case G_ADD:
232 case G_SUB: {
233 // Integer operations where the source and destination are in the
234 // same register class.
235 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
236 OperandsMapping = Ty.getSizeInBits() == 64
239 break;
240 }
241 case G_MUL:
242 case G_AND:
243 case G_OR:
244 case G_XOR:
245 case G_LSHR:
246 case G_ASHR:
247 case G_SHL:
248 case G_SDIV:
249 case G_UDIV:
250 case G_SEXT:
251 case G_ZEXT:
252 case G_ANYEXT:
253 case G_PTR_ADD:
254 case G_INTTOPTR:
255 case G_PTRTOINT:
256 case G_CTLZ:
257 // FIXME: We're abusing the fact that everything lives in a GPR for now; in
258 // the real world we would use different mappings.
259 OperandsMapping = &ARM::ValueMappings[ARM::GPR3OpsIdx];
260 break;
261 case G_TRUNC: {
262 // In some cases we may end up with a G_TRUNC from a 64-bit value to a
263 // 32-bit value. This isn't a real floating point trunc (that would be a
264 // G_FPTRUNC). Instead it is an integer trunc in disguise, which can appear
265 // because the legalizer doesn't distinguish between integer and floating
266 // point values so it may leave some 64-bit integers un-narrowed. Until we
267 // have a more principled solution that doesn't let such things sneak all
268 // the way to this point, just map the source to a DPR and the destination
269 // to a GPR.
270 LLT LargeTy = MRI.getType(MI.getOperand(1).getReg());
271 OperandsMapping =
272 LargeTy.getSizeInBits() <= 32
276 break;
277 }
278 case G_LOAD:
279 case G_STORE: {
280 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
281 OperandsMapping =
282 Ty.getSizeInBits() == 64
286 break;
287 }
288 case G_FADD:
289 case G_FSUB:
290 case G_FMUL:
291 case G_FDIV:
292 case G_FNEG: {
293 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
294 OperandsMapping =Ty.getSizeInBits() == 64
297 break;
298 }
299 case G_FMA: {
300 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
301 OperandsMapping =
302 Ty.getSizeInBits() == 64
311 break;
312 }
313 case G_FPEXT: {
314 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
315 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
316 if (ToTy.getSizeInBits() == 64 && FromTy.getSizeInBits() == 32)
317 OperandsMapping =
320 break;
321 }
322 case G_FPTRUNC: {
323 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
324 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
325 if (ToTy.getSizeInBits() == 32 && FromTy.getSizeInBits() == 64)
326 OperandsMapping =
329 break;
330 }
331 case G_FPTOSI:
332 case G_FPTOUI: {
333 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
334 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
335 if ((FromTy.getSizeInBits() == 32 || FromTy.getSizeInBits() == 64) &&
336 ToTy.getSizeInBits() == 32)
337 OperandsMapping =
338 FromTy.getSizeInBits() == 64
343 break;
344 }
345 case G_SITOFP:
346 case G_UITOFP: {
347 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
348 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
349 if (FromTy.getSizeInBits() == 32 &&
350 (ToTy.getSizeInBits() == 32 || ToTy.getSizeInBits() == 64))
351 OperandsMapping =
352 ToTy.getSizeInBits() == 64
357 break;
358 }
359 case G_FCONSTANT: {
360 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
361 OperandsMapping = getOperandsMapping(
364 nullptr});
365 break;
366 }
367 case G_CONSTANT:
368 case G_FRAME_INDEX:
369 case G_GLOBAL_VALUE:
370 OperandsMapping =
372 break;
373 case G_SELECT: {
374 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
375 (void)Ty;
376 LLT Ty2 = MRI.getType(MI.getOperand(1).getReg());
377 (void)Ty2;
378 assert(Ty.getSizeInBits() == 32 && "Unsupported size for G_SELECT");
379 assert(Ty2.getSizeInBits() == 1 && "Unsupported size for G_SELECT");
380 OperandsMapping =
385 break;
386 }
387 case G_ICMP: {
388 LLT Ty2 = MRI.getType(MI.getOperand(2).getReg());
389 (void)Ty2;
390 assert(Ty2.getSizeInBits() == 32 && "Unsupported size for G_ICMP");
391 OperandsMapping =
395 break;
396 }
397 case G_FCMP: {
398 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
399 (void)Ty;
400 LLT Ty1 = MRI.getType(MI.getOperand(2).getReg());
401 LLT Ty2 = MRI.getType(MI.getOperand(3).getReg());
402 (void)Ty2;
403 assert(Ty.getSizeInBits() == 1 && "Unsupported size for G_FCMP");
404 assert(Ty1.getSizeInBits() == Ty2.getSizeInBits() &&
405 "Mismatched operand sizes for G_FCMP");
406
407 unsigned Size = Ty1.getSizeInBits();
408 assert((Size == 32 || Size == 64) && "Unsupported size for G_FCMP");
409
410 auto FPRValueMapping = Size == 32 ? &ARM::ValueMappings[ARM::SPR3OpsIdx]
412 OperandsMapping =
414 FPRValueMapping, FPRValueMapping});
415 break;
416 }
417 case G_MERGE_VALUES: {
418 // We only support G_MERGE_VALUES for creating a double precision floating
419 // point value out of two GPRs.
420 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
421 LLT Ty1 = MRI.getType(MI.getOperand(1).getReg());
422 LLT Ty2 = MRI.getType(MI.getOperand(2).getReg());
423 if (Ty.getSizeInBits() != 64 || Ty1.getSizeInBits() != 32 ||
424 Ty2.getSizeInBits() != 32)
426 OperandsMapping =
430 break;
431 }
432 case G_UNMERGE_VALUES: {
433 // We only support G_UNMERGE_VALUES for splitting a double precision
434 // floating point value into two GPRs.
435 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
436 LLT Ty1 = MRI.getType(MI.getOperand(1).getReg());
437 LLT Ty2 = MRI.getType(MI.getOperand(2).getReg());
438 if (Ty.getSizeInBits() != 32 || Ty1.getSizeInBits() != 32 ||
439 Ty2.getSizeInBits() != 64)
441 OperandsMapping =
445 break;
446 }
447 case G_BR:
448 OperandsMapping = getOperandsMapping({nullptr});
449 break;
450 case G_BRCOND:
451 OperandsMapping =
453 break;
454 case DBG_VALUE: {
455 SmallVector<const ValueMapping *, 4> OperandBanks(NumOperands);
456 const MachineOperand &MaybeReg = MI.getOperand(0);
457 if (MaybeReg.isReg() && MaybeReg.getReg()) {
458 unsigned Size = MRI.getType(MaybeReg.getReg()).getSizeInBits();
459 if (Size > 32 && Size != 64)
461 OperandBanks[0] = Size == 64 ? &ARM::ValueMappings[ARM::DPR3OpsIdx]
463 }
464 OperandsMapping = getOperandsMapping(OperandBanks);
465 break;
466 }
467 case G_GET_FPENV:
468 case G_SET_FPENV:
469 OperandsMapping =
471 break;
472 case G_RESET_FPENV:
473 OperandsMapping = getOperandsMapping({nullptr});
474 break;
475 default:
477 }
478
479#ifndef NDEBUG
480 for (unsigned i = 0; i < NumOperands; i++) {
481 for (const auto &Mapping : OperandsMapping[i]) {
482 assert(
483 (Mapping.RegBank->getID() != ARM::FPRRegBankID ||
485 "Trying to use floating point register bank on target without vfp");
486 }
487 }
488#endif
489
490 return getInstructionMapping(DefaultMappingID, /*Cost=*/1, OperandsMapping,
491 NumOperands);
492}
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:271
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
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