LLVM 18.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(getMaximumSize(RBGPR.getID()) == 32 &&
166 "GPRs should hold up to 32-bit");
167
168#ifndef NDEBUG
171#endif
172 };
173
174 llvm::call_once(InitializeRegisterBankFlag, InitializeRegisterBankOnce);
175}
176
177const RegisterBank &
179 LLT) const {
180 using namespace ARM;
181
182 switch (RC.getID()) {
183 case GPRRegClassID:
184 case GPRwithAPSRRegClassID:
185 case GPRnoipRegClassID:
186 case GPRnopcRegClassID:
187 case GPRnoip_and_GPRnopcRegClassID:
188 case rGPRRegClassID:
189 case GPRspRegClassID:
190 case GPRnoip_and_tcGPRRegClassID:
191 case tcGPRRegClassID:
192 case tGPRRegClassID:
193 case tGPREvenRegClassID:
194 case tGPROddRegClassID:
195 case tGPR_and_tGPREvenRegClassID:
196 case tGPR_and_tGPROddRegClassID:
197 case tGPREven_and_tcGPRRegClassID:
198 case tGPREven_and_GPRnoip_and_tcGPRRegClassID:
199 case tGPROdd_and_tcGPRRegClassID:
200 return getRegBank(ARM::GPRRegBankID);
201 case HPRRegClassID:
202 case SPR_8RegClassID:
203 case SPRRegClassID:
204 case DPR_8RegClassID:
205 case DPRRegClassID:
206 case QPRRegClassID:
207 return getRegBank(ARM::FPRRegBankID);
208 default:
209 llvm_unreachable("Unsupported register kind");
210 }
211
212 llvm_unreachable("Switch should handle all register classes");
213}
214
217 auto Opc = MI.getOpcode();
218
219 // Try the default logic for non-generic instructions that are either copies
220 // or already have some operands assigned to banks.
221 if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {
222 const InstructionMapping &Mapping = getInstrMappingImpl(MI);
223 if (Mapping.isValid())
224 return Mapping;
225 }
226
227 using namespace TargetOpcode;
228
229 const MachineFunction &MF = *MI.getParent()->getParent();
230 const MachineRegisterInfo &MRI = MF.getRegInfo();
231 unsigned NumOperands = MI.getNumOperands();
232 const ValueMapping *OperandsMapping = &ARM::ValueMappings[ARM::GPR3OpsIdx];
233
234 switch (Opc) {
235 case G_ADD:
236 case G_SUB: {
237 // Integer operations where the source and destination are in the
238 // same register class.
239 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
240 OperandsMapping = Ty.getSizeInBits() == 64
243 break;
244 }
245 case G_MUL:
246 case G_AND:
247 case G_OR:
248 case G_XOR:
249 case G_LSHR:
250 case G_ASHR:
251 case G_SHL:
252 case G_SDIV:
253 case G_UDIV:
254 case G_SEXT:
255 case G_ZEXT:
256 case G_ANYEXT:
257 case G_PTR_ADD:
258 case G_INTTOPTR:
259 case G_PTRTOINT:
260 case G_CTLZ:
261 // FIXME: We're abusing the fact that everything lives in a GPR for now; in
262 // the real world we would use different mappings.
263 OperandsMapping = &ARM::ValueMappings[ARM::GPR3OpsIdx];
264 break;
265 case G_TRUNC: {
266 // In some cases we may end up with a G_TRUNC from a 64-bit value to a
267 // 32-bit value. This isn't a real floating point trunc (that would be a
268 // G_FPTRUNC). Instead it is an integer trunc in disguise, which can appear
269 // because the legalizer doesn't distinguish between integer and floating
270 // point values so it may leave some 64-bit integers un-narrowed. Until we
271 // have a more principled solution that doesn't let such things sneak all
272 // the way to this point, just map the source to a DPR and the destination
273 // to a GPR.
274 LLT LargeTy = MRI.getType(MI.getOperand(1).getReg());
275 OperandsMapping =
276 LargeTy.getSizeInBits() <= 32
280 break;
281 }
282 case G_LOAD:
283 case G_STORE: {
284 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
285 OperandsMapping =
286 Ty.getSizeInBits() == 64
290 break;
291 }
292 case G_FADD:
293 case G_FSUB:
294 case G_FMUL:
295 case G_FDIV:
296 case G_FNEG: {
297 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
298 OperandsMapping =Ty.getSizeInBits() == 64
301 break;
302 }
303 case G_FMA: {
304 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
305 OperandsMapping =
306 Ty.getSizeInBits() == 64
315 break;
316 }
317 case G_FPEXT: {
318 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
319 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
320 if (ToTy.getSizeInBits() == 64 && FromTy.getSizeInBits() == 32)
321 OperandsMapping =
324 break;
325 }
326 case G_FPTRUNC: {
327 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
328 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
329 if (ToTy.getSizeInBits() == 32 && FromTy.getSizeInBits() == 64)
330 OperandsMapping =
333 break;
334 }
335 case G_FPTOSI:
336 case G_FPTOUI: {
337 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
338 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
339 if ((FromTy.getSizeInBits() == 32 || FromTy.getSizeInBits() == 64) &&
340 ToTy.getSizeInBits() == 32)
341 OperandsMapping =
342 FromTy.getSizeInBits() == 64
347 break;
348 }
349 case G_SITOFP:
350 case G_UITOFP: {
351 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
352 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
353 if (FromTy.getSizeInBits() == 32 &&
354 (ToTy.getSizeInBits() == 32 || ToTy.getSizeInBits() == 64))
355 OperandsMapping =
356 ToTy.getSizeInBits() == 64
361 break;
362 }
363 case G_FCONSTANT: {
364 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
365 OperandsMapping = getOperandsMapping(
368 nullptr});
369 break;
370 }
371 case G_CONSTANT:
372 case G_FRAME_INDEX:
373 case G_GLOBAL_VALUE:
374 OperandsMapping =
376 break;
377 case G_SELECT: {
378 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
379 (void)Ty;
380 LLT Ty2 = MRI.getType(MI.getOperand(1).getReg());
381 (void)Ty2;
382 assert(Ty.getSizeInBits() == 32 && "Unsupported size for G_SELECT");
383 assert(Ty2.getSizeInBits() == 1 && "Unsupported size for G_SELECT");
384 OperandsMapping =
389 break;
390 }
391 case G_ICMP: {
392 LLT Ty2 = MRI.getType(MI.getOperand(2).getReg());
393 (void)Ty2;
394 assert(Ty2.getSizeInBits() == 32 && "Unsupported size for G_ICMP");
395 OperandsMapping =
399 break;
400 }
401 case G_FCMP: {
402 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
403 (void)Ty;
404 LLT Ty1 = MRI.getType(MI.getOperand(2).getReg());
405 LLT Ty2 = MRI.getType(MI.getOperand(3).getReg());
406 (void)Ty2;
407 assert(Ty.getSizeInBits() == 1 && "Unsupported size for G_FCMP");
408 assert(Ty1.getSizeInBits() == Ty2.getSizeInBits() &&
409 "Mismatched operand sizes for G_FCMP");
410
411 unsigned Size = Ty1.getSizeInBits();
412 assert((Size == 32 || Size == 64) && "Unsupported size for G_FCMP");
413
414 auto FPRValueMapping = Size == 32 ? &ARM::ValueMappings[ARM::SPR3OpsIdx]
416 OperandsMapping =
418 FPRValueMapping, FPRValueMapping});
419 break;
420 }
421 case G_MERGE_VALUES: {
422 // We only support G_MERGE_VALUES for creating a double precision floating
423 // point value out of two GPRs.
424 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
425 LLT Ty1 = MRI.getType(MI.getOperand(1).getReg());
426 LLT Ty2 = MRI.getType(MI.getOperand(2).getReg());
427 if (Ty.getSizeInBits() != 64 || Ty1.getSizeInBits() != 32 ||
428 Ty2.getSizeInBits() != 32)
430 OperandsMapping =
434 break;
435 }
436 case G_UNMERGE_VALUES: {
437 // We only support G_UNMERGE_VALUES for splitting a double precision
438 // floating point value into two GPRs.
439 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
440 LLT Ty1 = MRI.getType(MI.getOperand(1).getReg());
441 LLT Ty2 = MRI.getType(MI.getOperand(2).getReg());
442 if (Ty.getSizeInBits() != 32 || Ty1.getSizeInBits() != 32 ||
443 Ty2.getSizeInBits() != 64)
445 OperandsMapping =
449 break;
450 }
451 case G_BR:
452 OperandsMapping = getOperandsMapping({nullptr});
453 break;
454 case G_BRCOND:
455 OperandsMapping =
457 break;
458 case DBG_VALUE: {
459 SmallVector<const ValueMapping *, 4> OperandBanks(NumOperands);
460 const MachineOperand &MaybeReg = MI.getOperand(0);
461 if (MaybeReg.isReg() && MaybeReg.getReg()) {
462 unsigned Size = MRI.getType(MaybeReg.getReg()).getSizeInBits();
463 if (Size > 32 && Size != 64)
465 OperandBanks[0] = Size == 64 ? &ARM::ValueMappings[ARM::DPR3OpsIdx]
467 }
468 OperandsMapping = getOperandsMapping(OperandBanks);
469 break;
470 }
471 default:
473 }
474
475#ifndef NDEBUG
476 for (unsigned i = 0; i < NumOperands; i++) {
477 for (const auto &Mapping : OperandsMapping[i]) {
478 assert(
479 (Mapping.RegBank->getID() != ARM::FPRRegBankID ||
481 "Trying to use floating point register bank on target without vfp");
482 }
483 }
484#endif
485
486 return getInstructionMapping(DefaultMappingID, /*Cost=*/1, OperandsMapping,
487 NumOperands);
488}
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:330
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
Definition: LowLevelType.h:175
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:46
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:440
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