29#include "llvm/IR/IntrinsicsAMDGPU.h"
31#define DEBUG_TYPE "amdgpu-regbanklegalize"
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)) {}
53 "No AMDGPU RegBankLegalize rules defined for opcode",
61 "AMDGPU RegBankLegalize: none of the rules defined with "
62 "'Any' for MI's opcode matched MI",
70 B.setInsertPt(*
MI.getParent(), std::next(
MI.getIterator()));
80 if (!lower(
MI, *Mapping, WFI))
84 if (!executeInWaterfallLoop(B, WFI))
94 "Waterfall range not initialized");
111 const int OrigRangeSize = std::distance(BeginIt, EndIt);
120 B.buildInstr(TargetOpcode::IMPLICIT_DEF).addDef(InitSaveExecReg);
146 MBB.addSuccessor(LoopBB);
149 B.setInsertPt(*LoopBB, LoopBB->
end());
200 auto NewEnd = BodyBB->
end();
201 assert(std::distance(NewBegin, NewEnd) == OrigRangeSize);
214 auto OldVal = WaterfalledRegMap.
find(OldReg);
215 if (OldVal != WaterfalledRegMap.
end()) {
216 Op.setReg(OldVal->second);
229 unsigned OpSize =
OpTy.getSizeInBits();
230 unsigned PartSize = (OpSize % 64 == 0) ? 64 : 32;
232 unsigned NumParts = OpSize / PartSize;
238 CurrentLaneParts.
push_back(CurrentLaneReg);
240 auto UnmergeOp = B.buildUnmerge({VgprRB, PartTy}, OpReg);
241 auto UnmergeCurrLane = B.buildUnmerge({SgprRB, PartTy}, CurrentLaneReg);
242 for (
unsigned i = 0; i < NumParts; ++i) {
244 CurrentLaneParts.
push_back(UnmergeCurrLane.getReg(i));
248 for (
unsigned i = 0; i < NumParts; ++i) {
249 Register CmpReg = MRI.createVirtualRegister(VccRB_S1);
255 CondReg = B.buildAnd(VccRB_S1, CondReg, CmpReg).getReg(0);
258 Op.setReg(CurrentLaneReg);
261 WaterfalledRegMap.
insert(std::pair(OldReg,
Op.getReg()));
267 MRI.createVirtualRegister({WaveRC,
LLT::integer(IsWave32 ? 32 : 64)});
268 B.buildIntrinsic(Intrinsic::amdgcn_ballot, CondRegLM).addReg(CondReg);
274 MRI.setSimpleHint(SavedExec, CondRegLM);
276 B.setInsertPt(*BodyBB, BodyBB->
end());
288 B.buildInstr(AMDGPU::SI_WATERFALL_LOOP).addMBB(LoopBB);
292 B.buildInstr(LMC.
MovOpc).addDef(SaveExecReg).addReg(LMC.
ExecReg);
295 B.setInsertPt(*RestoreExecBB, RestoreExecBB->
begin());
300 B.setInsertPt(*RemainderBB, RemainderBB->
begin());
307unsigned RegBankLegalizeHelper::setBufferOffsets(
309 Register &SOffsetReg, int64_t &InstOffsetVal, Align Alignment) {
310 if (std::optional<int64_t>
Imm =
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;
320 const bool CheckNUW = ST.hasGFX1250Insts();
322 MRI, CombinedOffset,
nullptr,
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) {
329 SOffsetReg = B.buildConstant(SgprRB_I32, SOffset).getReg(0);
330 InstOffsetVal = ImmOffset;
335 VOffsetReg = B.buildConstant(VgprRB_I32, 0).getReg(0);
337 InstOffsetVal = ImmOffset;
343 if (
Add &&
static_cast<int32_t
>(
Offset) >= 0 &&
347 const RegisterBank *Src0Bank = MRI.getRegBank(Src0);
348 const RegisterBank *Src1Bank = MRI.getRegBank(Src1);
349 if (Src0Bank == VgprRB && Src1Bank == SgprRB) {
354 if (Src0Bank == SgprRB && Src1Bank == VgprRB) {
362 if (MRI.getRegBank(CombinedOffset) == VgprRB) {
363 VOffsetReg = CombinedOffset;
365 VOffsetReg = B.buildCopy(VgprRB_I32, CombinedOffset).getReg(0);
367 SOffsetReg = B.buildConstant(SgprRB_I32, 0).getReg(0);
371bool RegBankLegalizeHelper::splitLoad(MachineInstr &
MI,
373 MachineFunction &MF = B.getMF();
374 assert(
MI.getNumMemOperands() == 1);
375 MachineMemOperand &BaseMMO = **
MI.memoperands_begin();
377 const RegisterBank *DstRB = MRI.getRegBankOrNull(Dst);
379 LLT PtrTy = MRI.getType(
Base);
380 const RegisterBank *PtrRB = MRI.getRegBankOrNull(
Base);
384 unsigned ByteOffset = 0;
385 for (LLT PartTy : LLTBreakdown) {
387 if (ByteOffset == 0) {
388 BasePlusOffset =
Base;
390 auto Offset = B.buildConstant({PtrRB, OffsetTy}, ByteOffset);
394 auto *OffsetMMO = MF.getMachineMemOperand(&BaseMMO, ByteOffset, PartTy);
395 auto LoadPart = B.buildLoad({DstRB, PartTy}, BasePlusOffset, *OffsetMMO);
396 LoadPartRegs.
push_back(LoadPart.getReg(0));
402 B.buildMergeLikeInstr(Dst, LoadPartRegs);
408 if (MRI.getType(
Reg) == MergeTy) {
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));
416 B.buildMergeLikeInstr(Dst, MergeTyParts);
418 MI.eraseFromParent();
422bool RegBankLegalizeHelper::widenLoad(MachineInstr &
MI, LLT WideTy,
424 MachineFunction &MF = B.getMF();
425 assert(
MI.getNumMemOperands() == 1);
426 MachineMemOperand &BaseMMO = **
MI.memoperands_begin();
428 const RegisterBank *DstRB = MRI.getRegBankOrNull(Dst);
431 MachineMemOperand *WideMMO = MF.getMachineMemOperand(&BaseMMO, 0, WideTy);
432 auto WideLoad = B.buildLoad({DstRB, WideTy},
Base, *WideMMO);
435 B.buildTrunc(Dst, WideLoad);
438 auto Unmerge = B.buildUnmerge({DstRB, MergeTy}, WideLoad);
440 LLT DstTy = MRI.getType(Dst);
442 for (
unsigned i = 0; i < NumElts; ++i) {
443 MergeTyParts.
push_back(Unmerge.getReg(i));
445 B.buildMergeLikeInstr(Dst, MergeTyParts);
447 MI.eraseFromParent();
451bool RegBankLegalizeHelper::widenMMOToS32(GAnyLoad &
MI)
const {
454 MachineMemOperand &MMO =
MI.getMMO();
457 MachineMemOperand *WideMMO = B.getMF().getMachineMemOperand(&MMO, 0, S32);
459 if (
MI.getOpcode() == G_LOAD) {
460 B.buildLoad(Dst, Ptr, *WideMMO);
462 auto Load = B.buildLoad(SgprRB_I32, Ptr, *WideMMO);
464 if (
MI.getOpcode() == G_ZEXTLOAD) {
466 auto MaskCst = B.buildConstant(SgprRB_I32, Mask);
467 B.buildAnd(Dst, Load, MaskCst);
469 assert(
MI.getOpcode() == G_SEXTLOAD);
470 B.buildSExtInReg(Dst, Load, MemSize);
474 MI.eraseFromParent();
478bool RegBankLegalizeHelper::lowerVccExtToSel(MachineInstr &
MI) {
480 LLT Ty = MRI.getType(Dst);
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;
501 Hi = B.buildUndef({VgprRB_I32});
505 MF, MORE,
"amdgpu-regbanklegalize",
506 "AMDGPU RegBankLegalize: lowerVccExtToSel, Opcode not supported",
MI);
510 B.buildMergeValues(Dst, {
Lo.getReg(0),
Hi.getReg(0)});
513 MF, MORE,
"amdgpu-regbanklegalize",
514 "AMDGPU RegBankLegalize: lowerVccExtToSel, Type not supported",
MI);
518 MI.eraseFromParent();
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)};
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)};
537std::pair<Register, Register> RegBankLegalizeHelper::unpackAExt(
Register Reg) {
538 auto PackedI32 = B.buildBitcast(SgprRB_I32,
Reg);
540 auto Hi = B.buildLShr(SgprRB_I32, PackedI32, B.buildConstant(SgprRB_I32, 16));
541 return {
Lo.getReg(0),
Hi.getReg(0)};
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)};
552bool RegBankLegalizeHelper::lowerUnpackBitShift(MachineInstr &
MI) {
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);
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);
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);
578 MF, MORE,
"amdgpu-regbanklegalize",
579 "AMDGPU RegBankLegalize: lowerUnpackBitShift, case not implemented",
583 B.buildBuildVectorTrunc(
MI.getOperand(0).getReg(), {Lo, Hi});
584 MI.eraseFromParent();
588bool RegBankLegalizeHelper::lowerUnpackMinMax(MachineInstr &
MI) {
590 switch (
MI.getOpcode()) {
592 case AMDGPU::G_SMAX: {
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})
598 Hi = B.buildInstr(
MI.getOpcode(), {SgprRB_I32}, {Val0_Hi, Val1_Hi})
603 case AMDGPU::G_UMAX: {
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})
609 Hi = B.buildInstr(
MI.getOpcode(), {SgprRB_I32}, {Val0_Hi, Val1_Hi})
615 MF, MORE,
"amdgpu-regbanklegalize",
616 "AMDGPU RegBankLegalize: lowerUnpackMinMax, case not implemented",
MI);
619 B.buildBuildVectorTrunc(
MI.getOperand(0).getReg(), {Lo, Hi});
620 MI.eraseFromParent();
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();
635bool RegBankLegalizeHelper::lowerSBufToBuf(MachineInstr &
MI,
638 LLT Ty = MRI.getType(Dst);
639 const RegisterBank *RSrcBank = MRI.getRegBank(
MI.getOperand(1).getReg());
643 if (LoadSize == 256 || LoadSize == 512) {
644 NumLoads = LoadSize / 128;
647 for (
int i = 0; i < NumLoads; ++i)
648 LoadParts.
emplace_back(MRI.createVirtualRegister({VgprRB, Ty}));
649 MachineMemOperand *OrigMMO = *
MI.memoperands_begin();
651 MachineFunction &MF = B.getMF();
654 int64_t ImmOffset = 0;
655 unsigned MMOOffset = setBufferOffsets(B,
MI.getOperand(2).getReg(), VOffset,
656 SOffset, ImmOffset, Alignment);
661 MachineMemOperand *BaseMMO = MF.getMachineMemOperand(OrigMMO, 0, MemSize);
663 BaseMMO = MF.getMachineMemOperand(BaseMMO, MMOOffset, MemSize);
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;
673 case AMDGPU::G_AMDGPU_S_BUFFER_LOAD_UBYTE:
674 Opc = G_AMDGPU_BUFFER_LOAD_UBYTE;
676 case AMDGPU::G_AMDGPU_S_BUFFER_LOAD_SSHORT:
677 Opc = G_AMDGPU_BUFFER_LOAD_SSHORT;
679 case AMDGPU::G_AMDGPU_S_BUFFER_LOAD_USHORT:
680 Opc = G_AMDGPU_BUFFER_LOAD_USHORT;
685 for (
int i = 0; i < NumLoads; ++i) {
687 .addDef(LoadParts[i])
692 .addImm(ImmOffset + 16 * i)
695 .addMemOperand(MF.getMachineMemOperand(BaseMMO, 16 * i, MemSize));
698 B.buildCopy(Dst, LoadParts[0]);
700 B.buildMergeLikeInstr(Dst, LoadParts);
701 B.setInstr(*MRI.getVRegDef(LoadParts[0]));
702 if (RSrcBank != SgprRB) {
704 WFI.
Start = MRI.getVRegDef(LoadParts.
front());
705 WFI.
End = std::next(MRI.getVRegDef(LoadParts.
back())->getIterator());
707 MI.eraseFromParent();
713 return (GI->is(Intrinsic::amdgcn_sbfe));
715 return MI.getOpcode() == AMDGPU::G_SBFX;
718bool RegBankLegalizeHelper::lowerV_BFE(MachineInstr &
MI) {
725 Register Src =
MI.getOperand(FirstOpnd).getReg();
726 Register LSBit =
MI.getOperand(FirstOpnd + 1).getReg();
727 Register Width =
MI.getOperand(FirstOpnd + 2).getReg();
732 unsigned SHROpc =
Signed ? AMDGPU::G_ASHR : AMDGPU::G_LSHR;
733 auto SHRSrc = B.buildInstr(SHROpc, {VgprRB_I64}, {Src, LSBit});
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();
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;
755 if (WidthImm <= 32) {
757 auto Lo = B.buildInstr(BFXOpc, {VgprRB_I32}, {SHRSrcLo,
Zero, Width});
758 MachineInstrBuilder
Hi;
761 Hi = B.buildAShr(VgprRB_I32,
Lo, B.buildConstant(VgprRB_I32, 31));
766 B.buildMergeLikeInstr(Dst, {
Lo,
Hi});
768 auto Amt = B.buildConstant(VgprRB_I32, WidthImm - 32);
770 auto Hi = B.buildInstr(BFXOpc, {VgprRB_I32}, {SHRSrcHi,
Zero, Amt});
771 B.buildMergeLikeInstr(Dst, {SHRSrcLo,
Hi});
774 MI.eraseFromParent();
778bool RegBankLegalizeHelper::lowerS_BFE(MachineInstr &
MI) {
780 LLT Ty = MRI.getType(DstReg);
783 Register Src =
MI.getOperand(FirstOpnd).getReg();
784 Register LSBit =
MI.getOperand(FirstOpnd + 1).getReg();
785 Register Width =
MI.getOperand(FirstOpnd + 2).getReg();
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;
801 auto S_BFE = B.buildInstr(
Opc, {{SgprRB, Ty}},
802 {B.buildCopy(Ty, Src), B.buildCopy(I32, Src1)});
804 *ST.getRegisterInfo(), RBI);
806 B.buildCopy(DstReg,
S_BFE->getOperand(0).getReg());
807 MI.eraseFromParent();
811bool RegBankLegalizeHelper::lowerSplitTo32(MachineInstr &
MI) {
813 LLT DstTy = MRI.getType(Dst);
814 assert(DstTy == V4S16 || DstTy == V2S32 || DstTy == S64);
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();
821 B.buildInstr(
Opc, {{VgprRB, Ty}}, {Op1.getReg(0), Op2.getReg(0)},
Flags);
823 B.buildInstr(
Opc, {{VgprRB, Ty}}, {Op1.getReg(1), Op2.getReg(1)},
Flags);
824 B.buildMergeLikeInstr(Dst, {
Lo,
Hi});
825 MI.eraseFromParent();
829bool RegBankLegalizeHelper::lowerSplitTo32Mul(MachineInstr &
MI) {
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());
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);
844 B.buildMergeLikeInstr(Dst, {
Lo,
Hi});
845 MI.eraseFromParent();
849bool RegBankLegalizeHelper::lowerSplitTo16(MachineInstr &
MI) {
851 assert(MRI.getType(Dst) == V2S16);
852 unsigned Opc =
MI.getOpcode();
853 unsigned NumOps =
MI.getNumOperands();
856 auto [Op1Lo, Op1Hi] = unpackAExtTruncS16(
MI.getOperand(1).getReg());
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();
867 auto [Op2Lo, Op2Hi] = unpackAExtTruncS16(
MI.getOperand(2).getReg());
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();
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();
886bool RegBankLegalizeHelper::lowerUniMAD64(MachineInstr &
MI) {
893 const GCNSubtarget &ST = B.getMF().getSubtarget<GCNSubtarget>();
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});
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});
914 B.buildMergeLikeInstr(Dst0, {DstLo, DstHi});
915 B.buildConstant(Dst1, 0);
918 Register Src2Lo = MRI.createVirtualRegister(SgprRB_I32);
919 Register Src2Hi = MRI.createVirtualRegister(SgprRB_I32);
920 B.buildUnmerge({Src2Lo, Src2Hi}, Src2);
922 auto AddLo = B.buildUAddo(SgprRB_I32, SgprRB_I32, DstLo, Src2Lo);
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));
929 MI.eraseFromParent();
933bool RegBankLegalizeHelper::lowerSplitTo32Select(MachineInstr &
MI) {
935 LLT DstTy = MRI.getType(Dst);
936 assert(DstTy == V4S16 || DstTy == V2S32 || DstTy == S64 ||
939 auto Op2 = B.buildUnmerge({VgprRB, Ty},
MI.getOperand(2).
getReg());
940 auto Op3 = B.buildUnmerge({VgprRB, Ty},
MI.getOperand(3).
getReg());
944 B.buildSelect({VgprRB, Ty},
Cond, Op2.getReg(0), Op3.getReg(0), Flags);
946 B.buildSelect({VgprRB, Ty},
Cond, Op2.getReg(1), Op3.getReg(1), Flags);
948 B.buildMergeLikeInstr(Dst, {Lo, Hi});
949 MI.eraseFromParent();
953bool RegBankLegalizeHelper::lowerSplitTo32SExtInReg(MachineInstr &
MI) {
954 auto Op1 = B.buildUnmerge(VgprRB_I32,
MI.getOperand(1).getReg());
955 int Amt =
MI.getOperand(2).getImm();
959 auto Freeze = B.buildFreeze(VgprRB_I32, Op1.getReg(0));
962 Lo = Freeze.getReg(0);
965 Lo = B.buildSExtInReg(VgprRB_I32, Freeze, Amt).getReg(0);
968 auto SignExtCst = B.buildConstant(SgprRB_I32, 31);
969 Hi = B.buildAShr(VgprRB_I32,
Lo, SignExtCst).getReg(0);
973 Hi = B.buildSExtInReg(VgprRB_I32, Op1.getReg(1), Amt - 32).getReg(0);
976 B.buildMergeLikeInstr(
MI.getOperand(0).getReg(), {Lo, Hi});
977 MI.eraseFromParent();
981bool RegBankLegalizeHelper::lowerSplitBitCount64To32(MachineInstr &
MI) {
987 unsigned Opc =
MI.getOpcode();
996 case AMDGPU::G_AMDGPU_FFBH_U32:
998 AddOpc = AMDGPU::G_UADDSAT;
999 SearchFromMSB =
true;
1001 case AMDGPU::G_AMDGPU_FFBL_B32:
1003 AddOpc = AMDGPU::G_UADDSAT;
1004 SearchFromMSB =
false;
1006 case AMDGPU::G_CTLZ_ZERO_POISON:
1007 FFBOpc = AMDGPU::G_AMDGPU_FFBH_U32;
1008 AddOpc = AMDGPU::G_ADD;
1009 SearchFromMSB =
true;
1011 case AMDGPU::G_CTTZ_ZERO_POISON:
1012 FFBOpc = AMDGPU::G_AMDGPU_FFBL_B32;
1013 AddOpc = AMDGPU::G_ADD;
1014 SearchFromMSB =
false;
1020 auto Unmerge = B.buildUnmerge(VgprRB_I32,
MI.getOperand(1).getReg());
1027 auto Primary = B.buildInstr(FFBOpc, {VgprRB_I32}, {SearchFromMSB ?
Hi :
Lo});
1029 B.buildInstr(FFBOpc, {VgprRB_I32}, {SearchFromMSB ?
Lo :
Hi});
1031 auto Adjusted = B.buildInstr(AddOpc, {VgprRB_I32},
1032 {Secondary, B.buildConstant(VgprRB_I32, 32)});
1033 B.buildUMin(
MI.getOperand(0).getReg(), Primary, Adjusted);
1035 MI.eraseFromParent();
1039bool RegBankLegalizeHelper::lowerExtrVecEltToSel(MachineInstr &
MI) {
1051 LLT VecTy = MRI.getType(Src);
1054 MachineRegisterInfo::VRegAttrs VgprRB_EltTy = {VgprRB, ScalarTy};
1056 auto Unmerge = B.buildUnmerge(VgprRB_EltTy, Src);
1059 Register PrevSelect = Unmerge.getReg(0);
1060 for (
unsigned I = 1;
I < NumElts; ++
I) {
1061 auto IdxConst = B.buildConstant({SgprRB, MRI.getType(Idx)},
I);
1064 B.buildSelect(VgprRB_EltTy, Cmp, Unmerge.getReg(
I), PrevSelect)
1067 B.buildCopy(Dst, PrevSelect);
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);
1075 auto EltUnmerge = B.buildUnmerge(VgprRB_I32, Unmerge.getReg(
I));
1076 PrevLo = B.buildSelect(VgprRB_I32, Cmp, EltUnmerge.getReg(0), PrevLo)
1078 PrevHi = B.buildSelect(VgprRB_I32, Cmp, EltUnmerge.getReg(1), PrevHi)
1081 B.buildMergeLikeInstr(Dst, {PrevLo, PrevHi});
1084 MF, MORE,
"amdgpu-regbanklegalize",
1085 "AMDGPU RegBankLegalize: ExtrVecEltToSel unsupported element type",
MI);
1089 MI.eraseFromParent();
1093bool RegBankLegalizeHelper::lowerExtrVecEltTo32(MachineInstr &
MI) {
1106 LLT SrcTy = MRI.getType(Src);
1109 assert(MRI.getRegBank(Src) == VgprRB && MRI.getRegBank(Idx) == SgprRB &&
1110 "expected VGPR src and SGPR idx");
1112 auto CastSrc = B.buildBitcast({VgprRB, Vec32Ty}, Src);
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);
1119 auto ExtLo = B.buildExtractVectorElement(VgprRB_I32, CastSrc, IdxLo);
1120 auto ExtHi = B.buildExtractVectorElement(VgprRB_I32, CastSrc, IdxHi);
1122 B.buildMergeLikeInstr(Dst, {ExtLo.getReg(0), ExtHi.getReg(0)});
1124 MI.eraseFromParent();
1128bool RegBankLegalizeHelper::lowerInsVecEltToSel(MachineInstr &
MI) {
1141 LLT VecTy = MRI.getType(Src);
1144 const RegisterBank *SrcRB = MRI.getRegBank(Src);
1145 bool IsSGPR = (SrcRB == SgprRB);
1146 SmallVector<Register, 16> Selects;
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);
1158 B.buildSelect(VgprRB_I32, Cmp, EltLo, Unmerge.getReg(2 *
I))
1161 B.buildSelect(VgprRB_I32, Cmp, EltHi, Unmerge.getReg(2 *
I + 1))
1165 auto Vec32 = B.buildBuildVector({VgprRB, Vec32Ty}, Selects);
1166 B.buildBitcast(Dst, Vec32);
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);
1176 B.buildSelect(SrcRB_EltTy, Cmp, Elt, Unmerge.getReg(
I)).getReg(0));
1178 B.buildMergeLikeInstr(Dst, Selects);
1181 MF, MORE,
"amdgpu-regbanklegalize",
1182 "AMDGPU RegBankLegalize: InsVecEltToSel unsupported element type",
MI);
1186 MI.eraseFromParent();
1190bool RegBankLegalizeHelper::lowerInsVecEltTo32(MachineInstr &
MI) {
1205 LLT SrcTy = MRI.getType(Src);
1208 assert(MRI.getRegBank(Src) == VgprRB && MRI.getRegBank(Idx) == SgprRB &&
1209 "expected VGPR src and SGPR idx");
1211 MachineRegisterInfo::VRegAttrs VgprRB_Vec32Ty = {VgprRB, Vec32Ty};
1213 auto CastSrc = B.buildBitcast(VgprRB_Vec32Ty, Src);
1214 auto EltUnmerge = B.buildUnmerge(VgprRB_I32, Elt);
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);
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);
1226 B.buildBitcast(Dst, InsHi);
1228 MI.eraseFromParent();
1232bool RegBankLegalizeHelper::lowerAbsToNegMax(MachineInstr &
MI) {
1242 LLT Ty = MRI.getType(DstReg);
1248 Zero = B.buildBuildVector({VgprRB, Ty}, {Zero16, Zero16}).
getReg(0);
1250 assert((Ty == S32 || Ty == S16) &&
"unexpected type for AbsToNegMax");
1251 Zero = B.buildConstant({VgprRB, Ty}, 0).
getReg(0);
1254 auto Neg = B.buildSub({VgprRB, Ty},
Zero, SrcReg);
1255 B.buildSMax(DstReg, SrcReg, Neg);
1256 MI.eraseFromParent();
1260bool RegBankLegalizeHelper::lowerAbsToS32(MachineInstr &
MI) {
1270 auto Bitcast = B.buildBitcast({SgprRB_I32},
MI.getOperand(1).
getReg());
1271 auto SextInReg = B.buildSExtInReg({SgprRB_I32},
Bitcast, 16);
1273 B.buildAShr({SgprRB_I32},
Bitcast, B.buildConstant({SgprRB_I32}, 16));
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)});
1280 MI.eraseFromParent();
1286bool RegBankLegalizeHelper::lowerSetRounding(MachineInstr &
MI) {
1287 Register NewMode =
MI.getOperand(0).getReg();
1292 uint32_t ClampedVal = std::min(
1293 static_cast<uint32_t
>(ConstMode->Value.getZExtValue()),
1296 NewMode = B.buildConstant(SgprRB_I32, DecodedVal).getReg(0);
1300 KnownBits
Known = VT->getKnownBits(NewMode);
1301 const bool UseReducedTable =
Known.countMinLeadingZeros() >= 30;
1305 if (UseReducedTable) {
1307 auto BitTable = B.buildConstant(
1310 auto Two = B.buildConstant(SgprRB_I32, 2);
1311 auto RoundModeTimesNumBits = B.buildShl(SgprRB_I32, NewMode, Two);
1314 B.buildLShr(SgprRB_I32, BitTable, RoundModeTimesNumBits).getReg(0);
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);
1325 auto Two = B.buildConstant(SgprRB_I32, 2);
1326 auto RoundModeTimesNumBits = B.buildShl(SgprRB_I32, IndexVal, Two);
1331 B.buildLShr(SgprRB_I64, BitTable, RoundModeTimesNumBits);
1334 NewMode = B.buildTrunc(SgprRB_I32, TableValue).getReg(0);
1340 uint32_t BothRoundHwReg =
1344 .addImm(
static_cast<int16_t
>(BothRoundHwReg))
1347 MI.eraseFromParent();
1353bool RegBankLegalizeHelper::lowerGetRounding(MachineInstr &
MI) {
1356 uint32_t BothRoundHwReg =
1359 B.buildIntrinsic(Intrinsic::amdgcn_s_getreg, {SgprRB_I32},
1361 .addImm(BothRoundHwReg);
1392 auto Two = B.buildConstant(SgprRB_I32, 2);
1393 auto RoundModeTimesNumBits = B.buildShl(SgprRB_I32, GetReg, Two);
1397 auto TableValue = B.buildLShr(SgprRB_I64, BitTable, RoundModeTimesNumBits);
1398 auto TruncTable = B.buildTrunc(SgprRB_I32, TableValue);
1400 auto EntryMask = B.buildConstant(SgprRB_I32, 0xf);
1401 auto TableEntry = B.buildAnd(SgprRB_I32, TruncTable, EntryMask);
1405 auto Four = B.buildConstant(SgprRB_I32, 4);
1406 auto EnumOffset = B.buildAdd(SgprRB_I32, TableEntry, Four);
1407 auto IsStandardMode =
1409 B.buildSelect(Dst, IsStandardMode, TableEntry, EnumOffset);
1411 MI.eraseFromParent();
1415bool RegBankLegalizeHelper::lower(MachineInstr &
MI,
1423 return lowerVccExtToSel(
MI);
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);
1432 B.buildSelect(
MI.getOperand(0).getReg(),
MI.getOperand(1).getReg(), True,
1434 MI.eraseFromParent();
1438 return lowerUnpackBitShift(
MI);
1440 return lowerUnpackMinMax(
MI);
1442 return lowerSplitTo16(
MI);
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);
1451 case AMDGPU::G_SEXT: {
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);
1458 case AMDGPU::G_ANYEXT: {
1459 Hi = B.buildUndef({RB, I32});
1464 "AMDGPU RegBankLegalize: Ext32To64, unsuported opcode",
1469 B.buildMergeLikeInstr(
MI.getOperand(0).getReg(),
1470 {MI.getOperand(1).getReg(), Hi});
1471 MI.eraseFromParent();
1475 uint64_t ConstVal =
MI.getOperand(1).getCImm()->getZExtValue();
1476 B.buildConstant(
MI.getOperand(0).getReg(), ConstVal);
1478 MI.eraseFromParent();
1483 LLT Ty = MRI.getType(Src);
1487 Register BoolSrc = MRI.createVirtualRegister({VgprRB, Ty});
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});
1496 assert(Ty == S32 || Ty == S16);
1497 auto One = B.buildConstant({VgprRB, Ty}, 1);
1498 B.buildAnd(BoolSrc, Src, One);
1500 auto Zero = B.buildConstant({VgprRB, Ty}, 0);
1502 MI.eraseFromParent();
1506 return lowerV_BFE(
MI);
1508 return lowerS_BFE(
MI);
1510 return lowerUniMAD64(
MI);
1512 B.buildMul(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2));
1513 MI.eraseFromParent();
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);
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;
1525 B.buildInstr(NewOpc, {
MI.getOperand(0).getReg(), SgprRB_I32},
1527 MI.eraseFromParent();
1531 return lowerSplitTo32(
MI);
1533 return lowerSplitTo32Mul(
MI);
1535 return lowerSplitTo32Select(
MI);
1537 return lowerSplitTo32SExtInReg(
MI);
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));
1543 B.buildAdd(
MI.getOperand(0).getReg(), LoPopCnt, HiPopCnt,
1546 MI.eraseFromParent();
1550 return lowerSBufToBuf(
MI, WFI);
1552 LLT DstTy = MRI.getType(
MI.getOperand(0).getReg());
1563 if (
Size / 128 == 2)
1565 else if (
Size / 128 == 4)
1569 "AMDGPU RegBankLegalize: SplitLoad, unsuported type",
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);
1583 "AMDGPU RegBankLegalize: SplitLoad, unsuported type",
1590 const auto &TFI = *ST.getFrameLowering();
1594 "Stack grows upwards for AMDGPU");
1597 Register AllocSize =
MI.getOperand(1).getReg();
1602 B.setInsertPt(*
MI.getParent(), std::next(
MI.getIterator()));
1603 MI.eraseFromParent();
1605 if (MRI.getRegBank(AllocSize) != SgprRB) {
1606 auto WaveReduction =
1607 B.buildIntrinsic(Intrinsic::amdgcn_wave_reduce_umax, {SgprRB_I32})
1610 AllocSize = WaveReduction.getReg(0);
1613 LLT PtrTy = MRI.getType(Dst);
1615 "Expected 32-bit pointer for stack allocation");
1616 const SIMachineFunctionInfo *
Info = MF.getInfo<SIMachineFunctionInfo>();
1620 const bool HasFlatScratch = ST.hasFlatScratchEnabled();
1621 const unsigned WavefrontSizeLog2 = ST.getWavefrontSizeLog2();
1624 if (!HasFlatScratch) {
1625 auto WaveSize = B.buildConstant(SgprRB_I32, WavefrontSizeLog2);
1626 AdjustedSize = B.buildShl(SgprRB_I32, AllocSize, WaveSize).getReg(0);
1628 if (Alignment > TFI.getStackAlign()) {
1629 const uint64_t EffectiveAlignment =
1630 Alignment.
value() << (HasFlatScratch ? 0 : WavefrontSizeLog2);
1631 auto OldSP = B.buildCopy({SgprRB, PtrTy},
SPReg);
1633 B.buildPtrAdd({SgprRB, PtrTy}, OldSP,
1634 B.buildConstant(SgprRB_I32, EffectiveAlignment - 1));
1636 B.buildPtrMask(Dst, Tmp1, B.buildConstant(SgprRB_I32, Mask));
1638 B.buildCopy(Dst,
SPReg);
1640 auto PtrAdd = B.buildPtrAdd({SgprRB, PtrTy}, Dst, AdjustedSize);
1641 B.buildCopy(
SPReg, PtrAdd);
1645 LLT DstTy = MRI.getType(
MI.getOperand(0).getReg());
1647 widenLoad(
MI, S128);
1648 else if (DstTy == V3S32)
1649 widenLoad(
MI, V4S32, S32);
1650 else if (DstTy == V6S16)
1651 widenLoad(
MI, V8S16, V2S16);
1654 "AMDGPU RegBankLegalize: WidenLoad, unsuported type",
1661 return lowerUnpackAExt(
MI);
1666 return MRI.getRegBankOrNull(Op.getReg()) == SgprRB;
1672 return MRI.getRegBankOrNull(Op.getReg()) == VgprRB;
1674 B.setInstrAndDebugLoc(
MI);
1675 for (
unsigned i =
MI.getNumDefs(); i <
MI.getNumOperands(); ++i) {
1676 MachineOperand &
Op =
MI.getOperand(i);
1680 if (MRI.getRegBank(
Reg) != VgprRB) {
1681 auto Copy = B.buildCopy({VgprRB, MRI.getType(
Reg)},
Reg);
1682 Op.setReg(
Copy.getReg(0));
1692 "AMDGPU RegBankLegalize: unmerge not multiple of 32",
1697 B.setInstrAndDebugLoc(
MI);
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);
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);
1713 MI.eraseFromParent();
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);
1723 for (
unsigned i = 1; i <
MI.getNumOperands(); i += 2) {
1731 auto NewUse = B.buildAnyExt(SgprRB_I32,
UseReg);
1732 MI.getOperand(i).setReg(NewUse.getReg(0));
1740 return MRI.getRegBankOrNull(Op.getReg()) == SgprRB;
1745 assert(MRI.getRegBankOrNull(
MI.getOperand(0).getReg()) == VgprRB);
1749 const RegisterBank *RB = MRI.getRegBankOrNull(Op.getReg());
1750 return RB == VgprRB || RB == SgprRB;
1755 const AMDGPU::RsrcIntrinsic *RSrcIntrin =
1760 unsigned RsrcIdx = RSrcIntrin->
RsrcArg +
MI.getNumExplicitDefs() + 1;
1761 return applyRegisterBanksVgprWithSgprRsrc(
MI, RsrcIdx);
1767 unsigned RsrcIdx =
MI.getNumOperands();
1768 while (RsrcIdx-- >
MI.getNumExplicitDefs()) {
1769 const MachineOperand &
Op =
MI.getOperand(RsrcIdx);
1770 if (
Op.isReg() &&
Op.getReg().isVirtual())
1773 return applyRegisterBanksVgprWithSgprRsrc(
MI, RsrcIdx);
1776 return lowerSplitBitCount64To32(
MI);
1778 return lowerExtrVecEltToSel(
MI);
1780 return lowerExtrVecEltTo32(
MI);
1782 return lowerInsVecEltToSel(
MI);
1784 return lowerInsVecEltTo32(
MI);
1786 return lowerAbsToNegMax(
MI);
1788 return lowerAbsToS32(
MI);
1790 MI.eraseFromParent();
1793 return lowerSetRounding(
MI);
1795 return lowerGetRounding(
MI);
1918 return isAnyPtr(Ty, 32) ? Ty : LLT();
1921 return isAnyPtr(Ty, 64) ? Ty : LLT();
1924 return isAnyPtr(Ty, 128) ? Ty : LLT();
1964 const SIRegisterInfo *
TRI =
1965 static_cast<const SIRegisterInfo *
>(MRI.getTargetRegisterInfo());
1967 if (LLTSize >= 32 &&
TRI->getSGPRClassForBitWidth(LLTSize))
1972 const SIRegisterInfo *
TRI =
1973 static_cast<const SIRegisterInfo *
>(MRI.getTargetRegisterInfo());
2096bool RegBankLegalizeHelper::applyMappingDst(
2097 MachineInstr &
MI,
unsigned &
OpIdx,
2098 const SmallVectorImpl<RegBankLLTMappingApplyID> &MethodIDs) {
2103 MachineOperand &
Op =
MI.getOperand(
OpIdx);
2105 LLT Ty = MRI.getType(
Reg);
2106 [[maybe_unused]]
const RegisterBank *RB = MRI.getRegBank(
Reg);
2108 switch (MethodIDs[
OpIdx]) {
2185 Register NewAgprDst = MRI.createVirtualRegister({AgprRB, Ty});
2186 Op.setReg(NewAgprDst);
2187 if (!MRI.use_nodbg_empty(
Reg))
2188 B.buildCopy(
Reg, NewAgprDst);
2193 const RegisterBank *DstRB =
2194 MFI->selectAGPRFormMFMA(NumRegs) ? AgprRB : VgprRB;
2197 Register NewDst = MRI.createVirtualRegister({DstRB, Ty});
2199 if (!MRI.use_nodbg_empty(
Reg))
2200 B.buildCopy(
Reg, NewDst);
2207 Register NewDst = MRI.createVirtualRegister(VccRB_S1);
2209 if (!MRI.use_empty(
Reg)) {
2211 B.buildInstr(AMDGPU::G_AMDGPU_COPY_SCC_VCC, {SgprRB_I32}, {NewDst});
2212 B.buildTrunc(
Reg, CopyS32_Vcc);
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);
2225 B.buildTrunc(
Reg, NewSgprDstI32);
2244 Register NewVgprDst = MRI.createVirtualRegister({VgprRB, Ty});
2245 Op.setReg(NewVgprDst);
2258 Register NewVgprDst = MRI.createVirtualRegister({VgprRB, Ty});
2259 Op.setReg(NewVgprDst);
2267 Register NewDst = MRI.createVirtualRegister(SgprRB_I32);
2269 if (!MRI.use_empty(
Reg))
2270 B.buildTrunc(
Reg, NewDst);
2277 Op.setReg(MRI.createVirtualRegister({SgprRB, Ty}));
2278 B.buildCopy(
Reg,
Op.getReg());
2283 MF, MORE,
"amdgpu-regbanklegalize",
2284 "AMDGPU RegBankLegalize: missing fast rule ('Div' or 'Uni') for",
MI);
2289 MF, MORE,
"amdgpu-regbanklegalize",
2290 "AMDGPU RegBankLegalize: applyMappingDst, ID not supported",
MI);
2298bool RegBankLegalizeHelper::applyMappingSrc(
2299 MachineInstr &
MI,
unsigned &
OpIdx,
2300 const SmallVectorImpl<RegBankLLTMappingApplyID> &MethodIDs,
2302 for (
unsigned i = 0; i < MethodIDs.
size(); ++
OpIdx, ++i) {
2303 if (MethodIDs[i] ==
None || MethodIDs[i] ==
IntrId || MethodIDs[i] ==
Imm)
2306 MachineOperand &
Op =
MI.getOperand(
OpIdx);
2308 LLT Ty = MRI.getType(
Reg);
2309 const RegisterBank *RB = MRI.getRegBank(
Reg);
2311 switch (MethodIDs[i]) {
2314 assert(RB == VccRB || RB == SgprRB);
2316 auto Aext = B.buildAnyExt(SgprRB_I32,
Reg);
2318 B.buildInstr(AMDGPU::G_AMDGPU_COPY_VCC_SCC, {VccRB_S1}, {Aext});
2319 Op.setReg(CopyVcc_Scc.getReg(0));
2338 assert(Ty == getTyFromID(MethodIDs[i]));
2339 assert(RB == getRegBankFromID(MethodIDs[i]));
2353 assert(Ty == getBTyFromID(MethodIDs[i], Ty));
2354 assert(RB == getRegBankFromID(MethodIDs[i]));
2381 assert(Ty == getTyFromID(MethodIDs[i]));
2383 auto CopyToVgpr = B.buildCopy({VgprRB, Ty},
Reg);
2384 Op.setReg(CopyToVgpr.getReg(0));
2400 assert(Ty == getBTyFromID(MethodIDs[i], Ty));
2402 auto CopyToVgpr = B.buildCopy({VgprRB, Ty},
Reg);
2403 Op.setReg(CopyToVgpr.getReg(0));
2409 auto CopyToVgpr = B.buildCopy({VgprRB, Ty},
Reg);
2410 Op.setReg(CopyToVgpr.getReg(0));
2416 auto CopyToAgpr = B.buildCopy({AgprRB, Ty},
Reg);
2417 Op.setReg(CopyToAgpr.getReg(0));
2423 const RegisterBank *SrcRB =
2424 MFI->selectAGPRFormMFMA(NumRegs) ? AgprRB : VgprRB;
2426 Op.setReg(B.buildCopy({SrcRB, Ty},
Reg).getReg(0));
2432 assert(Ty == getTyFromID(MethodIDs[i]));
2437 WFI.
End = std::next(
MI.getIterator());
2444 assert(Ty == getTyFromID(MethodIDs[i]));
2450 while (
Start->getOpcode() != AMDGPU::ADJCALLSTACKUP)
2455 while (End->getOpcode() != AMDGPU::ADJCALLSTACKDOWN)
2467 assert(Ty == getBTyFromID(MethodIDs[i], Ty));
2471 Register NewSGPR = MRI.createVirtualRegister({SgprRB, Ty});
2478 assert(Ty == getTyFromID(MethodIDs[i]));
2482 Register NewSGPR = MRI.createVirtualRegister({SgprRB, Ty});
2492 auto Aext = B.buildAnyExt(SgprRB_I32,
Reg);
2493 Op.setReg(Aext.getReg(0));
2500 auto Aext = B.buildAnyExt(SgprRB_I32,
Reg);
2503 auto Cst1 = B.buildConstant(SgprRB_I32, 1);
2504 auto BoolInReg = B.buildAnd(SgprRB_I32, Aext, Cst1);
2505 Op.setReg(BoolInReg.getReg(0));
2511 auto Sext = B.buildSExt(SgprRB_I32,
Reg);
2512 Op.setReg(Sext.getReg(0));
2518 auto Zext = B.buildZExt(SgprRB_I32,
Reg);
2519 Op.setReg(Zext.getReg(0));
2525 auto Aext = B.buildAnyExt(VgprRB_I32,
Reg);
2526 Op.setReg(Aext.getReg(0));
2533 auto Sext = B.buildSExt(VgprRB_I32,
Reg);
2534 Op.setReg(Sext.getReg(0));
2541 auto Zext = B.buildZExt(VgprRB_I32,
Reg);
2542 Op.setReg(Zext.getReg(0));
2547 MF, MORE,
"amdgpu-regbanklegalize",
2548 "AMDGPU RegBankLegalize: applyMappingSrc, ID not supported",
MI);
2558 unsigned StartOpIdx,
2559 unsigned EndOpIdx) {
2560 for (
unsigned i = StartOpIdx; i <= EndOpIdx; ++i) {
2567bool RegBankLegalizeHelper::applyRegisterBanksVgprWithSgprRsrc(
2568 MachineInstr &
MI,
unsigned RsrcIdx) {
2569 const unsigned NumDefs =
MI.getNumExplicitDefs();
2571 MachineBasicBlock *
MBB =
MI.getParent();
2575 for (
unsigned i = 0; i < NumDefs; ++i) {
2577 if (MRI.getRegBank(
Reg) == VgprRB)
2580 Register NewVgprDst = MRI.createVirtualRegister({VgprRB, MRI.getType(
Reg)});
2581 MI.getOperand(i).setReg(NewVgprDst);
2585 B.setInstrAndDebugLoc(
MI);
2588 for (
unsigned i = NumDefs; i < RsrcIdx; ++i) {
2589 MachineOperand &
Op =
MI.getOperand(i);
2597 if (MRI.getRegBank(
Reg) == VgprRB)
2600 auto Copy = B.buildCopy({VgprRB, MRI.getType(
Reg)},
Reg);
2601 Op.setReg(
Copy.getReg(0));
2604 SmallSet<Register, 4> OpsToWaterfall;
2607 for (
unsigned i = RsrcIdx; i <
MI.getNumOperands(); ++i) {
2608 MachineOperand &
Op =
MI.getOperand(i);
2613 if (MRI.getRegBank(
Reg) != SgprRB)
2617 if (!OpsToWaterfall.
empty()) {
2619 executeInWaterfallLoop(B, {OpsToWaterfall, MII, std::next(MII)});
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 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)
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineIRBuilder class.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
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)
const unsigned XorTermOpc
const unsigned MovTermOpc
const unsigned AndSaveExecOpc
bool findRuleAndApplyMapping(MachineInstr &MI)
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.
@ ICMP_ULT
unsigned less than
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
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.
bool isValid() const
Check for null.
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.
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
This class keeps track of the SPI_SP_INPUT_ADDR config register, which tells the hardware which inter...
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
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()
#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
@ SgprV4S32_ReadFirstLane
@ SgprV8S32_ReadFirstLane
bool isAnyPtr(LLT Ty, unsigned Width)
@ TowardZeroF32_TowardNegativeF64
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.
@ VerifyAllSgprOrVgprGPHI
@ AextToS32InIncomingBlockGPHI
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.
@ 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
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
@ 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.
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...
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.
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.
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.
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...
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
constexpr T maskTrailingZeros(unsigned N)
Create a bitmask with the N right-most bits set to 0, and all other bits set to 1.
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.
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...
Align assumeAligned(uint64_t Value)
Treats the value 0 as a 1, so Align is always at least 1.
LLVM_ABI Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
constexpr T maskTrailingOnes(unsigned N)
Create a bitmask with the N right-most bits set to 1, and all other bits set to 0.
MCRegisterClass TargetRegisterClass
static constexpr uint64_t encode(Fields... Values)
LoweringMethodID LoweringMethod
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
MachineBasicBlock::iterator End
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.