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