LLVM 24.0.0git
AMDGPURegBankLegalizeHelper.cpp
Go to the documentation of this file.
1//===-- AMDGPURegBankLegalizeHelper.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//
9/// Implements actual lowering algorithms for each ID that can be used in
10/// Rule.OperandMapping. Similar to legalizer helper but with register banks.
11//
12//===----------------------------------------------------------------------===//
13
16#include "AMDGPUInstrInfo.h"
17#include "AMDGPULaneMaskUtils.h"
20#include "GCNSubtarget.h"
28#include "llvm/IR/IntrinsicsAMDGPU.h"
29
30#define DEBUG_TYPE "amdgpu-reg-bank-legalize"
31
32using namespace llvm;
33using namespace AMDGPU;
34
38 const RegBankLegalizeRules &RBLRules)
39 : MF(B.getMF()), MFI(MF.getInfo<SIMachineFunctionInfo>()),
40 ST(MF.getSubtarget<GCNSubtarget>()), TII(*ST.getInstrInfo()), B(B),
41 MRI(*B.getMRI()), MUI(MUI), VT(VT), RBI(RBI), MORE(MF, nullptr),
42 RBLRules(RBLRules), IsWave32(ST.isWave32()),
43 SgprRB(&RBI.getRegBank(AMDGPU::SGPRRegBankID)),
44 VgprRB(&RBI.getRegBank(AMDGPU::VGPRRegBankID)),
45 AgprRB(&RBI.getRegBank(AMDGPU::AGPRRegBankID)),
46 VccRB(&RBI.getRegBank(AMDGPU::VCCRegBankID)) {}
47
49 const SetOfRulesForOpcode *RuleSet = RBLRules.getRulesForOpc(MI);
50 if (!RuleSet) {
52 "No AMDGPU RegBankLegalize rules defined for opcode",
53 MI);
54 return false;
55 }
56
57 const RegBankLLTMapping *Mapping = RuleSet->findMappingForMI(MI, MRI, MUI);
58 if (!Mapping) {
60 "AMDGPU RegBankLegalize: none of the rules defined with "
61 "'Any' for MI's opcode matched MI",
62 MI);
63 return false;
64 }
65
66 WaterfallInfo WFI;
67 unsigned OpIdx = 0;
68 if (!Mapping->DstOpMapping.empty()) {
69 B.setInsertPt(*MI.getParent(), std::next(MI.getIterator()));
70 if (!applyMappingDst(MI, OpIdx, Mapping->DstOpMapping))
71 return false;
72 }
73 if (!Mapping->SrcOpMapping.empty()) {
74 B.setInstr(MI);
75 if (!applyMappingSrc(MI, OpIdx, Mapping->SrcOpMapping, WFI))
76 return false;
77 }
78
79 if (!lower(MI, *Mapping, WFI))
80 return false;
81
82 if (!WFI.SgprWaterfallOperandRegs.empty()) {
83 if (!executeInWaterfallLoop(B, WFI))
84 return false;
85 }
86
87 return true;
88}
89
90bool RegBankLegalizeHelper::executeInWaterfallLoop(MachineIRBuilder &B,
91 const WaterfallInfo &WFI) {
92 assert(WFI.Start.isValid() && WFI.End.isValid() &&
93 "Waterfall range not initialized");
94
95 // Track use registers which have already been expanded with a readfirstlane
96 // sequence. This may have multiple uses if moving a sequence.
97 DenseMap<Register, Register> WaterfalledRegMap;
98
99 MachineBasicBlock &MBB = B.getMBB();
100 MachineFunction &MF = B.getMF();
101
104
105 const SIRegisterInfo *TRI = ST.getRegisterInfo();
106 const TargetRegisterClass *WaveRC = TRI->getWaveMaskRegClass();
108
109#ifndef NDEBUG
110 const int OrigRangeSize = std::distance(BeginIt, EndIt);
111#endif
112
113 MachineRegisterInfo &MRI = *B.getMRI();
114 Register SaveExecReg = MRI.createVirtualRegister(WaveRC);
115 Register InitSaveExecReg = MRI.createVirtualRegister(WaveRC);
116
117 // Don't bother using generic instructions/registers for the exec mask.
118 B.setInstr(*WFI.Start);
119 B.buildInstr(TargetOpcode::IMPLICIT_DEF).addDef(InitSaveExecReg);
120
121 Register SavedExec = MRI.createVirtualRegister(WaveRC);
122
123 // To insert the loop we need to split the block. Move everything before
124 // this point to a new block, and insert a new empty block before this
125 // instruction.
128 MachineBasicBlock *RestoreExecBB = MF.CreateMachineBasicBlock();
129 MachineBasicBlock *RemainderBB = MF.CreateMachineBasicBlock();
131 ++MBBI;
132 MF.insert(MBBI, LoopBB);
133 MF.insert(MBBI, BodyBB);
134 MF.insert(MBBI, RestoreExecBB);
135 MF.insert(MBBI, RemainderBB);
136
137 LoopBB->addSuccessor(BodyBB);
138 BodyBB->addSuccessor(RestoreExecBB);
139 BodyBB->addSuccessor(LoopBB);
140
141 // Move the rest of the block into a new block.
143 RemainderBB->splice(RemainderBB->begin(), &MBB, EndIt, MBB.end());
144
145 MBB.addSuccessor(LoopBB);
146 RestoreExecBB->addSuccessor(RemainderBB);
147
148 B.setInsertPt(*LoopBB, LoopBB->end());
149
150 // +-MBB:------------+
151 // | ... |
152 // | %0 = G_INST_1 |
153 // | %Dst = MI %Vgpr |
154 // | %1 = G_INST_2 |
155 // | ... |
156 // +-----------------+
157 // ->
158 // +-MBB-------------------------------+
159 // | ... |
160 // | %0 = G_INST_1 |
161 // | %SaveExecReg = S_MOV_B32 $exec_lo |
162 // +----------------|------------------+
163 // | /------------------------------|
164 // V V |
165 // +-LoopBB---------------------------------------------------------------+ |
166 // | %CurrentLaneReg:sgpr(s32) = READFIRSTLANE %Vgpr | |
167 // | instead of executing for each lane, see if other lanes had | |
168 // | same value for %Vgpr and execute for them also. | |
169 // | %CondReg:vcc(s1) = G_ICMP eq %CurrentLaneReg, %Vgpr | |
170 // | %CondRegLM:sreg_32 = ballot %CondReg // copy vcc to sreg32 lane mask | |
171 // | %SavedExec = S_AND_SAVEEXEC_B32 %CondRegLM | |
172 // | exec is active for lanes with the same "CurrentLane value" in Vgpr | |
173 // +----------------|-----------------------------------------------------+ |
174 // V |
175 // +-BodyBB------------------------------------------------------------+ |
176 // | %Dst = MI %CurrentLaneReg:sgpr(s32) | |
177 // | executed only for active lanes and written to Dst | |
178 // | $exec = S_XOR_B32 $exec, %SavedExec | |
179 // | set active lanes to 0 in SavedExec, lanes that did not write to | |
180 // | Dst yet, and set this as new exec (for READFIRSTLANE and ICMP) | |
181 // | SI_WATERFALL_LOOP LoopBB |-----|
182 // +----------------|--------------------------------------------------+
183 // V
184 // +-RestoreExecBB--------------------------+
185 // | $exec_lo = S_MOV_B32_term %SaveExecReg |
186 // +----------------|-----------------------+
187 // V
188 // +-RemainderBB:----------------------+
189 // | %1 = G_INST_2 |
190 // | ... |
191 // +---------------------------------- +
192
193 // Move the instruction into the loop body. Note we moved everything after
194 // Range.end() already into a new block, so Range.end() is no longer valid.
195 BodyBB->splice(BodyBB->end(), &MBB, BeginIt, MBB.end());
196
197 // Figure out the iterator range after splicing the instructions.
198 MachineBasicBlock::iterator NewBegin = BeginIt;
199 auto NewEnd = BodyBB->end();
200 assert(std::distance(NewBegin, NewEnd) == OrigRangeSize);
201
202 B.setMBB(*LoopBB);
203 Register CondReg;
204
205 for (MachineInstr &MI : make_range(NewBegin, NewEnd)) {
206 for (MachineOperand &Op : MI.all_uses()) {
207 Register OldReg = Op.getReg();
208 if (!WFI.SgprWaterfallOperandRegs.count(OldReg))
209 continue;
210
211 // See if we already processed this register in another instruction in
212 // the sequence.
213 auto OldVal = WaterfalledRegMap.find(OldReg);
214 if (OldVal != WaterfalledRegMap.end()) {
215 Op.setReg(OldVal->second);
216 continue;
217 }
218
219 Register OpReg = Op.getReg();
220 LLT OpTy = MRI.getType(OpReg);
221
222 // TODO: support for agpr
223 assert(MRI.getRegBank(OpReg) == VgprRB);
224 Register CurrentLaneReg = MRI.createVirtualRegister({SgprRB, OpTy});
225 buildReadFirstLane(B, CurrentLaneReg, OpReg, RBI);
226
227 // Build the comparison(s), CurrentLaneReg == OpReg.
228 unsigned OpSize = OpTy.getSizeInBits();
229 unsigned PartSize = (OpSize % 64 == 0) ? 64 : 32;
230 LLT PartTy = LLT::integer(PartSize);
231 unsigned NumParts = OpSize / PartSize;
233 SmallVector<Register, 8> CurrentLaneParts;
234
235 if (NumParts == 1) {
236 OpParts.push_back(OpReg);
237 CurrentLaneParts.push_back(CurrentLaneReg);
238 } else {
239 auto UnmergeOp = B.buildUnmerge({VgprRB, PartTy}, OpReg);
240 auto UnmergeCurrLane = B.buildUnmerge({SgprRB, PartTy}, CurrentLaneReg);
241 for (unsigned i = 0; i < NumParts; ++i) {
242 OpParts.push_back(UnmergeOp.getReg(i));
243 CurrentLaneParts.push_back(UnmergeCurrLane.getReg(i));
244 }
245 }
246
247 for (unsigned i = 0; i < NumParts; ++i) {
248 Register CmpReg = MRI.createVirtualRegister(VccRB_S1);
249 B.buildICmp(CmpInst::ICMP_EQ, CmpReg, CurrentLaneParts[i], OpParts[i]);
250
251 if (!CondReg)
252 CondReg = CmpReg;
253 else
254 CondReg = B.buildAnd(VccRB_S1, CondReg, CmpReg).getReg(0);
255 }
256
257 Op.setReg(CurrentLaneReg);
258
259 // Make sure we don't re-process this register again.
260 WaterfalledRegMap.insert(std::pair(OldReg, Op.getReg()));
261 }
262 }
263
264 // Copy vcc to sgpr32/64, ballot becomes a no-op during instruction selection.
265 Register CondRegLM =
266 MRI.createVirtualRegister({WaveRC, LLT::integer(IsWave32 ? 32 : 64)});
267 B.buildIntrinsic(Intrinsic::amdgcn_ballot, CondRegLM).addReg(CondReg);
268
269 // Update EXEC, save the original EXEC value to SavedExec.
270 B.buildInstr(LMC.AndSaveExecOpc)
271 .addDef(SavedExec)
272 .addReg(CondRegLM, RegState::Kill);
273 MRI.setSimpleHint(SavedExec, CondRegLM);
274
275 B.setInsertPt(*BodyBB, BodyBB->end());
276
277 // Update EXEC, switch all done bits to 0 and all todo bits to 1.
278 B.buildInstr(LMC.XorTermOpc)
279 .addDef(LMC.ExecReg)
280 .addReg(LMC.ExecReg)
281 .addReg(SavedExec);
282
283 // XXX - s_xor_b64 sets scc to 1 if the result is nonzero, so can we use
284 // s_cbranch_scc0?
285
286 // Loop back to V_READFIRSTLANE_B32 if there are still variants to cover.
287 B.buildInstr(AMDGPU::SI_WATERFALL_LOOP).addMBB(LoopBB);
288
289 // Save the EXEC mask before the loop.
290 B.setInsertPt(MBB, MBB.end());
291 B.buildInstr(LMC.MovOpc).addDef(SaveExecReg).addReg(LMC.ExecReg);
292
293 // Restore the EXEC mask after the loop.
294 B.setInsertPt(*RestoreExecBB, RestoreExecBB->begin());
295 B.buildInstr(LMC.MovTermOpc).addDef(LMC.ExecReg).addReg(SaveExecReg);
296
297 // Set the insert point after the original instruction, so any new
298 // instructions will be in the remainder.
299 B.setInsertPt(*RemainderBB, RemainderBB->begin());
300
301 return true;
302}
303
304// Analyze a combined offset from an llvm.amdgcn.s.buffer intrinsic and store
305// the three offsets (voffset, soffset and instoffset)
306unsigned RegBankLegalizeHelper::setBufferOffsets(
307 MachineIRBuilder &B, Register CombinedOffset, Register &VOffsetReg,
308 Register &SOffsetReg, int64_t &InstOffsetVal, Align Alignment) {
309 if (std::optional<int64_t> Imm =
310 getIConstantVRegSExtVal(CombinedOffset, MRI)) {
311 uint32_t SOffset, ImmOffset;
312 if (TII.splitMUBUFOffset(*Imm, SOffset, ImmOffset, Alignment)) {
313 VOffsetReg = B.buildConstant(VgprRB_I32, 0).getReg(0);
314 SOffsetReg = B.buildConstant(SgprRB_I32, SOffset).getReg(0);
315 InstOffsetVal = ImmOffset;
316 return SOffset + ImmOffset;
317 }
318 }
319 const bool CheckNUW = ST.hasGFX1250Insts();
321 MRI, CombinedOffset, /*KnownBits=*/nullptr,
322 /*CheckNUW=*/CheckNUW);
323 uint32_t SOffset, ImmOffset;
324 if (static_cast<int32_t>(Offset) > 0 &&
325 TII.splitMUBUFOffset(Offset, SOffset, ImmOffset, Alignment)) {
326 if (Base.isValid() && MRI.getRegBank(Base) == VgprRB) {
327 VOffsetReg = Base;
328 SOffsetReg = B.buildConstant(SgprRB_I32, SOffset).getReg(0);
329 InstOffsetVal = ImmOffset;
330 return 0;
331 }
332 // If we have SGPR base, we can use it for soffset.
333 if (SOffset == 0) {
334 VOffsetReg = B.buildConstant(VgprRB_I32, 0).getReg(0);
335 SOffsetReg = Base;
336 InstOffsetVal = ImmOffset;
337 return 0;
338 }
339 }
340 // Handle the variable sgpr + vgpr case.
341 MachineInstr *Add = getOpcodeDef(AMDGPU::G_ADD, CombinedOffset, MRI);
342 if (Add && static_cast<int32_t>(Offset) >= 0 &&
343 (!CheckNUW || Add->getFlag(MachineInstr::NoUWrap))) {
344 Register Src0 = getSrcRegIgnoringCopies(Add->getOperand(1).getReg(), MRI);
345 Register Src1 = getSrcRegIgnoringCopies(Add->getOperand(2).getReg(), MRI);
346 const RegisterBank *Src0Bank = MRI.getRegBank(Src0);
347 const RegisterBank *Src1Bank = MRI.getRegBank(Src1);
348 if (Src0Bank == VgprRB && Src1Bank == SgprRB) {
349 VOffsetReg = Src0;
350 SOffsetReg = Src1;
351 return 0;
352 }
353 if (Src0Bank == SgprRB && Src1Bank == VgprRB) {
354 VOffsetReg = Src1;
355 SOffsetReg = Src0;
356 return 0;
357 }
358 }
359 // Ensure we have a VGPR for the combined offset. This could be an issue if we
360 // have an SGPR offset and a VGPR resource.
361 if (MRI.getRegBank(CombinedOffset) == VgprRB) {
362 VOffsetReg = CombinedOffset;
363 } else {
364 VOffsetReg = B.buildCopy(VgprRB_I32, CombinedOffset).getReg(0);
365 }
366 SOffsetReg = B.buildConstant(SgprRB_I32, 0).getReg(0);
367 return 0;
368}
369
370bool RegBankLegalizeHelper::splitLoad(MachineInstr &MI,
371 ArrayRef<LLT> LLTBreakdown, LLT MergeTy) {
372 MachineFunction &MF = B.getMF();
373 assert(MI.getNumMemOperands() == 1);
374 MachineMemOperand &BaseMMO = **MI.memoperands_begin();
375 Register Dst = MI.getOperand(0).getReg();
376 const RegisterBank *DstRB = MRI.getRegBankOrNull(Dst);
377 Register Base = MI.getOperand(1).getReg();
378 LLT PtrTy = MRI.getType(Base);
379 const RegisterBank *PtrRB = MRI.getRegBankOrNull(Base);
380 LLT OffsetTy = LLT::integer(PtrTy.getSizeInBits());
381 SmallVector<Register, 4> LoadPartRegs;
382
383 unsigned ByteOffset = 0;
384 for (LLT PartTy : LLTBreakdown) {
385 Register BasePlusOffset;
386 if (ByteOffset == 0) {
387 BasePlusOffset = Base;
388 } else {
389 auto Offset = B.buildConstant({PtrRB, OffsetTy}, ByteOffset);
390 BasePlusOffset =
391 B.buildObjectPtrOffset({PtrRB, PtrTy}, Base, Offset).getReg(0);
392 }
393 auto *OffsetMMO = MF.getMachineMemOperand(&BaseMMO, ByteOffset, PartTy);
394 auto LoadPart = B.buildLoad({DstRB, PartTy}, BasePlusOffset, *OffsetMMO);
395 LoadPartRegs.push_back(LoadPart.getReg(0));
396 ByteOffset += PartTy.getSizeInBytes();
397 }
398
399 if (!MergeTy.isValid()) {
400 // Loads are of same size, concat or merge them together.
401 B.buildMergeLikeInstr(Dst, LoadPartRegs);
402 } else {
403 // Loads are not all of same size, need to unmerge them to smaller pieces
404 // of MergeTy type, then merge pieces to Dst.
405 SmallVector<Register, 4> MergeTyParts;
406 for (Register Reg : LoadPartRegs) {
407 if (MRI.getType(Reg) == MergeTy) {
408 MergeTyParts.push_back(Reg);
409 } else {
410 auto Unmerge = B.buildUnmerge({DstRB, MergeTy}, Reg);
411 for (unsigned i = 0; i < Unmerge->getNumOperands() - 1; ++i)
412 MergeTyParts.push_back(Unmerge.getReg(i));
413 }
414 }
415 B.buildMergeLikeInstr(Dst, MergeTyParts);
416 }
417 MI.eraseFromParent();
418 return true;
419}
420
421bool RegBankLegalizeHelper::widenLoad(MachineInstr &MI, LLT WideTy,
422 LLT MergeTy) {
423 MachineFunction &MF = B.getMF();
424 assert(MI.getNumMemOperands() == 1);
425 MachineMemOperand &BaseMMO = **MI.memoperands_begin();
426 Register Dst = MI.getOperand(0).getReg();
427 const RegisterBank *DstRB = MRI.getRegBankOrNull(Dst);
428 Register Base = MI.getOperand(1).getReg();
429
430 MachineMemOperand *WideMMO = MF.getMachineMemOperand(&BaseMMO, 0, WideTy);
431 auto WideLoad = B.buildLoad({DstRB, WideTy}, Base, *WideMMO);
432
433 if (WideTy.isScalar()) {
434 B.buildTrunc(Dst, WideLoad);
435 } else {
436 SmallVector<Register, 4> MergeTyParts;
437 auto Unmerge = B.buildUnmerge({DstRB, MergeTy}, WideLoad);
438
439 LLT DstTy = MRI.getType(Dst);
440 unsigned NumElts = DstTy.getSizeInBits() / MergeTy.getSizeInBits();
441 for (unsigned i = 0; i < NumElts; ++i) {
442 MergeTyParts.push_back(Unmerge.getReg(i));
443 }
444 B.buildMergeLikeInstr(Dst, MergeTyParts);
445 }
446 MI.eraseFromParent();
447 return true;
448}
449
450bool RegBankLegalizeHelper::widenMMOToS32(GAnyLoad &MI) const {
451 Register Dst = MI.getDstReg();
452 Register Ptr = MI.getPointerReg();
453 MachineMemOperand &MMO = MI.getMMO();
454 unsigned MemSize = 8 * MMO.getSize().getValue();
455
456 MachineMemOperand *WideMMO = B.getMF().getMachineMemOperand(&MMO, 0, S32);
457
458 if (MI.getOpcode() == G_LOAD) {
459 B.buildLoad(Dst, Ptr, *WideMMO);
460 } else {
461 auto Load = B.buildLoad(SgprRB_I32, Ptr, *WideMMO);
462
463 if (MI.getOpcode() == G_ZEXTLOAD) {
464 APInt Mask = APInt::getLowBitsSet(S32.getSizeInBits(), MemSize);
465 auto MaskCst = B.buildConstant(SgprRB_I32, Mask);
466 B.buildAnd(Dst, Load, MaskCst);
467 } else {
468 assert(MI.getOpcode() == G_SEXTLOAD);
469 B.buildSExtInReg(Dst, Load, MemSize);
470 }
471 }
472
473 MI.eraseFromParent();
474 return true;
475}
476
477bool RegBankLegalizeHelper::lowerVccExtToSel(MachineInstr &MI) {
478 Register Dst = MI.getOperand(0).getReg();
479 LLT Ty = MRI.getType(Dst);
480 Register Src = MI.getOperand(1).getReg();
481 unsigned Opc = MI.getOpcode();
482 int TrueExtCst = Opc == G_SEXT ? -1 : 1;
483 if (Ty == S32 || Ty == S16) {
484 auto True = B.buildConstant({VgprRB, Ty}, TrueExtCst);
485 auto False = B.buildConstant({VgprRB, Ty}, 0);
486 B.buildSelect(Dst, Src, True, False);
487 } else if (Ty == S64) {
488 auto True = B.buildConstant({VgprRB_I32}, TrueExtCst);
489 auto False = B.buildConstant({VgprRB_I32}, 0);
490 auto Lo = B.buildSelect({VgprRB_I32}, Src, True, False);
491 MachineInstrBuilder Hi;
492 switch (Opc) {
493 case G_SEXT:
494 Hi = Lo;
495 break;
496 case G_ZEXT:
497 Hi = False;
498 break;
499 case G_ANYEXT:
500 Hi = B.buildUndef({VgprRB_I32});
501 break;
502 default:
504 MF, MORE, DEBUG_TYPE,
505 "AMDGPU RegBankLegalize: lowerVccExtToSel, Opcode not supported", MI);
506 return false;
507 }
508
509 B.buildMergeValues(Dst, {Lo.getReg(0), Hi.getReg(0)});
510 } else {
512 MF, MORE, DEBUG_TYPE,
513 "AMDGPU RegBankLegalize: lowerVccExtToSel, Type not supported", MI);
514 return false;
515 }
516
517 MI.eraseFromParent();
518 return true;
519}
520
521std::pair<Register, Register> RegBankLegalizeHelper::unpackZExt(Register Reg) {
522 auto PackedI32 = B.buildBitcast(SgprRB_I32, Reg);
523 auto Mask = B.buildConstant(SgprRB_I32, 0x0000ffff);
524 auto Lo = B.buildAnd(SgprRB_I32, PackedI32, Mask);
525 auto Hi = B.buildLShr(SgprRB_I32, PackedI32, B.buildConstant(SgprRB_I32, 16));
526 return {Lo.getReg(0), Hi.getReg(0)};
527}
528
529std::pair<Register, Register> RegBankLegalizeHelper::unpackSExt(Register Reg) {
530 auto PackedI32 = B.buildBitcast(SgprRB_I32, Reg);
531 auto Lo = B.buildSExtInReg(SgprRB_I32, PackedI32, 16);
532 auto Hi = B.buildAShr(SgprRB_I32, PackedI32, B.buildConstant(SgprRB_I32, 16));
533 return {Lo.getReg(0), Hi.getReg(0)};
534}
535
536std::pair<Register, Register> RegBankLegalizeHelper::unpackAExt(Register Reg) {
537 Register RegI32 = Reg;
538 if (MRI.getType(Reg) != I32)
539 RegI32 = B.buildBitcast(SgprRB_I32, Reg).getReg(0);
540
541 auto Hi = B.buildLShr(SgprRB_I32, RegI32, B.buildConstant(SgprRB_I32, 16));
542 return {RegI32, Hi.getReg(0)};
543}
544
545std::pair<Register, Register>
546RegBankLegalizeHelper::unpackAExtTruncS16(Register Reg) {
547 auto [Lo32, Hi32] = unpackAExt(Reg);
548 LLT EltTy = MRI.getType(Reg).getElementType();
549 return {B.buildTrunc({SgprRB, EltTy}, Lo32).getReg(0),
550 B.buildTrunc({SgprRB, EltTy}, Hi32).getReg(0)};
551}
552
553bool RegBankLegalizeHelper::lowerUnpackBitShift(MachineInstr &MI) {
554 Register Lo, Hi;
555 switch (MI.getOpcode()) {
556 case AMDGPU::G_SHL: {
557 auto [Val0, Val1] = unpackAExt(MI.getOperand(1).getReg());
558 auto [Amt0, Amt1] = unpackAExt(MI.getOperand(2).getReg());
559 Lo = B.buildInstr(MI.getOpcode(), {SgprRB_I32}, {Val0, Amt0}).getReg(0);
560 Hi = B.buildInstr(MI.getOpcode(), {SgprRB_I32}, {Val1, Amt1}).getReg(0);
561 break;
562 }
563 case AMDGPU::G_LSHR: {
564 auto [Val0, Val1] = unpackZExt(MI.getOperand(1).getReg());
565 auto [Amt0, Amt1] = unpackZExt(MI.getOperand(2).getReg());
566 Lo = B.buildInstr(MI.getOpcode(), {SgprRB_I32}, {Val0, Amt0}).getReg(0);
567 Hi = B.buildInstr(MI.getOpcode(), {SgprRB_I32}, {Val1, Amt1}).getReg(0);
568 break;
569 }
570 case AMDGPU::G_ASHR: {
571 auto [Val0, Val1] = unpackSExt(MI.getOperand(1).getReg());
572 auto [Amt0, Amt1] = unpackSExt(MI.getOperand(2).getReg());
573 Lo = B.buildAShr(SgprRB_I32, Val0, Amt0).getReg(0);
574 Hi = B.buildAShr(SgprRB_I32, Val1, Amt1).getReg(0);
575 break;
576 }
577 default:
579 MF, MORE, DEBUG_TYPE,
580 "AMDGPU RegBankLegalize: lowerUnpackBitShift, case not implemented",
581 MI);
582 return false;
583 }
584 B.buildBuildVectorTrunc(MI.getOperand(0).getReg(), {Lo, Hi});
585 MI.eraseFromParent();
586 return true;
587}
588
589bool RegBankLegalizeHelper::lowerUnpackMinMax(MachineInstr &MI) {
590 Register Lo, Hi;
591 switch (MI.getOpcode()) {
592 case AMDGPU::G_SMIN:
593 case AMDGPU::G_SMAX: {
594 // For signed operations, use sign extension
595 auto [Val0_Lo, Val0_Hi] = unpackSExt(MI.getOperand(1).getReg());
596 auto [Val1_Lo, Val1_Hi] = unpackSExt(MI.getOperand(2).getReg());
597 Lo = B.buildInstr(MI.getOpcode(), {SgprRB_I32}, {Val0_Lo, Val1_Lo})
598 .getReg(0);
599 Hi = B.buildInstr(MI.getOpcode(), {SgprRB_I32}, {Val0_Hi, Val1_Hi})
600 .getReg(0);
601 break;
602 }
603 case AMDGPU::G_UMIN:
604 case AMDGPU::G_UMAX: {
605 // For unsigned operations, use zero extension
606 auto [Val0_Lo, Val0_Hi] = unpackZExt(MI.getOperand(1).getReg());
607 auto [Val1_Lo, Val1_Hi] = unpackZExt(MI.getOperand(2).getReg());
608 Lo = B.buildInstr(MI.getOpcode(), {SgprRB_I32}, {Val0_Lo, Val1_Lo})
609 .getReg(0);
610 Hi = B.buildInstr(MI.getOpcode(), {SgprRB_I32}, {Val0_Hi, Val1_Hi})
611 .getReg(0);
612 break;
613 }
614 default:
616 MF, MORE, DEBUG_TYPE,
617 "AMDGPU RegBankLegalize: lowerUnpackMinMax, case not implemented", MI);
618 return false;
619 }
620 B.buildBuildVectorTrunc(MI.getOperand(0).getReg(), {Lo, Hi});
621 MI.eraseFromParent();
622 return true;
623}
624
625bool RegBankLegalizeHelper::lowerUnpackAExt(MachineInstr &MI) {
626 auto [Op1Lo, Op1Hi] = unpackAExt(MI.getOperand(1).getReg());
627 auto [Op2Lo, Op2Hi] = unpackAExt(MI.getOperand(2).getReg());
628 auto ResLo = B.buildInstr(MI.getOpcode(), {SgprRB_I32}, {Op1Lo, Op2Lo});
629 auto ResHi = B.buildInstr(MI.getOpcode(), {SgprRB_I32}, {Op1Hi, Op2Hi});
630 B.buildBuildVectorTrunc(MI.getOperand(0).getReg(),
631 {ResLo.getReg(0), ResHi.getReg(0)});
632 MI.eraseFromParent();
633 return true;
634}
635
636bool RegBankLegalizeHelper::lowerSBufToBuf(MachineInstr &MI,
637 WaterfallInfo &WFI) {
638 Register Dst = MI.getOperand(0).getReg();
639 LLT Ty = MRI.getType(Dst);
640 const RegisterBank *RSrcBank = MRI.getRegBank(MI.getOperand(1).getReg());
641 unsigned LoadSize = Ty.getSizeInBits();
642 int NumLoads = 1;
643 SmallVector<Register, 4> LoadParts;
644 if (LoadSize == 256 || LoadSize == 512) {
645 NumLoads = LoadSize / 128;
646 Ty = Ty.divide(NumLoads);
647 }
648 for (int I = 0; I < NumLoads; ++I)
649 LoadParts.emplace_back(MRI.createVirtualRegister({VgprRB, Ty}));
650 MachineMemOperand *OrigMMO = *MI.memoperands_begin();
651 const Align Alignment = OrigMMO->getAlign();
652 MachineFunction &MF = B.getMF();
653 Register SOffset;
654 Register VOffset;
655 int64_t ImmOffset = 0;
656 unsigned MMOOffset = setBufferOffsets(B, MI.getOperand(2).getReg(), VOffset,
657 SOffset, ImmOffset, Alignment);
658 const unsigned MemSize = divideCeil(OrigMMO->getSize().getValue(), NumLoads);
659 MachineMemOperand *BaseMMO = MF.getMachineMemOperand(OrigMMO, 0, MemSize);
660 if (MMOOffset != 0)
661 BaseMMO = MF.getMachineMemOperand(BaseMMO, MMOOffset, MemSize);
662 // If only the offset is divergent, emit a MUBUF buffer load
663 // instead. We can assume that the buffer is unswizzled.
664 Register RSrc = MI.getOperand(1).getReg();
665 Register VIndex = B.buildConstant(VgprRB_I32, 0).getReg(0);
666 unsigned CachePolicy = MI.getOperand(3).getImm();
667 unsigned Opc = AMDGPU::G_AMDGPU_BUFFER_LOAD;
668 switch (MI.getOpcode()) {
669 case AMDGPU::G_AMDGPU_S_BUFFER_LOAD_SBYTE:
670 Opc = G_AMDGPU_BUFFER_LOAD_SBYTE;
671 break;
672 case AMDGPU::G_AMDGPU_S_BUFFER_LOAD_UBYTE:
673 Opc = G_AMDGPU_BUFFER_LOAD_UBYTE;
674 break;
675 case AMDGPU::G_AMDGPU_S_BUFFER_LOAD_SSHORT:
676 Opc = G_AMDGPU_BUFFER_LOAD_SSHORT;
677 break;
678 case AMDGPU::G_AMDGPU_S_BUFFER_LOAD_USHORT:
679 Opc = G_AMDGPU_BUFFER_LOAD_USHORT;
680 break;
681 default:
682 break;
683 }
684 for (int I = 0; I < NumLoads; ++I) {
685 B.buildInstr(Opc)
686 .addDef(LoadParts[I]) // vdata
687 .addUse(RSrc) // rsrc
688 .addUse(VIndex) // vindex
689 .addUse(VOffset) // voffset
690 .addUse(SOffset) // soffset
691 .addImm(ImmOffset + 16 * I) // offset(imm)
692 .addImm(CachePolicy) // cachepolicy, swizzled buffer(imm)
693 .addImm(0) // idxen(imm)
694 .addMemOperand(MF.getMachineMemOperand(BaseMMO, 16 * I, MemSize));
695 }
696 if (NumLoads == 1)
697 B.buildCopy(Dst, LoadParts[0]);
698 else
699 B.buildMergeLikeInstr(Dst, LoadParts);
700 B.setInstr(*MRI.getVRegDef(LoadParts[0]));
701 if (RSrcBank != SgprRB) {
702 WFI.SgprWaterfallOperandRegs.insert(RSrc);
703 WFI.Start = MRI.getVRegDef(LoadParts.front());
704 WFI.End = std::next(MRI.getVRegDef(LoadParts.back())->getIterator());
705 }
706 MI.eraseFromParent();
707 return true;
708}
709
712 return (GI->is(Intrinsic::amdgcn_sbfe));
713
714 return MI.getOpcode() == AMDGPU::G_SBFX;
715}
716
717bool RegBankLegalizeHelper::lowerV_BFE(MachineInstr &MI) {
718 Register Dst = MI.getOperand(0).getReg();
719 assert(MRI.getType(Dst) == LLT::scalar(64));
720 bool Signed = isSignedBFE(MI);
721 unsigned FirstOpnd = isa<GIntrinsic>(MI) ? 2 : 1;
722 // Extract bitfield from Src, LSBit is the least-significant bit for the
723 // extraction (field offset) and Width is size of bitfield.
724 Register Src = MI.getOperand(FirstOpnd).getReg();
725 Register LSBit = MI.getOperand(FirstOpnd + 1).getReg();
726 Register Width = MI.getOperand(FirstOpnd + 2).getReg();
727 // Comments are for signed bitfield extract, similar for unsigned. x is sign
728 // bit. s is sign, l is LSB and y are remaining bits of bitfield to extract.
729
730 // Src >> LSBit Hi|Lo: x?????syyyyyyl??? -> xxxx?????syyyyyyl
731 unsigned SHROpc = Signed ? AMDGPU::G_ASHR : AMDGPU::G_LSHR;
732 auto SHRSrc = B.buildInstr(SHROpc, {VgprRB_I64}, {Src, LSBit});
733
734 auto ConstWidth = getIConstantVRegValWithLookThrough(Width, MRI);
735
736 // Expand to Src >> LSBit << (64 - Width) >> (64 - Width)
737 // << (64 - Width): Hi|Lo: xxxx?????syyyyyyl -> syyyyyyl000000000
738 // >> (64 - Width): Hi|Lo: syyyyyyl000000000 -> ssssssssssyyyyyyl
739 if (!ConstWidth) {
740 auto Amt = B.buildSub(VgprRB_I32, B.buildConstant(SgprRB_I32, 64), Width);
741 auto SignBit = B.buildShl(VgprRB_I64, SHRSrc, Amt);
742 B.buildInstr(SHROpc, {Dst}, {SignBit, Amt});
743 MI.eraseFromParent();
744 return true;
745 }
746
747 uint64_t WidthImm = ConstWidth->Value.getZExtValue();
748 auto UnmergeSHRSrc = B.buildUnmerge(VgprRB_I32, SHRSrc);
749 Register SHRSrcLo = UnmergeSHRSrc.getReg(0);
750 Register SHRSrcHi = UnmergeSHRSrc.getReg(1);
751 auto Zero = B.buildConstant(VgprRB_I32, 0);
752 unsigned BFXOpc = Signed ? AMDGPU::G_SBFX : AMDGPU::G_UBFX;
753
754 if (WidthImm <= 32) {
755 // SHRSrc Hi|Lo: ????????|???syyyl -> ????????|ssssyyyl
756 Register Lo = SHRSrcLo;
757 // V_BFE masks its width to 5 bits, so 32 would extract zero bits.
758 if (WidthImm < 32) {
759 Lo =
760 B.buildInstr(BFXOpc, {VgprRB_I32}, {SHRSrcLo, Zero, Width}).getReg(0);
761 }
762 MachineInstrBuilder Hi;
763 if (Signed) {
764 // SHRSrc Hi|Lo: ????????|ssssyyyl -> ssssssss|ssssyyyl
765 Hi = B.buildAShr(VgprRB_I32, Lo, B.buildConstant(VgprRB_I32, 31));
766 } else {
767 // SHRSrc Hi|Lo: ????????|000syyyl -> 00000000|000syyyl
768 Hi = Zero;
769 }
770 B.buildMergeLikeInstr(Dst, {Lo, Hi});
771 } else {
772 auto Amt = B.buildConstant(VgprRB_I32, WidthImm - 32);
773 // SHRSrc Hi|Lo: ??????sy|yyyyyyyl -> sssssssy|yyyyyyyl
774 auto Hi = B.buildInstr(BFXOpc, {VgprRB_I32}, {SHRSrcHi, Zero, Amt});
775 B.buildMergeLikeInstr(Dst, {SHRSrcLo, Hi});
776 }
777
778 MI.eraseFromParent();
779 return true;
780}
781
782bool RegBankLegalizeHelper::lowerS_BFE(MachineInstr &MI) {
783 Register DstReg = MI.getOperand(0).getReg();
784 LLT Ty = MRI.getType(DstReg);
785 bool Signed = isSignedBFE(MI);
786 unsigned FirstOpnd = isa<GIntrinsic>(MI) ? 2 : 1;
787 Register Src = MI.getOperand(FirstOpnd).getReg();
788 Register LSBit = MI.getOperand(FirstOpnd + 1).getReg();
789 Register Width = MI.getOperand(FirstOpnd + 2).getReg();
790 // For uniform bit field extract there are 4 available instructions, but
791 // LSBit(field offset) and Width(size of bitfield) need to be packed in S32,
792 // field offset in low and size in high 16 bits.
793
794 // Src1 Hi16|Lo16 = Size|FieldOffset
795 auto Mask = B.buildConstant(SgprRB_I32, maskTrailingOnes<unsigned>(6));
796 auto FieldOffset = B.buildAnd(SgprRB_I32, LSBit, Mask);
797 auto Size = B.buildShl(SgprRB_I32, Width, B.buildConstant(SgprRB_I32, 16));
798 auto Src1 = B.buildOr(SgprRB_I32, FieldOffset, Size);
799 unsigned Opc32 = Signed ? AMDGPU::S_BFE_I32 : AMDGPU::S_BFE_U32;
800 unsigned Opc64 = Signed ? AMDGPU::S_BFE_I64 : AMDGPU::S_BFE_U64;
801 unsigned Opc = Ty == S32 ? Opc32 : Opc64;
802
803 // Select machine instruction, because of reg class constraining, insert
804 // copies from reg class to reg bank.
805 auto S_BFE = B.buildInstr(Opc, {{SgprRB, Ty}},
806 {B.buildCopy(Ty, Src), B.buildCopy(I32, Src1)});
807 constrainSelectedInstRegOperands(*S_BFE, *ST.getInstrInfo(),
808 *ST.getRegisterInfo(), RBI);
809
810 B.buildCopy(DstReg, S_BFE->getOperand(0).getReg());
811 MI.eraseFromParent();
812 return true;
813}
814
815bool RegBankLegalizeHelper::lowerSplitTo32(MachineInstr &MI) {
816 Register Dst = MI.getOperand(0).getReg();
817 LLT DstTy = MRI.getType(Dst);
818 assert(DstTy == V4S16 || DstTy == V2S32 || DstTy == S64);
819 LLT Ty = DstTy.divide(2);
820 auto Op1 = B.buildUnmerge({VgprRB, Ty}, MI.getOperand(1).getReg());
821 auto Op2 = B.buildUnmerge({VgprRB, Ty}, MI.getOperand(2).getReg());
822 unsigned Opc = MI.getOpcode();
823 auto Flags = MI.getFlags();
824 auto Lo =
825 B.buildInstr(Opc, {{VgprRB, Ty}}, {Op1.getReg(0), Op2.getReg(0)}, Flags);
826 auto Hi =
827 B.buildInstr(Opc, {{VgprRB, Ty}}, {Op1.getReg(1), Op2.getReg(1)}, Flags);
828 B.buildMergeLikeInstr(Dst, {Lo, Hi});
829 MI.eraseFromParent();
830 return true;
831}
832
833bool RegBankLegalizeHelper::lowerSplitTo32Mul(MachineInstr &MI) {
834 Register Dst = MI.getOperand(0).getReg();
835 assert(MRI.getType(Dst) == S64);
836 auto Op1 = B.buildUnmerge({VgprRB_I32}, MI.getOperand(1).getReg());
837 auto Op2 = B.buildUnmerge({VgprRB_I32}, MI.getOperand(2).getReg());
838
839 // TODO: G_AMDGPU_MAD_* optimizations for G_MUL divergent S64 operation to
840 // match GlobalISel with old regbankselect.
841 auto Lo = B.buildMul(VgprRB_I32, Op1.getReg(0), Op2.getReg(0));
842 auto Carry = B.buildUMulH(VgprRB_I32, Op1.getReg(0), Op2.getReg(0));
843 auto MulLo0Hi1 = B.buildMul(VgprRB_I32, Op1.getReg(0), Op2.getReg(1));
844 auto MulHi0Lo1 = B.buildMul(VgprRB_I32, Op1.getReg(1), Op2.getReg(0));
845 auto Sum = B.buildAdd(VgprRB_I32, MulLo0Hi1, MulHi0Lo1);
846 auto Hi = B.buildAdd(VgprRB_I32, Sum, Carry);
847
848 B.buildMergeLikeInstr(Dst, {Lo, Hi});
849 MI.eraseFromParent();
850 return true;
851}
852
853bool RegBankLegalizeHelper::lowerSplitTo16(MachineInstr &MI) {
854 Register Dst = MI.getOperand(0).getReg();
855 assert(MRI.getType(Dst) == V2S16);
856 unsigned Opc = MI.getOpcode();
857 unsigned NumOps = MI.getNumOperands();
858 auto Flags = MI.getFlags();
859
860 auto [Op1Lo, Op1Hi] = unpackAExtTruncS16(MI.getOperand(1).getReg());
861 LLT EltTy = MRI.getType(Dst).getElementType();
862
863 if (NumOps == 2) {
864 auto Lo = B.buildInstr(Opc, {{SgprRB, EltTy}}, {Op1Lo}, Flags);
865 auto Hi = B.buildInstr(Opc, {{SgprRB, EltTy}}, {Op1Hi}, Flags);
866 B.buildMergeLikeInstr(Dst, {Lo, Hi});
867 MI.eraseFromParent();
868 return true;
869 }
870
871 auto [Op2Lo, Op2Hi] = unpackAExtTruncS16(MI.getOperand(2).getReg());
872
873 if (NumOps == 3) {
874 auto Lo = B.buildInstr(Opc, {{SgprRB, EltTy}}, {Op1Lo, Op2Lo}, Flags);
875 auto Hi = B.buildInstr(Opc, {{SgprRB, EltTy}}, {Op1Hi, Op2Hi}, Flags);
876 B.buildMergeLikeInstr(Dst, {Lo, Hi});
877 MI.eraseFromParent();
878 return true;
879 }
880
881 assert(NumOps == 4);
882 auto [Op3Lo, Op3Hi] = unpackAExtTruncS16(MI.getOperand(3).getReg());
883 auto Lo = B.buildInstr(Opc, {{SgprRB, EltTy}}, {Op1Lo, Op2Lo, Op3Lo}, Flags);
884 auto Hi = B.buildInstr(Opc, {{SgprRB, EltTy}}, {Op1Hi, Op2Hi, Op3Hi}, Flags);
885 B.buildMergeLikeInstr(Dst, {Lo, Hi});
886 MI.eraseFromParent();
887 return true;
888}
889
890bool RegBankLegalizeHelper::lowerUniMAD64(MachineInstr &MI) {
891 Register Dst0 = MI.getOperand(0).getReg();
892 Register Dst1 = MI.getOperand(1).getReg();
893 Register Src0 = MI.getOperand(2).getReg();
894 Register Src1 = MI.getOperand(3).getReg();
895 Register Src2 = MI.getOperand(4).getReg();
896
897 const GCNSubtarget &ST = B.getMF().getSubtarget<GCNSubtarget>();
898
899 // Keep the multiplication on the SALU.
900 Register DstLo = B.buildMul(SgprRB_I32, Src0, Src1).getReg(0);
901 Register DstHi = MRI.createVirtualRegister(SgprRB_I32);
902 if (ST.hasScalarMulHiInsts()) {
903 B.buildInstr(AMDGPU::G_UMULH, {{DstHi}}, {Src0, Src1});
904 } else {
905 auto VSrc0 = B.buildCopy(VgprRB_I32, Src0);
906 auto VSrc1 = B.buildCopy(VgprRB_I32, Src1);
907 auto MulHi = B.buildInstr(AMDGPU::G_UMULH, {VgprRB_I32}, {VSrc0, VSrc1});
908 buildReadAnyLane(B, DstHi, MulHi.getReg(0), RBI);
909 }
910
911 // Accumulate and produce the "carry-out" bit.
912
913 // The "carry-out" is defined as bit 64 of the result when computed as a
914 // big integer. For unsigned multiply-add, this matches the usual
915 // definition of carry-out.
916 if (mi_match(Src2, MRI, MIPatternMatch::m_ZeroInt())) {
917 // No accumulate: result is just the multiplication, carry is 0.
918 B.buildMergeLikeInstr(Dst0, {DstLo, DstHi});
919 B.buildConstant(Dst1, 0);
920 } else {
921 // Accumulate: add Src2 to the multiplication result with carry chain.
922 Register Src2Lo = MRI.createVirtualRegister(SgprRB_I32);
923 Register Src2Hi = MRI.createVirtualRegister(SgprRB_I32);
924 B.buildUnmerge({Src2Lo, Src2Hi}, Src2);
925
926 auto AddLo = B.buildUAddo(SgprRB_I32, SgprRB_I32, DstLo, Src2Lo);
927 auto AddHi =
928 B.buildUAdde(SgprRB_I32, SgprRB_I32, DstHi, Src2Hi, AddLo.getReg(1));
929 B.buildMergeLikeInstr(Dst0, {AddLo.getReg(0), AddHi.getReg(0)});
930 B.buildCopy(Dst1, AddHi.getReg(1));
931 }
932
933 MI.eraseFromParent();
934 return true;
935}
936
937bool RegBankLegalizeHelper::lowerSplitTo32Select(MachineInstr &MI) {
938 Register Dst = MI.getOperand(0).getReg();
939 LLT DstTy = MRI.getType(Dst);
940 assert(DstTy == V4S16 || DstTy == V2S32 || DstTy == S64 ||
941 (DstTy.isPointer() && DstTy.getSizeInBits() == 64));
942 LLT Ty = DstTy.isFloat() ? LLT::float32() : DstTy.divide(2);
943 auto Op2 = B.buildUnmerge({VgprRB, Ty}, MI.getOperand(2).getReg());
944 auto Op3 = B.buildUnmerge({VgprRB, Ty}, MI.getOperand(3).getReg());
945 Register Cond = MI.getOperand(1).getReg();
946 auto Flags = MI.getFlags();
947 auto Lo =
948 B.buildSelect({VgprRB, Ty}, Cond, Op2.getReg(0), Op3.getReg(0), Flags);
949 auto Hi =
950 B.buildSelect({VgprRB, Ty}, Cond, Op2.getReg(1), Op3.getReg(1), Flags);
951
952 B.buildMergeLikeInstr(Dst, {Lo, Hi});
953 MI.eraseFromParent();
954 return true;
955}
956
957bool RegBankLegalizeHelper::lowerSplitTo32SExtInReg(MachineInstr &MI) {
958 auto Op1 = B.buildUnmerge(VgprRB_I32, MI.getOperand(1).getReg());
959 int Amt = MI.getOperand(2).getImm();
960 Register Lo, Hi;
961 // Hi|Lo: s sign bit, ?/x bits changed/not changed by sign-extend
962 if (Amt <= 32) {
963 auto Freeze = B.buildFreeze(VgprRB_I32, Op1.getReg(0));
964 if (Amt == 32) {
965 // Hi|Lo: ????????|sxxxxxxx -> ssssssss|sxxxxxxx
966 Lo = Freeze.getReg(0);
967 } else {
968 // Hi|Lo: ????????|???sxxxx -> ssssssss|ssssxxxx
969 Lo = B.buildSExtInReg(VgprRB_I32, Freeze, Amt).getReg(0);
970 }
971
972 auto SignExtCst = B.buildConstant(SgprRB_I32, 31);
973 Hi = B.buildAShr(VgprRB_I32, Lo, SignExtCst).getReg(0);
974 } else {
975 // Hi|Lo: ?????sxx|xxxxxxxx -> ssssssxx|xxxxxxxx
976 Lo = Op1.getReg(0);
977 Hi = B.buildSExtInReg(VgprRB_I32, Op1.getReg(1), Amt - 32).getReg(0);
978 }
979
980 B.buildMergeLikeInstr(MI.getOperand(0).getReg(), {Lo, Hi});
981 MI.eraseFromParent();
982 return true;
983}
984
985bool RegBankLegalizeHelper::lowerSplitBitCount64To32(MachineInstr &MI) {
986 // Split 64-bit find-first-bit operations into 32-bit halves:
987 // (ffbh hi:lo) -> umin(ffbh(hi), uaddsat(ffbh(lo), 32))
988 // (ffbl hi:lo) -> umin(ffbl(lo), uaddsat(ffbl(hi), 32))
989 // (ctlz_zero_poison hi:lo) -> umin(ffbh(hi), add(ffbh(lo), 32))
990 // (cttz_zero_poison hi:lo) -> umin(ffbl(lo), add(ffbl(hi), 32))
991 unsigned Opc = MI.getOpcode();
992
993 // FFBH/FFBL return 0xFFFFFFFF on zero input, using uaddsat to avoid
994 // wrapping. CTLZ/CTTZ guarantee non-zero input (zero_poison), so plain add
995 // is fine.
996 unsigned FFBOpc;
997 unsigned AddOpc;
998 bool SearchFromMSB;
999 switch (Opc) {
1000 case AMDGPU::G_AMDGPU_FFBH_U32:
1001 FFBOpc = Opc;
1002 AddOpc = AMDGPU::G_UADDSAT;
1003 SearchFromMSB = true;
1004 break;
1005 case AMDGPU::G_AMDGPU_FFBL_B32:
1006 FFBOpc = Opc;
1007 AddOpc = AMDGPU::G_UADDSAT;
1008 SearchFromMSB = false;
1009 break;
1010 case AMDGPU::G_CTLZ_ZERO_POISON:
1011 FFBOpc = AMDGPU::G_AMDGPU_FFBH_U32;
1012 AddOpc = AMDGPU::G_ADD;
1013 SearchFromMSB = true;
1014 break;
1015 case AMDGPU::G_CTTZ_ZERO_POISON:
1016 FFBOpc = AMDGPU::G_AMDGPU_FFBL_B32;
1017 AddOpc = AMDGPU::G_ADD;
1018 SearchFromMSB = false;
1019 break;
1020 default:
1021 llvm_unreachable("unexpected opcode in lowerSplitBitCount64To32");
1022 }
1023
1024 auto Unmerge = B.buildUnmerge(VgprRB_I32, MI.getOperand(1).getReg());
1025 Register Lo = Unmerge.getReg(0);
1026 Register Hi = Unmerge.getReg(1);
1027
1028 // MSB-first (FFBH/CTLZ) searches hi first; LSB-first (FFBL/CTTZ) searches
1029 // lo first. The secondary half adds 32 to account for the primary half's
1030 // width.
1031 auto Primary = B.buildInstr(FFBOpc, {VgprRB_I32}, {SearchFromMSB ? Hi : Lo});
1032 auto Secondary =
1033 B.buildInstr(FFBOpc, {VgprRB_I32}, {SearchFromMSB ? Lo : Hi});
1034
1035 auto Adjusted = B.buildInstr(AddOpc, {VgprRB_I32},
1036 {Secondary, B.buildConstant(VgprRB_I32, 32)});
1037 B.buildUMin(MI.getOperand(0).getReg(), Primary, Adjusted);
1038
1039 MI.eraseFromParent();
1040 return true;
1041}
1042
1043bool RegBankLegalizeHelper::lowerExtrVecEltToSel(MachineInstr &MI) {
1044 // Lower extract vector element to a compare-select chain:
1045 // result = elt[0]
1046 // for i in 1..N-1:
1047 // result = (idx == i) ? elt[i] : result
1048 //
1049 // When the index is divergent, each lane may want a different element, so
1050 // we must check every element per lane.
1051 Register Dst = MI.getOperand(0).getReg();
1052 Register Src = MI.getOperand(1).getReg();
1053 Register Idx = MI.getOperand(2).getReg();
1054
1055 LLT VecTy = MRI.getType(Src);
1056 LLT ScalarTy = VecTy.getScalarType();
1057 unsigned NumElts = VecTy.getNumElements();
1058 MachineRegisterInfo::VRegAttrs VgprRB_EltTy = {VgprRB, ScalarTy};
1059
1060 auto Unmerge = B.buildUnmerge(VgprRB_EltTy, Src);
1061
1062 if (ScalarTy.getSizeInBits() == 32) {
1063 Register PrevSelect = Unmerge.getReg(0);
1064 for (unsigned I = 1; I < NumElts; ++I) {
1065 auto IdxConst = B.buildConstant({SgprRB, MRI.getType(Idx)}, I);
1066 auto Cmp = B.buildICmp(CmpInst::ICMP_EQ, VccRB_S1, Idx, IdxConst);
1067 PrevSelect =
1068 B.buildSelect(VgprRB_EltTy, Cmp, Unmerge.getReg(I), PrevSelect)
1069 .getReg(0);
1070 }
1071 B.buildCopy(Dst, PrevSelect);
1072 } else if (ScalarTy.getSizeInBits() == 64) {
1073 auto InitUnmerge = B.buildUnmerge(VgprRB_I32, Unmerge.getReg(0));
1074 Register PrevLo = InitUnmerge.getReg(0);
1075 Register PrevHi = InitUnmerge.getReg(1);
1076 for (unsigned I = 1; I < NumElts; ++I) {
1077 auto IdxConst = B.buildConstant({SgprRB, MRI.getType(Idx)}, I);
1078 auto Cmp = B.buildICmp(CmpInst::ICMP_EQ, VccRB_S1, Idx, IdxConst);
1079 auto EltUnmerge = B.buildUnmerge(VgprRB_I32, Unmerge.getReg(I));
1080 PrevLo = B.buildSelect(VgprRB_I32, Cmp, EltUnmerge.getReg(0), PrevLo)
1081 .getReg(0);
1082 PrevHi = B.buildSelect(VgprRB_I32, Cmp, EltUnmerge.getReg(1), PrevHi)
1083 .getReg(0);
1084 }
1085 B.buildMergeLikeInstr(Dst, {PrevLo, PrevHi});
1086 } else {
1088 MF, MORE, DEBUG_TYPE,
1089 "AMDGPU RegBankLegalize: ExtrVecEltToSel unsupported element type", MI);
1090 return false;
1091 }
1092
1093 MI.eraseFromParent();
1094 return true;
1095}
1096
1097bool RegBankLegalizeHelper::lowerExtrVecEltTo32(MachineInstr &MI) {
1098 // Reduce a 64-bit element extract to two 32-bit extracts:
1099 // vec32 = bitcast <N x s64> to <2N x s32>
1100 // lo = vec32[idx * 2]
1101 // hi = vec32[idx * 2 + 1]
1102 // result = merge(lo, hi)
1103 //
1104 // When the index is uniform, all lanes extract the same element, so we can
1105 // just split the s64 extract into two s32 extracts which lower to MOVREL.
1106 Register Dst = MI.getOperand(0).getReg();
1107 Register Src = MI.getOperand(1).getReg();
1108 Register Idx = MI.getOperand(2).getReg();
1109
1110 LLT SrcTy = MRI.getType(Src);
1111 LLT Vec32Ty = LLT::fixed_vector(2 * SrcTy.getNumElements(), 32);
1112
1113 assert(MRI.getRegBank(Src) == VgprRB && MRI.getRegBank(Idx) == SgprRB &&
1114 "expected VGPR src and SGPR idx");
1115
1116 auto CastSrc = B.buildBitcast({VgprRB, Vec32Ty}, Src);
1117
1118 // Calculate new Lo and Hi indices
1119 auto One = B.buildConstant(SgprRB_I32, 1);
1120 auto IdxLo = B.buildShl(SgprRB_I32, Idx, One);
1121 auto IdxHi = B.buildAdd(SgprRB_I32, IdxLo, One);
1122
1123 auto ExtLo = B.buildExtractVectorElement(VgprRB_I32, CastSrc, IdxLo);
1124 auto ExtHi = B.buildExtractVectorElement(VgprRB_I32, CastSrc, IdxHi);
1125
1126 B.buildMergeLikeInstr(Dst, {ExtLo.getReg(0), ExtHi.getReg(0)});
1127
1128 MI.eraseFromParent();
1129 return true;
1130}
1131
1132bool RegBankLegalizeHelper::lowerInsVecEltToSel(MachineInstr &MI) {
1133 // Lower insert vector element to a compare-select chain:
1134 // for i in 0..N-1:
1135 // result[i] = (idx == i) ? elt : srcVec[i]
1136 // dst = merge(result[0..N-1])
1137 //
1138 // VGPR B64 requires splitting to lo/hi s32 pairs since there is no
1139 // v_cndmask_b64. SGPR B64/B32 and VGPR B32 can be handled natively.
1140 Register Dst = MI.getOperand(0).getReg();
1141 Register Src = MI.getOperand(1).getReg();
1142 Register Elt = MI.getOperand(2).getReg();
1143 Register Idx = MI.getOperand(3).getReg();
1144
1145 LLT VecTy = MRI.getType(Src);
1146 LLT ScalarTy = VecTy.getScalarType();
1147 unsigned NumElts = VecTy.getNumElements();
1148 const RegisterBank *SrcRB = MRI.getRegBank(Src);
1149 bool IsSGPR = (SrcRB == SgprRB);
1150 SmallVector<Register, 16> Selects;
1151
1152 if (!IsSGPR && ScalarTy.getSizeInBits() == 64) {
1153 // VGPR B64: split to 32-bit lo/hi since there is no v_cndmask_b64.
1154 auto Unmerge = B.buildUnmerge(VgprRB_I32, Src);
1155 auto EltUnmerge = B.buildUnmerge(VgprRB_I32, Elt);
1156 Register EltLo = EltUnmerge.getReg(0);
1157 Register EltHi = EltUnmerge.getReg(1);
1158 for (unsigned I = 0; I < NumElts; ++I) {
1159 auto IdxConst = B.buildConstant(VgprRB_I32, I);
1160 auto Cmp = B.buildICmp(CmpInst::ICMP_EQ, VccRB_S1, Idx, IdxConst);
1161 Selects.push_back(
1162 B.buildSelect(VgprRB_I32, Cmp, EltLo, Unmerge.getReg(2 * I))
1163 .getReg(0));
1164 Selects.push_back(
1165 B.buildSelect(VgprRB_I32, Cmp, EltHi, Unmerge.getReg(2 * I + 1))
1166 .getReg(0));
1167 }
1168 LLT Vec32Ty = LLT::fixed_vector(2 * NumElts, 32);
1169 auto Vec32 = B.buildBuildVector({VgprRB, Vec32Ty}, Selects);
1170 B.buildBitcast(Dst, Vec32);
1171 } else if (ScalarTy.getSizeInBits() == 32 || ScalarTy.getSizeInBits() == 64) {
1172 // B32 (any bank) and SGPR B64: element-wise select at native width.
1173 MachineRegisterInfo::VRegAttrs SrcRB_EltTy = {SrcRB, ScalarTy};
1174 MachineRegisterInfo::VRegAttrs CmpTy = IsSGPR ? SgprRB_I32 : VccRB_S1;
1175 auto Unmerge = B.buildUnmerge(SrcRB_EltTy, Src);
1176 for (unsigned I = 0; I < NumElts; ++I) {
1177 auto IdxConst = B.buildConstant(SgprRB_I32, I);
1178 auto Cmp = B.buildICmp(CmpInst::ICMP_EQ, CmpTy, Idx, IdxConst);
1179 Selects.push_back(
1180 B.buildSelect(SrcRB_EltTy, Cmp, Elt, Unmerge.getReg(I)).getReg(0));
1181 }
1182 B.buildMergeLikeInstr(Dst, Selects);
1183 } else {
1185 MF, MORE, DEBUG_TYPE,
1186 "AMDGPU RegBankLegalize: InsVecEltToSel unsupported element type", MI);
1187 return false;
1188 }
1189
1190 MI.eraseFromParent();
1191 return true;
1192}
1193
1194bool RegBankLegalizeHelper::lowerInsVecEltTo32(MachineInstr &MI) {
1195 // Reduce a 64-bit element insert to two 32-bit inserts:
1196 // vec32 = bitcast <N x s64> to <2N x s32>
1197 // lo, hi = unmerge elt
1198 // vec32[idx * 2] = lo
1199 // vec32[idx * 2 + 1] = hi
1200 // dst = bitcast <2N x s32> to <N x s64>
1201 //
1202 // When the index is uniform, all lanes insert at the same position, so we
1203 // can split the s64 insert into two s32 inserts which lower to MOVREL/GPRIDX.
1204 Register Dst = MI.getOperand(0).getReg();
1205 Register Src = MI.getOperand(1).getReg();
1206 Register Elt = MI.getOperand(2).getReg();
1207 Register Idx = MI.getOperand(3).getReg();
1208
1209 LLT SrcTy = MRI.getType(Src);
1210 LLT Vec32Ty = LLT::fixed_vector(2 * SrcTy.getNumElements(), 32);
1211
1212 assert(MRI.getRegBank(Src) == VgprRB && MRI.getRegBank(Idx) == SgprRB &&
1213 "expected VGPR src and SGPR idx");
1214
1215 MachineRegisterInfo::VRegAttrs VgprRB_Vec32Ty = {VgprRB, Vec32Ty};
1216
1217 auto CastSrc = B.buildBitcast(VgprRB_Vec32Ty, Src);
1218 auto EltUnmerge = B.buildUnmerge(VgprRB_I32, Elt);
1219
1220 // Calculate new Lo and Hi indices
1221 auto One = B.buildConstant(SgprRB_I32, 1);
1222 auto IdxLo = B.buildShl(SgprRB_I32, Idx, One);
1223 auto IdxHi = B.buildAdd(SgprRB_I32, IdxLo, One);
1224
1225 auto InsLo = B.buildInsertVectorElement(VgprRB_Vec32Ty, CastSrc,
1226 EltUnmerge.getReg(0), IdxLo);
1227 auto InsHi = B.buildInsertVectorElement(VgprRB_Vec32Ty, InsLo,
1228 EltUnmerge.getReg(1), IdxHi);
1229
1230 B.buildBitcast(Dst, InsHi);
1231
1232 MI.eraseFromParent();
1233 return true;
1234}
1235
1236bool RegBankLegalizeHelper::lowerAbsToNegMax(MachineInstr &MI) {
1237 // Lower divergent G_ABS to smax(x, 0 - x) in the VGPR bank:
1238 // zero = 0
1239 // neg = G_SUB zero, x
1240 // dst = G_SMAX x, neg
1241 //
1242 // There is no integer v_abs instruction on AMDGPU, so divergent G_ABS is
1243 // expanded to this sub/smax pair.
1244 Register DstReg = MI.getOperand(0).getReg();
1245 Register SrcReg = MI.getOperand(1).getReg();
1246 LLT Ty = MRI.getType(DstReg);
1247
1248 Register Zero;
1249 if (Ty == V2S16) {
1250 // buildConstant cannot produce a V2S16 directly; pack two S16 zeros.
1251 Register Zero16 = B.buildConstant({VgprRB, I16}, 0).getReg(0);
1252 Zero = B.buildBuildVector({VgprRB, Ty}, {Zero16, Zero16}).getReg(0);
1253 } else {
1254 assert((Ty == S32 || Ty == S16) && "unexpected type for AbsToNegMax");
1255 Zero = B.buildConstant({VgprRB, Ty}, 0).getReg(0);
1256 }
1257
1258 auto Neg = B.buildSub({VgprRB, Ty}, Zero, SrcReg);
1259 B.buildSMax(DstReg, SrcReg, Neg);
1260 MI.eraseFromParent();
1261 return true;
1262}
1263
1264bool RegBankLegalizeHelper::lowerAbsToS32(MachineInstr &MI) {
1265 // Lower uniform V2S16 abs by unpacking the values to two separate SGPR
1266 // registers and re-emitting G_ABS on each:
1267 // packed = bitcast <2 x s16> src to s32
1268 // lo = sext_inreg packed, 16
1269 // hi = ashr packed, 16
1270 // dst = build_vector_trunc G_ABS(lo), G_ABS(hi)
1271 //
1272 // SALU only has s_abs_i32, with no direct uniform V2S16 abs. The
1273 // re-emitted G_ABS(SgprRB, S32) selects to s_abs_i32 on each value.
1274 auto Bitcast = B.buildBitcast({SgprRB_I32}, MI.getOperand(1).getReg());
1275 auto SextInReg = B.buildSExtInReg({SgprRB_I32}, Bitcast, 16);
1276 auto ShiftHi =
1277 B.buildAShr({SgprRB_I32}, Bitcast, B.buildConstant({SgprRB_I32}, 16));
1278
1279 auto AbsLo = B.buildInstr(AMDGPU::G_ABS, {{SgprRB_I32}}, {SextInReg});
1280 auto AbsHi = B.buildInstr(AMDGPU::G_ABS, {{SgprRB_I32}}, {ShiftHi});
1281 B.buildBuildVectorTrunc(MI.getOperand(0).getReg(),
1282 {AbsLo.getReg(0), AbsHi.getReg(0)});
1283
1284 MI.eraseFromParent();
1285 return true;
1286}
1287
1288// Ported from SITargetLowering::lowerSET_ROUNDING in SIISelLowering.cpp.
1289// Keep the mapping logic and conversion tables aligned with the SDAG lowering.
1290bool RegBankLegalizeHelper::lowerSetRounding(MachineInstr &MI) {
1291 Register NewMode = MI.getOperand(0).getReg();
1292
1293 // Index a table of 4-bit entries mapping from the C FLT_ROUNDS values to the
1294 // hardware MODE.fp_round values.
1295 if (auto ConstMode = getIConstantVRegValWithLookThrough(NewMode, MRI)) {
1296 uint32_t ClampedVal = std::min(
1297 static_cast<uint32_t>(ConstMode->Value.getZExtValue()),
1298 static_cast<uint32_t>(AMDGPU::TowardZeroF32_TowardNegativeF64));
1299 uint32_t DecodedVal = AMDGPU::decodeFltRoundToHWConversionTable(ClampedVal);
1300 NewMode = B.buildConstant(SgprRB_I32, DecodedVal).getReg(0);
1301 } else {
1302 // If we know the input can only be one of the supported standard modes in
1303 // the range 0-3, we can use a simplified mapping to hardware values.
1304 KnownBits Known = VT->getKnownBits(NewMode);
1305 const bool UseReducedTable = Known.countMinLeadingZeros() >= 30;
1306 // The supported standard values are 0-3. The extended values start at 8. We
1307 // need to offset by 4 if the value is in the extended range.
1308
1309 if (UseReducedTable) {
1310 // Truncate to the low 32-bits.
1311 auto BitTable = B.buildConstant(
1312 SgprRB_I32, AMDGPU::FltRoundToHWConversionTable & 0xffff);
1313
1314 auto Two = B.buildConstant(SgprRB_I32, 2);
1315 auto RoundModeTimesNumBits = B.buildShl(SgprRB_I32, NewMode, Two);
1316
1317 NewMode =
1318 B.buildLShr(SgprRB_I32, BitTable, RoundModeTimesNumBits).getReg(0);
1319
1320 // TODO: A demanded-bits simplification on the setreg source here could
1321 // likely reduce the table extracted bits into inline immediates.
1322 } else {
1323 // table_index = umin(value, value - 4)
1324 // MODE.fp_round = (bit_table >> (table_index << 2)) & 0xf
1325 auto NegFour = B.buildConstant(SgprRB_I32, -4);
1326 auto OffsetEnum = B.buildAdd(SgprRB_I32, NewMode, NegFour);
1327 auto IndexVal = B.buildUMin(SgprRB_I32, NewMode, OffsetEnum);
1328
1329 auto Two = B.buildConstant(SgprRB_I32, 2);
1330 auto RoundModeTimesNumBits = B.buildShl(SgprRB_I32, IndexVal, Two);
1331
1332 auto BitTable =
1333 B.buildConstant(SgprRB_I64, AMDGPU::FltRoundToHWConversionTable);
1334 auto TableValue =
1335 B.buildLShr(SgprRB_I64, BitTable, RoundModeTimesNumBits);
1336 // No need to mask out the high bits since the setreg will ignore them
1337 // anyway.
1338 NewMode = B.buildTrunc(SgprRB_I32, TableValue).getReg(0);
1339 }
1340 }
1341
1342 // N.B. The setreg will be later folded into s_round_mode on supported
1343 // targets.
1344 uint32_t BothRoundHwReg =
1346 B.buildIntrinsic(Intrinsic::amdgcn_s_setreg, ArrayRef<DstOp>(),
1347 /*HasSideEffects=*/true, /*isConvergent=*/false)
1348 .addImm(static_cast<int16_t>(BothRoundHwReg))
1349 .addReg(NewMode);
1350
1351 MI.eraseFromParent();
1352 return true;
1353}
1354
1355// Ported from SITargetLowering::lowerGET_ROUNDING in SIISelLowering.cpp.
1356// Keep the mapping logic and conversion tables aligned with the SDAG lowering.
1357bool RegBankLegalizeHelper::lowerGetRounding(MachineInstr &MI) {
1358 Register Dst = MI.getOperand(0).getReg();
1359
1360 uint32_t BothRoundHwReg =
1362 auto GetReg =
1363 B.buildIntrinsic(Intrinsic::amdgcn_s_getreg, {SgprRB_I32},
1364 /*HasSideEffects=*/true, /*isConvergent=*/false)
1365 .addImm(BothRoundHwReg);
1366
1367 // There are two rounding modes, one for f32 and one for f64/f16. We only
1368 // report in the standard value range if both are the same.
1369 //
1370 // The raw values also differ from the expected FLT_ROUNDS values. Nearest
1371 // ties away from zero is not supported, and the other values are rotated by
1372 // 1.
1373 //
1374 // If the two rounding modes are not the same, report a target defined value.
1375
1376 // Mode register rounding mode fields:
1377 //
1378 // [1:0] Single-precision round mode.
1379 // [3:2] Double/Half-precision round mode.
1380 //
1381 // 0=nearest even; 1= +infinity; 2= -infinity, 3= toward zero.
1382 //
1383 // Hardware Spec
1384 // Toward-0 3 0
1385 // Nearest Even 0 1
1386 // +Inf 1 2
1387 // -Inf 2 3
1388 // NearestAway0 N/A 4
1389 //
1390 // We have to handle 16 permutations of a 4-bit value, so we create a 64-bit
1391 // table we can index by the raw hardware mode.
1392 //
1393 // (trunc (FltRoundConversionTable >> MODE.fp_round)) & 0xf
1394 auto BitTable = B.buildConstant(SgprRB_I64, AMDGPU::FltRoundConversionTable);
1395
1396 auto Two = B.buildConstant(SgprRB_I32, 2);
1397 auto RoundModeTimesNumBits = B.buildShl(SgprRB_I32, GetReg, Two);
1398
1399 // TODO: We could possibly avoid a 64-bit shift and use a simpler table if we
1400 // knew only one mode was demanded.
1401 auto TableValue = B.buildLShr(SgprRB_I64, BitTable, RoundModeTimesNumBits);
1402 auto TruncTable = B.buildTrunc(SgprRB_I32, TableValue);
1403
1404 auto EntryMask = B.buildConstant(SgprRB_I32, 0xf);
1405 auto TableEntry = B.buildAnd(SgprRB_I32, TruncTable, EntryMask);
1406
1407 // There's a gap in the 4-bit encoded table and actual enum values, so offset
1408 // if it's an extended value.
1409 auto Four = B.buildConstant(SgprRB_I32, 4);
1410 auto EnumOffset = B.buildAdd(SgprRB_I32, TableEntry, Four);
1411 auto IsStandardMode =
1412 B.buildICmp(CmpInst::ICMP_ULT, SgprRB_I32, TableEntry, Four);
1413 B.buildSelect(Dst, IsStandardMode, TableEntry, EnumOffset);
1414
1415 MI.eraseFromParent();
1416 return true;
1417}
1418
1419bool RegBankLegalizeHelper::lower(MachineInstr &MI,
1420 const RegBankLLTMapping &Mapping,
1421 WaterfallInfo &WFI) {
1422
1423 switch (Mapping.LoweringMethod) {
1424 case DoNotLower:
1425 break;
1426 case VccExtToSel:
1427 return lowerVccExtToSel(MI);
1428 case UniExtToSel: {
1429 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1430 auto True = B.buildConstant({SgprRB, Ty},
1431 MI.getOpcode() == AMDGPU::G_SEXT ? -1 : 1);
1432 auto False = B.buildConstant({SgprRB, Ty}, 0);
1433 // Input to G_{Z|S}EXT is 'Legalizer legal' S1. Most common case is compare.
1434 // We are making select here. S1 cond was already 'any-extended to S32' +
1435 // 'AND with 1 to clean high bits' by Sgpr32AExtBoolInReg.
1436 B.buildSelect(MI.getOperand(0).getReg(), MI.getOperand(1).getReg(), True,
1437 False);
1438 MI.eraseFromParent();
1439 return true;
1440 }
1441 case UnpackBitShift:
1442 return lowerUnpackBitShift(MI);
1443 case UnpackMinMax:
1444 return lowerUnpackMinMax(MI);
1445 case ScalarizeToS16:
1446 return lowerSplitTo16(MI);
1447 case Ext32To64: {
1448 const RegisterBank *RB = MRI.getRegBank(MI.getOperand(0).getReg());
1449 MachineInstrBuilder Hi;
1450 switch (MI.getOpcode()) {
1451 case AMDGPU::G_ZEXT: {
1452 Hi = B.buildConstant({RB, I32}, 0);
1453 break;
1454 }
1455 case AMDGPU::G_SEXT: {
1456 // Replicate sign bit from 32-bit extended part.
1457 auto ShiftAmt = B.buildConstant({RB, I32}, 31);
1458 Hi = B.buildAShr({RB, MRI.getType(MI.getOperand(1).getReg())},
1459 MI.getOperand(1).getReg(), ShiftAmt);
1460 break;
1461 }
1462 case AMDGPU::G_ANYEXT: {
1463 Hi = B.buildUndef({RB, I32});
1464 break;
1465 }
1466 default:
1468 "AMDGPU RegBankLegalize: Ext32To64, unsuported opcode",
1469 MI);
1470 return false;
1471 }
1472
1473 B.buildMergeLikeInstr(MI.getOperand(0).getReg(),
1474 {MI.getOperand(1).getReg(), Hi});
1475 MI.eraseFromParent();
1476 return true;
1477 }
1478 case UniCstExt: {
1479 uint64_t ConstVal = MI.getOperand(1).getCImm()->getZExtValue();
1480 B.buildConstant(MI.getOperand(0).getReg(), ConstVal);
1481
1482 MI.eraseFromParent();
1483 return true;
1484 }
1485 case VgprToVccCopy: {
1486 Register Src = MI.getOperand(1).getReg();
1487 LLT Ty = MRI.getType(Src);
1488 // Take lowest bit from each lane and put it in lane mask.
1489 // Lowering via compare, but we need to clean high bits first as compare
1490 // compares all bits in register.
1491 Register BoolSrc = MRI.createVirtualRegister({VgprRB, Ty});
1492 if (Ty == S64) {
1493 auto Src64 = B.buildUnmerge(VgprRB_I32, Src);
1494 auto One = B.buildConstant(VgprRB_I32, 1);
1495 auto AndLo = B.buildAnd(VgprRB_I32, Src64.getReg(0), One);
1496 auto Zero = B.buildConstant(VgprRB_I32, 0);
1497 auto AndHi = B.buildAnd(VgprRB_I32, Src64.getReg(1), Zero);
1498 B.buildMergeLikeInstr(BoolSrc, {AndLo, AndHi});
1499 } else {
1500 assert(Ty == S32 || Ty == S16);
1501 auto One = B.buildConstant({VgprRB, Ty}, 1);
1502 B.buildAnd(BoolSrc, Src, One);
1503 }
1504 auto Zero = B.buildConstant({VgprRB, Ty}, 0);
1505 B.buildICmp(CmpInst::ICMP_NE, MI.getOperand(0).getReg(), BoolSrc, Zero);
1506 MI.eraseFromParent();
1507 return true;
1508 }
1509 case V_BFE:
1510 return lowerV_BFE(MI);
1511 case S_BFE:
1512 return lowerS_BFE(MI);
1513 case UniMAD64:
1514 return lowerUniMAD64(MI);
1515 case UniMul64: {
1516 B.buildMul(MI.getOperand(0), MI.getOperand(1), MI.getOperand(2));
1517 MI.eraseFromParent();
1518 return true;
1519 }
1520 case DivSMulToMAD: {
1521 auto Op1 = B.buildTrunc(VgprRB_I32, MI.getOperand(1));
1522 auto Op2 = B.buildTrunc(VgprRB_I32, MI.getOperand(2));
1523 auto Zero = B.buildConstant(VgprRB_I64, 0);
1524
1525 unsigned NewOpc = MI.getOpcode() == AMDGPU::G_AMDGPU_S_MUL_U64_U32
1526 ? AMDGPU::G_AMDGPU_MAD_U64_U32
1527 : AMDGPU::G_AMDGPU_MAD_I64_I32;
1528
1529 B.buildInstr(NewOpc, {MI.getOperand(0).getReg(), SgprRB_I32},
1530 {Op1, Op2, Zero});
1531 MI.eraseFromParent();
1532 return true;
1533 }
1534 case SplitTo32:
1535 return lowerSplitTo32(MI);
1536 case SplitTo32Mul:
1537 return lowerSplitTo32Mul(MI);
1538 case SplitTo32Select:
1539 return lowerSplitTo32Select(MI);
1540 case SplitTo32SExtInReg:
1541 return lowerSplitTo32SExtInReg(MI);
1542 case CtPop64To32: {
1543 auto Unmerge = B.buildUnmerge(VgprRB_I32, MI.getOperand(1).getReg());
1544 auto LoPopCnt = B.buildCTPOP(VgprRB_I32, Unmerge.getReg(0));
1545 auto HiPopCnt = B.buildCTPOP(VgprRB_I32, Unmerge.getReg(1));
1546 // Max popcount of two 32-bit values is 64, so this add cannot overflow.
1547 B.buildAdd(MI.getOperand(0).getReg(), LoPopCnt, HiPopCnt,
1549
1550 MI.eraseFromParent();
1551 break;
1552 }
1553 case S_BUF_to_BUF:
1554 return lowerSBufToBuf(MI, WFI);
1555 case SplitLoad: {
1556 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
1557 unsigned Size = DstTy.getSizeInBits();
1558 // Even split to 128-bit loads
1559 if (Size > 128) {
1560 LLT B128;
1561 if (DstTy.isVector()) {
1562 LLT EltTy = DstTy.getElementType();
1563 B128 = LLT::fixed_vector(128 / EltTy.getSizeInBits(), EltTy);
1564 } else {
1565 B128 = LLT::integer(128);
1566 }
1567 if (Size / 128 == 2)
1568 splitLoad(MI, {B128, B128});
1569 else if (Size / 128 == 4)
1570 splitLoad(MI, {B128, B128, B128, B128});
1571 else {
1573 "AMDGPU RegBankLegalize: SplitLoad, unsuported type",
1574 MI);
1575 return false;
1576 }
1577 }
1578 // 64 and 32 bit load
1579 else if (DstTy == S96)
1580 splitLoad(MI, {S64, S32}, S32);
1581 else if (DstTy == V3S32)
1582 splitLoad(MI, {V2S32, S32}, S32);
1583 else if (DstTy == V6S16)
1584 splitLoad(MI, {V4S16, V2S16}, V2S16);
1585 else {
1587 "AMDGPU RegBankLegalize: SplitLoad, unsuported type",
1588 MI);
1589 return false;
1590 }
1591 return true;
1592 }
1593 case DynStackAlloc: {
1594 const auto &TFI = *ST.getFrameLowering();
1595 // Guard in case the stack growth direction ever changes with scratch
1596 // instructions.
1597 assert(TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsUp &&
1598 "Stack grows upwards for AMDGPU");
1599
1600 Register Dst = MI.getOperand(0).getReg();
1601 Register AllocSize = MI.getOperand(1).getReg();
1602 Align Alignment = assumeAligned(MI.getOperand(2).getImm());
1603
1604 // Erase before building new instrs to avoid hitting multiple Dst assert
1605 // with CSE.
1606 B.setInsertPt(*MI.getParent(), std::next(MI.getIterator()));
1607 MI.eraseFromParent();
1608
1609 if (MRI.getRegBank(AllocSize) != SgprRB) {
1610 auto WaveReduction =
1611 B.buildIntrinsic(Intrinsic::amdgcn_wave_reduce_umax, {SgprRB_I32})
1612 .addUse(AllocSize)
1613 .addImm(0);
1614 AllocSize = WaveReduction.getReg(0);
1615 }
1616
1617 LLT PtrTy = MRI.getType(Dst);
1618 assert(PtrTy.getSizeInBits() == 32 &&
1619 "Expected 32-bit pointer for stack allocation");
1620 const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();
1621 Register SPReg = Info->getStackPtrOffsetReg();
1622
1623 // When using flat-scratch, the stack offset is unscaled.
1624 const bool HasFlatScratch = ST.hasFlatScratchEnabled();
1625 const unsigned WavefrontSizeLog2 = ST.getWavefrontSizeLog2();
1626
1627 Register AdjustedSize = AllocSize;
1628 if (!HasFlatScratch) {
1629 auto WaveSize = B.buildConstant(SgprRB_I32, WavefrontSizeLog2);
1630 AdjustedSize = B.buildShl(SgprRB_I32, AllocSize, WaveSize).getReg(0);
1631 }
1632 if (Alignment > TFI.getStackAlign()) {
1633 const uint64_t EffectiveAlignment =
1634 Alignment.value() << (HasFlatScratch ? 0 : WavefrontSizeLog2);
1635 auto OldSP = B.buildCopy({SgprRB, PtrTy}, SPReg);
1636 auto Tmp1 =
1637 B.buildPtrAdd({SgprRB, PtrTy}, OldSP,
1638 B.buildConstant(SgprRB_I32, EffectiveAlignment - 1));
1639 uint64_t Mask = maskTrailingZeros<uint64_t>(Log2_64(EffectiveAlignment));
1640 B.buildPtrMask(Dst, Tmp1, B.buildConstant(SgprRB_I32, Mask));
1641 } else {
1642 B.buildCopy(Dst, SPReg);
1643 }
1644 auto PtrAdd = B.buildPtrAdd({SgprRB, PtrTy}, Dst, AdjustedSize);
1645 B.buildCopy(SPReg, PtrAdd);
1646 return true;
1647 }
1648 case WidenLoad: {
1649 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
1650 if (DstTy == S96)
1651 widenLoad(MI, S128);
1652 else if (DstTy == V3S32)
1653 widenLoad(MI, V4S32, S32);
1654 else if (DstTy == V6S16)
1655 widenLoad(MI, V8S16, V2S16);
1656 else {
1658 "AMDGPU RegBankLegalize: WidenLoad, unsuported type",
1659 MI);
1660 return false;
1661 }
1662 return true;
1663 }
1664 case UnpackAExt:
1665 return lowerUnpackAExt(MI);
1666 case WidenMMOToS32:
1667 return widenMMOToS32(cast<GAnyLoad>(MI));
1668 case VerifyAllSgpr: {
1669 assert(llvm::all_of(MI.operands(), [&](const MachineOperand &Op) {
1670 return MRI.getRegBankOrNull(Op.getReg()) == SgprRB;
1671 }));
1672 return true;
1673 }
1674 case ApplyAllVgpr: {
1675 assert(llvm::all_of(MI.defs(), [&](const MachineOperand &Op) {
1676 return MRI.getRegBankOrNull(Op.getReg()) == VgprRB;
1677 }));
1678 B.setInstrAndDebugLoc(MI);
1679 for (unsigned i = MI.getNumDefs(); i < MI.getNumOperands(); ++i) {
1680 MachineOperand &Op = MI.getOperand(i);
1681 if (!Op.isReg())
1682 continue;
1683 Register Reg = Op.getReg();
1684 if (MRI.getRegBank(Reg) != VgprRB) {
1685 auto Copy = B.buildCopy({VgprRB, MRI.getType(Reg)}, Reg);
1686 Op.setReg(Copy.getReg(0));
1687 }
1688 }
1689 return true;
1690 }
1691 case UnmergeToShiftTrunc: {
1692 GUnmerge *Unmerge = dyn_cast<GUnmerge>(&MI);
1693 LLT Ty = MRI.getType(Unmerge->getSourceReg());
1694 if (Ty.getSizeInBits() % 32 != 0) {
1696 "AMDGPU RegBankLegalize: unmerge not multiple of 32",
1697 MI);
1698 return false;
1699 }
1700
1701 B.setInstrAndDebugLoc(MI);
1702 if (Ty.getSizeInBits() > 32) {
1703 auto UnmergeV2S16 =
1704 B.buildUnmerge({SgprRB, V2S16}, Unmerge->getSourceReg());
1705 for (unsigned i = 0; i < UnmergeV2S16->getNumDefs(); ++i) {
1706 auto [Dst0I32, Dst1I32] =
1707 unpackAExt(UnmergeV2S16->getOperand(i).getReg());
1708 B.buildTrunc(MI.getOperand(i * 2).getReg(), Dst0I32);
1709 B.buildTrunc(MI.getOperand(i * 2 + 1).getReg(), Dst1I32);
1710 }
1711 } else {
1712 auto [Dst0I32, Dst1I32] = unpackAExt(MI.getOperand(2).getReg());
1713 B.buildTrunc(MI.getOperand(0).getReg(), Dst0I32);
1714 B.buildTrunc(MI.getOperand(1).getReg(), Dst1I32);
1715 }
1716
1717 MI.eraseFromParent();
1718 return true;
1719 }
1721 Register Dst = MI.getOperand(0).getReg();
1722 Register NewDst = MRI.createVirtualRegister(SgprRB_I32);
1723 B.setInsertPt(*MI.getParent(), MI.getParent()->getFirstNonPHI());
1724 MI.getOperand(0).setReg(NewDst);
1725 B.buildTrunc(Dst, NewDst);
1726
1727 for (unsigned i = 1; i < MI.getNumOperands(); i += 2) {
1728 Register UseReg = MI.getOperand(i).getReg();
1729
1730 auto DefMI = MRI.getVRegDef(UseReg)->getIterator();
1731 MachineBasicBlock *DefMBB = DefMI->getParent();
1732
1733 B.setInsertPt(*DefMBB, DefMBB->SkipPHIsAndLabels(std::next(DefMI)));
1734
1735 auto NewUse = B.buildAnyExt(SgprRB_I32, UseReg);
1736 MI.getOperand(i).setReg(NewUse.getReg(0));
1737 }
1738 break;
1739 }
1740 case VerifyAllSgprGPHI: {
1741 assert(llvm::all_of(MI.operands(), [&](const MachineOperand &Op) {
1742 if (Op.isMBB())
1743 return true;
1744 return MRI.getRegBankOrNull(Op.getReg()) == SgprRB;
1745 }));
1746 return true;
1747 }
1749 assert(MRI.getRegBankOrNull(MI.getOperand(0).getReg()) == VgprRB);
1750 assert(llvm::all_of(MI.operands(), [&](const MachineOperand &Op) {
1751 if (Op.isMBB())
1752 return true;
1753 const RegisterBank *RB = MRI.getRegBankOrNull(Op.getReg());
1754 return RB == VgprRB || RB == SgprRB;
1755 }));
1756 return true;
1757 }
1758 case ApplyINTRIN_IMAGE: {
1759 const AMDGPU::RsrcIntrinsic *RSrcIntrin =
1761 assert(RSrcIntrin && RSrcIntrin->IsImage);
1762 // The reported argument index is relative to the IR intrinsic call
1763 // arguments, so shift by the number of defs and the intrinsic ID.
1764 unsigned RsrcIdx = RSrcIntrin->RsrcArg + MI.getNumExplicitDefs() + 1;
1765 return applyRegisterBanksVgprWithSgprRsrc(MI, RsrcIdx);
1766 }
1768 // Rsrc is the last register operand. Base BVH trails an A16 immediate
1769 // after rsrc; dual/BVH8 do not. Scan backwards for the last virtual
1770 // register.
1771 unsigned RsrcIdx = MI.getNumOperands();
1772 while (RsrcIdx-- > MI.getNumExplicitDefs()) {
1773 const MachineOperand &Op = MI.getOperand(RsrcIdx);
1774 if (Op.isReg() && Op.getReg().isVirtual())
1775 break;
1776 }
1777 return applyRegisterBanksVgprWithSgprRsrc(MI, RsrcIdx);
1778 }
1780 return lowerSplitBitCount64To32(MI);
1781 case ExtrVecEltToSel:
1782 return lowerExtrVecEltToSel(MI);
1783 case ExtrVecEltTo32:
1784 return lowerExtrVecEltTo32(MI);
1785 case InsVecEltToSel:
1786 return lowerInsVecEltToSel(MI);
1787 case InsVecEltTo32:
1788 return lowerInsVecEltTo32(MI);
1789 case AbsToNegMax:
1790 return lowerAbsToNegMax(MI);
1791 case AbsToS32:
1792 return lowerAbsToS32(MI);
1793 case DeletePrefetch:
1794 MI.eraseFromParent();
1795 return true;
1796 case LowerSetRounding:
1797 return lowerSetRounding(MI);
1798 case LowerGetRounding:
1799 return lowerGetRounding(MI);
1800 }
1801
1802 return true;
1803}
1804
1805LLT RegBankLegalizeHelper::getTyFromID(RegBankLLTMappingApplyID ID) {
1806 switch (ID) {
1807 case Vcc:
1808 case UniInVcc:
1809 return LLT::scalar(1);
1810 case Sgpr16:
1811 case Vgpr16:
1812 case UniInVgprS16:
1813 return LLT::scalar(16);
1814 case Sgpr32:
1815 case Sgpr32_WF:
1816 case Sgpr32Trunc:
1817 case Sgpr32AExt:
1819 case Sgpr32SExt:
1820 case Sgpr32ZExt:
1821 case UniInVgprS32:
1822 case Sgpr32ToVgprDst:
1823 case Vgpr32:
1824 case Vgpr32AExt:
1825 case Vgpr32SExt:
1826 case Vgpr32ZExt:
1827 return LLT::scalar(32);
1828 case Sgpr64:
1829 case Vgpr64:
1830 case UniInVgprS64:
1831 case Sgpr64ToVgprDst:
1832 return LLT::scalar(64);
1833 case Sgpr128:
1834 case Vgpr128:
1835 return LLT::scalar(128);
1836 case SgprP0:
1837 case SgprP0Call_WF:
1838 case VgprP0:
1839 return LLT::pointer(0, 64);
1840 case SgprP1:
1841 case VgprP1:
1842 return LLT::pointer(1, 64);
1843 case SgprP2:
1844 case VgprP2:
1845 return LLT::pointer(2, 32);
1846 case SgprP3:
1847 case VgprP3:
1848 return LLT::pointer(3, 32);
1849 case SgprP4:
1850 case SgprP4Call_WF:
1851 case VgprP4:
1852 return LLT::pointer(4, 64);
1853 case SgprP5:
1854 case VgprP5:
1855 return LLT::pointer(5, 32);
1856 case SgprP6:
1857 return LLT::pointer(6, 32);
1858 case SgprP8:
1859 return LLT::pointer(8, 128);
1860 case SgprV2S16:
1861 case VgprV2S16:
1862 case UniInVgprV2S16:
1863 return LLT::fixed_vector(2, 16);
1864 case SgprV2S32:
1865 case VgprV2S32:
1866 case UniInVgprV2S32:
1867 return LLT::fixed_vector(2, 32);
1868 case VgprV3S32:
1869 case UniInVgprV3S32:
1870 return LLT::fixed_vector(3, 32);
1871 case VgprV4S16:
1872 return LLT::fixed_vector(4, 16);
1873 case VgprV8S16:
1874 case UniInVgprV8S16:
1875 return LLT::fixed_vector(8, 16);
1876 case VgprV16S16:
1877 case UniInVgprV16S16:
1878 return LLT::fixed_vector(16, 16);
1879 case SgprV4S32:
1880 case SgprV4S32_WF:
1882 case VgprV4S32:
1883 case UniInVgprV4S32:
1884 return LLT::fixed_vector(4, 32);
1885 case VgprV8S32:
1886 case UniInVgprV8S32:
1888 return LLT::fixed_vector(8, 32);
1889 case VgprV2S64:
1890 case UniInVgprV2S64:
1891 return LLT::fixed_vector(2, 64);
1892 case VgprV6S32:
1893 case UniInVgprV6S32:
1894 return LLT::fixed_vector(6, 32);
1895 case VgprV16S32:
1896 case UniInVgprV16S32:
1897 return LLT::fixed_vector(16, 32);
1898 case VgprV32S16:
1899 case UniInVgprV32S16:
1900 return LLT::fixed_vector(32, 16);
1901 case VgprV32S32:
1902 case UniInVgprV32S32:
1903 return LLT::fixed_vector(32, 32);
1904 default:
1905 return LLT();
1906 }
1907}
1908
1909LLT RegBankLegalizeHelper::getBTyFromID(RegBankLLTMappingApplyID ID, LLT Ty) {
1910 switch (ID) {
1911 case SgprB32:
1912 case VgprB32:
1913 case SgprB32_M0:
1915 case UniInVgprB32:
1916 if (Ty == LLT::scalar(32) || Ty == LLT::fixed_vector(2, 16) ||
1917 isAnyPtr(Ty, 32))
1918 return Ty;
1919 return LLT();
1920 case SgprPtr32:
1921 case VgprPtr32:
1922 return isAnyPtr(Ty, 32) ? Ty : LLT();
1923 case SgprPtr64:
1924 case VgprPtr64:
1925 return isAnyPtr(Ty, 64) ? Ty : LLT();
1926 case SgprPtr128:
1927 case VgprPtr128:
1928 return isAnyPtr(Ty, 128) ? Ty : LLT();
1929 case SgprB64:
1930 case VgprB64:
1932 case UniInVgprB64:
1933 if (Ty == LLT::scalar(64) || Ty == LLT::fixed_vector(2, 32) ||
1934 Ty == LLT::fixed_vector(4, 16) || isAnyPtr(Ty, 64))
1935 return Ty;
1936 return LLT();
1937 case SgprB96:
1938 case VgprB96:
1939 case UniInVgprB96:
1940 if (Ty == LLT::scalar(96) || Ty == LLT::fixed_vector(3, 32) ||
1941 Ty == LLT::fixed_vector(6, 16))
1942 return Ty;
1943 return LLT();
1944 case SgprB128:
1945 case VgprB128:
1946 case UniInVgprB128:
1947 if (Ty.getSizeInBits() == 128)
1948 return Ty;
1949 return LLT();
1950 case VgprB160:
1951 case UniInVgprB160:
1952 if (Ty.getSizeInBits() == 160)
1953 return Ty;
1954 return LLT();
1955 case SgprB256:
1956 case VgprB256:
1957 case UniInVgprB256:
1958 if (Ty.getSizeInBits() == 256)
1959 return Ty;
1960 return LLT();
1961 case SgprB512:
1962 case VgprB512:
1963 case UniInVgprB512:
1964 if (Ty.getSizeInBits() == 512)
1965 return Ty;
1966 return LLT();
1967 case SgprBRC: {
1968 const SIRegisterInfo *TRI =
1969 static_cast<const SIRegisterInfo *>(MRI.getTargetRegisterInfo());
1970 unsigned LLTSize = Ty.getSizeInBits();
1971 if (LLTSize >= 32 && TRI->getSGPRClassForBitWidth(LLTSize))
1972 return Ty;
1973 return LLT();
1974 }
1975 case VgprBRC: {
1976 const SIRegisterInfo *TRI =
1977 static_cast<const SIRegisterInfo *>(MRI.getTargetRegisterInfo());
1978 if (TRI->getSGPRClassForBitWidth(Ty.getSizeInBits()))
1979 return Ty;
1980 return LLT();
1981 }
1982 default:
1983 return LLT();
1984 }
1985}
1986
1987const RegisterBank *
1988RegBankLegalizeHelper::getRegBankFromID(RegBankLLTMappingApplyID ID) {
1989 switch (ID) {
1990 case Vcc:
1991 return VccRB;
1992 case Sgpr16:
1993 case Sgpr32:
1994 case Sgpr32_WF:
1995 case Sgpr64:
1996 case Sgpr128:
1997 case SgprP0:
1998 case SgprP0Call_WF:
1999 case SgprP1:
2000 case SgprP2:
2001 case SgprP3:
2002 case SgprP4:
2003 case SgprP4Call_WF:
2004 case SgprP5:
2005 case SgprP6:
2006 case SgprP8:
2007 case SgprPtr32:
2008 case SgprPtr64:
2009 case SgprPtr128:
2010 case SgprV2S16:
2011 case SgprV2S32:
2012 case SgprV4S32:
2013 case SgprV4S32_WF:
2016 case SgprB32:
2017 case SgprB64:
2018 case SgprB96:
2019 case SgprB128:
2020 case SgprB256:
2021 case SgprB512:
2022 case SgprBRC:
2023 case UniInVcc:
2024 case UniInVgprS16:
2025 case UniInVgprS32:
2026 case UniInVgprS64:
2027 case UniInVgprV2S16:
2028 case UniInVgprV2S32:
2029 case UniInVgprV3S32:
2030 case UniInVgprV4S32:
2031 case UniInVgprV2S64:
2032 case UniInVgprV6S32:
2033 case UniInVgprV8S16:
2034 case UniInVgprV8S32:
2035 case UniInVgprV16S16:
2036 case UniInVgprV16S32:
2037 case UniInVgprV32S16:
2038 case UniInVgprV32S32:
2039 case UniInVgprB32:
2040 case UniInVgprB64:
2041 case UniInVgprB96:
2042 case UniInVgprB128:
2043 case UniInVgprB160:
2044 case UniInVgprB256:
2045 case UniInVgprB512:
2046 case Sgpr32Trunc:
2047 case Sgpr32AExt:
2049 case Sgpr32SExt:
2050 case Sgpr32ZExt:
2051 return SgprRB;
2052 case AgprAnyTy:
2053 return AgprRB;
2054 case Vgpr16:
2055 case Vgpr32:
2056 case Vgpr64:
2057 case Vgpr128:
2058 case VgprP0:
2059 case VgprP1:
2060 case VgprP2:
2061 case VgprP3:
2062 case VgprP4:
2063 case VgprP5:
2064 case VgprPtr32:
2065 case VgprPtr64:
2066 case VgprPtr128:
2067 case VgprV2S16:
2068 case VgprV2S32:
2069 case VgprV2S64:
2070 case VgprV3S32:
2071 case VgprV4S16:
2072 case VgprV8S16:
2073 case VgprV16S16:
2074 case VgprV4S32:
2075 case VgprV6S32:
2076 case VgprV8S32:
2077 case VgprV16S32:
2078 case VgprV32S16:
2079 case VgprV32S32:
2080 case VgprB32:
2081 case VgprB64:
2082 case VgprB96:
2083 case VgprB128:
2084 case VgprB160:
2085 case VgprB256:
2086 case VgprB512:
2087 case VgprBRC:
2088 case VgprAnyTy:
2089 case Vgpr32AExt:
2090 case Vgpr32SExt:
2091 case Vgpr32ZExt:
2092 case Sgpr32ToVgprDst:
2093 case Sgpr64ToVgprDst:
2094 return VgprRB;
2095 default:
2096 return nullptr;
2097 }
2098}
2099
2100bool RegBankLegalizeHelper::applyMappingDst(
2101 MachineInstr &MI, unsigned &OpIdx,
2102 const SmallVectorImpl<RegBankLLTMappingApplyID> &MethodIDs) {
2103 // Defs start from operand 0
2104 for (; OpIdx < MethodIDs.size(); ++OpIdx) {
2105 if (MethodIDs[OpIdx] == None)
2106 continue;
2107 MachineOperand &Op = MI.getOperand(OpIdx);
2108 Register Reg = Op.getReg();
2109 LLT Ty = MRI.getType(Reg);
2110 [[maybe_unused]] const RegisterBank *RB = MRI.getRegBank(Reg);
2111
2112 switch (MethodIDs[OpIdx]) {
2113 // vcc, sgpr and vgpr scalars, pointers and vectors
2114 case Vcc:
2115 case Sgpr16:
2116 case Sgpr32:
2117 case Sgpr64:
2118 case Sgpr128:
2119 case SgprP0:
2120 case SgprP1:
2121 case SgprP3:
2122 case SgprP4:
2123 case SgprP5:
2124 case SgprP6:
2125 case SgprP8:
2126 case SgprV2S16:
2127 case SgprV2S32:
2128 case SgprV4S32:
2129 case Vgpr16:
2130 case Vgpr32:
2131 case Vgpr64:
2132 case Vgpr128:
2133 case VgprP0:
2134 case VgprP1:
2135 case VgprP2:
2136 case VgprP3:
2137 case VgprP4:
2138 case VgprP5:
2139 case VgprV2S16:
2140 case VgprV2S32:
2141 case VgprV2S64:
2142 case VgprV3S32:
2143 case VgprV4S16:
2144 case VgprV8S16:
2145 case VgprV16S16:
2146 case VgprV4S32:
2147 case VgprV6S32:
2148 case VgprV8S32:
2149 case VgprV16S32:
2150 case VgprV32S16:
2151 case VgprV32S32: {
2152 assert(Ty == getTyFromID(MethodIDs[OpIdx]));
2153 assert(RB == getRegBankFromID(MethodIDs[OpIdx]));
2154 break;
2155 }
2156 // sgpr and vgpr B-types
2157 case SgprB32:
2158 case SgprB64:
2159 case SgprB96:
2160 case SgprB128:
2161 case SgprB256:
2162 case SgprB512:
2163 case SgprBRC:
2164 case SgprPtr32:
2165 case SgprPtr64:
2166 case SgprPtr128:
2167 case VgprB32:
2168 case VgprB64:
2169 case VgprB96:
2170 case VgprB128:
2171 case VgprB160:
2172 case VgprB256:
2173 case VgprB512:
2174 case VgprBRC:
2175 case VgprPtr32:
2176 case VgprPtr64:
2177 case VgprPtr128: {
2178 assert(Ty == getBTyFromID(MethodIDs[OpIdx], Ty));
2179 assert(RB == getRegBankFromID(MethodIDs[OpIdx]));
2180 break;
2181 }
2182 case VgprAnyTy: {
2183 assert(RB == VgprRB);
2184 break;
2185 }
2186 case AgprAnyTy: {
2187 if (RB == AgprRB)
2188 break;
2189 Register NewAgprDst = MRI.createVirtualRegister({AgprRB, Ty});
2190 Op.setReg(NewAgprDst);
2191 if (!MRI.use_nodbg_empty(Reg))
2192 B.buildCopy(Reg, NewAgprDst);
2193 break;
2194 }
2195 case VgprOrAgprAnyTy: {
2196 const unsigned NumRegs = Ty.getSizeInBits() / 32;
2197 const RegisterBank *DstRB =
2198 MFI->selectAGPRFormMFMA(NumRegs) ? AgprRB : VgprRB;
2199 if (RB == DstRB)
2200 break;
2201 Register NewDst = MRI.createVirtualRegister({DstRB, Ty});
2202 Op.setReg(NewDst);
2203 if (!MRI.use_nodbg_empty(Reg))
2204 B.buildCopy(Reg, NewDst);
2205 break;
2206 }
2207 // uniform in vcc/vgpr: scalars, vectors and B-types
2208 case UniInVcc: {
2209 assert(Ty == S1);
2210 assert(RB == SgprRB);
2211 Register NewDst = MRI.createVirtualRegister(VccRB_S1);
2212 Op.setReg(NewDst);
2213 if (!MRI.use_empty(Reg)) {
2214 auto CopyS32_Vcc =
2215 B.buildInstr(AMDGPU::G_AMDGPU_COPY_SCC_VCC, {SgprRB_I32}, {NewDst});
2216 B.buildTrunc(Reg, CopyS32_Vcc);
2217 }
2218 break;
2219 }
2220 case UniInVgprS16: {
2221 assert(Ty == getTyFromID(MethodIDs[OpIdx]));
2222 assert(RB == SgprRB);
2223 Register NewVgprDst16 = MRI.createVirtualRegister({VgprRB, Ty});
2224 Register NewVgprDstI32 = MRI.createVirtualRegister(VgprRB_I32);
2225 Register NewSgprDstI32 = MRI.createVirtualRegister(SgprRB_I32);
2226 Op.setReg(NewVgprDst16);
2227 B.buildAnyExt(NewVgprDstI32, NewVgprDst16);
2228 buildReadAnyLane(B, NewSgprDstI32, NewVgprDstI32, RBI);
2229 B.buildTrunc(Reg, NewSgprDstI32);
2230 break;
2231 }
2232 case UniInVgprS32:
2233 case UniInVgprS64:
2234 case UniInVgprV2S16:
2235 case UniInVgprV2S32:
2236 case UniInVgprV3S32:
2237 case UniInVgprV4S32:
2238 case UniInVgprV2S64:
2239 case UniInVgprV6S32:
2240 case UniInVgprV8S16:
2241 case UniInVgprV8S32:
2242 case UniInVgprV16S16:
2243 case UniInVgprV16S32:
2244 case UniInVgprV32S16:
2245 case UniInVgprV32S32: {
2246 assert(Ty == getTyFromID(MethodIDs[OpIdx]));
2247 assert(RB == SgprRB);
2248 Register NewVgprDst = MRI.createVirtualRegister({VgprRB, Ty});
2249 Op.setReg(NewVgprDst);
2250 buildReadAnyLane(B, Reg, NewVgprDst, RBI);
2251 break;
2252 }
2253 case UniInVgprB32:
2254 case UniInVgprB64:
2255 case UniInVgprB96:
2256 case UniInVgprB128:
2257 case UniInVgprB160:
2258 case UniInVgprB256:
2259 case UniInVgprB512: {
2260 assert(Ty == getBTyFromID(MethodIDs[OpIdx], Ty));
2261 assert(RB == SgprRB);
2262 Register NewVgprDst = MRI.createVirtualRegister({VgprRB, Ty});
2263 Op.setReg(NewVgprDst);
2264 AMDGPU::buildReadAnyLane(B, Reg, NewVgprDst, RBI);
2265 break;
2266 }
2267 // sgpr trunc
2268 case Sgpr32Trunc: {
2269 assert(Ty.getSizeInBits() < 32);
2270 assert(RB == SgprRB);
2271 Register NewDst = MRI.createVirtualRegister(SgprRB_I32);
2272 Op.setReg(NewDst);
2273 if (!MRI.use_empty(Reg))
2274 B.buildTrunc(Reg, NewDst);
2275 break;
2276 }
2277 case Sgpr32ToVgprDst:
2278 case Sgpr64ToVgprDst: {
2279 assert(Ty == getTyFromID(MethodIDs[OpIdx]));
2280 assert(RB == VgprRB);
2281 Op.setReg(MRI.createVirtualRegister({SgprRB, Ty}));
2282 B.buildCopy(Reg, Op.getReg());
2283 break;
2284 }
2285 case InvalidMapping: {
2287 MF, MORE, DEBUG_TYPE,
2288 "AMDGPU RegBankLegalize: missing fast rule ('Div' or 'Uni') for", MI);
2289 return false;
2290 }
2291 default:
2293 MF, MORE, DEBUG_TYPE,
2294 "AMDGPU RegBankLegalize: applyMappingDst, ID not supported", MI);
2295 return false;
2296 }
2297 }
2298
2299 return true;
2300}
2301
2302bool RegBankLegalizeHelper::applyMappingSrc(
2303 MachineInstr &MI, unsigned &OpIdx,
2304 const SmallVectorImpl<RegBankLLTMappingApplyID> &MethodIDs,
2305 WaterfallInfo &WFI) {
2306 for (unsigned i = 0; i < MethodIDs.size(); ++OpIdx, ++i) {
2307 if (MethodIDs[i] == None || MethodIDs[i] == IntrId || MethodIDs[i] == Imm)
2308 continue;
2309
2310 MachineOperand &Op = MI.getOperand(OpIdx);
2311 Register Reg = Op.getReg();
2312 LLT Ty = MRI.getType(Reg);
2313 const RegisterBank *RB = MRI.getRegBank(Reg);
2314
2315 switch (MethodIDs[i]) {
2316 case Vcc: {
2317 assert(Ty == S1);
2318 assert(RB == VccRB || RB == SgprRB);
2319 if (RB == SgprRB) {
2320 auto Aext = B.buildAnyExt(SgprRB_I32, Reg);
2321 auto Cst1 = B.buildConstant(SgprRB_I32, 1);
2322 auto BoolInReg = B.buildAnd(SgprRB_I32, Aext, Cst1);
2323 auto CopyVcc_Scc = B.buildInstr(AMDGPU::G_AMDGPU_COPY_VCC_SCC,
2324 {VccRB_S1}, {BoolInReg});
2325 Op.setReg(CopyVcc_Scc.getReg(0));
2326 }
2327 break;
2328 }
2329 // sgpr scalars, pointers and vectors
2330 case Sgpr16:
2331 case Sgpr32:
2332 case Sgpr64:
2333 case Sgpr128:
2334 case SgprP0:
2335 case SgprP1:
2336 case SgprP3:
2337 case SgprP4:
2338 case SgprP5:
2339 case SgprP6:
2340 case SgprP8:
2341 case SgprV2S16:
2342 case SgprV2S32:
2343 case SgprV4S32: {
2344 assert(Ty == getTyFromID(MethodIDs[i]));
2345 assert(RB == getRegBankFromID(MethodIDs[i]));
2346 break;
2347 }
2348 // sgpr B-types
2349 case SgprB32:
2350 case SgprB64:
2351 case SgprB96:
2352 case SgprB128:
2353 case SgprB256:
2354 case SgprB512:
2355 case SgprBRC:
2356 case SgprPtr32:
2357 case SgprPtr64:
2358 case SgprPtr128: {
2359 assert(Ty == getBTyFromID(MethodIDs[i], Ty));
2360 assert(RB == getRegBankFromID(MethodIDs[i]));
2361 break;
2362 }
2363 // vgpr scalars, pointers and vectors
2364 case Vgpr16:
2365 case Vgpr32:
2366 case Vgpr64:
2367 case Vgpr128:
2368 case VgprP0:
2369 case VgprP1:
2370 case VgprP2:
2371 case VgprP3:
2372 case VgprP4:
2373 case VgprP5:
2374 case VgprV2S16:
2375 case VgprV2S32:
2376 case VgprV2S64:
2377 case VgprV3S32:
2378 case VgprV4S16:
2379 case VgprV8S16:
2380 case VgprV16S16:
2381 case VgprV4S32:
2382 case VgprV6S32:
2383 case VgprV8S32:
2384 case VgprV16S32:
2385 case VgprV32S16:
2386 case VgprV32S32: {
2387 assert(Ty == getTyFromID(MethodIDs[i]));
2388 if (RB != VgprRB) {
2389 auto CopyToVgpr = B.buildCopy({VgprRB, Ty}, Reg);
2390 Op.setReg(CopyToVgpr.getReg(0));
2391 }
2392 break;
2393 }
2394 // vgpr B-types
2395 case VgprB32:
2396 case VgprB64:
2397 case VgprB96:
2398 case VgprB128:
2399 case VgprB160:
2400 case VgprB256:
2401 case VgprB512:
2402 case VgprBRC:
2403 case VgprPtr32:
2404 case VgprPtr64:
2405 case VgprPtr128: {
2406 assert(Ty == getBTyFromID(MethodIDs[i], Ty));
2407 if (RB != VgprRB) {
2408 auto CopyToVgpr = B.buildCopy({VgprRB, Ty}, Reg);
2409 Op.setReg(CopyToVgpr.getReg(0));
2410 }
2411 break;
2412 }
2413 case VgprAnyTy: {
2414 if (RB != VgprRB) {
2415 auto CopyToVgpr = B.buildCopy({VgprRB, Ty}, Reg);
2416 Op.setReg(CopyToVgpr.getReg(0));
2417 }
2418 break;
2419 }
2420 case AgprAnyTy: {
2421 if (RB != AgprRB) {
2422 auto CopyToAgpr = B.buildCopy({AgprRB, Ty}, Reg);
2423 Op.setReg(CopyToAgpr.getReg(0));
2424 }
2425 break;
2426 }
2427 case VgprOrAgprAnyTy: {
2428 const unsigned NumRegs = Ty.getSizeInBits() / 32;
2429 const RegisterBank *SrcRB =
2430 MFI->selectAGPRFormMFMA(NumRegs) ? AgprRB : VgprRB;
2431 if (RB != SrcRB)
2432 Op.setReg(B.buildCopy({SrcRB, Ty}, Reg).getReg(0));
2433 break;
2434 }
2435 // sgpr waterfall, scalars, and vectors
2436 case Sgpr32_WF:
2437 case SgprV4S32_WF: {
2438 assert(Ty == getTyFromID(MethodIDs[i]));
2439 if (RB != SgprRB) {
2440 WFI.SgprWaterfallOperandRegs.insert(Reg);
2441 if (!WFI.Start.isValid()) {
2442 WFI.Start = MI.getIterator();
2443 WFI.End = std::next(MI.getIterator());
2444 }
2445 }
2446 break;
2447 }
2448 case SgprP0Call_WF:
2449 case SgprP4Call_WF: {
2450 assert(Ty == getTyFromID(MethodIDs[i]));
2451 if (RB != SgprRB) {
2452 WFI.SgprWaterfallOperandRegs.insert(Reg);
2453
2454 // Find the ADJCALLSTACKUP before the call.
2455 MachineBasicBlock::iterator Start = MI.getIterator();
2456 while (Start->getOpcode() != AMDGPU::ADJCALLSTACKUP)
2457 --Start;
2458
2459 // Find the ADJCALLSTACKDOWN after the call (include it in range).
2460 MachineBasicBlock::iterator End = MI.getIterator();
2461 while (End->getOpcode() != AMDGPU::ADJCALLSTACKDOWN)
2462 ++End;
2463 ++End;
2464
2465 WFI.Start = Start;
2466 WFI.End = End;
2467 }
2468 break;
2469 }
2470 case SgprB32_M0:
2472 case SgprB64_ReadFirstLane: {
2473 assert(Ty == getBTyFromID(MethodIDs[i], Ty));
2474 if (RB == SgprRB)
2475 break;
2476 assert(RB == VgprRB);
2477 Register NewSGPR = MRI.createVirtualRegister({SgprRB, Ty});
2478 buildReadFirstLane(B, NewSGPR, Op.getReg(), RBI);
2479 Op.setReg(NewSGPR);
2480 break;
2481 }
2484 assert(Ty == getTyFromID(MethodIDs[i]));
2485 if (RB == SgprRB)
2486 break;
2487 assert(RB == VgprRB);
2488 Register NewSGPR = MRI.createVirtualRegister({SgprRB, Ty});
2489 buildReadFirstLane(B, NewSGPR, Op.getReg(), RBI);
2490 Op.setReg(NewSGPR);
2491 break;
2492 }
2493 // sgpr and vgpr scalars with extend
2494 case Sgpr32AExt: {
2495 // Note: this ext allows S1, and it is meant to be combined away.
2496 assert(Ty.getSizeInBits() < 32);
2497 assert(RB == SgprRB);
2498 auto Aext = B.buildAnyExt(SgprRB_I32, Reg);
2499 Op.setReg(Aext.getReg(0));
2500 break;
2501 }
2502 case Sgpr32AExtBoolInReg: {
2503 // Note: this ext allows S1, and it is meant to be combined away.
2504 assert(Ty.getSizeInBits() == 1);
2505 assert(RB == SgprRB);
2506 auto Aext = B.buildAnyExt(SgprRB_I32, Reg);
2507 // Zext SgprS1 is not legal, make AND with 1 instead. This instruction is
2508 // most of times meant to be combined away in AMDGPURegBankCombiner.
2509 auto Cst1 = B.buildConstant(SgprRB_I32, 1);
2510 auto BoolInReg = B.buildAnd(SgprRB_I32, Aext, Cst1);
2511 Op.setReg(BoolInReg.getReg(0));
2512 break;
2513 }
2514 case Sgpr32SExt: {
2515 assert(1 < Ty.getSizeInBits() && Ty.getSizeInBits() < 32);
2516 assert(RB == SgprRB);
2517 auto Sext = B.buildSExt(SgprRB_I32, Reg);
2518 Op.setReg(Sext.getReg(0));
2519 break;
2520 }
2521 case Sgpr32ZExt: {
2522 assert(1 < Ty.getSizeInBits() && Ty.getSizeInBits() < 32);
2523 assert(RB == SgprRB);
2524 auto Zext = B.buildZExt(SgprRB_I32, Reg);
2525 Op.setReg(Zext.getReg(0));
2526 break;
2527 }
2528 case Vgpr32AExt: {
2529 assert(Ty.getSizeInBits() < 32);
2530 assert(RB == VgprRB);
2531 auto Aext = B.buildAnyExt(VgprRB_I32, Reg);
2532 Op.setReg(Aext.getReg(0));
2533 break;
2534 }
2535 case Vgpr32SExt: {
2536 // Note this ext allows S1, and it is meant to be combined away.
2537 assert(Ty.getSizeInBits() < 32);
2538 assert(RB == VgprRB);
2539 auto Sext = B.buildSExt(VgprRB_I32, Reg);
2540 Op.setReg(Sext.getReg(0));
2541 break;
2542 }
2543 case Vgpr32ZExt: {
2544 // Note this ext allows S1, and it is meant to be combined away.
2545 assert(Ty.getSizeInBits() < 32);
2546 assert(RB == VgprRB);
2547 auto Zext = B.buildZExt(VgprRB_I32, Reg);
2548 Op.setReg(Zext.getReg(0));
2549 break;
2550 }
2551 default:
2553 MF, MORE, DEBUG_TYPE,
2554 "AMDGPU RegBankLegalize: applyMappingSrc, ID not supported", MI);
2555 return false;
2556 }
2557 }
2558 return true;
2559}
2560
2561[[maybe_unused]] static bool verifyRegBankOnOperands(MachineInstr &MI,
2562 const RegisterBank *RB,
2564 unsigned StartOpIdx,
2565 unsigned EndOpIdx) {
2566 for (unsigned i = StartOpIdx; i <= EndOpIdx; ++i) {
2567 if (MRI.getRegBankOrNull(MI.getOperand(i).getReg()) != RB)
2568 return false;
2569 }
2570 return true;
2571}
2572
2573bool RegBankLegalizeHelper::applyRegisterBanksVgprWithSgprRsrc(
2574 MachineInstr &MI, unsigned RsrcIdx) {
2575 const unsigned NumDefs = MI.getNumExplicitDefs();
2576
2577 MachineBasicBlock *MBB = MI.getParent();
2578 B.setInsertPt(*MBB, MBB->SkipPHIsAndLabels(std::next(MI.getIterator())));
2579
2580 // Defs are vgpr.
2581 for (unsigned i = 0; i < NumDefs; ++i) {
2582 Register Reg = MI.getOperand(i).getReg();
2583 if (MRI.getRegBank(Reg) == VgprRB)
2584 continue;
2585
2586 Register NewVgprDst = MRI.createVirtualRegister({VgprRB, MRI.getType(Reg)});
2587 MI.getOperand(i).setReg(NewVgprDst);
2588 buildReadAnyLane(B, Reg, NewVgprDst, RBI);
2589 }
2590
2591 B.setInstrAndDebugLoc(MI);
2592
2593 // Register uses before RsrcIdx are vgpr.
2594 for (unsigned i = NumDefs; i < RsrcIdx; ++i) {
2595 MachineOperand &Op = MI.getOperand(i);
2596 if (!Op.isReg())
2597 continue;
2598
2599 Register Reg = Op.getReg();
2600 if (!Reg.isVirtual())
2601 continue;
2602
2603 if (MRI.getRegBank(Reg) == VgprRB)
2604 continue;
2605
2606 auto Copy = B.buildCopy({VgprRB, MRI.getType(Reg)}, Reg);
2607 Op.setReg(Copy.getReg(0));
2608 }
2609
2610 SmallSet<Register, 4> OpsToWaterfall;
2611
2612 // Register use RsrcIdx (and later register operands) is sgpr.
2613 for (unsigned i = RsrcIdx; i < MI.getNumOperands(); ++i) {
2614 MachineOperand &Op = MI.getOperand(i);
2615 if (!Op.isReg())
2616 continue;
2617
2618 Register Reg = Op.getReg();
2619 if (MRI.getRegBank(Reg) != SgprRB)
2620 OpsToWaterfall.insert(Reg);
2621 }
2622
2623 if (!OpsToWaterfall.empty()) {
2624 MachineBasicBlock::iterator MII = MI.getIterator();
2625 executeInWaterfallLoop(B, {OpsToWaterfall, MII, std::next(MII)});
2626 }
2627
2628 return true;
2629}
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
Contains the definition of a TargetInstrInfo class that is common to all AMD GPUs.
static bool isSignedBFE(MachineInstr &MI)
static bool verifyRegBankOnOperands(MachineInstr &MI, const RegisterBank *RB, MachineRegisterInfo &MRI, unsigned StartOpIdx, unsigned EndOpIdx)
This file declares the targeting of the RegisterBankInfo class for AMDGPU.
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator MBBI
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
AMD GCN specific subclass of TargetSubtarget.
Provides analysis for querying information about KnownBits during GISel passes.
#define DEBUG_TYPE
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
static Register UseReg(const MachineOperand &MO)
IRTranslator LLVM IR MI
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineIRBuilder class.
Register Reg
Register const TargetRegisterInfo * TRI
Machine IR instance of the generic uniformity analysis.
Promote Memory to Register
Definition Mem2Reg.cpp:110
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
static constexpr MCPhysReg SPReg
const SmallVectorImpl< MachineOperand > & Cond
static const LaneMaskConstants & get(const GCNSubtarget &ST)
RegBankLegalizeHelper(MachineIRBuilder &B, const MachineUniformityInfo &MUI, GISelValueTracking *VT, const RegisterBankInfo &RBI, const RegBankLegalizeRules &RBLRules)
const RegBankLLTMapping * findMappingForMI(const MachineInstr &MI, const MachineRegisterInfo &MRI, const MachineUniformityInfo &MUI) const
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Definition APInt.h:303
@ ICMP_ULT
unsigned less than
Definition InstrTypes.h:765
@ ICMP_NE
not equal
Definition InstrTypes.h:762
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:223
iterator end()
Definition DenseMap.h:141
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition DenseMap.h:284
const SIRegisterInfo * getRegisterInfo() const override
Represents a call to an intrinsic.
Register getSourceReg() const
Get the unmerge source register.
constexpr bool isScalar() const
LLT getScalarType() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isFloat() const
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr bool isPointer() const
LLT divide(int Factor) const
Return a type that is Factor times smaller.
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
static LLT integer(unsigned SizeInBits)
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
static constexpr LLT float32()
Get a 32-bit IEEE float value.
TypeSize getValue() const
LLVM_ABI void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *FromMBB)
Transfers all the successors, as in transferSuccessors, and update PHI operands in the successor bloc...
LLVM_ABI iterator SkipPHIsAndLabels(iterator I)
Return the first instruction in MBB after I that is not a PHI or a label.
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineInstrBundleIterator< MachineInstr > iterator
BasicBlockListType::iterator iterator
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
void insert(iterator MBBI, MachineBasicBlock *MBB)
Helper class to build MachineInstr.
Representation of each machine instruction.
const MachineBasicBlock * getParent() const
LocationSize getSize() const
Return the size in bytes of the memory reference.
LLVM_ABI Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
MachineOperand class - Representation of each machine instruction operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
const RegisterBank * getRegBank(Register Reg) const
Return the register bank of Reg.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
const RegisterBank * getRegBankOrNull(Register Reg) const
Return the register bank of Reg, or null if Reg has not been assigned a register bank or has been ass...
Holds all the information related to register banks.
This class implements the register bank concept.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
This class keeps track of the SPI_SP_INPUT_ADDR config register, which tells the hardware which inter...
bool empty() const
Definition SmallSet.h:169
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition SmallSet.h:184
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
self_iterator getIterator()
Definition ilist_node.h:123
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
const uint64_t FltRoundToHWConversionTable
bool isAnyPtr(LLT Ty, unsigned Width)
uint32_t decodeFltRoundToHWConversionTable(uint32_t FltRounds)
Read the hardware rounding mode equivalent of a AMDGPUFltRounds value.
Intrinsic::ID getIntrinsicID(const MachineInstr &I)
Return the intrinsic ID for opcodes with the G_AMDGPU_INTRIN_ prefix.
std::pair< Register, unsigned > getBaseWithConstantOffset(MachineRegisterInfo &MRI, Register Reg, GISelValueTracking *ValueTracking=nullptr, bool CheckNUW=false)
Returns base register and constant offset.
void buildReadAnyLane(MachineIRBuilder &B, Register SgprDst, Register VgprSrc, const RegisterBankInfo &RBI)
const RsrcIntrinsic * lookupRsrcIntrinsic(unsigned Intr)
void buildReadFirstLane(MachineIRBuilder &B, Register SgprDst, Register VgprSrc, const RegisterBankInfo &RBI)
const uint64_t FltRoundConversionTable
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ Bitcast
Perform the operation on a different, but equivalently sized type.
SpecificConstantMatch m_ZeroInt()
Convenience matchers for specific integer values.
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
This is an optimization pass for GlobalISel generic memory operations.
GenericUniformityInfo< MachineSSAContext > MachineUniformityInfo
@ Offset
Definition DWP.cpp:577
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1739
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
Definition Utils.cpp:656
@ Known
Known to have no common set bits.
@ Kill
The last use of a register.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI void constrainSelectedInstRegOperands(MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Mutate the newly-selected instruction I to constrain its (possibly generic) virtual register operands...
Definition Utils.cpp:159
@ Load
The value being inserted comes from a load (InsertElement only).
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
unsigned Log2_64(uint64_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:332
LLVM_ABI std::optional< int64_t > getIConstantVRegSExtVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT fits in int64_t returns it.
Definition Utils.cpp:317
LLVM_ABI void reportGISelFailure(MachineFunction &MF, MachineOptimizationRemarkEmitter &MORE, MachineOptimizationRemarkMissed &R)
Report an ISel error as a missed optimization remark to the LLVMContext's diagnostic stream.
Definition Utils.cpp:261
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
Definition MathExtras.h:389
constexpr T maskTrailingZeros(unsigned N)
Create a bitmask with the N right-most bits set to 0, and all other bits set to 1.
Definition MathExtras.h:95
@ Add
Sum of integers.
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
Definition Utils.cpp:436
Align assumeAligned(uint64_t Value)
Treats the value 0 as a 1, so Align is always at least 1.
Definition Alignment.h:100
LLVM_ABI Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
Definition Utils.cpp:504
constexpr T maskTrailingOnes(unsigned N)
Create a bitmask with the N right-most bits set to 1, and all other bits set to 0.
Definition MathExtras.h:78
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
static constexpr uint64_t encode(Fields... Values)
SmallVector< RegBankLLTMappingApplyID, 2 > DstOpMapping
SmallVector< RegBankLLTMappingApplyID, 4 > SrcOpMapping
Holds waterfall loop information: the set of SGPR operand registers that need waterfalling,...
MachineBasicBlock::iterator Start
SmallSet< Register, 4 > SgprWaterfallOperandRegs