1//===- AArch64RegisterBankInfo.cpp ----------------------------------------===//
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
10/// AArch64.
11/// \todo This should be generated by TableGen.
12//===----------------------------------------------------------------------===//
13
14#include "AArch64RegisterBankInfo.h"
15#include "AArch64RegisterInfo.h"
16#include "AArch64Subtarget.h"
17#include "MCTargetDesc/AArch64AddressingModes.h"
18#include "MCTargetDesc/AArch64MCTargetDesc.h"
19#include "llvm/ADT/APInt.h"
20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/SmallVector.h"
22#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
23#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
24#include "llvm/CodeGen/GlobalISel/Utils.h"
25#include "llvm/CodeGen/LowLevelTypeUtils.h"
26#include "llvm/CodeGen/MachineFunction.h"
27#include "llvm/CodeGen/MachineInstr.h"
28#include "llvm/CodeGen/MachineOperand.h"
29#include "llvm/CodeGen/MachineRegisterInfo.h"
30#include "llvm/CodeGen/MachineSizeOpts.h"
31#include "llvm/CodeGen/RegisterBank.h"
32#include "llvm/CodeGen/RegisterBankInfo.h"
33#include "llvm/CodeGen/TargetOpcodes.h"
34#include "llvm/CodeGen/TargetRegisterInfo.h"
35#include "llvm/CodeGen/TargetSubtargetInfo.h"
36#include "llvm/IR/Constants.h"
37#include "llvm/IR/IntrinsicsAArch64.h"
38#include "llvm/Support/ErrorHandling.h"
39#include "llvm/Support/Threading.h"
40#include <cassert>
41
42#define GET_TARGET_REGBANK_IMPL
43#include "AArch64GenRegisterBank.inc"
44
45// This file will be TableGen'ed at some point.
46#include "AArch64GenRegisterBankInfo.def"
47
48using namespace llvm;
49static const unsigned CustomMappingID = 1;
50
51AArch64RegisterBankInfo::AArch64RegisterBankInfo(
52 const TargetRegisterInfo &TRI) {
53 static llvm::once_flag InitializeRegisterBankFlag;
54
55 static auto InitializeRegisterBankOnce = [&]() {
56 // We have only one set of register banks, whatever the subtarget
57 // is. Therefore, the initialization of the RegBanks table should be
58 // done only once. Indeed the table of all register banks
59 // (AArch64::RegBanks) is unique in the compiler. At some point, it
60 // will get tablegen'ed and the whole constructor becomes empty.
61
62 const RegisterBank &RBGPR = getRegBank(ID: AArch64::GPRRegBankID);
63 (void)RBGPR;
64 assert(&AArch64::GPRRegBank == &RBGPR &&
65 "The order in RegBanks is messed up");
66
67 const RegisterBank &RBFPR = getRegBank(ID: AArch64::FPRRegBankID);
68 (void)RBFPR;
69 assert(&AArch64::FPRRegBank == &RBFPR &&
70 "The order in RegBanks is messed up");
71
72 const RegisterBank &RBCCR = getRegBank(ID: AArch64::CCRegBankID);
73 (void)RBCCR;
74 assert(&AArch64::CCRegBank == &RBCCR &&
75 "The order in RegBanks is messed up");
76
77 // The GPR register bank is fully defined by all the registers in
78 // GR64all + its subclasses.
79 assert(RBGPR.covers(*TRI.getRegClass(AArch64::GPR32RegClassID)) &&
80 "Subclass not added?");
81 assert(getMaximumSize(RBGPR.getID()) == 128 &&
82 "GPRs should hold up to 128-bit");
83
84 // The FPR register bank is fully defined by all the registers in
85 // GR64all + its subclasses.
86 assert(RBFPR.covers(*TRI.getRegClass(AArch64::QQRegClassID)) &&
87 "Subclass not added?");
88 assert(RBFPR.covers(*TRI.getRegClass(AArch64::FPR64RegClassID)) &&
89 "Subclass not added?");
90 assert(getMaximumSize(RBFPR.getID()) == 512 &&
91 "FPRs should hold up to 512-bit via QQQQ sequence");
92
93 assert(RBCCR.covers(*TRI.getRegClass(AArch64::CCRRegClassID)) &&
94 "Class not added?");
95 assert(getMaximumSize(RBCCR.getID()) == 32 &&
96 "CCR should hold up to 32-bit");
97
98 // Check that the TableGen'ed like file is in sync we our expectations.
99 // First, the Idx.
100 assert(checkPartialMappingIdx(PMI_FirstGPR, PMI_LastGPR,
101 {PMI_GPR32, PMI_GPR64, PMI_GPR128}) &&
102 "PartialMappingIdx's are incorrectly ordered");
103 assert(checkPartialMappingIdx(PMI_FirstFPR, PMI_LastFPR,
104 {PMI_FPR16, PMI_FPR32, PMI_FPR64, PMI_FPR128,
105 PMI_FPR256, PMI_FPR512}) &&
106 "PartialMappingIdx's are incorrectly ordered");
107// Now, the content.
108// Check partial mapping.
109#define CHECK_PARTIALMAP(Idx, ValStartIdx, ValLength, RB) \
110 do { \
111 assert( \
112 checkPartialMap(PartialMappingIdx::Idx, ValStartIdx, ValLength, RB) && \
113 #Idx " is incorrectly initialized"); \
114 } while (false)
115
116 CHECK_PARTIALMAP(PMI_GPR32, 0, 32, RBGPR);
117 CHECK_PARTIALMAP(PMI_GPR64, 0, 64, RBGPR);
118 CHECK_PARTIALMAP(PMI_GPR128, 0, 128, RBGPR);
119 CHECK_PARTIALMAP(PMI_FPR16, 0, 16, RBFPR);
120 CHECK_PARTIALMAP(PMI_FPR32, 0, 32, RBFPR);
121 CHECK_PARTIALMAP(PMI_FPR64, 0, 64, RBFPR);
122 CHECK_PARTIALMAP(PMI_FPR128, 0, 128, RBFPR);
123 CHECK_PARTIALMAP(PMI_FPR256, 0, 256, RBFPR);
124 CHECK_PARTIALMAP(PMI_FPR512, 0, 512, RBFPR);
125
126// Check value mapping.
127#define CHECK_VALUEMAP_IMPL(RBName, Size, Offset) \
128 do { \
129 assert(checkValueMapImpl(PartialMappingIdx::PMI_##RBName##Size, \
130 PartialMappingIdx::PMI_First##RBName, Size, \
131 Offset) && \
132 #RBName #Size " " #Offset " is incorrectly initialized"); \
133 } while (false)
134
135#define CHECK_VALUEMAP(RBName, Size) CHECK_VALUEMAP_IMPL(RBName, Size, 0)
136
137 CHECK_VALUEMAP(GPR, 32);
138 CHECK_VALUEMAP(GPR, 64);
139 CHECK_VALUEMAP(GPR, 128);
140 CHECK_VALUEMAP(FPR, 16);
141 CHECK_VALUEMAP(FPR, 32);
142 CHECK_VALUEMAP(FPR, 64);
143 CHECK_VALUEMAP(FPR, 128);
144 CHECK_VALUEMAP(FPR, 256);
145 CHECK_VALUEMAP(FPR, 512);
146
147// Check the value mapping for 3-operands instructions where all the operands
148// map to the same value mapping.
149#define CHECK_VALUEMAP_3OPS(RBName, Size) \
150 do { \
151 CHECK_VALUEMAP_IMPL(RBName, Size, 0); \
152 CHECK_VALUEMAP_IMPL(RBName, Size, 1); \
153 CHECK_VALUEMAP_IMPL(RBName, Size, 2); \
154 } while (false)
155
156 CHECK_VALUEMAP_3OPS(GPR, 32);
157 CHECK_VALUEMAP_3OPS(GPR, 64);
158 CHECK_VALUEMAP_3OPS(GPR, 128);
159 CHECK_VALUEMAP_3OPS(FPR, 32);
160 CHECK_VALUEMAP_3OPS(FPR, 64);
161 CHECK_VALUEMAP_3OPS(FPR, 128);
162 CHECK_VALUEMAP_3OPS(FPR, 256);
163 CHECK_VALUEMAP_3OPS(FPR, 512);
164
165#define CHECK_VALUEMAP_CROSSREGCPY(RBNameDst, RBNameSrc, Size) \
166 do { \
167 unsigned PartialMapDstIdx = PMI_##RBNameDst##Size - PMI_Min; \
168 unsigned PartialMapSrcIdx = PMI_##RBNameSrc##Size - PMI_Min; \
169 (void)PartialMapDstIdx; \
170 (void)PartialMapSrcIdx; \
171 const ValueMapping *Map = getCopyMapping(AArch64::RBNameDst##RegBankID, \
172 AArch64::RBNameSrc##RegBankID, \
173 TypeSize::getFixed(Size)); \
174 (void)Map; \
175 assert(Map[0].BreakDown == \
176 &AArch64GenRegisterBankInfo::PartMappings[PartialMapDstIdx] && \
177 Map[0].NumBreakDowns == 1 && \
178 #RBNameDst #Size " Dst is incorrectly initialized"); \
179 assert(Map[1].BreakDown == \
180 &AArch64GenRegisterBankInfo::PartMappings[PartialMapSrcIdx] && \
181 Map[1].NumBreakDowns == 1 && \
182 #RBNameSrc #Size " Src is incorrectly initialized"); \
183 \
184 } while (false)
185
186 CHECK_VALUEMAP_CROSSREGCPY(GPR, GPR, 32);
187 CHECK_VALUEMAP_CROSSREGCPY(GPR, FPR, 32);
188 CHECK_VALUEMAP_CROSSREGCPY(GPR, GPR, 64);
189 CHECK_VALUEMAP_CROSSREGCPY(GPR, FPR, 64);
190 CHECK_VALUEMAP_CROSSREGCPY(FPR, FPR, 32);
191 CHECK_VALUEMAP_CROSSREGCPY(FPR, GPR, 32);
192 CHECK_VALUEMAP_CROSSREGCPY(FPR, FPR, 64);
193 CHECK_VALUEMAP_CROSSREGCPY(FPR, GPR, 64);
194
195#define CHECK_VALUEMAP_FPEXT(DstSize, SrcSize) \
196 do { \
197 unsigned PartialMapDstIdx = PMI_FPR##DstSize - PMI_Min; \
198 unsigned PartialMapSrcIdx = PMI_FPR##SrcSize - PMI_Min; \
199 (void)PartialMapDstIdx; \
200 (void)PartialMapSrcIdx; \
201 const ValueMapping *Map = getFPExtMapping(DstSize, SrcSize); \
202 (void)Map; \
203 assert(Map[0].BreakDown == \
204 &AArch64GenRegisterBankInfo::PartMappings[PartialMapDstIdx] && \
205 Map[0].NumBreakDowns == 1 && "FPR" #DstSize \
206 " Dst is incorrectly initialized"); \
207 assert(Map[1].BreakDown == \
208 &AArch64GenRegisterBankInfo::PartMappings[PartialMapSrcIdx] && \
209 Map[1].NumBreakDowns == 1 && "FPR" #SrcSize \
210 " Src is incorrectly initialized"); \
211 \
212 } while (false)
213
214 CHECK_VALUEMAP_FPEXT(32, 16);
215 CHECK_VALUEMAP_FPEXT(64, 16);
216 CHECK_VALUEMAP_FPEXT(64, 32);
217 CHECK_VALUEMAP_FPEXT(128, 64);
218
219 assert(verify(TRI) && "Invalid register bank information");
220 };
221
222 llvm::call_once(flag&: InitializeRegisterBankFlag, F&: InitializeRegisterBankOnce);
223}
224
225unsigned AArch64RegisterBankInfo::copyCost(const RegisterBank &A,
226 const RegisterBank &B,
227 const TypeSize Size) const {
228 // What do we do with different size?
229 // copy are same size.
230 // Will introduce other hooks for different size:
231 // * extract cost.
232 // * build_sequence cost.
233
234 // Copy from (resp. to) GPR to (resp. from) FPR involves FMOV.
235 // FIXME: This should be deduced from the scheduling model.
236 if (&A == &AArch64::GPRRegBank && &B == &AArch64::FPRRegBank)
237 // FMOVXDr or FMOVWSr.
238 return 5;
239 if (&A == &AArch64::FPRRegBank && &B == &AArch64::GPRRegBank)
240 // FMOVDXr or FMOVSWr.
241 return 4;
242
243 return RegisterBankInfo::copyCost(A, B, Size);
244}
245
246const RegisterBank &
247AArch64RegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC,
248 LLT Ty) const {
249 switch (RC.getID()) {
250 case AArch64::GPR64sponlyRegClassID:
251 return getRegBank(ID: AArch64::GPRRegBankID);
252 default:
253 return AArch64GenRegisterBankInfo::getRegBankFromRegClass(RC, Ty);
254 }
255}
256
257RegisterBankInfo::InstructionMappings
258AArch64RegisterBankInfo::getInstrAlternativeMappings(
259 const MachineInstr &MI) const {
260 const MachineFunction &MF = *MI.getParent()->getParent();
261 const TargetSubtargetInfo &STI = MF.getSubtarget();
262 const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
263 const MachineRegisterInfo &MRI = MF.getRegInfo();
264
265 switch (MI.getOpcode()) {
266 case TargetOpcode::G_OR: {
267 // 32 and 64-bit or can be mapped on either FPR or
268 // GPR for the same cost.
269 TypeSize Size = getSizeInBits(Reg: MI.getOperand(i: 0).getReg(), MRI, TRI);
270 if (Size != 32 && Size != 64)
271 break;
272
273 // If the instruction has any implicit-defs or uses,
274 // do not mess with it.
275 if (MI.getNumOperands() != 3)
276 break;
277 InstructionMappings AltMappings;
278 const InstructionMapping &GPRMapping = getInstructionMapping(
279 /*ID*/ 1, /*Cost*/ 1, OperandsMapping: getValueMapping(RBIdx: PMI_FirstGPR, Size),
280 /*NumOperands*/ 3);
281 const InstructionMapping &FPRMapping = getInstructionMapping(
282 /*ID*/ 2, /*Cost*/ 1, OperandsMapping: getValueMapping(RBIdx: PMI_FirstFPR, Size),
283 /*NumOperands*/ 3);
284
285 AltMappings.push_back(Elt: &GPRMapping);
286 AltMappings.push_back(Elt: &FPRMapping);
287 return AltMappings;
288 }
289 case TargetOpcode::G_BITCAST: {
290 TypeSize Size = getSizeInBits(Reg: MI.getOperand(i: 0).getReg(), MRI, TRI);
291 if (Size != 32 && Size != 64)
292 break;
293
294 // If the instruction has any implicit-defs or uses,
295 // do not mess with it.
296 if (MI.getNumOperands() != 2)
297 break;
298
299 InstructionMappings AltMappings;
300 const InstructionMapping &GPRMapping = getInstructionMapping(
301 /*ID*/ 1, /*Cost*/ 1,
302 OperandsMapping: getCopyMapping(DstBankID: AArch64::GPRRegBankID, SrcBankID: AArch64::GPRRegBankID, Size),
303 /*NumOperands*/ 2);
304 const InstructionMapping &FPRMapping = getInstructionMapping(
305 /*ID*/ 2, /*Cost*/ 1,
306 OperandsMapping: getCopyMapping(DstBankID: AArch64::FPRRegBankID, SrcBankID: AArch64::FPRRegBankID, Size),
307 /*NumOperands*/ 2);
308 const InstructionMapping &GPRToFPRMapping = getInstructionMapping(
309 /*ID*/ 3,
310 /*Cost*/
311 copyCost(A: AArch64::GPRRegBank, B: AArch64::FPRRegBank,
312 Size: TypeSize::getFixed(ExactSize: Size)),
313 OperandsMapping: getCopyMapping(DstBankID: AArch64::FPRRegBankID, SrcBankID: AArch64::GPRRegBankID, Size),
314 /*NumOperands*/ 2);
315 const InstructionMapping &FPRToGPRMapping = getInstructionMapping(
316 /*ID*/ 3,
317 /*Cost*/
318 copyCost(A: AArch64::GPRRegBank, B: AArch64::FPRRegBank,
319 Size: TypeSize::getFixed(ExactSize: Size)),
320 OperandsMapping: getCopyMapping(DstBankID: AArch64::GPRRegBankID, SrcBankID: AArch64::FPRRegBankID, Size),
321 /*NumOperands*/ 2);
322
323 AltMappings.push_back(Elt: &GPRMapping);
324 AltMappings.push_back(Elt: &FPRMapping);
325 AltMappings.push_back(Elt: &GPRToFPRMapping);
326 AltMappings.push_back(Elt: &FPRToGPRMapping);
327 return AltMappings;
328 }
329 case TargetOpcode::G_LOAD: {
330 TypeSize Size = getSizeInBits(Reg: MI.getOperand(i: 0).getReg(), MRI, TRI);
331 if (Size != 64)
332 break;
333
334 // If the instruction has any implicit-defs or uses,
335 // do not mess with it.
336 if (MI.getNumOperands() != 2)
337 break;
338
339 InstructionMappings AltMappings;
340 const InstructionMapping &GPRMapping = getInstructionMapping(
341 /*ID*/ 1, /*Cost*/ 1,
342 OperandsMapping: getOperandsMapping(
343 OpdsMapping: {getValueMapping(RBIdx: PMI_FirstGPR, Size),
344 // Addresses are GPR 64-bit.
345 getValueMapping(RBIdx: PMI_FirstGPR, Size: TypeSize::getFixed(ExactSize: 64))}),
346 /*NumOperands*/ 2);
347 const InstructionMapping &FPRMapping = getInstructionMapping(
348 /*ID*/ 2, /*Cost*/ 1,
349 OperandsMapping: getOperandsMapping(
350 OpdsMapping: {getValueMapping(RBIdx: PMI_FirstFPR, Size),
351 // Addresses are GPR 64-bit.
352 getValueMapping(RBIdx: PMI_FirstGPR, Size: TypeSize::getFixed(ExactSize: 64))}),
353 /*NumOperands*/ 2);
354
355 AltMappings.push_back(Elt: &GPRMapping);
356 AltMappings.push_back(Elt: &FPRMapping);
357 return AltMappings;
358 }
359 default:
360 break;
361 }
362 return RegisterBankInfo::getInstrAlternativeMappings(MI);
363}
364
365static bool preferGPRForFPImm(const MachineInstr &MI,
366 const MachineRegisterInfo &MRI,
367 const AArch64Subtarget &STI) {
368 assert(MI.getOpcode() == TargetOpcode::G_FCONSTANT);
369 Register Dst = MI.getOperand(i: 0).getReg();
370 LLT Ty = MRI.getType(Reg: Dst);
371
372 unsigned Size = Ty.getSizeInBits();
373 if (Size != 16 && Size != 32 && Size != 64)
374 return false;
375
376 EVT VT = EVT::getFloatingPointVT(BitWidth: Size);
377 const AArch64TargetLowering *TLI = STI.getTargetLowering();
378
379 const APFloat Imm = MI.getOperand(i: 1).getFPImm()->getValueAPF();
380 const APInt ImmBits = Imm.bitcastToAPInt();
381
382 // Check if we can encode this as a movi. Note, we only have one pattern so
383 // far for movis, hence the one check.
384 if (Size == 32) {
385 uint64_t Val = APInt::getSplat(NewLen: 64, V: ImmBits).getZExtValue();
386 if (AArch64_AM::isAdvSIMDModImmType4(Imm: Val))
387 return false;
388 }
389
390 // We want to use GPR when the value cannot be encoded as the immediate value
391 // of a fmov and when it will not result in a constant pool load. As
392 // AArch64TargetLowering::isFPImmLegal is used by the instruction selector
393 // to choose whether to emit a constant pool load, negating this check will
394 // ensure it would not have become a constant pool load.
395 bool OptForSize =
396 shouldOptimizeForSize(F: &MI.getMF()->getFunction(), PSI: nullptr, BFI: nullptr);
397 bool IsLegal = TLI->isFPImmLegal(Imm, VT, ForCodeSize: OptForSize);
398 bool IsFMov = TLI->isFPImmLegalAsFMov(Imm, VT);
399 return !IsFMov && IsLegal;
400}
401
402// Some of the instructions in applyMappingImpl attempt to anyext small values.
403// It may be that these values come from a G_CONSTANT that has been expanded to
404// 32 bits and then truncated. If this is the case, we shouldn't insert an
405// anyext and should instead make use of the G_CONSTANT directly, deleting the
406// trunc if possible.
407static bool foldTruncOfI32Constant(MachineInstr &MI, unsigned OpIdx,
408 MachineRegisterInfo &MRI,
409 const AArch64RegisterBankInfo &RBI) {
410 MachineOperand &Op = MI.getOperand(i: OpIdx);
411
412 Register ScalarReg = Op.getReg();
413 MachineInstr *TruncMI = MRI.getVRegDef(Reg: ScalarReg);
414 if (!TruncMI || TruncMI->getOpcode() != TargetOpcode::G_TRUNC)
415 return false;
416
417 Register TruncSrc = TruncMI->getOperand(i: 1).getReg();
418 MachineInstr *SrcDef = MRI.getVRegDef(Reg: TruncSrc);
419 if (!SrcDef || SrcDef->getOpcode() != TargetOpcode::G_CONSTANT)
420 return false;
421
422 LLT TruncSrcTy = MRI.getType(Reg: TruncSrc);
423 if (!TruncSrcTy.isScalar() || TruncSrcTy.getSizeInBits() != 32)
424 return false;
425
426 // Avoid truncating and extending a constant, this helps with selection.
427 Op.setReg(TruncSrc);
428 MRI.setRegBank(Reg: TruncSrc, RegBank: RBI.getRegBank(ID: AArch64::GPRRegBankID));
429
430 if (MRI.use_empty(RegNo: ScalarReg))
431 TruncMI->eraseFromParent();
432
433 return true;
434}
435
436void AArch64RegisterBankInfo::applyMappingImpl(
437 MachineIRBuilder &Builder, const OperandsMapper &OpdMapper) const {
438 MachineInstr &MI = OpdMapper.getMI();
439 MachineRegisterInfo &MRI = OpdMapper.getMRI();
440
441 switch (MI.getOpcode()) {
442 case TargetOpcode::G_CONSTANT: {
443 Register Dst = MI.getOperand(i: 0).getReg();
444 [[maybe_unused]] LLT DstTy = MRI.getType(Reg: Dst);
445 assert(MRI.getRegBank(Dst) == &AArch64::GPRRegBank && DstTy.isScalar() &&
446 DstTy.getSizeInBits() < 32 &&
447 "Expected a scalar smaller than 32 bits on a GPR.");
448 Builder.setInsertPt(MBB&: *MI.getParent(), II: std::next(x: MI.getIterator()));
449 Register ExtReg = MRI.createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: 32));
450 Builder.buildTrunc(Res: Dst, Op: ExtReg);
451
452 APInt Val = MI.getOperand(i: 1).getCImm()->getValue().zext(width: 32);
453 LLVMContext &Ctx = Builder.getMF().getFunction().getContext();
454 MI.getOperand(i: 1).setCImm(ConstantInt::get(Context&: Ctx, V: Val));
455 MI.getOperand(i: 0).setReg(ExtReg);
456 MRI.setRegBank(Reg: ExtReg, RegBank: AArch64::GPRRegBank);
457
458 return applyDefaultMapping(OpdMapper);
459 }
460 case TargetOpcode::G_FCONSTANT: {
461 Register Dst = MI.getOperand(i: 0).getReg();
462 assert(MRI.getRegBank(Dst) == &AArch64::GPRRegBank &&
463 "Expected Dst to be on a GPR.");
464 const APFloat &Imm = MI.getOperand(i: 1).getFPImm()->getValueAPF();
465 APInt Bits = Imm.bitcastToAPInt();
466 Builder.setInsertPt(MBB&: *MI.getParent(), II: MI.getIterator());
467 if (Bits.getBitWidth() < 32) {
468 Register ExtReg = MRI.createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: 32));
469 Builder.buildConstant(Res: ExtReg, Val: Bits.zext(width: 32));
470 Builder.buildTrunc(Res: Dst, Op: ExtReg);
471 MRI.setRegBank(Reg: ExtReg, RegBank: AArch64::GPRRegBank);
472 } else {
473 Builder.buildConstant(Res: Dst, Val: Bits);
474 }
475 MI.eraseFromParent();
476 return;
477 }
478 case TargetOpcode::G_STORE: {
479 Register Dst = MI.getOperand(i: 0).getReg();
480 LLT Ty = MRI.getType(Reg: Dst);
481
482 if (MRI.getRegBank(Reg: Dst) == &AArch64::GPRRegBank && Ty.isScalar() &&
483 Ty.getSizeInBits() < 32) {
484
485 if (foldTruncOfI32Constant(MI, OpIdx: 0, MRI, RBI: *this))
486 return applyDefaultMapping(OpdMapper);
487
488 Builder.setInsertPt(MBB&: *MI.getParent(), II: MI.getIterator());
489 auto Ext = Builder.buildAnyExt(Res: LLT::scalar(SizeInBits: 32), Op: Dst);
490 MI.getOperand(i: 0).setReg(Ext.getReg(Idx: 0));
491 MRI.setRegBank(Reg: Ext.getReg(Idx: 0), RegBank: AArch64::GPRRegBank);
492 }
493 return applyDefaultMapping(OpdMapper);
494 }
495 case TargetOpcode::G_LOAD: {
496 Register Dst = MI.getOperand(i: 0).getReg();
497 LLT Ty = MRI.getType(Reg: Dst);
498 if (MRI.getRegBank(Reg: Dst) == &AArch64::GPRRegBank && Ty.isScalar() &&
499 Ty.getSizeInBits() < 32) {
500 Builder.setInsertPt(MBB&: *MI.getParent(), II: std::next(x: MI.getIterator()));
501 Register ExtReg = MRI.createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: 32));
502 Builder.buildTrunc(Res: Dst, Op: ExtReg);
503 MI.getOperand(i: 0).setReg(ExtReg);
504 MRI.setRegBank(Reg: ExtReg, RegBank: AArch64::GPRRegBank);
505 }
506 [[fallthrough]];
507 }
508 case TargetOpcode::G_OR:
509 case TargetOpcode::G_BITCAST:
510 // Those ID must match getInstrAlternativeMappings.
511 assert((OpdMapper.getInstrMapping().getID() >= 1 &&
512 OpdMapper.getInstrMapping().getID() <= 4) &&
513 "Don't know how to handle that ID");
514 return applyDefaultMapping(OpdMapper);
515 case TargetOpcode::G_INSERT_VECTOR_ELT: {
516 if (foldTruncOfI32Constant(MI, OpIdx: 2, MRI, RBI: *this))
517 return applyDefaultMapping(OpdMapper);
518
519 // Extend smaller gpr operands to 32 bit.
520 Builder.setInsertPt(MBB&: *MI.getParent(), II: MI.getIterator());
521 auto Ext = Builder.buildAnyExt(Res: LLT::scalar(SizeInBits: 32), Op: MI.getOperand(i: 2).getReg());
522 MRI.setRegBank(Reg: Ext.getReg(Idx: 0), RegBank: getRegBank(ID: AArch64::GPRRegBankID));
523 MI.getOperand(i: 2).setReg(Ext.getReg(Idx: 0));
524 return applyDefaultMapping(OpdMapper);
525 }
526 case AArch64::G_DUP: {
527 if (foldTruncOfI32Constant(MI, OpIdx: 1, MRI, RBI: *this))
528 return applyDefaultMapping(OpdMapper);
529
530 // Extend smaller gpr to 32-bits
531 assert(MRI.getType(MI.getOperand(1).getReg()).getSizeInBits() < 32 &&
532 "Expected sources smaller than 32-bits");
533 Builder.setInsertPt(MBB&: *MI.getParent(), II: MI.getIterator());
534
535 Register ConstReg =
536 Builder.buildAnyExt(Res: LLT::scalar(SizeInBits: 32), Op: MI.getOperand(i: 1).getReg())
537 .getReg(Idx: 0);
538 MRI.setRegBank(Reg: ConstReg, RegBank: getRegBank(ID: AArch64::GPRRegBankID));
539 MI.getOperand(i: 1).setReg(ConstReg);
540
541 return applyDefaultMapping(OpdMapper);
542 }
543 default:
544 llvm_unreachable("Don't know how to handle that operation");
545 }
546}
547
548const RegisterBankInfo::InstructionMapping &
549AArch64RegisterBankInfo::getSameKindOfOperandsMapping(
550 const MachineInstr &MI) const {
551 const unsigned Opc = MI.getOpcode();
552 const MachineFunction &MF = *MI.getParent()->getParent();
553 const MachineRegisterInfo &MRI = MF.getRegInfo();
554
555 unsigned NumOperands = MI.getNumOperands();
556 assert(NumOperands <= 3 &&
557 "This code is for instructions with 3 or less operands");
558
559 LLT Ty = MRI.getType(Reg: MI.getOperand(i: 0).getReg());
560 TypeSize Size = Ty.getSizeInBits();
561 bool IsFPR = Ty.isVector() || isPreISelGenericFloatingPointOpcode(Opc);
562
563 PartialMappingIdx RBIdx = IsFPR ? PMI_FirstFPR : PMI_FirstGPR;
564
565#ifndef NDEBUG
566 // Make sure all the operands are using similar size and type.
567 // Should probably be checked by the machine verifier.
568 // This code won't catch cases where the number of lanes is
569 // different between the operands.
570 // If we want to go to that level of details, it is probably
571 // best to check that the types are the same, period.
572 // Currently, we just check that the register banks are the same
573 // for each types.
574 for (unsigned Idx = 1; Idx != NumOperands; ++Idx) {
575 LLT OpTy = MRI.getType(MI.getOperand(Idx).getReg());
576 assert(
577 AArch64GenRegisterBankInfo::getRegBankBaseIdxOffset(
578 RBIdx, OpTy.getSizeInBits()) ==
579 AArch64GenRegisterBankInfo::getRegBankBaseIdxOffset(RBIdx, Size) &&
580 "Operand has incompatible size");
581 bool OpIsFPR = OpTy.isVector() || isPreISelGenericFloatingPointOpcode(Opc);
582 (void)OpIsFPR;
583 assert(IsFPR == OpIsFPR && "Operand has incompatible type");
584 }
585#endif // End NDEBUG.
586
587 return getInstructionMapping(ID: DefaultMappingID, Cost: 1,
588 OperandsMapping: getValueMapping(RBIdx, Size), NumOperands);
589}
590
591/// \returns true if a given intrinsic only uses and defines FPRs.
592static bool isFPIntrinsic(const MachineRegisterInfo &MRI,
593 const MachineInstr &MI) {
594 // TODO: Add more intrinsics.
595 switch (cast<GIntrinsic>(Val: MI).getIntrinsicID()) {
596 default:
597 return false;
598 case Intrinsic::aarch64_neon_uaddlv:
599 case Intrinsic::aarch64_neon_uaddv:
600 case Intrinsic::aarch64_neon_saddv:
601 case Intrinsic::aarch64_neon_umaxv:
602 case Intrinsic::aarch64_neon_smaxv:
603 case Intrinsic::aarch64_neon_uminv:
604 case Intrinsic::aarch64_neon_sminv:
605 case Intrinsic::aarch64_neon_faddv:
606 case Intrinsic::aarch64_neon_fmaxv:
607 case Intrinsic::aarch64_neon_fminv:
608 case Intrinsic::aarch64_neon_fmaxnmv:
609 case Intrinsic::aarch64_neon_fminnmv:
610 case Intrinsic::aarch64_neon_fmulx:
611 case Intrinsic::aarch64_neon_frecpe:
612 case Intrinsic::aarch64_neon_frecps:
613 case Intrinsic::aarch64_neon_frecpx:
614 case Intrinsic::aarch64_neon_frsqrte:
615 case Intrinsic::aarch64_neon_frsqrts:
616 case Intrinsic::aarch64_neon_facge:
617 case Intrinsic::aarch64_neon_facgt:
618 case Intrinsic::aarch64_neon_fabd:
619 case Intrinsic::aarch64_neon_sqrdmlah:
620 case Intrinsic::aarch64_neon_sqrdmlsh:
621 case Intrinsic::aarch64_neon_sqrdmulh:
622 case Intrinsic::aarch64_neon_suqadd:
623 case Intrinsic::aarch64_neon_usqadd:
624 case Intrinsic::aarch64_neon_uqadd:
625 case Intrinsic::aarch64_neon_sqadd:
626 case Intrinsic::aarch64_neon_uqsub:
627 case Intrinsic::aarch64_neon_sqsub:
628 case Intrinsic::aarch64_neon_srshl:
629 case Intrinsic::aarch64_neon_urshl:
630 case Intrinsic::aarch64_neon_sqshl:
631 case Intrinsic::aarch64_neon_uqshl:
632 case Intrinsic::aarch64_neon_sqrshl:
633 case Intrinsic::aarch64_neon_uqrshl:
634 case Intrinsic::aarch64_neon_ushl:
635 case Intrinsic::aarch64_neon_sshl:
636 case Intrinsic::aarch64_neon_sqshrn:
637 case Intrinsic::aarch64_neon_sqshrun:
638 case Intrinsic::aarch64_neon_sqrshrn:
639 case Intrinsic::aarch64_neon_sqrshrun:
640 case Intrinsic::aarch64_neon_uqshrn:
641 case Intrinsic::aarch64_neon_uqrshrn:
642 case Intrinsic::aarch64_crypto_sha1h:
643 case Intrinsic::aarch64_crypto_sha1c:
644 case Intrinsic::aarch64_crypto_sha1p:
645 case Intrinsic::aarch64_crypto_sha1m:
646 case Intrinsic::aarch64_sisd_fcvtxn:
647 case Intrinsic::aarch64_sisd_fabd:
648 return true;
649 case Intrinsic::aarch64_neon_saddlv: {
650 const LLT SrcTy = MRI.getType(Reg: MI.getOperand(i: 2).getReg());
651 return SrcTy.getElementType().getSizeInBits() >= 16 &&
652 SrcTy.getElementCount().getFixedValue() >= 4;
653 }
654 }
655}
656
657bool AArch64RegisterBankInfo::isPHIWithFPConstraints(
658 const MachineInstr &MI, const MachineRegisterInfo &MRI,
659 const AArch64RegisterInfo &TRI, const unsigned Depth) const {
660 if (!MI.isPHI() || Depth > MaxFPRSearchDepth)
661 return false;
662
663 return any_of(Range: MRI.use_nodbg_instructions(Reg: MI.getOperand(i: 0).getReg()),
664 P: [&](const MachineInstr &UseMI) {
665 if (onlyUsesFP(MI: UseMI, MRI, TRI, Depth: Depth + 1))
666 return true;
667 return isPHIWithFPConstraints(MI: UseMI, MRI, TRI, Depth: Depth + 1);
668 });
669}
670
671bool AArch64RegisterBankInfo::hasFPConstraints(const MachineInstr &MI,
672 const MachineRegisterInfo &MRI,
673 const AArch64RegisterInfo &TRI,
674 unsigned Depth) const {
675 unsigned Op = MI.getOpcode();
676 if (Op == TargetOpcode::G_INTRINSIC && isFPIntrinsic(MRI, MI))
677 return true;
678
679 // Do we have an explicit floating point instruction?
680 if (isPreISelGenericFloatingPointOpcode(Opc: Op))
681 return true;
682
683 // No. Check if we have a copy-like instruction. If we do, then we could
684 // still be fed by floating point instructions.
685 if (Op != TargetOpcode::COPY && !MI.isPHI() &&
686 !isPreISelGenericOptimizationHint(Opcode: Op))
687 return false;
688
689 // Check if we already know the register bank.
690 auto *RB = getRegBank(Reg: MI.getOperand(i: 0).getReg(), MRI, TRI);
691 if (RB == &AArch64::FPRRegBank)
692 return true;
693 if (RB == &AArch64::GPRRegBank)
694 return false;
695
696 // We don't know anything.
697 //
698 // If we have a phi, we may be able to infer that it will be assigned a FPR
699 // based off of its inputs.
700 if (!MI.isPHI() || Depth > MaxFPRSearchDepth)
701 return false;
702
703 return any_of(Range: MI.explicit_uses(), P: [&](const MachineOperand &Op) {
704 return Op.isReg() &&
705 onlyDefinesFP(MI: *MRI.getVRegDef(Reg: Op.getReg()), MRI, TRI, Depth: Depth + 1);
706 });
707}
708
709bool AArch64RegisterBankInfo::onlyUsesFP(const MachineInstr &MI,
710 const MachineRegisterInfo &MRI,
711 const AArch64RegisterInfo &TRI,
712 unsigned Depth) const {
713 switch (MI.getOpcode()) {
714 case TargetOpcode::G_FPTOSI:
715 case TargetOpcode::G_FPTOUI:
716 case TargetOpcode::G_FPTOSI_SAT:
717 case TargetOpcode::G_FPTOUI_SAT:
718 case TargetOpcode::G_FCMP:
719 case TargetOpcode::G_LROUND:
720 case TargetOpcode::G_LLROUND:
721 case AArch64::G_PMULL:
722 case AArch64::G_SLI:
723 case AArch64::G_SRI:
724 return true;
725 case TargetOpcode::G_INTRINSIC:
726 switch (cast<GIntrinsic>(Val: MI).getIntrinsicID()) {
727 case Intrinsic::aarch64_neon_fcvtas:
728 case Intrinsic::aarch64_neon_fcvtau:
729 case Intrinsic::aarch64_neon_fcvtzs:
730 case Intrinsic::aarch64_neon_fcvtzu:
731 case Intrinsic::aarch64_neon_fcvtms:
732 case Intrinsic::aarch64_neon_fcvtmu:
733 case Intrinsic::aarch64_neon_fcvtns:
734 case Intrinsic::aarch64_neon_fcvtnu:
735 case Intrinsic::aarch64_neon_fcvtps:
736 case Intrinsic::aarch64_neon_fcvtpu:
737 return true;
738 default:
739 break;
740 }
741 break;
742 default:
743 break;
744 }
745 return hasFPConstraints(MI, MRI, TRI, Depth);
746}
747
748bool AArch64RegisterBankInfo::onlyDefinesFP(const MachineInstr &MI,
749 const MachineRegisterInfo &MRI,
750 const AArch64RegisterInfo &TRI,
751 unsigned Depth) const {
752 switch (MI.getOpcode()) {
753 case AArch64::G_DUP:
754 case AArch64::G_SADDLP:
755 case AArch64::G_UADDLP:
756 case TargetOpcode::G_SITOFP:
757 case TargetOpcode::G_UITOFP:
758 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
759 case TargetOpcode::G_INSERT_VECTOR_ELT:
760 case TargetOpcode::G_BUILD_VECTOR:
761 case TargetOpcode::G_BUILD_VECTOR_TRUNC:
762 case AArch64::G_SLI:
763 case AArch64::G_SRI:
764 return true;
765 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
766 switch (cast<GIntrinsic>(Val: MI).getIntrinsicID()) {
767 case Intrinsic::aarch64_neon_ld1x2:
768 case Intrinsic::aarch64_neon_ld1x3:
769 case Intrinsic::aarch64_neon_ld1x4:
770 case Intrinsic::aarch64_neon_ld2:
771 case Intrinsic::aarch64_neon_ld2lane:
772 case Intrinsic::aarch64_neon_ld2r:
773 case Intrinsic::aarch64_neon_ld3:
774 case Intrinsic::aarch64_neon_ld3lane:
775 case Intrinsic::aarch64_neon_ld3r:
776 case Intrinsic::aarch64_neon_ld4:
777 case Intrinsic::aarch64_neon_ld4lane:
778 case Intrinsic::aarch64_neon_ld4r:
779 return true;
780 default:
781 break;
782 }
783 break;
784 default:
785 break;
786 }
787 return hasFPConstraints(MI, MRI, TRI, Depth);
788}
789
790bool AArch64RegisterBankInfo::prefersFPUse(const MachineInstr &MI,
791 const MachineRegisterInfo &MRI,
792 const AArch64RegisterInfo &TRI,
793 unsigned Depth) const {
794 switch (MI.getOpcode()) {
795 case TargetOpcode::G_SITOFP:
796 case TargetOpcode::G_UITOFP:
797 return MRI.getType(Reg: MI.getOperand(i: 0).getReg()).getSizeInBits() ==
798 MRI.getType(Reg: MI.getOperand(i: 1).getReg()).getSizeInBits();
799 }
800 return onlyDefinesFP(MI, MRI, TRI, Depth);
801}
802
803bool AArch64RegisterBankInfo::isLoadFromFPType(const MachineInstr &MI) const {
804 // GMemOperation because we also want to match indexed loads.
805 auto *MemOp = cast<GMemOperation>(Val: &MI);
806 const Value *LdVal = MemOp->getMMO().getValue();
807 if (!LdVal)
808 return false;
809
810 Type *EltTy = nullptr;
811 if (const GlobalValue *GV = dyn_cast<GlobalValue>(Val: LdVal)) {
812 EltTy = GV->getValueType();
813 // Look at the first element of the struct to determine the type we are
814 // loading
815 while (StructType *StructEltTy = dyn_cast<StructType>(Val: EltTy)) {
816 if (StructEltTy->getNumElements() == 0)
817 break;
818 EltTy = StructEltTy->getTypeAtIndex(N: 0U);
819 }
820 // Look at the first element of the array to determine its type
821 if (isa<ArrayType>(Val: EltTy))
822 EltTy = EltTy->getArrayElementType();
823 } else if (!isa<Constant>(Val: LdVal)) {
824 // FIXME: grubbing around uses is pretty ugly, but with no more
825 // `getPointerElementType` there's not much else we can do.
826 for (const auto *LdUser : LdVal->users()) {
827 if (isa<LoadInst>(Val: LdUser)) {
828 EltTy = LdUser->getType();
829 break;
830 }
831 if (isa<StoreInst>(Val: LdUser) && LdUser->getOperand(i: 1) == LdVal) {
832 EltTy = LdUser->getOperand(i: 0)->getType();
833 break;
834 }
835 }
836 }
837 return EltTy && EltTy->isFPOrFPVectorTy();
838}
839
840const RegisterBankInfo::InstructionMapping &
841AArch64RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
842 const unsigned Opc = MI.getOpcode();
843
844 // Try the default logic for non-generic instructions that are either copies
845 // or already have some operands assigned to banks.
846 if ((Opc != TargetOpcode::COPY && !isPreISelGenericOpcode(Opcode: Opc)) ||
847 Opc == TargetOpcode::G_PHI) {
848 const RegisterBankInfo::InstructionMapping &Mapping =
849 getInstrMappingImpl(MI);
850 if (Mapping.isValid())
851 return Mapping;
852 }
853
854 const MachineFunction &MF = *MI.getParent()->getParent();
855 const MachineRegisterInfo &MRI = MF.getRegInfo();
856 const AArch64Subtarget &STI = MF.getSubtarget<AArch64Subtarget>();
857 const AArch64RegisterInfo &TRI = *STI.getRegisterInfo();
858
859 switch (Opc) {
860 // G_{F|S|U}REM are not listed because they are not legal.
861 // Arithmetic ops.
862 case TargetOpcode::G_ADD:
863 case TargetOpcode::G_SUB:
864 case TargetOpcode::G_PTR_ADD:
865 case TargetOpcode::G_MUL:
866 case TargetOpcode::G_SDIV:
867 case TargetOpcode::G_UDIV:
868 // Bitwise ops.
869 case TargetOpcode::G_AND:
870 case TargetOpcode::G_OR:
871 case TargetOpcode::G_XOR:
872 // Floating point ops.
873 case TargetOpcode::G_FADD:
874 case TargetOpcode::G_FSUB:
875 case TargetOpcode::G_FMUL:
876 case TargetOpcode::G_FDIV:
877 case TargetOpcode::G_FMAXIMUM:
878 case TargetOpcode::G_FMINIMUM:
879 return getSameKindOfOperandsMapping(MI);
880 case TargetOpcode::G_FPEXT: {
881 LLT DstTy = MRI.getType(Reg: MI.getOperand(i: 0).getReg());
882 LLT SrcTy = MRI.getType(Reg: MI.getOperand(i: 1).getReg());
883 return getInstructionMapping(
884 ID: DefaultMappingID, /*Cost*/ 1,
885 OperandsMapping: getFPExtMapping(DstSize: DstTy.getSizeInBits(), SrcSize: SrcTy.getSizeInBits()),
886 /*NumOperands*/ 2);
887 }
888 // Shifts.
889 case TargetOpcode::G_SHL:
890 case TargetOpcode::G_LSHR:
891 case TargetOpcode::G_ASHR: {
892 LLT ShiftAmtTy = MRI.getType(Reg: MI.getOperand(i: 2).getReg());
893 LLT SrcTy = MRI.getType(Reg: MI.getOperand(i: 1).getReg());
894 if (ShiftAmtTy.getSizeInBits() == 64 && SrcTy.getSizeInBits() == 32)
895 return getInstructionMapping(ID: DefaultMappingID, Cost: 1,
896 OperandsMapping: &ValMappings[Shift64Imm], NumOperands: 3);
897 return getSameKindOfOperandsMapping(MI);
898 }
899 case TargetOpcode::COPY: {
900 Register DstReg = MI.getOperand(i: 0).getReg();
901 Register SrcReg = MI.getOperand(i: 1).getReg();
902 // Check if one of the register is not a generic register.
903 if ((DstReg.isPhysical() || !MRI.getType(Reg: DstReg).isValid()) ||
904 (SrcReg.isPhysical() || !MRI.getType(Reg: SrcReg).isValid())) {
905 const RegisterBank *DstRB = getRegBank(Reg: DstReg, MRI, TRI);
906 const RegisterBank *SrcRB = getRegBank(Reg: SrcReg, MRI, TRI);
907 if (!DstRB)
908 DstRB = SrcRB;
909 else if (!SrcRB)
910 SrcRB = DstRB;
911 // If both RB are null that means both registers are generic.
912 // We shouldn't be here.
913 assert(DstRB && SrcRB && "Both RegBank were nullptr");
914 TypeSize Size = getSizeInBits(Reg: DstReg, MRI, TRI);
915 return getInstructionMapping(
916 ID: DefaultMappingID, Cost: copyCost(A: *DstRB, B: *SrcRB, Size),
917 OperandsMapping: getCopyMapping(DstBankID: DstRB->getID(), SrcBankID: SrcRB->getID(), Size),
918 // We only care about the mapping of the destination.
919 /*NumOperands*/ 1);
920 }
921 // Both registers are generic, use G_BITCAST.
922 [[fallthrough]];
923 }
924 case TargetOpcode::G_BITCAST: {
925 LLT DstTy = MRI.getType(Reg: MI.getOperand(i: 0).getReg());
926 LLT SrcTy = MRI.getType(Reg: MI.getOperand(i: 1).getReg());
927 TypeSize Size = DstTy.getSizeInBits();
928 bool DstIsGPR = !DstTy.isVector() && DstTy.getSizeInBits() <= 64;
929 bool SrcIsGPR = !SrcTy.isVector() && SrcTy.getSizeInBits() <= 64;
930 const RegisterBank &DstRB =
931 DstIsGPR ? AArch64::GPRRegBank : AArch64::FPRRegBank;
932 const RegisterBank &SrcRB =
933 SrcIsGPR ? AArch64::GPRRegBank : AArch64::FPRRegBank;
934 return getInstructionMapping(
935 ID: DefaultMappingID, Cost: copyCost(A: DstRB, B: SrcRB, Size),
936 OperandsMapping: getCopyMapping(DstBankID: DstRB.getID(), SrcBankID: SrcRB.getID(), Size),
937 // We only care about the mapping of the destination for COPY.
938 /*NumOperands*/ Opc == TargetOpcode::G_BITCAST ? 2 : 1);
939 }
940 default:
941 break;
942 }
943
944 unsigned NumOperands = MI.getNumOperands();
945 unsigned MappingID = DefaultMappingID;
946
947 // Track the size and bank of each register. We don't do partial mappings.
948 SmallVector<unsigned, 4> OpSize(NumOperands);
949 SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands);
950 for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
951 auto &MO = MI.getOperand(i: Idx);
952 if (!MO.isReg() || !MO.getReg())
953 continue;
954
955 LLT Ty = MRI.getType(Reg: MO.getReg());
956 if (!Ty.isValid())
957 continue;
958 OpSize[Idx] = Ty.getSizeInBits().getKnownMinValue();
959
960 // As a top-level guess, vectors including both scalable and non-scalable
961 // ones go in FPRs, scalars and pointers in GPRs.
962 // For floating-point instructions, scalars go in FPRs.
963 if (Ty.isVector())
964 OpRegBankIdx[Idx] = PMI_FirstFPR;
965 else if (isPreISelGenericFloatingPointOpcode(Opc) ||
966 (MO.isDef() && onlyDefinesFP(MI, MRI, TRI)) ||
967 (MO.isUse() && onlyUsesFP(MI, MRI, TRI)) ||
968 Ty.getSizeInBits() > 64)
969 OpRegBankIdx[Idx] = PMI_FirstFPR;
970 else
971 OpRegBankIdx[Idx] = PMI_FirstGPR;
972 }
973
974 unsigned Cost = 1;
975 // Some of the floating-point instructions have mixed GPR and FPR operands:
976 // fine-tune the computed mapping.
977 switch (Opc) {
978 case TargetOpcode::G_CONSTANT: {
979 Register Dst = MI.getOperand(i: 0).getReg();
980 LLT DstTy = MRI.getType(Reg: Dst);
981 if (DstTy.isScalar() && DstTy.getSizeInBits() < 32)
982 MappingID = CustomMappingID;
983 break;
984 }
985 case TargetOpcode::G_FCONSTANT: {
986 if (preferGPRForFPImm(MI, MRI, STI)) {
987 // Materialize in GPR and rely on later bank copies for FP uses.
988 MappingID = CustomMappingID;
989 OpRegBankIdx = {PMI_FirstGPR};
990 }
991 break;
992 }
993 case AArch64::G_DUP: {
994 Register ScalarReg = MI.getOperand(i: 1).getReg();
995 LLT ScalarTy = MRI.getType(Reg: ScalarReg);
996 auto ScalarDef = MRI.getVRegDef(Reg: ScalarReg);
997 // We want to select dup(load) into LD1R.
998 if (ScalarDef->getOpcode() == TargetOpcode::G_LOAD)
999 OpRegBankIdx = {PMI_FirstFPR, PMI_FirstFPR};
1000 // s8 is an exception for G_DUP, which we always want on gpr.
1001 else if (ScalarTy.getSizeInBits() != 8 &&
1002 (getRegBank(Reg: ScalarReg, MRI, TRI) == &AArch64::FPRRegBank ||
1003 onlyDefinesFP(MI: *ScalarDef, MRI, TRI)))
1004 OpRegBankIdx = {PMI_FirstFPR, PMI_FirstFPR};
1005 else {
1006 if (ScalarTy.getSizeInBits() < 32 &&
1007 getRegBank(Reg: ScalarReg, MRI, TRI) == &AArch64::GPRRegBank) {
1008 // Calls applyMappingImpl()
1009 MappingID = CustomMappingID;
1010 }
1011 OpRegBankIdx = {PMI_FirstFPR, PMI_FirstGPR};
1012 }
1013 break;
1014 }
1015 case TargetOpcode::G_TRUNC: {
1016 LLT SrcTy = MRI.getType(Reg: MI.getOperand(i: 1).getReg());
1017 if (!SrcTy.isVector() && SrcTy.getSizeInBits() == 128)
1018 OpRegBankIdx = {PMI_FirstFPR, PMI_FirstFPR};
1019 break;
1020 }
1021 case TargetOpcode::G_SITOFP:
1022 case TargetOpcode::G_UITOFP: {
1023 if (MRI.getType(Reg: MI.getOperand(i: 0).getReg()).isVector())
1024 break;
1025 // Integer to FP conversions don't necessarily happen between GPR -> FPR
1026 // regbanks. They can also be done within an FPR register.
1027 Register SrcReg = MI.getOperand(i: 1).getReg();
1028 if (getRegBank(Reg: SrcReg, MRI, TRI) == &AArch64::FPRRegBank &&
1029 MRI.getType(Reg: SrcReg).getSizeInBits() ==
1030 MRI.getType(Reg: MI.getOperand(i: 0).getReg()).getSizeInBits())
1031 OpRegBankIdx = {PMI_FirstFPR, PMI_FirstFPR};
1032 else
1033 OpRegBankIdx = {PMI_FirstFPR, PMI_FirstGPR};
1034 break;
1035 }
1036 case TargetOpcode::G_FPTOSI_SAT:
1037 case TargetOpcode::G_FPTOUI_SAT:
1038 case TargetOpcode::G_FPTOSI:
1039 case TargetOpcode::G_FPTOUI:
1040 case TargetOpcode::G_INTRINSIC_LRINT:
1041 case TargetOpcode::G_INTRINSIC_LLRINT:
1042 case TargetOpcode::G_LROUND:
1043 case TargetOpcode::G_LLROUND: {
1044 LLT DstType = MRI.getType(Reg: MI.getOperand(i: 0).getReg());
1045 if (DstType.isVector())
1046 break;
1047 if (DstType == LLT::scalar(SizeInBits: 16)) {
1048 OpRegBankIdx = {PMI_FirstFPR, PMI_FirstFPR};
1049 break;
1050 }
1051 TypeSize DstSize = getSizeInBits(Reg: MI.getOperand(i: 0).getReg(), MRI, TRI);
1052 TypeSize SrcSize = getSizeInBits(Reg: MI.getOperand(i: 1).getReg(), MRI, TRI);
1053 if (((DstSize == SrcSize) || STI.hasFeature(Feature: AArch64::FeatureFPRCVT)) &&
1054 all_of(Range: MRI.use_nodbg_instructions(Reg: MI.getOperand(i: 0).getReg()),
1055 P: [&](const MachineInstr &UseMI) {
1056 return onlyUsesFP(MI: UseMI, MRI, TRI) ||
1057 prefersFPUse(MI: UseMI, MRI, TRI);
1058 }))
1059 OpRegBankIdx = {PMI_FirstFPR, PMI_FirstFPR};
1060 else
1061 OpRegBankIdx = {PMI_FirstGPR, PMI_FirstFPR};
1062 break;
1063 }
1064 case TargetOpcode::G_FCMP: {
1065 // If the result is a vector, it must use a FPR.
1066 AArch64GenRegisterBankInfo::PartialMappingIdx Idx0 =
1067 MRI.getType(Reg: MI.getOperand(i: 0).getReg()).isVector() ? PMI_FirstFPR
1068 : PMI_FirstGPR;
1069 OpRegBankIdx = {Idx0,
1070 /* Predicate */ PMI_None, PMI_FirstFPR, PMI_FirstFPR};
1071 break;
1072 }
1073 case TargetOpcode::G_BITCAST:
1074 // This is going to be a cross register bank copy and this is expensive.
1075 if (OpRegBankIdx[0] != OpRegBankIdx[1])
1076 Cost = copyCost(
1077 A: *AArch64GenRegisterBankInfo::PartMappings[OpRegBankIdx[0]].RegBank,
1078 B: *AArch64GenRegisterBankInfo::PartMappings[OpRegBankIdx[1]].RegBank,
1079 Size: TypeSize::getFixed(ExactSize: OpSize[0]));
1080 break;
1081 case TargetOpcode::G_LOAD: {
1082 // Loading in vector unit is slightly more expensive.
1083 // This is actually only true for the LD1R and co instructions,
1084 // but anyway for the fast mode this number does not matter and
1085 // for the greedy mode the cost of the cross bank copy will
1086 // offset this number.
1087 // FIXME: Should be derived from the scheduling model.
1088 if (OpRegBankIdx[0] != PMI_FirstGPR) {
1089 Cost = 2;
1090 break;
1091 }
1092
1093 if (cast<GLoad>(Val: MI).isAtomic()) {
1094 // Atomics always use GPR destinations. Don't refine any further.
1095 OpRegBankIdx[0] = PMI_FirstGPR;
1096 if (MRI.getType(Reg: MI.getOperand(i: 0).getReg()).getSizeInBits() < 32)
1097 MappingID = CustomMappingID;
1098 break;
1099 }
1100
1101 // Try to guess the type of the load from the MMO.
1102 if (isLoadFromFPType(MI)) {
1103 OpRegBankIdx[0] = PMI_FirstFPR;
1104 break;
1105 }
1106
1107 // Check if that load feeds fp instructions.
1108 // In that case, we want the default mapping to be on FPR
1109 // instead of blind map every scalar to GPR.
1110 if (any_of(Range: MRI.use_nodbg_instructions(Reg: MI.getOperand(i: 0).getReg()),
1111 P: [&](const MachineInstr &UseMI) {
1112 // If we have at least one direct or indirect use
1113 // in a FP instruction,
1114 // assume this was a floating point load in the IR. If it was
1115 // not, we would have had a bitcast before reaching that
1116 // instruction.
1117 //
1118 // Int->FP conversion operations are also captured in
1119 // prefersFPUse().
1120
1121 if (isPHIWithFPConstraints(MI: UseMI, MRI, TRI))
1122 return true;
1123
1124 return onlyUsesFP(MI: UseMI, MRI, TRI) ||
1125 prefersFPUse(MI: UseMI, MRI, TRI);
1126 }))
1127 OpRegBankIdx[0] = PMI_FirstFPR;
1128
1129 // On GPR, extend any load < 32bits to 32bit.
1130 LLT Ty = MRI.getType(Reg: MI.getOperand(i: 0).getReg());
1131 if (Ty.isScalar() && Ty.getSizeInBits() < 32)
1132 MappingID = CustomMappingID;
1133 break;
1134 }
1135 case TargetOpcode::G_STORE:
1136 // Check if that store is fed by fp instructions.
1137 if (OpRegBankIdx[0] == PMI_FirstGPR) {
1138 Register VReg = MI.getOperand(i: 0).getReg();
1139 if (VReg) {
1140 MachineInstr *DefMI = MRI.getVRegDef(Reg: VReg);
1141 if (onlyDefinesFP(MI: *DefMI, MRI, TRI)) {
1142 OpRegBankIdx[0] = PMI_FirstFPR;
1143 break;
1144 }
1145 }
1146
1147 // On GPR, extend any store < 32bits to 32bit.
1148 LLT Ty = MRI.getType(Reg: MI.getOperand(i: 0).getReg());
1149 if (Ty.isScalar() && Ty.getSizeInBits() < 32)
1150 MappingID = CustomMappingID;
1151 }
1152 break;
1153 case TargetOpcode::G_INDEXED_STORE:
1154 if (OpRegBankIdx[1] == PMI_FirstGPR) {
1155 Register VReg = MI.getOperand(i: 1).getReg();
1156 if (!VReg)
1157 break;
1158 MachineInstr *DefMI = MRI.getVRegDef(Reg: VReg);
1159 if (onlyDefinesFP(MI: *DefMI, MRI, TRI))
1160 OpRegBankIdx[1] = PMI_FirstFPR;
1161 break;
1162 }
1163 break;
1164 case TargetOpcode::G_INDEXED_SEXTLOAD:
1165 case TargetOpcode::G_INDEXED_ZEXTLOAD:
1166 // These should always be GPR.
1167 OpRegBankIdx[0] = PMI_FirstGPR;
1168 break;
1169 case TargetOpcode::G_INDEXED_LOAD: {
1170 if (isLoadFromFPType(MI))
1171 OpRegBankIdx[0] = PMI_FirstFPR;
1172 break;
1173 }
1174 case TargetOpcode::G_SELECT: {
1175 // If the destination is FPR, preserve that.
1176 if (OpRegBankIdx[0] != PMI_FirstGPR)
1177 break;
1178
1179 // If we're taking in vectors, we have no choice but to put everything on
1180 // FPRs, except for the condition. The condition must always be on a GPR.
1181 LLT SrcTy = MRI.getType(Reg: MI.getOperand(i: 2).getReg());
1182 if (SrcTy.isVector()) {
1183 OpRegBankIdx = {PMI_FirstFPR, PMI_FirstGPR, PMI_FirstFPR, PMI_FirstFPR};
1184 break;
1185 }
1186
1187 // Try to minimize the number of copies. If we have more floating point
1188 // constrained values than not, then we'll put everything on FPR. Otherwise,
1189 // everything has to be on GPR.
1190 unsigned NumFP = 0;
1191
1192 // Check if the uses of the result always produce floating point values.
1193 //
1194 // For example:
1195 //
1196 // %z = G_SELECT %cond %x %y
1197 // fpr = G_FOO %z ...
1198 if (any_of(Range: MRI.use_nodbg_instructions(Reg: MI.getOperand(i: 0).getReg()),
1199 P: [&](MachineInstr &MI) { return onlyUsesFP(MI, MRI, TRI); }))
1200 ++NumFP;
1201
1202 // Check if the defs of the source values always produce floating point
1203 // values.
1204 //
1205 // For example:
1206 //
1207 // %x = G_SOMETHING_ALWAYS_FLOAT %a ...
1208 // %z = G_SELECT %cond %x %y
1209 //
1210 // Also check whether or not the sources have already been decided to be
1211 // FPR. Keep track of this.
1212 //
1213 // This doesn't check the condition, since it's just whatever is in NZCV.
1214 // This isn't passed explicitly in a register to fcsel/csel.
1215 for (unsigned Idx = 2; Idx < 4; ++Idx) {
1216 Register VReg = MI.getOperand(i: Idx).getReg();
1217 MachineInstr *DefMI = MRI.getVRegDef(Reg: VReg);
1218 if (getRegBank(Reg: VReg, MRI, TRI) == &AArch64::FPRRegBank ||
1219 onlyDefinesFP(MI: *DefMI, MRI, TRI))
1220 ++NumFP;
1221 }
1222
1223 // If we have more FP constraints than not, then move everything over to
1224 // FPR.
1225 if (NumFP >= 2)
1226 OpRegBankIdx = {PMI_FirstFPR, PMI_FirstGPR, PMI_FirstFPR, PMI_FirstFPR};
1227
1228 break;
1229 }
1230 case TargetOpcode::G_UNMERGE_VALUES: {
1231 // If the first operand belongs to a FPR register bank, then make sure that
1232 // we preserve that.
1233 if (OpRegBankIdx[0] != PMI_FirstGPR)
1234 break;
1235
1236 LLT SrcTy = MRI.getType(Reg: MI.getOperand(i: MI.getNumOperands()-1).getReg());
1237 // UNMERGE into scalars from a vector should always use FPR.
1238 // Likewise if any of the uses are FP instructions.
1239 if (SrcTy.isVector() || SrcTy == LLT::scalar(SizeInBits: 128) ||
1240 any_of(Range: MRI.use_nodbg_instructions(Reg: MI.getOperand(i: 0).getReg()),
1241 P: [&](MachineInstr &MI) { return onlyUsesFP(MI, MRI, TRI); })) {
1242 // Set the register bank of every operand to FPR.
1243 for (unsigned Idx = 0, NumOperands = MI.getNumOperands();
1244 Idx < NumOperands; ++Idx)
1245 OpRegBankIdx[Idx] = PMI_FirstFPR;
1246 }
1247 break;
1248 }
1249 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
1250 // Destination and source need to be FPRs.
1251 OpRegBankIdx[0] = PMI_FirstFPR;
1252 OpRegBankIdx[1] = PMI_FirstFPR;
1253
1254 // Index needs to be a GPR.
1255 OpRegBankIdx[2] = PMI_FirstGPR;
1256 break;
1257 case AArch64::G_SQSHLU_I:
1258 // Destination and source need to be FPRs.
1259 OpRegBankIdx[0] = PMI_FirstFPR;
1260 OpRegBankIdx[1] = PMI_FirstFPR;
1261
1262 // Shift Index needs to be a GPR.
1263 OpRegBankIdx[2] = PMI_FirstGPR;
1264 break;
1265
1266 case TargetOpcode::G_INSERT_VECTOR_ELT:
1267 OpRegBankIdx[0] = PMI_FirstFPR;
1268 OpRegBankIdx[1] = PMI_FirstFPR;
1269
1270 // The element may be either a GPR or FPR. Preserve that behaviour.
1271 if (getRegBank(Reg: MI.getOperand(i: 2).getReg(), MRI, TRI) == &AArch64::FPRRegBank)
1272 OpRegBankIdx[2] = PMI_FirstFPR;
1273 else {
1274 // If the type is i8/i16, and the regank will be GPR, then we change the
1275 // type to i32 in applyMappingImpl.
1276 LLT Ty = MRI.getType(Reg: MI.getOperand(i: 2).getReg());
1277 if (Ty.getSizeInBits() == 8 || Ty.getSizeInBits() == 16) {
1278 // Calls applyMappingImpl()
1279 MappingID = CustomMappingID;
1280 }
1281 OpRegBankIdx[2] = PMI_FirstGPR;
1282 }
1283
1284 // Index needs to be a GPR.
1285 OpRegBankIdx[3] = PMI_FirstGPR;
1286 break;
1287 case TargetOpcode::G_EXTRACT: {
1288 // For s128 sources we have to use fpr unless we know otherwise.
1289 auto Src = MI.getOperand(i: 1).getReg();
1290 LLT SrcTy = MRI.getType(Reg: MI.getOperand(i: 1).getReg());
1291 if (SrcTy.getSizeInBits() != 128)
1292 break;
1293 auto Idx = MRI.getRegClassOrNull(Reg: Src) == &AArch64::XSeqPairsClassRegClass
1294 ? PMI_FirstGPR
1295 : PMI_FirstFPR;
1296 OpRegBankIdx[0] = Idx;
1297 OpRegBankIdx[1] = Idx;
1298 break;
1299 }
1300 case TargetOpcode::G_BUILD_VECTOR: {
1301 // If the first source operand belongs to a FPR register bank, then make
1302 // sure that we preserve that.
1303 if (OpRegBankIdx[1] != PMI_FirstGPR)
1304 break;
1305 Register VReg = MI.getOperand(i: 1).getReg();
1306 if (!VReg)
1307 break;
1308
1309 // Get the instruction that defined the source operand reg, and check if
1310 // it's a floating point operation. Or, if it's a type like s16 which
1311 // doesn't have a exact size gpr register class. The exception is if the
1312 // build_vector has all constant operands, which may be better to leave as
1313 // gpr without copies, so it can be matched in imported patterns.
1314 MachineInstr *DefMI = MRI.getVRegDef(Reg: VReg);
1315 unsigned DefOpc = DefMI->getOpcode();
1316 const LLT SrcTy = MRI.getType(Reg: VReg);
1317 if (all_of(Range: MI.operands(), P: [&](const MachineOperand &Op) {
1318 return Op.isDef() || MRI.getVRegDef(Reg: Op.getReg())->getOpcode() ==
1319 TargetOpcode::G_CONSTANT;
1320 }))
1321 break;
1322 if (isPreISelGenericFloatingPointOpcode(Opc: DefOpc) ||
1323 SrcTy.getSizeInBits() < 32 ||
1324 getRegBank(Reg: VReg, MRI, TRI) == &AArch64::FPRRegBank) {
1325 // Have a floating point op.
1326 // Make sure every operand gets mapped to a FPR register class.
1327 unsigned NumOperands = MI.getNumOperands();
1328 for (unsigned Idx = 0; Idx < NumOperands; ++Idx)
1329 OpRegBankIdx[Idx] = PMI_FirstFPR;
1330 }
1331 break;
1332 }
1333 case TargetOpcode::G_VECREDUCE_FADD:
1334 case TargetOpcode::G_VECREDUCE_FMUL:
1335 case TargetOpcode::G_VECREDUCE_FMAX:
1336 case TargetOpcode::G_VECREDUCE_FMIN:
1337 case TargetOpcode::G_VECREDUCE_FMAXIMUM:
1338 case TargetOpcode::G_VECREDUCE_FMINIMUM:
1339 case TargetOpcode::G_VECREDUCE_ADD:
1340 case TargetOpcode::G_VECREDUCE_MUL:
1341 case TargetOpcode::G_VECREDUCE_AND:
1342 case TargetOpcode::G_VECREDUCE_OR:
1343 case TargetOpcode::G_VECREDUCE_XOR:
1344 case TargetOpcode::G_VECREDUCE_SMAX:
1345 case TargetOpcode::G_VECREDUCE_SMIN:
1346 case TargetOpcode::G_VECREDUCE_UMAX:
1347 case TargetOpcode::G_VECREDUCE_UMIN:
1348 // Reductions produce a scalar value from a vector, the scalar should be on
1349 // FPR bank.
1350 OpRegBankIdx = {PMI_FirstFPR, PMI_FirstFPR};
1351 break;
1352 case TargetOpcode::G_VECREDUCE_SEQ_FADD:
1353 case TargetOpcode::G_VECREDUCE_SEQ_FMUL:
1354 // These reductions also take a scalar accumulator input.
1355 // Assign them FPR for now.
1356 OpRegBankIdx = {PMI_FirstFPR, PMI_FirstFPR, PMI_FirstFPR};
1357 break;
1358 case TargetOpcode::G_INTRINSIC:
1359 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS: {
1360 switch (cast<GIntrinsic>(Val: MI).getIntrinsicID()) {
1361 case Intrinsic::aarch64_neon_fcvtas:
1362 case Intrinsic::aarch64_neon_fcvtau:
1363 case Intrinsic::aarch64_neon_fcvtzs:
1364 case Intrinsic::aarch64_neon_fcvtzu:
1365 case Intrinsic::aarch64_neon_fcvtms:
1366 case Intrinsic::aarch64_neon_fcvtmu:
1367 case Intrinsic::aarch64_neon_fcvtns:
1368 case Intrinsic::aarch64_neon_fcvtnu:
1369 case Intrinsic::aarch64_neon_fcvtps:
1370 case Intrinsic::aarch64_neon_fcvtpu: {
1371 OpRegBankIdx[2] = PMI_FirstFPR;
1372 if (MRI.getType(Reg: MI.getOperand(i: 0).getReg()).isVector()) {
1373 OpRegBankIdx[0] = PMI_FirstFPR;
1374 break;
1375 }
1376 TypeSize DstSize = getSizeInBits(Reg: MI.getOperand(i: 0).getReg(), MRI, TRI);
1377 TypeSize SrcSize = getSizeInBits(Reg: MI.getOperand(i: 2).getReg(), MRI, TRI);
1378 // Fp conversions to i16 must be kept on fp register banks to ensure
1379 // proper saturation, as there are no 16-bit gprs.
1380 // In addition, conversion intrinsics have fpr output when the input
1381 // size matches the output size, or FPRCVT is present.
1382 if (DstSize == 16 ||
1383 ((DstSize == SrcSize || STI.hasFeature(Feature: AArch64::FeatureFPRCVT)) &&
1384 all_of(Range: MRI.use_nodbg_instructions(Reg: MI.getOperand(i: 0).getReg()),
1385 P: [&](const MachineInstr &UseMI) {
1386 return onlyUsesFP(MI: UseMI, MRI, TRI) ||
1387 prefersFPUse(MI: UseMI, MRI, TRI);
1388 })))
1389 OpRegBankIdx[0] = PMI_FirstFPR;
1390 else
1391 OpRegBankIdx[0] = PMI_FirstGPR;
1392 break;
1393 }
1394 case Intrinsic::aarch64_neon_vcvtfxs2fp:
1395 case Intrinsic::aarch64_neon_vcvtfxu2fp:
1396 case Intrinsic::aarch64_neon_vcvtfp2fxs:
1397 case Intrinsic::aarch64_neon_vcvtfp2fxu:
1398 // Override these intrinsics, because they would have a partial
1399 // mapping. This is needed for 'half' types, which otherwise don't
1400 // get legalised correctly.
1401 OpRegBankIdx[0] = PMI_FirstFPR;
1402 OpRegBankIdx[2] = PMI_FirstFPR;
1403 // OpRegBankIdx[1] is the intrinsic ID.
1404 // OpRegBankIdx[3] is an integer immediate.
1405 break;
1406 default: {
1407 // Check if we know that the intrinsic has any constraints on its register
1408 // banks. If it does, then update the mapping accordingly.
1409 unsigned Idx = 0;
1410 if (onlyDefinesFP(MI, MRI, TRI))
1411 for (const auto &Op : MI.defs()) {
1412 if (Op.isReg())
1413 OpRegBankIdx[Idx] = PMI_FirstFPR;
1414 ++Idx;
1415 }
1416 else
1417 Idx += MI.getNumExplicitDefs();
1418
1419 if (onlyUsesFP(MI, MRI, TRI))
1420 for (const auto &Op : MI.explicit_uses()) {
1421 if (Op.isReg())
1422 OpRegBankIdx[Idx] = PMI_FirstFPR;
1423 ++Idx;
1424 }
1425 break;
1426 }
1427 }
1428 break;
1429 }
1430 }
1431
1432 // Finally construct the computed mapping.
1433 SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);
1434 for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
1435 if (MI.getOperand(i: Idx).isReg() && MI.getOperand(i: Idx).getReg()) {
1436 LLT Ty = MRI.getType(Reg: MI.getOperand(i: Idx).getReg());
1437 if (!Ty.isValid())
1438 continue;
1439 auto Mapping =
1440 getValueMapping(RBIdx: OpRegBankIdx[Idx], Size: TypeSize::getFixed(ExactSize: OpSize[Idx]));
1441 if (!Mapping->isValid())
1442 return getInvalidInstructionMapping();
1443
1444 OpdsMapping[Idx] = Mapping;
1445 }
1446 }
1447
1448 return getInstructionMapping(ID: MappingID, Cost, OperandsMapping: getOperandsMapping(OpdsMapping),
1449 NumOperands);
1450}
1451