Line data Source code
1 : //===- AArch64RegisterBankInfo.cpp ----------------------------------------===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : /// \file
10 : /// This file implements the targeting of the RegisterBankInfo class for
11 : /// AArch64.
12 : /// \todo This should be generated by TableGen.
13 : //===----------------------------------------------------------------------===//
14 :
15 : #include "AArch64RegisterBankInfo.h"
16 : #include "AArch64InstrInfo.h"
17 : #include "llvm/ADT/SmallVector.h"
18 : #include "llvm/CodeGen/GlobalISel/RegisterBank.h"
19 : #include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
20 : #include "llvm/CodeGen/LowLevelType.h"
21 : #include "llvm/CodeGen/MachineFunction.h"
22 : #include "llvm/CodeGen/MachineInstr.h"
23 : #include "llvm/CodeGen/MachineOperand.h"
24 : #include "llvm/CodeGen/MachineRegisterInfo.h"
25 : #include "llvm/CodeGen/TargetOpcodes.h"
26 : #include "llvm/CodeGen/TargetRegisterInfo.h"
27 : #include "llvm/CodeGen/TargetSubtargetInfo.h"
28 : #include "llvm/Support/ErrorHandling.h"
29 : #include <algorithm>
30 : #include <cassert>
31 :
32 : #define GET_TARGET_REGBANK_IMPL
33 : #include "AArch64GenRegisterBank.inc"
34 :
35 : // This file will be TableGen'ed at some point.
36 : #include "AArch64GenRegisterBankInfo.def"
37 :
38 : using namespace llvm;
39 :
40 1570 : AArch64RegisterBankInfo::AArch64RegisterBankInfo(const TargetRegisterInfo &TRI)
41 1570 : : AArch64GenRegisterBankInfo() {
42 : static bool AlreadyInit = false;
43 : // We have only one set of register banks, whatever the subtarget
44 : // is. Therefore, the initialization of the RegBanks table should be
45 : // done only once. Indeed the table of all register banks
46 : // (AArch64::RegBanks) is unique in the compiler. At some point, it
47 : // will get tablegen'ed and the whole constructor becomes empty.
48 1570 : if (AlreadyInit)
49 : return;
50 1553 : AlreadyInit = true;
51 :
52 : const RegisterBank &RBGPR = getRegBank(AArch64::GPRRegBankID);
53 : (void)RBGPR;
54 : assert(&AArch64::GPRRegBank == &RBGPR &&
55 : "The order in RegBanks is messed up");
56 :
57 : const RegisterBank &RBFPR = getRegBank(AArch64::FPRRegBankID);
58 : (void)RBFPR;
59 : assert(&AArch64::FPRRegBank == &RBFPR &&
60 : "The order in RegBanks is messed up");
61 :
62 : const RegisterBank &RBCCR = getRegBank(AArch64::CCRegBankID);
63 : (void)RBCCR;
64 : assert(&AArch64::CCRegBank == &RBCCR && "The order in RegBanks is messed up");
65 :
66 : // The GPR register bank is fully defined by all the registers in
67 : // GR64all + its subclasses.
68 : assert(RBGPR.covers(*TRI.getRegClass(AArch64::GPR32RegClassID)) &&
69 : "Subclass not added?");
70 : assert(RBGPR.getSize() == 64 && "GPRs should hold up to 64-bit");
71 :
72 : // The FPR register bank is fully defined by all the registers in
73 : // GR64all + its subclasses.
74 : assert(RBFPR.covers(*TRI.getRegClass(AArch64::QQRegClassID)) &&
75 : "Subclass not added?");
76 : assert(RBFPR.covers(*TRI.getRegClass(AArch64::FPR64RegClassID)) &&
77 : "Subclass not added?");
78 : assert(RBFPR.getSize() == 512 &&
79 : "FPRs should hold up to 512-bit via QQQQ sequence");
80 :
81 : assert(RBCCR.covers(*TRI.getRegClass(AArch64::CCRRegClassID)) &&
82 : "Class not added?");
83 : assert(RBCCR.getSize() == 32 && "CCR should hold up to 32-bit");
84 :
85 : // Check that the TableGen'ed like file is in sync we our expectations.
86 : // First, the Idx.
87 : assert(checkPartialMappingIdx(PMI_FirstGPR, PMI_LastGPR,
88 : {PMI_GPR32, PMI_GPR64}) &&
89 : "PartialMappingIdx's are incorrectly ordered");
90 : assert(checkPartialMappingIdx(PMI_FirstFPR, PMI_LastFPR,
91 : {PMI_FPR16, PMI_FPR32, PMI_FPR64, PMI_FPR128,
92 : PMI_FPR256, PMI_FPR512}) &&
93 : "PartialMappingIdx's are incorrectly ordered");
94 : // Now, the content.
95 : // Check partial mapping.
96 : #define CHECK_PARTIALMAP(Idx, ValStartIdx, ValLength, RB) \
97 : do { \
98 : assert( \
99 : checkPartialMap(PartialMappingIdx::Idx, ValStartIdx, ValLength, RB) && \
100 : #Idx " is incorrectly initialized"); \
101 : } while (false)
102 :
103 : CHECK_PARTIALMAP(PMI_GPR32, 0, 32, RBGPR);
104 : CHECK_PARTIALMAP(PMI_GPR64, 0, 64, RBGPR);
105 : CHECK_PARTIALMAP(PMI_FPR16, 0, 16, RBFPR);
106 : CHECK_PARTIALMAP(PMI_FPR32, 0, 32, RBFPR);
107 : CHECK_PARTIALMAP(PMI_FPR64, 0, 64, RBFPR);
108 : CHECK_PARTIALMAP(PMI_FPR128, 0, 128, RBFPR);
109 : CHECK_PARTIALMAP(PMI_FPR256, 0, 256, RBFPR);
110 : CHECK_PARTIALMAP(PMI_FPR512, 0, 512, RBFPR);
111 :
112 : // Check value mapping.
113 : #define CHECK_VALUEMAP_IMPL(RBName, Size, Offset) \
114 : do { \
115 : assert(checkValueMapImpl(PartialMappingIdx::PMI_##RBName##Size, \
116 : PartialMappingIdx::PMI_First##RBName, Size, \
117 : Offset) && \
118 : #RBName #Size " " #Offset " is incorrectly initialized"); \
119 : } while (false)
120 :
121 : #define CHECK_VALUEMAP(RBName, Size) CHECK_VALUEMAP_IMPL(RBName, Size, 0)
122 :
123 : CHECK_VALUEMAP(GPR, 32);
124 : CHECK_VALUEMAP(GPR, 64);
125 : CHECK_VALUEMAP(FPR, 16);
126 : CHECK_VALUEMAP(FPR, 32);
127 : CHECK_VALUEMAP(FPR, 64);
128 : CHECK_VALUEMAP(FPR, 128);
129 : CHECK_VALUEMAP(FPR, 256);
130 : CHECK_VALUEMAP(FPR, 512);
131 :
132 : // Check the value mapping for 3-operands instructions where all the operands
133 : // map to the same value mapping.
134 : #define CHECK_VALUEMAP_3OPS(RBName, Size) \
135 : do { \
136 : CHECK_VALUEMAP_IMPL(RBName, Size, 0); \
137 : CHECK_VALUEMAP_IMPL(RBName, Size, 1); \
138 : CHECK_VALUEMAP_IMPL(RBName, Size, 2); \
139 : } while (false)
140 :
141 : CHECK_VALUEMAP_3OPS(GPR, 32);
142 : CHECK_VALUEMAP_3OPS(GPR, 64);
143 : CHECK_VALUEMAP_3OPS(FPR, 32);
144 : CHECK_VALUEMAP_3OPS(FPR, 64);
145 : CHECK_VALUEMAP_3OPS(FPR, 128);
146 : CHECK_VALUEMAP_3OPS(FPR, 256);
147 : CHECK_VALUEMAP_3OPS(FPR, 512);
148 :
149 : #define CHECK_VALUEMAP_CROSSREGCPY(RBNameDst, RBNameSrc, Size) \
150 : do { \
151 : unsigned PartialMapDstIdx = PMI_##RBNameDst##Size - PMI_Min; \
152 : unsigned PartialMapSrcIdx = PMI_##RBNameSrc##Size - PMI_Min; \
153 : (void)PartialMapDstIdx; \
154 : (void)PartialMapSrcIdx; \
155 : const ValueMapping *Map = getCopyMapping( \
156 : AArch64::RBNameDst##RegBankID, AArch64::RBNameSrc##RegBankID, Size); \
157 : (void)Map; \
158 : assert(Map[0].BreakDown == \
159 : &AArch64GenRegisterBankInfo::PartMappings[PartialMapDstIdx] && \
160 : Map[0].NumBreakDowns == 1 && #RBNameDst #Size \
161 : " Dst is incorrectly initialized"); \
162 : assert(Map[1].BreakDown == \
163 : &AArch64GenRegisterBankInfo::PartMappings[PartialMapSrcIdx] && \
164 : Map[1].NumBreakDowns == 1 && #RBNameSrc #Size \
165 : " Src is incorrectly initialized"); \
166 : \
167 : } while (false)
168 :
169 1553 : CHECK_VALUEMAP_CROSSREGCPY(GPR, GPR, 32);
170 1553 : CHECK_VALUEMAP_CROSSREGCPY(GPR, FPR, 32);
171 1553 : CHECK_VALUEMAP_CROSSREGCPY(GPR, GPR, 64);
172 1553 : CHECK_VALUEMAP_CROSSREGCPY(GPR, FPR, 64);
173 1553 : CHECK_VALUEMAP_CROSSREGCPY(FPR, FPR, 32);
174 1553 : CHECK_VALUEMAP_CROSSREGCPY(FPR, GPR, 32);
175 1553 : CHECK_VALUEMAP_CROSSREGCPY(FPR, FPR, 64);
176 1553 : CHECK_VALUEMAP_CROSSREGCPY(FPR, GPR, 64);
177 :
178 : #define CHECK_VALUEMAP_FPEXT(DstSize, SrcSize) \
179 : do { \
180 : unsigned PartialMapDstIdx = PMI_FPR##DstSize - PMI_Min; \
181 : unsigned PartialMapSrcIdx = PMI_FPR##SrcSize - PMI_Min; \
182 : (void)PartialMapDstIdx; \
183 : (void)PartialMapSrcIdx; \
184 : const ValueMapping *Map = getFPExtMapping(DstSize, SrcSize); \
185 : (void)Map; \
186 : assert(Map[0].BreakDown == \
187 : &AArch64GenRegisterBankInfo::PartMappings[PartialMapDstIdx] && \
188 : Map[0].NumBreakDowns == 1 && "FPR" #DstSize \
189 : " Dst is incorrectly initialized"); \
190 : assert(Map[1].BreakDown == \
191 : &AArch64GenRegisterBankInfo::PartMappings[PartialMapSrcIdx] && \
192 : Map[1].NumBreakDowns == 1 && "FPR" #SrcSize \
193 : " Src is incorrectly initialized"); \
194 : \
195 : } while (false)
196 :
197 1553 : CHECK_VALUEMAP_FPEXT(32, 16);
198 1553 : CHECK_VALUEMAP_FPEXT(64, 16);
199 1553 : CHECK_VALUEMAP_FPEXT(64, 32);
200 1553 : CHECK_VALUEMAP_FPEXT(128, 64);
201 :
202 : assert(verify(TRI) && "Invalid register bank information");
203 : }
204 :
205 380 : unsigned AArch64RegisterBankInfo::copyCost(const RegisterBank &A,
206 : const RegisterBank &B,
207 : unsigned Size) const {
208 : // What do we do with different size?
209 : // copy are same size.
210 : // Will introduce other hooks for different size:
211 : // * extract cost.
212 : // * build_sequence cost.
213 :
214 : // Copy from (resp. to) GPR to (resp. from) FPR involves FMOV.
215 : // FIXME: This should be deduced from the scheduling model.
216 380 : if (&A == &AArch64::GPRRegBank && &B == &AArch64::FPRRegBank)
217 : // FMOVXDr or FMOVWSr.
218 : return 5;
219 346 : if (&A == &AArch64::FPRRegBank && &B == &AArch64::GPRRegBank)
220 : // FMOVDXr or FMOVSWr.
221 : return 4;
222 :
223 312 : return RegisterBankInfo::copyCost(A, B, Size);
224 : }
225 :
226 3056 : const RegisterBank &AArch64RegisterBankInfo::getRegBankFromRegClass(
227 : const TargetRegisterClass &RC) const {
228 6112 : switch (RC.getID()) {
229 1510 : case AArch64::FPR8RegClassID:
230 : case AArch64::FPR16RegClassID:
231 : case AArch64::FPR32RegClassID:
232 : case AArch64::FPR64RegClassID:
233 : case AArch64::FPR128RegClassID:
234 : case AArch64::FPR128_loRegClassID:
235 : case AArch64::DDRegClassID:
236 : case AArch64::DDDRegClassID:
237 : case AArch64::DDDDRegClassID:
238 : case AArch64::QQRegClassID:
239 : case AArch64::QQQRegClassID:
240 : case AArch64::QQQQRegClassID:
241 1510 : return getRegBank(AArch64::FPRRegBankID);
242 1546 : case AArch64::GPR32commonRegClassID:
243 : case AArch64::GPR32RegClassID:
244 : case AArch64::GPR32spRegClassID:
245 : case AArch64::GPR32sponlyRegClassID:
246 : case AArch64::GPR32allRegClassID:
247 : case AArch64::GPR64commonRegClassID:
248 : case AArch64::GPR64RegClassID:
249 : case AArch64::GPR64spRegClassID:
250 : case AArch64::GPR64sponlyRegClassID:
251 : case AArch64::GPR64allRegClassID:
252 : case AArch64::tcGPR64RegClassID:
253 : case AArch64::WSeqPairsClassRegClassID:
254 : case AArch64::XSeqPairsClassRegClassID:
255 1546 : return getRegBank(AArch64::GPRRegBankID);
256 0 : case AArch64::CCRRegClassID:
257 0 : return getRegBank(AArch64::CCRegBankID);
258 0 : default:
259 0 : llvm_unreachable("Register class not supported");
260 : }
261 : }
262 :
263 : RegisterBankInfo::InstructionMappings
264 97 : AArch64RegisterBankInfo::getInstrAlternativeMappings(
265 : const MachineInstr &MI) const {
266 97 : const MachineFunction &MF = *MI.getParent()->getParent();
267 97 : const TargetSubtargetInfo &STI = MF.getSubtarget();
268 97 : const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
269 97 : const MachineRegisterInfo &MRI = MF.getRegInfo();
270 :
271 194 : switch (MI.getOpcode()) {
272 3 : case TargetOpcode::G_OR: {
273 : // 32 and 64-bit or can be mapped on either FPR or
274 : // GPR for the same cost.
275 3 : unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI);
276 3 : if (Size != 32 && Size != 64)
277 : break;
278 :
279 : // If the instruction has any implicit-defs or uses,
280 : // do not mess with it.
281 3 : if (MI.getNumOperands() != 3)
282 : break;
283 : InstructionMappings AltMappings;
284 : const InstructionMapping &GPRMapping = getInstructionMapping(
285 : /*ID*/ 1, /*Cost*/ 1, getValueMapping(PMI_FirstGPR, Size),
286 3 : /*NumOperands*/ 3);
287 : const InstructionMapping &FPRMapping = getInstructionMapping(
288 : /*ID*/ 2, /*Cost*/ 1, getValueMapping(PMI_FirstFPR, Size),
289 3 : /*NumOperands*/ 3);
290 :
291 3 : AltMappings.push_back(&GPRMapping);
292 3 : AltMappings.push_back(&FPRMapping);
293 : return AltMappings;
294 : }
295 12 : case TargetOpcode::G_BITCAST: {
296 12 : unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI);
297 12 : if (Size != 32 && Size != 64)
298 : break;
299 :
300 : // If the instruction has any implicit-defs or uses,
301 : // do not mess with it.
302 10 : if (MI.getNumOperands() != 2)
303 : break;
304 :
305 : InstructionMappings AltMappings;
306 : const InstructionMapping &GPRMapping = getInstructionMapping(
307 : /*ID*/ 1, /*Cost*/ 1,
308 : getCopyMapping(AArch64::GPRRegBankID, AArch64::GPRRegBankID, Size),
309 10 : /*NumOperands*/ 2);
310 : const InstructionMapping &FPRMapping = getInstructionMapping(
311 : /*ID*/ 2, /*Cost*/ 1,
312 : getCopyMapping(AArch64::FPRRegBankID, AArch64::FPRRegBankID, Size),
313 10 : /*NumOperands*/ 2);
314 : const InstructionMapping &GPRToFPRMapping = getInstructionMapping(
315 : /*ID*/ 3,
316 : /*Cost*/ copyCost(AArch64::GPRRegBank, AArch64::FPRRegBank, Size),
317 : getCopyMapping(AArch64::FPRRegBankID, AArch64::GPRRegBankID, Size),
318 10 : /*NumOperands*/ 2);
319 : const InstructionMapping &FPRToGPRMapping = getInstructionMapping(
320 : /*ID*/ 3,
321 : /*Cost*/ copyCost(AArch64::GPRRegBank, AArch64::FPRRegBank, Size),
322 : getCopyMapping(AArch64::GPRRegBankID, AArch64::FPRRegBankID, Size),
323 10 : /*NumOperands*/ 2);
324 :
325 10 : AltMappings.push_back(&GPRMapping);
326 10 : AltMappings.push_back(&FPRMapping);
327 10 : AltMappings.push_back(&GPRToFPRMapping);
328 10 : AltMappings.push_back(&FPRToGPRMapping);
329 : return AltMappings;
330 : }
331 3 : case TargetOpcode::G_LOAD: {
332 3 : unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI);
333 3 : if (Size != 64)
334 : break;
335 :
336 : // If the instruction has any implicit-defs or uses,
337 : // do not mess with it.
338 2 : if (MI.getNumOperands() != 2)
339 : break;
340 :
341 : InstructionMappings AltMappings;
342 : const InstructionMapping &GPRMapping = getInstructionMapping(
343 : /*ID*/ 1, /*Cost*/ 1,
344 2 : getOperandsMapping({getValueMapping(PMI_FirstGPR, Size),
345 : // Addresses are GPR 64-bit.
346 2 : getValueMapping(PMI_FirstGPR, 64)}),
347 2 : /*NumOperands*/ 2);
348 : const InstructionMapping &FPRMapping = getInstructionMapping(
349 : /*ID*/ 2, /*Cost*/ 1,
350 2 : getOperandsMapping({getValueMapping(PMI_FirstFPR, Size),
351 : // Addresses are GPR 64-bit.
352 2 : getValueMapping(PMI_FirstGPR, 64)}),
353 2 : /*NumOperands*/ 2);
354 :
355 2 : AltMappings.push_back(&GPRMapping);
356 2 : AltMappings.push_back(&FPRMapping);
357 : return AltMappings;
358 : }
359 : default:
360 : break;
361 : }
362 82 : return RegisterBankInfo::getInstrAlternativeMappings(MI);
363 : }
364 :
365 10 : void AArch64RegisterBankInfo::applyMappingImpl(
366 : const OperandsMapper &OpdMapper) const {
367 10 : switch (OpdMapper.getMI().getOpcode()) {
368 10 : case TargetOpcode::G_OR:
369 : case TargetOpcode::G_BITCAST:
370 : case TargetOpcode::G_LOAD:
371 : // Those ID must match getInstrAlternativeMappings.
372 : assert((OpdMapper.getInstrMapping().getID() >= 1 &&
373 : OpdMapper.getInstrMapping().getID() <= 4) &&
374 : "Don't know how to handle that ID");
375 10 : return applyDefaultMapping(OpdMapper);
376 0 : default:
377 0 : llvm_unreachable("Don't know how to handle that operation");
378 : }
379 : }
380 :
381 : /// Returns whether opcode \p Opc is a pre-isel generic floating-point opcode,
382 : /// having only floating-point operands.
383 : static bool isPreISelGenericFloatingPointOpcode(unsigned Opc) {
384 : switch (Opc) {
385 : case TargetOpcode::G_FADD:
386 : case TargetOpcode::G_FSUB:
387 : case TargetOpcode::G_FMUL:
388 : case TargetOpcode::G_FDIV:
389 : case TargetOpcode::G_FCONSTANT:
390 : case TargetOpcode::G_FPEXT:
391 : case TargetOpcode::G_FPTRUNC:
392 : return true;
393 : }
394 : return false;
395 : }
396 :
397 : const RegisterBankInfo::InstructionMapping &
398 291 : AArch64RegisterBankInfo::getSameKindOfOperandsMapping(
399 : const MachineInstr &MI) const {
400 291 : const unsigned Opc = MI.getOpcode();
401 291 : const MachineFunction &MF = *MI.getParent()->getParent();
402 291 : const MachineRegisterInfo &MRI = MF.getRegInfo();
403 :
404 291 : unsigned NumOperands = MI.getNumOperands();
405 : assert(NumOperands <= 3 &&
406 : "This code is for instructions with 3 or less operands");
407 :
408 291 : LLT Ty = MRI.getType(MI.getOperand(0).getReg());
409 291 : unsigned Size = Ty.getSizeInBits();
410 291 : bool IsFPR = Ty.isVector() || isPreISelGenericFloatingPointOpcode(Opc);
411 :
412 : PartialMappingIdx RBIdx = IsFPR ? PMI_FirstFPR : PMI_FirstGPR;
413 :
414 : #ifndef NDEBUG
415 : // Make sure all the operands are using similar size and type.
416 : // Should probably be checked by the machine verifier.
417 : // This code won't catch cases where the number of lanes is
418 : // different between the operands.
419 : // If we want to go to that level of details, it is probably
420 : // best to check that the types are the same, period.
421 : // Currently, we just check that the register banks are the same
422 : // for each types.
423 : for (unsigned Idx = 1; Idx != NumOperands; ++Idx) {
424 : LLT OpTy = MRI.getType(MI.getOperand(Idx).getReg());
425 : assert(
426 : AArch64GenRegisterBankInfo::getRegBankBaseIdxOffset(
427 : RBIdx, OpTy.getSizeInBits()) ==
428 : AArch64GenRegisterBankInfo::getRegBankBaseIdxOffset(RBIdx, Size) &&
429 : "Operand has incompatible size");
430 : bool OpIsFPR = OpTy.isVector() || isPreISelGenericFloatingPointOpcode(Opc);
431 : (void)OpIsFPR;
432 : assert(IsFPR == OpIsFPR && "Operand has incompatible type");
433 : }
434 : #endif // End NDEBUG.
435 :
436 : return getInstructionMapping(DefaultMappingID, 1,
437 291 : getValueMapping(RBIdx, Size), NumOperands);
438 : }
439 :
440 : const RegisterBankInfo::InstructionMapping &
441 1445 : AArch64RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
442 1445 : const unsigned Opc = MI.getOpcode();
443 :
444 : // Try the default logic for non-generic instructions that are either copies
445 : // or already have some operands assigned to banks.
446 1445 : if ((Opc != TargetOpcode::COPY && !isPreISelGenericOpcode(Opc)) ||
447 : Opc == TargetOpcode::G_PHI) {
448 : const RegisterBankInfo::InstructionMapping &Mapping =
449 19 : getInstrMappingImpl(MI);
450 : if (Mapping.isValid())
451 : return Mapping;
452 : }
453 :
454 1434 : const MachineFunction &MF = *MI.getParent()->getParent();
455 1434 : const MachineRegisterInfo &MRI = MF.getRegInfo();
456 1434 : const TargetSubtargetInfo &STI = MF.getSubtarget();
457 1434 : const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
458 :
459 1434 : switch (Opc) {
460 : // G_{F|S|U}REM are not listed because they are not legal.
461 : // Arithmetic ops.
462 291 : case TargetOpcode::G_ADD:
463 : case TargetOpcode::G_SUB:
464 : case TargetOpcode::G_GEP:
465 : case TargetOpcode::G_MUL:
466 : case TargetOpcode::G_SDIV:
467 : case TargetOpcode::G_UDIV:
468 : // Bitwise ops.
469 : case TargetOpcode::G_AND:
470 : case TargetOpcode::G_OR:
471 : case TargetOpcode::G_XOR:
472 : // Shifts.
473 : case TargetOpcode::G_SHL:
474 : case TargetOpcode::G_LSHR:
475 : case TargetOpcode::G_ASHR:
476 : // Floating point ops.
477 : case TargetOpcode::G_FADD:
478 : case TargetOpcode::G_FSUB:
479 : case TargetOpcode::G_FMUL:
480 : case TargetOpcode::G_FDIV:
481 291 : return getSameKindOfOperandsMapping(MI);
482 9 : case TargetOpcode::G_FPEXT: {
483 9 : LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
484 9 : LLT SrcTy = MRI.getType(MI.getOperand(1).getReg());
485 : return getInstructionMapping(
486 : DefaultMappingID, /*Cost*/ 1,
487 : getFPExtMapping(DstTy.getSizeInBits(), SrcTy.getSizeInBits()),
488 9 : /*NumOperands*/ 2);
489 : }
490 307 : case TargetOpcode::COPY: {
491 307 : unsigned DstReg = MI.getOperand(0).getReg();
492 307 : unsigned SrcReg = MI.getOperand(1).getReg();
493 : // Check if one of the register is not a generic register.
494 222 : if ((TargetRegisterInfo::isPhysicalRegister(DstReg) ||
495 525 : !MRI.getType(DstReg).isValid()) ||
496 42 : (TargetRegisterInfo::isPhysicalRegister(SrcReg) ||
497 : !MRI.getType(SrcReg).isValid())) {
498 269 : const RegisterBank *DstRB = getRegBank(DstReg, MRI, TRI);
499 269 : const RegisterBank *SrcRB = getRegBank(SrcReg, MRI, TRI);
500 269 : if (!DstRB)
501 : DstRB = SrcRB;
502 92 : else if (!SrcRB)
503 : SrcRB = DstRB;
504 : // If both RB are null that means both registers are generic.
505 : // We shouldn't be here.
506 : assert(DstRB && SrcRB && "Both RegBank were nullptr");
507 269 : unsigned Size = getSizeInBits(DstReg, MRI, TRI);
508 : return getInstructionMapping(
509 : DefaultMappingID, copyCost(*DstRB, *SrcRB, Size),
510 : getCopyMapping(DstRB->getID(), SrcRB->getID(), Size),
511 : // We only care about the mapping of the destination.
512 269 : /*NumOperands*/ 1);
513 : }
514 : // Both registers are generic, use G_BITCAST.
515 : LLVM_FALLTHROUGH;
516 : }
517 : case TargetOpcode::G_BITCAST: {
518 62 : LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
519 62 : LLT SrcTy = MRI.getType(MI.getOperand(1).getReg());
520 62 : unsigned Size = DstTy.getSizeInBits();
521 62 : bool DstIsGPR = !DstTy.isVector() && DstTy.getSizeInBits() <= 64;
522 62 : bool SrcIsGPR = !SrcTy.isVector() && SrcTy.getSizeInBits() <= 64;
523 62 : const RegisterBank &DstRB =
524 : DstIsGPR ? AArch64::GPRRegBank : AArch64::FPRRegBank;
525 62 : const RegisterBank &SrcRB =
526 : SrcIsGPR ? AArch64::GPRRegBank : AArch64::FPRRegBank;
527 : return getInstructionMapping(
528 : DefaultMappingID, copyCost(DstRB, SrcRB, Size),
529 : getCopyMapping(DstRB.getID(), SrcRB.getID(), Size),
530 : // We only care about the mapping of the destination for COPY.
531 100 : /*NumOperands*/ Opc == TargetOpcode::G_BITCAST ? 2 : 1);
532 : }
533 : default:
534 : break;
535 : }
536 :
537 803 : unsigned NumOperands = MI.getNumOperands();
538 :
539 : // Track the size and bank of each register. We don't do partial mappings.
540 803 : SmallVector<unsigned, 4> OpSize(NumOperands);
541 803 : SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands);
542 2419 : for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
543 1616 : auto &MO = MI.getOperand(Idx);
544 1616 : if (!MO.isReg() || !MO.getReg())
545 405 : continue;
546 :
547 1211 : LLT Ty = MRI.getType(MO.getReg());
548 1211 : OpSize[Idx] = Ty.getSizeInBits();
549 :
550 : // As a top-level guess, vectors go in FPRs, scalars and pointers in GPRs.
551 : // For floating-point instructions, scalars go in FPRs.
552 1211 : if (Ty.isVector() || isPreISelGenericFloatingPointOpcode(Opc) ||
553 1180 : Ty.getSizeInBits() > 64)
554 37 : OpRegBankIdx[Idx] = PMI_FirstFPR;
555 : else
556 1174 : OpRegBankIdx[Idx] = PMI_FirstGPR;
557 : }
558 :
559 : unsigned Cost = 1;
560 : // Some of the floating-point instructions have mixed GPR and FPR operands:
561 : // fine-tune the computed mapping.
562 803 : switch (Opc) {
563 18 : case TargetOpcode::G_SITOFP:
564 : case TargetOpcode::G_UITOFP:
565 : OpRegBankIdx = {PMI_FirstFPR, PMI_FirstGPR};
566 18 : break;
567 22 : case TargetOpcode::G_FPTOSI:
568 : case TargetOpcode::G_FPTOUI:
569 : OpRegBankIdx = {PMI_FirstGPR, PMI_FirstFPR};
570 22 : break;
571 1 : case TargetOpcode::G_FCMP:
572 : OpRegBankIdx = {PMI_FirstGPR,
573 : /* Predicate */ PMI_None, PMI_FirstFPR, PMI_FirstFPR};
574 1 : break;
575 : case TargetOpcode::G_BITCAST:
576 : // This is going to be a cross register bank copy and this is expensive.
577 0 : if (OpRegBankIdx[0] != OpRegBankIdx[1])
578 0 : Cost = copyCost(
579 0 : *AArch64GenRegisterBankInfo::PartMappings[OpRegBankIdx[0]].RegBank,
580 0 : *AArch64GenRegisterBankInfo::PartMappings[OpRegBankIdx[1]].RegBank,
581 : OpSize[0]);
582 : break;
583 : case TargetOpcode::G_LOAD:
584 : // Loading in vector unit is slightly more expensive.
585 : // This is actually only true for the LD1R and co instructions,
586 : // but anyway for the fast mode this number does not matter and
587 : // for the greedy mode the cost of the cross bank copy will
588 : // offset this number.
589 : // FIXME: Should be derived from the scheduling model.
590 134 : if (OpRegBankIdx[0] != PMI_FirstGPR)
591 : Cost = 2;
592 : else
593 : // Check if that load feeds fp instructions.
594 : // In that case, we want the default mapping to be on FPR
595 : // instead of blind map every scalar to GPR.
596 123 : for (const MachineInstr &UseMI :
597 378 : MRI.use_instructions(MI.getOperand(0).getReg())) {
598 : // If we have at least one direct use in a FP instruction,
599 : // assume this was a floating point load in the IR.
600 : // If it was not, we would have had a bitcast before
601 : // reaching that instruction.
602 131 : unsigned UseOpc = UseMI.getOpcode();
603 127 : if (isPreISelGenericFloatingPointOpcode(UseOpc) ||
604 : // Check if we feed a copy-like instruction with
605 : // floating point constraints. In that case, we are still
606 : // feeding fp instructions, but indirectly
607 : // (e.g., through ABI copies).
608 12 : ((UseOpc == TargetOpcode::COPY || UseMI.isPHI()) &&
609 12 : getRegBank(UseMI.getOperand(0).getReg(), MRI, TRI) ==
610 : &AArch64::FPRRegBank)) {
611 8 : OpRegBankIdx[0] = PMI_FirstFPR;
612 8 : break;
613 : }
614 : }
615 : break;
616 : case TargetOpcode::G_STORE:
617 : // Check if that store is fed by fp instructions.
618 189 : if (OpRegBankIdx[0] == PMI_FirstGPR) {
619 189 : unsigned VReg = MI.getOperand(0).getReg();
620 189 : if (!VReg)
621 : break;
622 189 : MachineInstr *DefMI = MRI.getVRegDef(VReg);
623 189 : unsigned DefOpc = DefMI->getOpcode();
624 171 : if (isPreISelGenericFloatingPointOpcode(DefOpc) ||
625 : // Check if we come from a copy-like instruction with
626 : // floating point constraints. In that case, we are still
627 : // fed by fp instructions, but indirectly
628 : // (e.g., through ABI copies).
629 24 : ((DefOpc == TargetOpcode::COPY || DefMI->isPHI()) &&
630 24 : getRegBank(DefMI->getOperand(0).getReg(), MRI, TRI) ==
631 : &AArch64::FPRRegBank))
632 22 : OpRegBankIdx[0] = PMI_FirstFPR;
633 : break;
634 0 : }
635 : }
636 :
637 : // Finally construct the computed mapping.
638 803 : SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);
639 2419 : for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
640 3232 : if (MI.getOperand(Idx).isReg() && MI.getOperand(Idx).getReg()) {
641 2422 : auto Mapping = getValueMapping(OpRegBankIdx[Idx], OpSize[Idx]);
642 1211 : if (!Mapping->isValid())
643 0 : return getInvalidInstructionMapping();
644 :
645 1211 : OpdsMapping[Idx] = Mapping;
646 : }
647 : }
648 :
649 : return getInstructionMapping(DefaultMappingID, Cost,
650 803 : getOperandsMapping(OpdsMapping), NumOperands);
651 : }
|