1 | //===- MipsRegisterBankInfo.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 Mips. |
10 | /// \todo This should be generated by TableGen. |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "MipsRegisterBankInfo.h" |
14 | #include "MipsInstrInfo.h" |
15 | #include "MipsTargetMachine.h" |
16 | #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" |
17 | #include "llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h" |
18 | #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" |
19 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
20 | |
21 | #define GET_TARGET_REGBANK_IMPL |
22 | |
23 | #include "MipsGenRegisterBank.inc" |
24 | |
25 | namespace llvm { |
26 | namespace Mips { |
27 | enum PartialMappingIdx { |
28 | PMI_GPR, |
29 | PMI_SPR, |
30 | PMI_DPR, |
31 | PMI_MSA, |
32 | PMI_Min = PMI_GPR, |
33 | }; |
34 | |
35 | const RegisterBankInfo::PartialMapping PartMappings[]{ |
36 | {0, 32, GPRBRegBank}, |
37 | {0, 32, FPRBRegBank}, |
38 | {0, 64, FPRBRegBank}, |
39 | {0, 128, FPRBRegBank} |
40 | }; |
41 | |
42 | enum ValueMappingIdx { |
43 | InvalidIdx = 0, |
44 | GPRIdx = 1, |
45 | SPRIdx = 4, |
46 | DPRIdx = 7, |
47 | MSAIdx = 10 |
48 | }; |
49 | |
50 | const RegisterBankInfo::ValueMapping ValueMappings[] = { |
51 | // invalid |
52 | {nullptr, 0}, |
53 | // up to 3 operands in GPRs |
54 | {&PartMappings[PMI_GPR - PMI_Min], 1}, |
55 | {&PartMappings[PMI_GPR - PMI_Min], 1}, |
56 | {&PartMappings[PMI_GPR - PMI_Min], 1}, |
57 | // up to 3 operands in FPRs - single precission |
58 | {&PartMappings[PMI_SPR - PMI_Min], 1}, |
59 | {&PartMappings[PMI_SPR - PMI_Min], 1}, |
60 | {&PartMappings[PMI_SPR - PMI_Min], 1}, |
61 | // up to 3 operands in FPRs - double precission |
62 | {&PartMappings[PMI_DPR - PMI_Min], 1}, |
63 | {&PartMappings[PMI_DPR - PMI_Min], 1}, |
64 | {&PartMappings[PMI_DPR - PMI_Min], 1}, |
65 | // up to 3 operands in FPRs - MSA |
66 | {&PartMappings[PMI_MSA - PMI_Min], 1}, |
67 | {&PartMappings[PMI_MSA - PMI_Min], 1}, |
68 | {&PartMappings[PMI_MSA - PMI_Min], 1} |
69 | }; |
70 | |
71 | } // end namespace Mips |
72 | } // end namespace llvm |
73 | |
74 | using namespace llvm; |
75 | |
76 | MipsRegisterBankInfo::MipsRegisterBankInfo(const TargetRegisterInfo &TRI) {} |
77 | |
78 | const RegisterBank & |
79 | MipsRegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC, |
80 | LLT) const { |
81 | using namespace Mips; |
82 | |
83 | switch (RC.getID()) { |
84 | case Mips::GPR32RegClassID: |
85 | case Mips::CPU16Regs_and_GPRMM16ZeroRegClassID: |
86 | case Mips::GPRMM16MovePPairFirstRegClassID: |
87 | case Mips::CPU16Regs_and_GPRMM16MovePPairSecondRegClassID: |
88 | case Mips::GPRMM16MoveP_and_CPU16Regs_and_GPRMM16ZeroRegClassID: |
89 | case Mips::GPRMM16MovePPairFirst_and_GPRMM16MovePPairSecondRegClassID: |
90 | case Mips::SP32RegClassID: |
91 | case Mips::GP32RegClassID: |
92 | return getRegBank(ID: Mips::GPRBRegBankID); |
93 | case Mips::FGRCCRegClassID: |
94 | case Mips::FGR32RegClassID: |
95 | case Mips::FGR64RegClassID: |
96 | case Mips::AFGR64RegClassID: |
97 | case Mips::MSA128BRegClassID: |
98 | case Mips::MSA128HRegClassID: |
99 | case Mips::MSA128WRegClassID: |
100 | case Mips::MSA128DRegClassID: |
101 | return getRegBank(ID: Mips::FPRBRegBankID); |
102 | default: |
103 | llvm_unreachable("Register class not supported" ); |
104 | } |
105 | } |
106 | |
107 | // Instructions where use operands are floating point registers. |
108 | // Def operands are general purpose. |
109 | static bool isFloatingPointOpcodeUse(unsigned Opc) { |
110 | switch (Opc) { |
111 | case TargetOpcode::G_FPTOSI: |
112 | case TargetOpcode::G_FPTOUI: |
113 | case TargetOpcode::G_FCMP: |
114 | return true; |
115 | default: |
116 | return isPreISelGenericFloatingPointOpcode(Opc); |
117 | } |
118 | } |
119 | |
120 | // Instructions where def operands are floating point registers. |
121 | // Use operands are general purpose. |
122 | static bool isFloatingPointOpcodeDef(unsigned Opc) { |
123 | switch (Opc) { |
124 | case TargetOpcode::G_SITOFP: |
125 | case TargetOpcode::G_UITOFP: |
126 | return true; |
127 | default: |
128 | return isPreISelGenericFloatingPointOpcode(Opc); |
129 | } |
130 | } |
131 | |
132 | static bool isGprbTwoInstrUnalignedLoadOrStore(const MachineInstr *MI) { |
133 | if (MI->getOpcode() == TargetOpcode::G_LOAD || |
134 | MI->getOpcode() == TargetOpcode::G_STORE) { |
135 | auto MMO = *MI->memoperands_begin(); |
136 | const MipsSubtarget &STI = MI->getMF()->getSubtarget<MipsSubtarget>(); |
137 | if (MMO->getSize() == 4 && (!STI.systemSupportsUnalignedAccess() && |
138 | (!MMO->getSize().hasValue() || |
139 | MMO->getAlign() < MMO->getSize().getValue()))) |
140 | return true; |
141 | } |
142 | return false; |
143 | } |
144 | |
145 | static bool isAmbiguous(unsigned Opc) { |
146 | switch (Opc) { |
147 | case TargetOpcode::G_LOAD: |
148 | case TargetOpcode::G_STORE: |
149 | case TargetOpcode::G_PHI: |
150 | case TargetOpcode::G_SELECT: |
151 | case TargetOpcode::G_IMPLICIT_DEF: |
152 | case TargetOpcode::G_UNMERGE_VALUES: |
153 | case TargetOpcode::G_MERGE_VALUES: |
154 | return true; |
155 | default: |
156 | return false; |
157 | } |
158 | } |
159 | |
160 | void MipsRegisterBankInfo::AmbiguousRegDefUseContainer::addDefUses( |
161 | Register Reg, const MachineRegisterInfo &MRI) { |
162 | assert(!MRI.getType(Reg).isPointer() && |
163 | "Pointers are gprb, they should not be considered as ambiguous.\n" ); |
164 | for (MachineInstr &UseMI : MRI.use_instructions(Reg)) { |
165 | MachineInstr *NonCopyInstr = skipCopiesOutgoing(MI: &UseMI); |
166 | // Copy with many uses. |
167 | if (NonCopyInstr->getOpcode() == TargetOpcode::COPY && |
168 | !NonCopyInstr->getOperand(i: 0).getReg().isPhysical()) |
169 | addDefUses(Reg: NonCopyInstr->getOperand(i: 0).getReg(), MRI); |
170 | else |
171 | DefUses.push_back(Elt: skipCopiesOutgoing(MI: &UseMI)); |
172 | } |
173 | } |
174 | |
175 | void MipsRegisterBankInfo::AmbiguousRegDefUseContainer::addUseDef( |
176 | Register Reg, const MachineRegisterInfo &MRI) { |
177 | assert(!MRI.getType(Reg).isPointer() && |
178 | "Pointers are gprb, they should not be considered as ambiguous.\n" ); |
179 | MachineInstr *DefMI = MRI.getVRegDef(Reg); |
180 | UseDefs.push_back(Elt: skipCopiesIncoming(MI: DefMI)); |
181 | } |
182 | |
183 | MachineInstr * |
184 | MipsRegisterBankInfo::AmbiguousRegDefUseContainer::skipCopiesOutgoing( |
185 | MachineInstr *MI) const { |
186 | const MachineFunction &MF = *MI->getParent()->getParent(); |
187 | const MachineRegisterInfo &MRI = MF.getRegInfo(); |
188 | MachineInstr *Ret = MI; |
189 | while (Ret->getOpcode() == TargetOpcode::COPY && |
190 | !Ret->getOperand(i: 0).getReg().isPhysical() && |
191 | MRI.hasOneUse(RegNo: Ret->getOperand(i: 0).getReg())) { |
192 | Ret = &(*MRI.use_instr_begin(RegNo: Ret->getOperand(i: 0).getReg())); |
193 | } |
194 | return Ret; |
195 | } |
196 | |
197 | MachineInstr * |
198 | MipsRegisterBankInfo::AmbiguousRegDefUseContainer::skipCopiesIncoming( |
199 | MachineInstr *MI) const { |
200 | const MachineFunction &MF = *MI->getParent()->getParent(); |
201 | const MachineRegisterInfo &MRI = MF.getRegInfo(); |
202 | MachineInstr *Ret = MI; |
203 | while (Ret->getOpcode() == TargetOpcode::COPY && |
204 | !Ret->getOperand(i: 1).getReg().isPhysical()) |
205 | Ret = MRI.getVRegDef(Reg: Ret->getOperand(i: 1).getReg()); |
206 | return Ret; |
207 | } |
208 | |
209 | MipsRegisterBankInfo::AmbiguousRegDefUseContainer::AmbiguousRegDefUseContainer( |
210 | const MachineInstr *MI) { |
211 | assert(isAmbiguous(MI->getOpcode()) && |
212 | "Not implemented for non Ambiguous opcode.\n" ); |
213 | |
214 | const MachineRegisterInfo &MRI = MI->getMF()->getRegInfo(); |
215 | |
216 | if (MI->getOpcode() == TargetOpcode::G_LOAD) |
217 | addDefUses(Reg: MI->getOperand(i: 0).getReg(), MRI); |
218 | |
219 | if (MI->getOpcode() == TargetOpcode::G_STORE) |
220 | addUseDef(Reg: MI->getOperand(i: 0).getReg(), MRI); |
221 | |
222 | if (auto *PHI = dyn_cast<GPhi>(Val: MI)) { |
223 | addDefUses(Reg: PHI->getReg(Idx: 0), MRI); |
224 | |
225 | for (unsigned I = 1; I < PHI->getNumIncomingValues(); ++I) |
226 | addUseDef(Reg: PHI->getIncomingValue(I), MRI); |
227 | } |
228 | |
229 | if (MI->getOpcode() == TargetOpcode::G_SELECT) { |
230 | addDefUses(Reg: MI->getOperand(i: 0).getReg(), MRI); |
231 | |
232 | addUseDef(Reg: MI->getOperand(i: 2).getReg(), MRI); |
233 | addUseDef(Reg: MI->getOperand(i: 3).getReg(), MRI); |
234 | } |
235 | |
236 | if (MI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF) |
237 | addDefUses(Reg: MI->getOperand(i: 0).getReg(), MRI); |
238 | |
239 | if (MI->getOpcode() == TargetOpcode::G_UNMERGE_VALUES) |
240 | addUseDef(Reg: MI->getOperand(i: MI->getNumOperands() - 1).getReg(), MRI); |
241 | |
242 | if (MI->getOpcode() == TargetOpcode::G_MERGE_VALUES) |
243 | addDefUses(Reg: MI->getOperand(i: 0).getReg(), MRI); |
244 | } |
245 | |
246 | bool MipsRegisterBankInfo::TypeInfoForMF::visit( |
247 | const MachineInstr *MI, const MachineInstr *WaitingForTypeOfMI, |
248 | InstType &AmbiguousTy) { |
249 | assert(isAmbiguous(MI->getOpcode()) && "Visiting non-Ambiguous opcode.\n" ); |
250 | if (wasVisited(MI)) |
251 | return true; // InstType has already been determined for MI. |
252 | |
253 | startVisit(MI); |
254 | AmbiguousRegDefUseContainer DefUseContainer(MI); |
255 | |
256 | if (isGprbTwoInstrUnalignedLoadOrStore(MI)) { |
257 | setTypes(MI, ITy: Integer); |
258 | return true; |
259 | } |
260 | |
261 | if (AmbiguousTy == InstType::Ambiguous && |
262 | (MI->getOpcode() == TargetOpcode::G_MERGE_VALUES || |
263 | MI->getOpcode() == TargetOpcode::G_UNMERGE_VALUES)) |
264 | AmbiguousTy = InstType::AmbiguousWithMergeOrUnmerge; |
265 | |
266 | // Visit instructions where MI's DEF operands are USED. |
267 | if (visitAdjacentInstrs(MI, AdjacentInstrs&: DefUseContainer.getDefUses(), isDefUse: true, AmbiguousTy)) |
268 | return true; |
269 | |
270 | // Visit instructions that DEFINE MI's USE operands. |
271 | if (visitAdjacentInstrs(MI, AdjacentInstrs&: DefUseContainer.getUseDefs(), isDefUse: false, AmbiguousTy)) |
272 | return true; |
273 | |
274 | // All MI's adjacent instructions, are ambiguous. |
275 | if (!WaitingForTypeOfMI) { |
276 | // This is chain of ambiguous instructions. |
277 | setTypes(MI, ITy: AmbiguousTy); |
278 | return true; |
279 | } |
280 | // Excluding WaitingForTypeOfMI, MI is either connected to chains of ambiguous |
281 | // instructions or has no other adjacent instructions. Anyway InstType could |
282 | // not be determined. There could be unexplored path from some of |
283 | // WaitingForTypeOfMI's adjacent instructions to an instruction with only one |
284 | // mapping available. |
285 | // We are done with this branch, add MI to WaitingForTypeOfMI's WaitingQueue, |
286 | // this way when WaitingForTypeOfMI figures out its InstType same InstType |
287 | // will be assigned to all instructions in this branch. |
288 | addToWaitingQueue(MI: WaitingForTypeOfMI, WaitingForMI: MI); |
289 | return false; |
290 | } |
291 | |
292 | bool MipsRegisterBankInfo::TypeInfoForMF::visitAdjacentInstrs( |
293 | const MachineInstr *MI, SmallVectorImpl<MachineInstr *> &AdjacentInstrs, |
294 | bool isDefUse, InstType &AmbiguousTy) { |
295 | while (!AdjacentInstrs.empty()) { |
296 | MachineInstr *AdjMI = AdjacentInstrs.pop_back_val(); |
297 | |
298 | if (isDefUse ? isFloatingPointOpcodeUse(Opc: AdjMI->getOpcode()) |
299 | : isFloatingPointOpcodeDef(Opc: AdjMI->getOpcode())) { |
300 | setTypes(MI, ITy: InstType::FloatingPoint); |
301 | return true; |
302 | } |
303 | |
304 | // Determine InstType from register bank of phys register that is |
305 | // 'isDefUse ? def : use' of this copy. |
306 | if (AdjMI->getOpcode() == TargetOpcode::COPY) { |
307 | setTypesAccordingToPhysicalRegister(MI, CopyInst: AdjMI, Op: isDefUse ? 0 : 1); |
308 | return true; |
309 | } |
310 | |
311 | // Defaults to integer instruction. Small registers in G_MERGE (uses) and |
312 | // G_UNMERGE (defs) will always be gprb. |
313 | if ((!isDefUse && AdjMI->getOpcode() == TargetOpcode::G_UNMERGE_VALUES) || |
314 | (isDefUse && AdjMI->getOpcode() == TargetOpcode::G_MERGE_VALUES) || |
315 | !isAmbiguous(Opc: AdjMI->getOpcode())) { |
316 | setTypes(MI, ITy: InstType::Integer); |
317 | return true; |
318 | } |
319 | |
320 | // When AdjMI was visited first, MI has to continue to explore remaining |
321 | // adjacent instructions and determine InstType without visiting AdjMI. |
322 | if (!wasVisited(MI: AdjMI) || |
323 | getRecordedTypeForInstr(MI: AdjMI) != InstType::NotDetermined) { |
324 | if (visit(MI: AdjMI, WaitingForTypeOfMI: MI, AmbiguousTy)) { |
325 | // InstType is successfully determined and is same as for AdjMI. |
326 | setTypes(MI, ITy: getRecordedTypeForInstr(MI: AdjMI)); |
327 | return true; |
328 | } |
329 | } |
330 | } |
331 | return false; |
332 | } |
333 | |
334 | void MipsRegisterBankInfo::TypeInfoForMF::setTypes(const MachineInstr *MI, |
335 | InstType InstTy) { |
336 | changeRecordedTypeForInstr(MI, InstTy); |
337 | for (const MachineInstr *WaitingInstr : getWaitingQueueFor(MI)) { |
338 | setTypes(MI: WaitingInstr, InstTy); |
339 | } |
340 | } |
341 | |
342 | void MipsRegisterBankInfo::TypeInfoForMF::setTypesAccordingToPhysicalRegister( |
343 | const MachineInstr *MI, const MachineInstr *CopyInst, unsigned Op) { |
344 | assert((CopyInst->getOperand(Op).getReg().isPhysical()) && |
345 | "Copies of non physical registers should not be considered here.\n" ); |
346 | |
347 | const MachineFunction &MF = *CopyInst->getMF(); |
348 | const MachineRegisterInfo &MRI = MF.getRegInfo(); |
349 | const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); |
350 | const RegisterBankInfo &RBI = |
351 | *CopyInst->getMF()->getSubtarget().getRegBankInfo(); |
352 | const RegisterBank *Bank = |
353 | RBI.getRegBank(Reg: CopyInst->getOperand(i: Op).getReg(), MRI, TRI); |
354 | |
355 | if (Bank == &Mips::FPRBRegBank) |
356 | setTypes(MI, InstTy: InstType::FloatingPoint); |
357 | else if (Bank == &Mips::GPRBRegBank) |
358 | setTypes(MI, InstTy: InstType::Integer); |
359 | else |
360 | llvm_unreachable("Unsupported register bank.\n" ); |
361 | } |
362 | |
363 | MipsRegisterBankInfo::InstType |
364 | MipsRegisterBankInfo::TypeInfoForMF::determineInstType(const MachineInstr *MI) { |
365 | InstType DefaultAmbiguousType = InstType::Ambiguous; |
366 | visit(MI, WaitingForTypeOfMI: nullptr, AmbiguousTy&: DefaultAmbiguousType); |
367 | return getRecordedTypeForInstr(MI); |
368 | } |
369 | |
370 | void MipsRegisterBankInfo::TypeInfoForMF::cleanupIfNewFunction( |
371 | llvm::StringRef FunctionName) { |
372 | if (MFName != FunctionName) { |
373 | MFName = std::string(FunctionName); |
374 | WaitingQueues.clear(); |
375 | Types.clear(); |
376 | } |
377 | } |
378 | |
379 | static const MipsRegisterBankInfo::ValueMapping * |
380 | getMSAMapping(const MachineFunction &MF) { |
381 | assert(MF.getSubtarget<MipsSubtarget>().hasMSA() && |
382 | "MSA mapping not available on target without MSA." ); |
383 | return &Mips::ValueMappings[Mips::MSAIdx]; |
384 | } |
385 | |
386 | static const MipsRegisterBankInfo::ValueMapping *getFprbMapping(unsigned Size) { |
387 | return Size == 32 ? &Mips::ValueMappings[Mips::SPRIdx] |
388 | : &Mips::ValueMappings[Mips::DPRIdx]; |
389 | } |
390 | |
391 | static const unsigned CustomMappingID = 1; |
392 | |
393 | // Only 64 bit mapping is available in fprb and will be marked as custom, i.e. |
394 | // will be split into two 32 bit registers in gprb. |
395 | static const MipsRegisterBankInfo::ValueMapping * |
396 | getGprbOrCustomMapping(unsigned Size, unsigned &MappingID) { |
397 | if (Size == 32) |
398 | return &Mips::ValueMappings[Mips::GPRIdx]; |
399 | |
400 | MappingID = CustomMappingID; |
401 | return &Mips::ValueMappings[Mips::DPRIdx]; |
402 | } |
403 | |
404 | const RegisterBankInfo::InstructionMapping & |
405 | MipsRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { |
406 | |
407 | static TypeInfoForMF TI; |
408 | |
409 | // Reset TI internal data when MF changes. |
410 | TI.cleanupIfNewFunction(FunctionName: MI.getMF()->getName()); |
411 | |
412 | unsigned Opc = MI.getOpcode(); |
413 | const MachineFunction &MF = *MI.getParent()->getParent(); |
414 | const MachineRegisterInfo &MRI = MF.getRegInfo(); |
415 | |
416 | if (MI.getOpcode() != TargetOpcode::G_PHI) { |
417 | const RegisterBankInfo::InstructionMapping &Mapping = |
418 | getInstrMappingImpl(MI); |
419 | if (Mapping.isValid()) |
420 | return Mapping; |
421 | } |
422 | |
423 | using namespace TargetOpcode; |
424 | |
425 | unsigned NumOperands = MI.getNumOperands(); |
426 | const ValueMapping *OperandsMapping = &Mips::ValueMappings[Mips::GPRIdx]; |
427 | unsigned MappingID = DefaultMappingID; |
428 | |
429 | // Check if LLT sizes match sizes of available register banks. |
430 | for (const MachineOperand &Op : MI.operands()) { |
431 | if (Op.isReg()) { |
432 | LLT RegTy = MRI.getType(Reg: Op.getReg()); |
433 | |
434 | if (RegTy.isScalar() && |
435 | (RegTy.getSizeInBits() != 32 && RegTy.getSizeInBits() != 64)) |
436 | return getInvalidInstructionMapping(); |
437 | |
438 | if (RegTy.isVector() && RegTy.getSizeInBits() != 128) |
439 | return getInvalidInstructionMapping(); |
440 | } |
441 | } |
442 | |
443 | const LLT Op0Ty = MRI.getType(Reg: MI.getOperand(i: 0).getReg()); |
444 | unsigned Op0Size = Op0Ty.getSizeInBits(); |
445 | InstType InstTy = InstType::Integer; |
446 | |
447 | switch (Opc) { |
448 | case G_TRUNC: |
449 | case G_UMULH: |
450 | case G_ZEXTLOAD: |
451 | case G_SEXTLOAD: |
452 | case G_PTR_ADD: |
453 | case G_INTTOPTR: |
454 | case G_PTRTOINT: |
455 | case G_AND: |
456 | case G_OR: |
457 | case G_XOR: |
458 | case G_SHL: |
459 | case G_ASHR: |
460 | case G_LSHR: |
461 | case G_BRINDIRECT: |
462 | case G_VASTART: |
463 | case G_BSWAP: |
464 | case G_CTLZ: |
465 | OperandsMapping = &Mips::ValueMappings[Mips::GPRIdx]; |
466 | break; |
467 | case G_ADD: |
468 | case G_SUB: |
469 | case G_MUL: |
470 | case G_SDIV: |
471 | case G_SREM: |
472 | case G_UDIV: |
473 | case G_UREM: |
474 | OperandsMapping = &Mips::ValueMappings[Mips::GPRIdx]; |
475 | if (Op0Size == 128) |
476 | OperandsMapping = getMSAMapping(MF); |
477 | break; |
478 | case G_STORE: |
479 | case G_LOAD: { |
480 | if (Op0Size == 128) { |
481 | OperandsMapping = getOperandsMapping( |
482 | OpdsMapping: {getMSAMapping(MF), &Mips::ValueMappings[Mips::GPRIdx]}); |
483 | break; |
484 | } |
485 | |
486 | if (!Op0Ty.isPointer()) |
487 | InstTy = TI.determineInstType(MI: &MI); |
488 | |
489 | if (isFloatingPoint_32or64(InstTy, OpSize: Op0Size) || |
490 | isAmbiguous_64(InstTy, OpSize: Op0Size)) { |
491 | OperandsMapping = getOperandsMapping( |
492 | OpdsMapping: {getFprbMapping(Size: Op0Size), &Mips::ValueMappings[Mips::GPRIdx]}); |
493 | } else { |
494 | assert((isInteger_32(InstTy, Op0Size) || |
495 | isAmbiguous_32(InstTy, Op0Size) || |
496 | isAmbiguousWithMergeOrUnmerge_64(InstTy, Op0Size)) && |
497 | "Unexpected Inst type" ); |
498 | OperandsMapping = |
499 | getOperandsMapping(OpdsMapping: {getGprbOrCustomMapping(Size: Op0Size, MappingID), |
500 | &Mips::ValueMappings[Mips::GPRIdx]}); |
501 | } |
502 | |
503 | break; |
504 | } |
505 | case G_PHI: { |
506 | if (!Op0Ty.isPointer()) |
507 | InstTy = TI.determineInstType(MI: &MI); |
508 | |
509 | // PHI is copylike and should have one regbank in mapping for def register. |
510 | if (isAmbiguousWithMergeOrUnmerge_64(InstTy, OpSize: Op0Size)) { |
511 | OperandsMapping = |
512 | getOperandsMapping(OpdsMapping: {&Mips::ValueMappings[Mips::DPRIdx]}); |
513 | TI.clearTypeInfoData(MI: &MI); |
514 | return getInstructionMapping(ID: CustomMappingID, /*Cost=*/1, OperandsMapping, |
515 | /*NumOperands=*/1); |
516 | } |
517 | assert((isInteger_32(InstTy, Op0Size) || |
518 | isFloatingPoint_32or64(InstTy, Op0Size) || |
519 | isAmbiguous_32or64(InstTy, Op0Size)) && |
520 | "Unexpected Inst type" ); |
521 | // Use default handling for PHI, i.e. set reg bank of def operand to match |
522 | // register banks of use operands. |
523 | return getInstrMappingImpl(MI); |
524 | } |
525 | case G_SELECT: { |
526 | if (!Op0Ty.isPointer()) |
527 | InstTy = TI.determineInstType(MI: &MI); |
528 | if (isFloatingPoint_32or64(InstTy, OpSize: Op0Size) || |
529 | isAmbiguous_64(InstTy, OpSize: Op0Size)) { |
530 | const RegisterBankInfo::ValueMapping *Bank = getFprbMapping(Size: Op0Size); |
531 | OperandsMapping = getOperandsMapping( |
532 | OpdsMapping: {Bank, &Mips::ValueMappings[Mips::GPRIdx], Bank, Bank}); |
533 | break; |
534 | } else { |
535 | assert((isInteger_32(InstTy, Op0Size) || |
536 | isAmbiguous_32(InstTy, Op0Size) || |
537 | isAmbiguousWithMergeOrUnmerge_64(InstTy, Op0Size)) && |
538 | "Unexpected Inst type" ); |
539 | const RegisterBankInfo::ValueMapping *Bank = |
540 | getGprbOrCustomMapping(Size: Op0Size, MappingID); |
541 | OperandsMapping = getOperandsMapping( |
542 | OpdsMapping: {Bank, &Mips::ValueMappings[Mips::GPRIdx], Bank, Bank}); |
543 | } |
544 | break; |
545 | } |
546 | case G_IMPLICIT_DEF: { |
547 | if (!Op0Ty.isPointer()) |
548 | InstTy = TI.determineInstType(MI: &MI); |
549 | |
550 | if (isFloatingPoint_32or64(InstTy, OpSize: Op0Size)) |
551 | OperandsMapping = getFprbMapping(Size: Op0Size); |
552 | else { |
553 | assert((isInteger_32(InstTy, Op0Size) || |
554 | isAmbiguousWithMergeOrUnmerge_64(InstTy, Op0Size)) && |
555 | "Unexpected Inst type" ); |
556 | OperandsMapping = getGprbOrCustomMapping(Size: Op0Size, MappingID); |
557 | } |
558 | } break; |
559 | case G_UNMERGE_VALUES: { |
560 | assert(MI.getNumOperands() == 3 && "Unsupported G_UNMERGE_VALUES" ); |
561 | unsigned Op3Size = MRI.getType(Reg: MI.getOperand(i: 2).getReg()).getSizeInBits(); |
562 | InstTy = TI.determineInstType(MI: &MI); |
563 | assert((isAmbiguousWithMergeOrUnmerge_64(InstTy, Op3Size) || |
564 | isFloatingPoint_64(InstTy, Op3Size)) && |
565 | "Unexpected Inst type" ); |
566 | OperandsMapping = getOperandsMapping(OpdsMapping: {&Mips::ValueMappings[Mips::GPRIdx], |
567 | &Mips::ValueMappings[Mips::GPRIdx], |
568 | &Mips::ValueMappings[Mips::DPRIdx]}); |
569 | if (isAmbiguousWithMergeOrUnmerge_64(InstTy, OpSize: Op3Size)) |
570 | MappingID = CustomMappingID; |
571 | break; |
572 | } |
573 | case G_MERGE_VALUES: { |
574 | InstTy = TI.determineInstType(MI: &MI); |
575 | assert((isAmbiguousWithMergeOrUnmerge_64(InstTy, Op0Size) || |
576 | isFloatingPoint_64(InstTy, Op0Size)) && |
577 | "Unexpected Inst type" ); |
578 | OperandsMapping = getOperandsMapping(OpdsMapping: {&Mips::ValueMappings[Mips::DPRIdx], |
579 | &Mips::ValueMappings[Mips::GPRIdx], |
580 | &Mips::ValueMappings[Mips::GPRIdx]}); |
581 | if (isAmbiguousWithMergeOrUnmerge_64(InstTy, OpSize: Op0Size)) |
582 | MappingID = CustomMappingID; |
583 | break; |
584 | } |
585 | case G_FADD: |
586 | case G_FSUB: |
587 | case G_FMUL: |
588 | case G_FDIV: |
589 | case G_FABS: |
590 | case G_FSQRT: |
591 | OperandsMapping = getFprbMapping(Size: Op0Size); |
592 | if (Op0Size == 128) |
593 | OperandsMapping = getMSAMapping(MF); |
594 | break; |
595 | case G_FCONSTANT: |
596 | OperandsMapping = getOperandsMapping(OpdsMapping: {getFprbMapping(Size: Op0Size), nullptr}); |
597 | break; |
598 | case G_FCMP: { |
599 | unsigned Op2Size = MRI.getType(Reg: MI.getOperand(i: 2).getReg()).getSizeInBits(); |
600 | OperandsMapping = |
601 | getOperandsMapping(OpdsMapping: {&Mips::ValueMappings[Mips::GPRIdx], nullptr, |
602 | getFprbMapping(Size: Op2Size), getFprbMapping(Size: Op2Size)}); |
603 | break; |
604 | } |
605 | case G_FPEXT: |
606 | OperandsMapping = getOperandsMapping(OpdsMapping: {&Mips::ValueMappings[Mips::DPRIdx], |
607 | &Mips::ValueMappings[Mips::SPRIdx]}); |
608 | break; |
609 | case G_FPTRUNC: |
610 | OperandsMapping = getOperandsMapping(OpdsMapping: {&Mips::ValueMappings[Mips::SPRIdx], |
611 | &Mips::ValueMappings[Mips::DPRIdx]}); |
612 | break; |
613 | case G_FPTOSI: { |
614 | assert((Op0Size == 32) && "Unsupported integer size" ); |
615 | unsigned SizeFP = MRI.getType(Reg: MI.getOperand(i: 1).getReg()).getSizeInBits(); |
616 | OperandsMapping = getOperandsMapping( |
617 | OpdsMapping: {&Mips::ValueMappings[Mips::GPRIdx], getFprbMapping(Size: SizeFP)}); |
618 | break; |
619 | } |
620 | case G_SITOFP: |
621 | assert((MRI.getType(MI.getOperand(1).getReg()).getSizeInBits() == 32) && |
622 | "Unsupported integer size" ); |
623 | OperandsMapping = getOperandsMapping( |
624 | OpdsMapping: {getFprbMapping(Size: Op0Size), &Mips::ValueMappings[Mips::GPRIdx]}); |
625 | break; |
626 | case G_CONSTANT: |
627 | case G_FRAME_INDEX: |
628 | case G_GLOBAL_VALUE: |
629 | case G_JUMP_TABLE: |
630 | case G_BRCOND: |
631 | OperandsMapping = |
632 | getOperandsMapping(OpdsMapping: {&Mips::ValueMappings[Mips::GPRIdx], nullptr}); |
633 | break; |
634 | case G_BRJT: |
635 | OperandsMapping = |
636 | getOperandsMapping(OpdsMapping: {&Mips::ValueMappings[Mips::GPRIdx], nullptr, |
637 | &Mips::ValueMappings[Mips::GPRIdx]}); |
638 | break; |
639 | case G_ICMP: |
640 | OperandsMapping = |
641 | getOperandsMapping(OpdsMapping: {&Mips::ValueMappings[Mips::GPRIdx], nullptr, |
642 | &Mips::ValueMappings[Mips::GPRIdx], |
643 | &Mips::ValueMappings[Mips::GPRIdx]}); |
644 | break; |
645 | default: |
646 | return getInvalidInstructionMapping(); |
647 | } |
648 | |
649 | if (MappingID == CustomMappingID) |
650 | TI.clearTypeInfoData(MI: &MI); |
651 | return getInstructionMapping(ID: MappingID, /*Cost=*/1, OperandsMapping, |
652 | NumOperands); |
653 | } |
654 | |
655 | using InstListTy = GISelWorkList<4>; |
656 | namespace { |
657 | class InstManager : public GISelChangeObserver { |
658 | InstListTy &InstList; |
659 | MachineIRBuilder &B; |
660 | |
661 | public: |
662 | InstManager(MachineIRBuilder &B, InstListTy &Insts) : InstList(Insts), B(B) { |
663 | assert(!B.isObservingChanges()); |
664 | B.setChangeObserver(*this); |
665 | } |
666 | |
667 | ~InstManager() { B.stopObservingChanges(); } |
668 | |
669 | void createdInstr(MachineInstr &MI) override { InstList.insert(I: &MI); } |
670 | void erasingInstr(MachineInstr &MI) override {} |
671 | void changingInstr(MachineInstr &MI) override {} |
672 | void changedInstr(MachineInstr &MI) override {} |
673 | }; |
674 | } // end anonymous namespace |
675 | |
676 | void MipsRegisterBankInfo::setRegBank(MachineInstr &MI, |
677 | MachineRegisterInfo &MRI) const { |
678 | Register Dest = MI.getOperand(i: 0).getReg(); |
679 | switch (MI.getOpcode()) { |
680 | case TargetOpcode::G_STORE: |
681 | // No def operands, skip this instruction. |
682 | break; |
683 | case TargetOpcode::G_CONSTANT: |
684 | case TargetOpcode::G_LOAD: |
685 | case TargetOpcode::G_SELECT: |
686 | case TargetOpcode::G_PHI: |
687 | case TargetOpcode::G_IMPLICIT_DEF: { |
688 | assert(MRI.getType(Dest) == LLT::scalar(32) && "Unexpected operand type." ); |
689 | MRI.setRegBank(Reg: Dest, RegBank: getRegBank(ID: Mips::GPRBRegBankID)); |
690 | break; |
691 | } |
692 | case TargetOpcode::G_PTR_ADD: { |
693 | assert(MRI.getType(Dest).isPointer() && "Unexpected operand type." ); |
694 | MRI.setRegBank(Reg: Dest, RegBank: getRegBank(ID: Mips::GPRBRegBankID)); |
695 | break; |
696 | } |
697 | default: |
698 | llvm_unreachable("Unexpected opcode." ); |
699 | } |
700 | } |
701 | |
702 | static void |
703 | combineAwayG_UNMERGE_VALUES(LegalizationArtifactCombiner &ArtCombiner, |
704 | GUnmerge &MI, GISelChangeObserver &Observer) { |
705 | SmallVector<Register, 4> UpdatedDefs; |
706 | SmallVector<MachineInstr *, 2> DeadInstrs; |
707 | ArtCombiner.tryCombineUnmergeValues(MI, DeadInsts&: DeadInstrs, |
708 | UpdatedDefs, Observer); |
709 | for (MachineInstr *DeadMI : DeadInstrs) |
710 | DeadMI->eraseFromParent(); |
711 | } |
712 | |
713 | void MipsRegisterBankInfo::applyMappingImpl( |
714 | MachineIRBuilder &Builder, const OperandsMapper &OpdMapper) const { |
715 | MachineInstr &MI = OpdMapper.getMI(); |
716 | Builder.setInstrAndDebugLoc(MI); |
717 | |
718 | InstListTy NewInstrs; |
719 | MachineFunction *MF = MI.getMF(); |
720 | MachineRegisterInfo &MRI = OpdMapper.getMRI(); |
721 | const LegalizerInfo &LegInfo = *MF->getSubtarget().getLegalizerInfo(); |
722 | |
723 | InstManager NewInstrObserver(Builder, NewInstrs); |
724 | LegalizerHelper Helper(*MF, NewInstrObserver, Builder); |
725 | LegalizationArtifactCombiner ArtCombiner(Builder, MF->getRegInfo(), LegInfo); |
726 | |
727 | switch (MI.getOpcode()) { |
728 | case TargetOpcode::G_LOAD: |
729 | case TargetOpcode::G_STORE: |
730 | case TargetOpcode::G_PHI: |
731 | case TargetOpcode::G_SELECT: |
732 | case TargetOpcode::G_IMPLICIT_DEF: { |
733 | Helper.narrowScalar(MI, TypeIdx: 0, NarrowTy: LLT::scalar(SizeInBits: 32)); |
734 | // Handle new instructions. |
735 | while (!NewInstrs.empty()) { |
736 | MachineInstr *NewMI = NewInstrs.pop_back_val(); |
737 | // This is new G_UNMERGE that was created during narrowScalar and will |
738 | // not be considered for regbank selection. RegBankSelect for mips |
739 | // visits/makes corresponding G_MERGE first. Combine them here. |
740 | if (auto *Unmerge = dyn_cast<GUnmerge>(Val: NewMI)) |
741 | combineAwayG_UNMERGE_VALUES(ArtCombiner, MI&: *Unmerge, Observer&: NewInstrObserver); |
742 | // This G_MERGE will be combined away when its corresponding G_UNMERGE |
743 | // gets regBankSelected. |
744 | else if (NewMI->getOpcode() == TargetOpcode::G_MERGE_VALUES) |
745 | continue; |
746 | else |
747 | // Manually set register banks for def operands to 32 bit gprb. |
748 | setRegBank(MI&: *NewMI, MRI); |
749 | } |
750 | return; |
751 | } |
752 | case TargetOpcode::G_UNMERGE_VALUES: |
753 | combineAwayG_UNMERGE_VALUES(ArtCombiner, MI&: cast<GUnmerge>(Val&: MI), |
754 | Observer&: NewInstrObserver); |
755 | return; |
756 | default: |
757 | break; |
758 | } |
759 | |
760 | return applyDefaultMapping(OpdMapper); |
761 | } |
762 | |