LLVM 20.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
175 auto Opc = MI.getOpcode();
176
177 // Try the default logic for non-generic instructions that are either copies
178 // or already have some operands assigned to banks.
179 if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {
180 const InstructionMapping &Mapping = getInstrMappingImpl(MI);
181 if (Mapping.isValid())
182 return Mapping;
183 }
184
185 using namespace TargetOpcode;
186
187 const MachineFunction &MF = *MI.getParent()->getParent();
188 const MachineRegisterInfo &MRI = MF.getRegInfo();
189 unsigned NumOperands = MI.getNumOperands();
190 const ValueMapping *OperandsMapping = &ARM::ValueMappings[ARM::GPR3OpsIdx];
191
192 switch (Opc) {
193 case G_ADD:
194 case G_SUB: {
195 // Integer operations where the source and destination are in the
196 // same register class.
197 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
198 OperandsMapping = Ty.getSizeInBits() == 64
201 break;
202 }
203 case G_MUL:
204 case G_AND:
205 case G_OR:
206 case G_XOR:
207 case G_LSHR:
208 case G_ASHR:
209 case G_SHL:
210 case G_SDIV:
211 case G_UDIV:
212 case G_SEXT:
213 case G_ZEXT:
214 case G_ANYEXT:
215 case G_PTR_ADD:
216 case G_INTTOPTR:
217 case G_PTRTOINT:
218 case G_CTLZ:
219 // FIXME: We're abusing the fact that everything lives in a GPR for now; in
220 // the real world we would use different mappings.
221 OperandsMapping = &ARM::ValueMappings[ARM::GPR3OpsIdx];
222 break;
223 case G_TRUNC: {
224 // In some cases we may end up with a G_TRUNC from a 64-bit value to a
225 // 32-bit value. This isn't a real floating point trunc (that would be a
226 // G_FPTRUNC). Instead it is an integer trunc in disguise, which can appear
227 // because the legalizer doesn't distinguish between integer and floating
228 // point values so it may leave some 64-bit integers un-narrowed. Until we
229 // have a more principled solution that doesn't let such things sneak all
230 // the way to this point, just map the source to a DPR and the destination
231 // to a GPR.
232 LLT LargeTy = MRI.getType(MI.getOperand(1).getReg());
233 OperandsMapping =
234 LargeTy.getSizeInBits() <= 32
238 break;
239 }
240 case G_LOAD:
241 case G_STORE: {
242 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
243 OperandsMapping =
244 Ty.getSizeInBits() == 64
248 break;
249 }
250 case G_FADD:
251 case G_FSUB:
252 case G_FMUL:
253 case G_FDIV:
254 case G_FNEG: {
255 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
256 OperandsMapping =Ty.getSizeInBits() == 64
259 break;
260 }
261 case G_FMA: {
262 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
263 OperandsMapping =
264 Ty.getSizeInBits() == 64
273 break;
274 }
275 case G_FPEXT: {
276 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
277 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
278 if (ToTy.getSizeInBits() == 64 && FromTy.getSizeInBits() == 32)
279 OperandsMapping =
282 break;
283 }
284 case G_FPTRUNC: {
285 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
286 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
287 if (ToTy.getSizeInBits() == 32 && FromTy.getSizeInBits() == 64)
288 OperandsMapping =
291 break;
292 }
293 case G_FPTOSI:
294 case G_FPTOUI: {
295 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
296 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
297 if ((FromTy.getSizeInBits() == 32 || FromTy.getSizeInBits() == 64) &&
298 ToTy.getSizeInBits() == 32)
299 OperandsMapping =
300 FromTy.getSizeInBits() == 64
305 break;
306 }
307 case G_SITOFP:
308 case G_UITOFP: {
309 LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
310 LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
311 if (FromTy.getSizeInBits() == 32 &&
312 (ToTy.getSizeInBits() == 32 || ToTy.getSizeInBits() == 64))
313 OperandsMapping =
314 ToTy.getSizeInBits() == 64
319 break;
320 }
321 case G_FCONSTANT: {
322 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
323 OperandsMapping = getOperandsMapping(
326 nullptr});
327 break;
328 }
329 case G_CONSTANT:
330 case G_FRAME_INDEX:
331 case G_GLOBAL_VALUE:
332 OperandsMapping =
334 break;
335 case G_SELECT: {
336 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
337 (void)Ty;
338 LLT Ty2 = MRI.getType(MI.getOperand(1).getReg());
339 (void)Ty2;
340 assert(Ty.getSizeInBits() == 32 && "Unsupported size for G_SELECT");
341 assert(Ty2.getSizeInBits() == 1 && "Unsupported size for G_SELECT");
342 OperandsMapping =
347 break;
348 }
349 case G_ICMP: {
350 LLT Ty2 = MRI.getType(MI.getOperand(2).getReg());
351 (void)Ty2;
352 assert(Ty2.getSizeInBits() == 32 && "Unsupported size for G_ICMP");
353 OperandsMapping =
357 break;
358 }
359 case G_FCMP: {
360 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
361 (void)Ty;
362 LLT Ty1 = MRI.getType(MI.getOperand(2).getReg());
363 LLT Ty2 = MRI.getType(MI.getOperand(3).getReg());
364 (void)Ty2;
365 assert(Ty.getSizeInBits() == 1 && "Unsupported size for G_FCMP");
366 assert(Ty1.getSizeInBits() == Ty2.getSizeInBits() &&
367 "Mismatched operand sizes for G_FCMP");
368
369 unsigned Size = Ty1.getSizeInBits();
370 assert((Size == 32 || Size == 64) && "Unsupported size for G_FCMP");
371
372 auto FPRValueMapping = Size == 32 ? &ARM::ValueMappings[ARM::SPR3OpsIdx]
374 OperandsMapping =
376 FPRValueMapping, FPRValueMapping});
377 break;
378 }
379 case G_MERGE_VALUES: {
380 // We only support G_MERGE_VALUES for creating a double precision floating
381 // point value out of two GPRs.
382 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
383 LLT Ty1 = MRI.getType(MI.getOperand(1).getReg());
384 LLT Ty2 = MRI.getType(MI.getOperand(2).getReg());
385 if (Ty.getSizeInBits() != 64 || Ty1.getSizeInBits() != 32 ||
386 Ty2.getSizeInBits() != 32)
388 OperandsMapping =
392 break;
393 }
394 case G_UNMERGE_VALUES: {
395 // We only support G_UNMERGE_VALUES for splitting a double precision
396 // floating point value into two GPRs.
397 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
398 LLT Ty1 = MRI.getType(MI.getOperand(1).getReg());
399 LLT Ty2 = MRI.getType(MI.getOperand(2).getReg());
400 if (Ty.getSizeInBits() != 32 || Ty1.getSizeInBits() != 32 ||
401 Ty2.getSizeInBits() != 64)
403 OperandsMapping =
407 break;
408 }
409 case G_BR:
410 OperandsMapping = getOperandsMapping({nullptr});
411 break;
412 case G_BRCOND:
413 OperandsMapping =
415 break;
416 case DBG_VALUE: {
417 SmallVector<const ValueMapping *, 4> OperandBanks(NumOperands);
418 const MachineOperand &MaybeReg = MI.getOperand(0);
419 if (MaybeReg.isReg() && MaybeReg.getReg()) {
420 unsigned Size = MRI.getType(MaybeReg.getReg()).getSizeInBits();
421 if (Size > 32 && Size != 64)
423 OperandBanks[0] = Size == 64 ? &ARM::ValueMappings[ARM::DPR3OpsIdx]
425 }
426 OperandsMapping = getOperandsMapping(OperandBanks);
427 break;
428 }
429 case G_GET_FPENV:
430 case G_SET_FPENV:
431 case G_GET_FPMODE:
432 OperandsMapping =
434 break;
435 case G_RESET_FPENV:
436 OperandsMapping = getOperandsMapping({nullptr});
437 break;
438 default:
440 }
441
442#ifndef NDEBUG
443 for (unsigned i = 0; i < NumOperands; i++) {
444 for (const auto &Mapping : OperandsMapping[i]) {
445 assert(
446 (Mapping.RegBank->getID() != ARM::FPRRegBankID ||
448 "Trying to use floating point register bank on target without vfp");
449 }
450 }
451#endif
452
453 return getInstructionMapping(DefaultMappingID, /*Cost=*/1, OperandsMapping,
454 NumOperands);
455}
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())
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
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
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:480
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