LLVM 17.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
94 return VM.NumBreakDowns == 1 && VM.BreakDown == BreakDown;
95}
96
97static void checkValueMappings() {
100 "Wrong value mapping for 3 GPR ops instruction");
103 "Wrong value mapping for 3 GPR ops instruction");
106 "Wrong value mapping for 3 GPR ops instruction");
107
110 "Wrong value mapping for 3 SPR ops instruction");
113 "Wrong value mapping for 3 SPR ops instruction");
116 "Wrong value mapping for 3 SPR ops instruction");
117
120 "Wrong value mapping for 3 DPR ops instruction");
123 "Wrong value mapping for 3 DPR ops instruction");
126 "Wrong value mapping for 3 DPR ops instruction");
127}
128#endif
129} // end namespace arm
130} // end namespace llvm
131
133 // We have only one set of register banks, whatever the subtarget
134 // is. Therefore, the initialization of the RegBanks table should be
135 // done only once. Indeed the table of all register banks
136 // (ARM::RegBanks) is unique in the compiler. At some point, it
137 // will get tablegen'ed and the whole constructor becomes empty.
138 static llvm::once_flag InitializeRegisterBankFlag;
139
140 static auto InitializeRegisterBankOnce = [&]() {
141 const RegisterBank &RBGPR = getRegBank(ARM::GPRRegBankID);
142 (void)RBGPR;
143 assert(&ARM::GPRRegBank == &RBGPR && "The order in RegBanks is messed up");
144
145 // Initialize the GPR bank.
146 assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRRegClassID)) &&
147 "Subclass not added?");
148 assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRwithAPSRRegClassID)) &&
149 "Subclass not added?");
150 assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRnopcRegClassID)) &&
151 "Subclass not added?");
152 assert(RBGPR.covers(*TRI.getRegClass(ARM::rGPRRegClassID)) &&
153 "Subclass not added?");
154 assert(RBGPR.covers(*TRI.getRegClass(ARM::tGPRRegClassID)) &&
155 "Subclass not added?");
156 assert(RBGPR.covers(*TRI.getRegClass(ARM::tcGPRRegClassID)) &&
157 "Subclass not added?");
158 assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRnoip_and_tcGPRRegClassID)) &&
159 "Subclass not added?");
160 assert(RBGPR.covers(*TRI.getRegClass(
161 ARM::tGPREven_and_GPRnoip_and_tcGPRRegClassID)) &&
162 "Subclass not added?");
163 assert(RBGPR.covers(*TRI.getRegClass(ARM::tGPROdd_and_tcGPRRegClassID)) &&
164 "Subclass not added?");
165 assert(RBGPR.getSize() == 32 && "GPRs should hold up to 32-bit");
166
167#ifndef NDEBUG
170#endif
171 };
172
173 llvm::call_once(InitializeRegisterBankFlag, InitializeRegisterBankOnce);
174}
175
176const RegisterBank &
178 LLT) const {
179 using namespace ARM;
180
181 switch (RC.getID()) {
182 case GPRRegClassID:
183 case GPRwithAPSRRegClassID:
184 case GPRnoipRegClassID:
185 case GPRnopcRegClassID:
186 case GPRnoip_and_GPRnopcRegClassID:
187 case rGPRRegClassID:
188 case GPRspRegClassID:
189 case GPRnoip_and_tcGPRRegClassID:
190 case tcGPRRegClassID:
191 case tGPRRegClassID:
192 case tGPREvenRegClassID:
193 case tGPROddRegClassID:
194 case tGPR_and_tGPREvenRegClassID:
195 case tGPR_and_tGPROddRegClassID:
196 case tGPREven_and_tcGPRRegClassID:
197 case tGPREven_and_GPRnoip_and_tcGPRRegClassID:
198 case tGPROdd_and_tcGPRRegClassID:
199 return getRegBank(ARM::GPRRegBankID);
200 case HPRRegClassID:
201 case SPR_8RegClassID:
202 case SPRRegClassID:
203 case DPR_8RegClassID:
204 case DPRRegClassID:
205 case QPRRegClassID:
206 return getRegBank(ARM::FPRRegBankID);
207 default:
208 llvm_unreachable("Unsupported register kind");
209 }
210
211 llvm_unreachable("Switch should handle all register classes");
212}
213
216 auto Opc = MI.getOpcode();
217
218 // Try the default logic for non-generic instructions that are either copies
219 // or already have some operands assigned to banks.
220 if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {
221 const InstructionMapping &Mapping = getInstrMappingImpl(MI);
222 if (Mapping.isValid())
223 return Mapping;
224 }
225
226 using namespace TargetOpcode;
227
228 const MachineFunction &MF = *MI.getParent()->getParent();
229 const MachineRegisterInfo &MRI = MF.getRegInfo();
230 unsigned NumOperands = MI.getNumOperands();
231 const ValueMapping *OperandsMapping = &ARM::ValueMappings[ARM::GPR3OpsIdx];
232
233 switch (Opc) {
234 case G_ADD:
235 case G_SUB: {
236 // Integer operations where the source and destination are in the
237 // same register class.
238 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
239 OperandsMapping = Ty.getSizeInBits() == 64
242 break;
243 }
244 case G_MUL:
245 case G_AND:
246 case G_OR:
247 case G_XOR:
248 case G_LSHR:
249 case G_ASHR:
250 case G_SHL:
251 case G_SDIV:
252 case G_UDIV:
253 case G_SEXT:
254 case G_ZEXT:
255 case G_ANYEXT:
256 case G_PTR_ADD:
257 case G_INTTOPTR:
258 case G_PTRTOINT:
259 case G_CTLZ:
260 // FIXME: We're abusing the fact that everything lives in a GPR for now; in
261 // the real world we would use different mappings.
262 OperandsMapping = &ARM::ValueMappings[ARM::GPR3OpsIdx];
263 break;
264 case G_TRUNC: {
265 // In some cases we may end up with a G_TRUNC from a 64-bit value to a
266 // 32-bit value. This isn't a real floating point trunc (that would be a
267 // G_FPTRUNC). Instead it is an integer trunc in disguise, which can appear
268 // because the legalizer doesn't distinguish between integer and floating
269 // point values so it may leave some 64-bit integers un-narrowed. Until we
270 // have a more principled solution that doesn't let such things sneak all
271 // the way to this point, just map the source to a DPR and the destination
272 // to a GPR.
273 LLT LargeTy = MRI.getType(MI.getOperand(1).getReg());
274 OperandsMapping =
275 LargeTy.getSizeInBits() <= 32
279 break;
280 }
281 case G_LOAD:
282 case G_STORE: {
283 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
284 OperandsMapping =
285 Ty.getSizeInBits() == 64
289 break;
290 }
291 case G_FADD:
292 case G_FSUB:
293 case G_FMUL:
294 case G_FDIV:
295 case G_FNEG: {
296 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
297 OperandsMapping =Ty.getSizeInBits() == 64
300 break;
301 }
302 case G_FMA: {
303 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
304 OperandsMapping =
305 Ty.getSizeInBits() == 64
314 break;
315 }
316 case G_FPEXT: {
317 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
318 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
319 if (ToTy.getSizeInBits() == 64 && FromTy.getSizeInBits() == 32)
320 OperandsMapping =
323 break;
324 }
325 case G_FPTRUNC: {
326 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
327 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
328 if (ToTy.getSizeInBits() == 32 && FromTy.getSizeInBits() == 64)
329 OperandsMapping =
332 break;
333 }
334 case G_FPTOSI:
335 case G_FPTOUI: {
336 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
337 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
338 if ((FromTy.getSizeInBits() == 32 || FromTy.getSizeInBits() == 64) &&
339 ToTy.getSizeInBits() == 32)
340 OperandsMapping =
341 FromTy.getSizeInBits() == 64
346 break;
347 }
348 case G_SITOFP:
349 case G_UITOFP: {
350 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
351 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
352 if (FromTy.getSizeInBits() == 32 &&
353 (ToTy.getSizeInBits() == 32 || ToTy.getSizeInBits() == 64))
354 OperandsMapping =
355 ToTy.getSizeInBits() == 64
360 break;
361 }
362 case G_FCONSTANT: {
363 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
364 OperandsMapping = getOperandsMapping(
367 nullptr});
368 break;
369 }
370 case G_CONSTANT:
371 case G_FRAME_INDEX:
372 case G_GLOBAL_VALUE:
373 OperandsMapping =
375 break;
376 case G_SELECT: {
377 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
378 (void)Ty;
379 LLT Ty2 = MRI.getType(MI.getOperand(1).getReg());
380 (void)Ty2;
381 assert(Ty.getSizeInBits() == 32 && "Unsupported size for G_SELECT");
382 assert(Ty2.getSizeInBits() == 1 && "Unsupported size for G_SELECT");
383 OperandsMapping =
388 break;
389 }
390 case G_ICMP: {
391 LLT Ty2 = MRI.getType(MI.getOperand(2).getReg());
392 (void)Ty2;
393 assert(Ty2.getSizeInBits() == 32 && "Unsupported size for G_ICMP");
394 OperandsMapping =
398 break;
399 }
400 case G_FCMP: {
401 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
402 (void)Ty;
403 LLT Ty1 = MRI.getType(MI.getOperand(2).getReg());
404 LLT Ty2 = MRI.getType(MI.getOperand(3).getReg());
405 (void)Ty2;
406 assert(Ty.getSizeInBits() == 1 && "Unsupported size for G_FCMP");
407 assert(Ty1.getSizeInBits() == Ty2.getSizeInBits() &&
408 "Mismatched operand sizes for G_FCMP");
409
410 unsigned Size = Ty1.getSizeInBits();
411 assert((Size == 32 || Size == 64) && "Unsupported size for G_FCMP");
412
413 auto FPRValueMapping = Size == 32 ? &ARM::ValueMappings[ARM::SPR3OpsIdx]
415 OperandsMapping =
417 FPRValueMapping, FPRValueMapping});
418 break;
419 }
420 case G_MERGE_VALUES: {
421 // We only support G_MERGE_VALUES for creating a double precision floating
422 // point value out of two GPRs.
423 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
424 LLT Ty1 = MRI.getType(MI.getOperand(1).getReg());
425 LLT Ty2 = MRI.getType(MI.getOperand(2).getReg());
426 if (Ty.getSizeInBits() != 64 || Ty1.getSizeInBits() != 32 ||
427 Ty2.getSizeInBits() != 32)
429 OperandsMapping =
433 break;
434 }
435 case G_UNMERGE_VALUES: {
436 // We only support G_UNMERGE_VALUES for splitting a double precision
437 // floating point value into two GPRs.
438 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
439 LLT Ty1 = MRI.getType(MI.getOperand(1).getReg());
440 LLT Ty2 = MRI.getType(MI.getOperand(2).getReg());
441 if (Ty.getSizeInBits() != 32 || Ty1.getSizeInBits() != 32 ||
442 Ty2.getSizeInBits() != 64)
444 OperandsMapping =
448 break;
449 }
450 case G_BR:
451 OperandsMapping = getOperandsMapping({nullptr});
452 break;
453 case G_BRCOND:
454 OperandsMapping =
456 break;
457 case DBG_VALUE: {
458 SmallVector<const ValueMapping *, 4> OperandBanks(NumOperands);
459 const MachineOperand &MaybeReg = MI.getOperand(0);
460 if (MaybeReg.isReg() && MaybeReg.getReg()) {
461 unsigned Size = MRI.getType(MaybeReg.getReg()).getSizeInBits();
462 if (Size > 32 && Size != 64)
464 OperandBanks[0] = Size == 64 ? &ARM::ValueMappings[ARM::DPR3OpsIdx]
466 }
467 OperandsMapping = getOperandsMapping(OperandBanks);
468 break;
469 }
470 default:
472 }
473
474#ifndef NDEBUG
475 for (unsigned i = 0; i < NumOperands; i++) {
476 for (const auto &Mapping : OperandsMapping[i]) {
477 assert(
478 (Mapping.RegBank->getID() != ARM::FPRRegBankID ||
480 "Trying to use floating point register bank on target without vfp");
481 }
482 }
483#endif
484
485 return getInstructionMapping(DefaultMappingID, /*Cost=*/1, OperandsMapping,
486 NumOperands);
487}
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:332
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
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.
RegisterBank & getRegBank(unsigned ID)
Get the register bank identified by ID.
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
unsigned getSize() const
Get the maximal size in bits that fits in this register bank.
Definition: RegisterBank.h:54
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:47
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...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static void checkPartialMappings()
static void checkValueMappings()
RegisterBankInfo::PartialMapping PartMappings[]
RegisterBankInfo::ValueMapping ValueMappings[]
static bool checkValueMapping(const RegisterBankInfo::ValueMapping &VM, 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:406
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