31#define DEBUG_TYPE "si-peephole-sdwa"
33STATISTIC(NumSDWAPatternsFound,
"Number of SDWA patterns found.");
35 "Number of instruction converted to SDWA.");
54 SDWAOperandsMap PotentialMatches;
61 std::optional<std::pair<MachineOperand *, AMDGPU::SDWA::SdwaSel>>
73 bool convertToSDWA(
MachineInstr &
MI,
const SDWAOperandsVector &SDWAOperands);
85 SIPeepholeSDWALegacy() : MachineFunctionPass(ID) {}
87 StringRef getPassName()
const override {
return "SI Peephole SDWA"; }
91 void getAnalysisUsage(AnalysisUsage &AU)
const override {
101 MachineOperand *Target;
102 MachineOperand *Replaced;
106 virtual bool canCombineSelections(
const MachineInstr &
MI,
107 const SIInstrInfo *
TII) = 0;
110 SDWAOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp)
111 : Target(TargetOp), Replaced(ReplacedOp) {
113 assert(Replaced->isReg());
116 virtual ~SDWAOperand() =
default;
118 virtual MachineInstr *potentialToConvert(
const SIInstrInfo *
TII,
119 const GCNSubtarget &ST,
120 SDWAOperandsMap *PotentialMatches =
nullptr) = 0;
121 virtual bool convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII) = 0;
123 MachineOperand *getTargetOperand()
const {
return Target; }
124 MachineOperand *getReplacedOperand()
const {
return Replaced; }
125 MachineInstr *getParentInst()
const {
return Target->getParent(); }
127 MachineRegisterInfo *getMRI()
const {
128 return &getParentInst()->getMF()->getRegInfo();
131#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
132 virtual void print(raw_ostream& OS)
const = 0;
137class SDWASrcOperand :
public SDWAOperand {
145 SDWASrcOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp,
146 SdwaSel SrcSel_ =
DWORD,
bool Abs_ =
false,
bool Neg_ =
false,
148 : SDWAOperand(TargetOp, ReplacedOp), SrcSel(SrcSel_), Abs(Abs_),
149 Neg(Neg_), Sext(Sext_) {}
151 MachineInstr *potentialToConvert(
const SIInstrInfo *
TII,
152 const GCNSubtarget &ST,
153 SDWAOperandsMap *PotentialMatches =
nullptr)
override;
154 bool convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII)
override;
155 bool canCombineSelections(
const MachineInstr &
MI,
156 const SIInstrInfo *
TII)
override;
158 SdwaSel getSrcSel()
const {
return SrcSel; }
159 bool getAbs()
const {
return Abs; }
160 bool getNeg()
const {
return Neg; }
161 bool getSext()
const {
return Sext; }
165#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
166 void print(raw_ostream& OS)
const override;
170class SDWADstOperand :
public SDWAOperand {
176 SDWADstOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp,
178 : SDWAOperand(TargetOp, ReplacedOp), DstSel(DstSel_), DstUn(DstUn_) {}
180 MachineInstr *potentialToConvert(
const SIInstrInfo *
TII,
181 const GCNSubtarget &ST,
182 SDWAOperandsMap *PotentialMatches =
nullptr)
override;
183 bool convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII)
override;
184 bool canCombineSelections(
const MachineInstr &
MI,
185 const SIInstrInfo *
TII)
override;
187 SdwaSel getDstSel()
const {
return DstSel; }
188 DstUnused getDstUnused()
const {
return DstUn; }
190#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
191 void print(raw_ostream& OS)
const override;
195class SDWADstPreserveOperand :
public SDWADstOperand {
197 MachineOperand *Preserve;
200 SDWADstPreserveOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp,
203 Preserve(PreserveOp) {}
205 bool convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII)
override;
206 bool canCombineSelections(
const MachineInstr &
MI,
207 const SIInstrInfo *
TII)
override;
209 MachineOperand *getPreservedOperand()
const {
return Preserve; }
211#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
212 void print(raw_ostream& OS)
const override;
221char SIPeepholeSDWALegacy::ID = 0;
225#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
228 case BYTE_0: OS <<
"BYTE_0";
break;
229 case BYTE_1: OS <<
"BYTE_1";
break;
230 case BYTE_2: OS <<
"BYTE_2";
break;
231 case BYTE_3: OS <<
"BYTE_3";
break;
232 case WORD_0: OS <<
"WORD_0";
break;
233 case WORD_1: OS <<
"WORD_1";
break;
234 case DWORD: OS <<
"DWORD";
break;
250 OS <<
"SDWA src: " << *getTargetOperand()
251 <<
" src_sel:" << getSrcSel()
252 <<
" abs:" << getAbs() <<
" neg:" << getNeg()
253 <<
" sext:" << getSext() <<
'\n';
257void SDWADstOperand::print(raw_ostream& OS)
const {
258 OS <<
"SDWA dst: " << *getTargetOperand()
259 <<
" dst_sel:" << getDstSel()
260 <<
" dst_unused:" << getDstUnused() <<
'\n';
264void SDWADstPreserveOperand::print(raw_ostream& OS)
const {
265 OS <<
"SDWA preserve dst: " << *getTargetOperand()
266 <<
" dst_sel:" << getDstSel()
267 <<
" preserve:" << *getPreservedOperand() <<
'\n';
285 return LHS.isReg() &&
287 LHS.getReg() ==
RHS.getReg() &&
288 LHS.getSubReg() ==
RHS.getSubReg();
293 if (!
Reg->isReg() || !
Reg->isDef())
296 return MRI->getOneNonDBGUse(
Reg->getReg());
304 return MRI->getOneDef(
Reg->getReg());
319 if (Sel == SdwaSel::DWORD)
322 if (OperandSel == SdwaSel::DWORD)
325 if (Sel == SdwaSel::WORD_1 || Sel == SdwaSel::BYTE_2 ||
326 Sel == SdwaSel::BYTE_3)
330 if (OperandSel == SdwaSel::WORD_0)
334 if (OperandSel == SdwaSel::BYTE_0 && Sel == SdwaSel::BYTE_0)
335 return SdwaSel::BYTE_0;
337 if (OperandSel == SdwaSel::WORD_1) {
338 if (Sel == SdwaSel::BYTE_0)
339 return SdwaSel::BYTE_2;
340 if (Sel == SdwaSel::BYTE_1)
341 return SdwaSel::BYTE_3;
342 if (Sel == SdwaSel::WORD_0)
343 return SdwaSel::WORD_1;
352 "Float and integer src modifiers can't be set simultaneously");
355 }
else if (ExistingSel == SdwaSel::DWORD) {
368MachineInstr *SDWASrcOperand::potentialToConvert(
const SIInstrInfo *
TII,
369 const GCNSubtarget &ST,
370 SDWAOperandsMap *PotentialMatches) {
371 if (PotentialMatches !=
nullptr) {
373 MachineOperand *
Reg = getReplacedOperand();
374 if (!
Reg->isReg() || !
Reg->isDef())
377 for (MachineInstr &
UseMI : getMRI()->use_nodbg_instructions(
Reg->getReg()))
379 if (!isConvertibleToSDWA(
UseMI, ST,
TII) ||
385 for (MachineOperand &UseMO : getMRI()->use_nodbg_operands(
Reg->getReg())) {
389 SDWAOperandsMap &potentialMatchesMap = *PotentialMatches;
390 MachineInstr *
UseMI = UseMO.getParent();
391 potentialMatchesMap[
UseMI].push_back(
this);
398 MachineOperand *PotentialMO =
findSingleRegUse(getReplacedOperand(), getMRI());
402 MachineInstr *Parent = PotentialMO->
getParent();
404 return canCombineSelections(*Parent,
TII) ? Parent :
nullptr;
407bool SDWASrcOperand::convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII) {
408 assert((!Sext || !
TII->getSubtarget().zeroesHigh16BitsOfDest(
410 "Cannot use sign-extension with instruction that zeroes high bits");
411 switch (
MI.getOpcode()) {
412 case AMDGPU::V_CVT_F32_FP8_sdwa:
413 case AMDGPU::V_CVT_F32_BF8_sdwa:
414 case AMDGPU::V_CVT_PK_F32_FP8_sdwa:
415 case AMDGPU::V_CVT_PK_F32_BF8_sdwa:
418 case AMDGPU::V_CNDMASK_B32_sdwa:
437 bool IsPreserveSrc =
false;
438 MachineOperand *Src =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
439 MachineOperand *SrcSel =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0_sel);
440 MachineOperand *SrcMods =
441 TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers);
442 assert(Src && (Src->isReg() || Src->isImm()));
443 if (!
isSameReg(*Src, *getReplacedOperand())) {
445 Src =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
446 SrcSel =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_sel);
447 SrcMods =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers);
450 !
isSameReg(*Src, *getReplacedOperand())) {
457 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
459 TII->getNamedOperand(
MI, AMDGPU::OpName::dst_unused);
462 DstUnused->getImm() == AMDGPU::SDWA::DstUnused::UNUSED_PRESERVE) {
468 TII->getNamedImmOperand(
MI, AMDGPU::OpName::dst_sel));
469 if (DstSel == AMDGPU::SDWA::SdwaSel::WORD_1 &&
470 getSrcSel() == AMDGPU::SDWA::SdwaSel::WORD_0) {
471 IsPreserveSrc =
true;
472 auto DstIdx = AMDGPU::getNamedOperandIdx(
MI.getOpcode(),
473 AMDGPU::OpName::vdst);
474 auto TiedIdx =
MI.findTiedOperandIdx(DstIdx);
475 Src = &
MI.getOperand(TiedIdx);
484 assert(Src && Src->isReg());
486 if ((
MI.getOpcode() == AMDGPU::V_FMAC_F16_sdwa ||
487 MI.getOpcode() == AMDGPU::V_FMAC_F32_sdwa ||
488 MI.getOpcode() == AMDGPU::V_MAC_F16_sdwa ||
489 MI.getOpcode() == AMDGPU::V_MAC_F32_sdwa) &&
490 !
isSameReg(*Src, *getReplacedOperand())) {
497 (IsPreserveSrc || (SrcSel && SrcMods)));
500 if (!IsPreserveSrc) {
503 SrcMods->
setImm(getSrcMods(SrcMods->
getImm(), ExistingSel));
505 getTargetOperand()->setIsKill(
false);
513 AMDGPU::OpName SrcOpName,
522 auto SrcSel =
static_cast<SdwaSel>(
TII->getNamedImmOperand(
MI, SrcSelOpName));
526bool SDWASrcOperand::canCombineSelections(
const MachineInstr &
MI,
527 const SIInstrInfo *
TII) {
528 if (!
TII->isSDWA(
MI.getOpcode()))
531 using namespace AMDGPU;
534 getReplacedOperand(), getSrcSel()) &&
536 getReplacedOperand(), getSrcSel());
539MachineInstr *SDWADstOperand::potentialToConvert(
const SIInstrInfo *
TII,
540 const GCNSubtarget &ST,
541 SDWAOperandsMap *PotentialMatches) {
544 MachineRegisterInfo *
MRI = getMRI();
545 MachineInstr *ParentMI = getParentInst();
553 if (&UseInst != ParentMI)
557 MachineInstr *Parent = PotentialMO->
getParent();
558 return canCombineSelections(*Parent,
TII) ? Parent :
nullptr;
561bool SDWADstOperand::convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII) {
564 if ((
MI.getOpcode() == AMDGPU::V_FMAC_F16_sdwa ||
565 MI.getOpcode() == AMDGPU::V_FMAC_F32_sdwa ||
566 MI.getOpcode() == AMDGPU::V_MAC_F16_sdwa ||
567 MI.getOpcode() == AMDGPU::V_MAC_F32_sdwa) &&
573 MachineOperand *Operand =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
576 isSameReg(*Operand, *getReplacedOperand()));
578 MachineOperand *DstSel=
TII->getNamedOperand(
MI, AMDGPU::OpName::dst_sel);
581 DstSel->
setImm(getDstSel());
583 MachineOperand *
DstUnused=
TII->getNamedOperand(
MI, AMDGPU::OpName::dst_unused);
589 getParentInst()->eraseFromParent();
593bool SDWADstOperand::canCombineSelections(
const MachineInstr &
MI,
594 const SIInstrInfo *
TII) {
595 if (!
TII->isSDWA(
MI.getOpcode()))
600 return TII->getNamedImmOperand(
MI, AMDGPU::OpName::dst_sel) == SdwaSel::DWORD;
603bool SDWADstPreserveOperand::convertToSDWA(MachineInstr &
MI,
604 const SIInstrInfo *
TII) {
606 MI.getParent()->remove(&
MI);
607 getParentInst()->getParent()->insert(getParentInst(), &
MI);
610 MachineInstrBuilder MIB(*
MI.getMF(),
MI);
611 MIB.addReg(getPreservedOperand()->
getReg(), RegState::Implicit,
612 getPreservedOperand()->getSubReg());
615 MI.tieOperands(AMDGPU::getNamedOperandIdx(
MI.getOpcode(), AMDGPU::OpName::vdst),
616 MI.getNumOperands() - 1);
619 return SDWADstOperand::convertToSDWA(
MI,
TII);
622bool SDWADstPreserveOperand::canCombineSelections(
const MachineInstr &
MI,
623 const SIInstrInfo *
TII) {
625 assert(
TII->getNamedImmOperand(
MI, AMDGPU::OpName::dst_sel) == getDstSel());
629std::optional<int64_t>
630SIPeepholeSDWA::foldToImm(
const MachineOperand &
Op)
const {
642 const MachineInstr *DefInst =
Def.getParent();
643 if (!
TII->isFoldableCopy(*DefInst))
646 const MachineOperand &Copied = DefInst->
getOperand(1);
657std::optional<std::pair<MachineOperand *, SdwaSel>>
658SIPeepholeSDWA::matchAndMask(MachineInstr &
MI)
const {
659 if (
MI.getOpcode() != AMDGPU::V_AND_B32_e32 &&
660 MI.getOpcode() != AMDGPU::V_AND_B32_e64)
663 MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
664 MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
665 MachineOperand *ValSrc =
Src1;
666 std::optional<int64_t>
Imm = foldToImm(*Src0);
668 Imm = foldToImm(*Src1);
671 if (!
Imm || (*
Imm != 0x0000ffff && *
Imm != 0x000000ff))
677bool SIPeepholeSDWA::isSDWAWithDstSel(
const MachineInstr &Inst)
const {
678 return TII->isSDWA(Inst) &&
682std::unique_ptr<SDWAOperand>
683SIPeepholeSDWA::matchSDWAOperand(MachineInstr &
MI) {
684 unsigned Opcode =
MI.getOpcode();
686 case AMDGPU::V_LSHRREV_B32_e32:
687 case AMDGPU::V_ASHRREV_I32_e32:
688 case AMDGPU::V_LSHLREV_B32_e32:
689 case AMDGPU::V_LSHRREV_B32_e64:
690 case AMDGPU::V_ASHRREV_I32_e64:
691 case AMDGPU::V_LSHLREV_B32_e64: {
700 MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
701 auto Imm = foldToImm(*Src0);
705 if (*
Imm != 16 && *
Imm != 24)
708 MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
709 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
710 if (!
Src1->isReg() ||
Src1->getReg().isPhysical() ||
711 Dst->getReg().isPhysical())
714 if (Opcode == AMDGPU::V_LSHLREV_B32_e32 ||
715 Opcode == AMDGPU::V_LSHLREV_B32_e64) {
716 return std::make_unique<SDWADstOperand>(
719 return std::make_unique<SDWASrcOperand>(
721 Opcode != AMDGPU::V_LSHRREV_B32_e32 &&
722 Opcode != AMDGPU::V_LSHRREV_B32_e64);
726 case AMDGPU::V_LSHRREV_B16_e32:
727 case AMDGPU::V_LSHLREV_B16_e32:
728 case AMDGPU::V_LSHRREV_B16_e64:
729 case AMDGPU::V_LSHRREV_B16_opsel_e64:
730 case AMDGPU::V_LSHLREV_B16_opsel_e64:
731 case AMDGPU::V_LSHLREV_B16_e64: {
740 MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
741 auto Imm = foldToImm(*Src0);
745 MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
746 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
748 if (!
Src1->isReg() ||
Src1->getReg().isPhysical() ||
749 Dst->getReg().isPhysical())
752 if (Opcode == AMDGPU::V_LSHLREV_B16_e32 ||
753 Opcode == AMDGPU::V_LSHLREV_B16_opsel_e64 ||
754 Opcode == AMDGPU::V_LSHLREV_B16_e64)
756 return std::make_unique<SDWASrcOperand>(Src1, Dst,
BYTE_1,
false,
false,
761 case AMDGPU::V_BFE_I32_e64:
762 case AMDGPU::V_BFE_U32_e64: {
777 MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
778 auto Offset = foldToImm(*Src1);
782 MachineOperand *
Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
783 auto Width = foldToImm(*Src2);
789 if (*
Offset == 0 && *Width == 8)
791 else if (*
Offset == 0 && *Width == 16)
793 else if (*
Offset == 0 && *Width == 32)
795 else if (*
Offset == 8 && *Width == 8)
797 else if (*
Offset == 16 && *Width == 8)
799 else if (*
Offset == 16 && *Width == 16)
801 else if (*
Offset == 24 && *Width == 8)
806 MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
807 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
809 if (!
Src0->isReg() ||
Src0->getReg().isPhysical() ||
810 Dst->getReg().isPhysical())
813 return std::make_unique<SDWASrcOperand>(
814 Src0, Dst, SrcSel,
false,
false, Opcode != AMDGPU::V_BFE_U32_e64);
817 case AMDGPU::V_AND_B32_e32:
818 case AMDGPU::V_AND_B32_e64: {
822 auto Mask = matchAndMask(
MI);
825 MachineOperand *ValSrc =
Mask->first;
827 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
830 Dst->getReg().isPhysical())
833 return std::make_unique<SDWASrcOperand>(ValSrc, Dst,
Mask->second);
836 case AMDGPU::V_OR_B32_e32:
837 case AMDGPU::V_OR_B32_e64: {
848 std::optional<std::pair<MachineOperand *, MachineOperand *>>;
849 auto CheckOROperandsForSDWA =
850 [&](
const MachineOperand *Op1,
const MachineOperand *Op2) -> CheckRetType {
851 if (!Op1 || !Op1->
isReg() || !Op2 || !Op2->isReg())
852 return CheckRetType(std::nullopt);
856 return CheckRetType(std::nullopt);
858 MachineInstr *Op1Inst = Op1Def->
getParent();
859 if (!isSDWAWithDstSel(*Op1Inst))
860 return CheckRetType(std::nullopt);
864 return CheckRetType(std::nullopt);
866 return CheckRetType(std::pair(Op1Def, Op2Def));
869 MachineOperand *OrSDWA =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
870 MachineOperand *OrOther =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
871 assert(OrSDWA && OrOther);
872 auto Res = CheckOROperandsForSDWA(OrSDWA, OrOther);
874 OrSDWA =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
875 OrOther =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
876 assert(OrSDWA && OrOther);
877 Res = CheckOROperandsForSDWA(OrSDWA, OrOther);
882 MachineOperand *OrSDWADef = Res->first;
883 MachineOperand *OrOtherDef = Res->second;
884 assert(OrSDWADef && OrOtherDef);
886 MachineInstr *SDWAInst = OrSDWADef->
getParent();
887 MachineInstr *OtherInst = OrOtherDef->
getParent();
909 if (!isSDWAWithDstSel(*OtherInst))
913 TII->getNamedImmOperand(*SDWAInst, AMDGPU::OpName::dst_sel));
915 TII->getNamedImmOperand(*OtherInst, AMDGPU::OpName::dst_sel));
917 bool DstSelAgree =
false;
920 (OtherDstSel ==
BYTE_3) ||
924 (OtherDstSel ==
BYTE_1) ||
928 (OtherDstSel ==
BYTE_2) ||
929 (OtherDstSel ==
BYTE_3) ||
933 (OtherDstSel ==
BYTE_2) ||
934 (OtherDstSel ==
BYTE_3) ||
938 (OtherDstSel ==
BYTE_1) ||
939 (OtherDstSel ==
BYTE_3) ||
943 (OtherDstSel ==
BYTE_1) ||
944 (OtherDstSel ==
BYTE_2) ||
947 default: DstSelAgree =
false;
955 TII->getNamedImmOperand(*OtherInst, AMDGPU::OpName::dst_unused));
956 if (OtherDstUnused != DstUnused::UNUSED_PAD)
960 MachineOperand *OrDst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
963 return std::make_unique<SDWADstPreserveOperand>(
964 OrDst, OrSDWADef, OrOtherDef, DstSel);
969 return std::unique_ptr<SDWAOperand>(
nullptr);
979void SIPeepholeSDWA::matchSDWAOperands(MachineBasicBlock &
MBB) {
980 for (MachineInstr &
MI :
MBB) {
981 if (
auto Operand = matchSDWAOperand(
MI)) {
983 SDWAOperands[&
MI] = std::move(Operand);
984 ++NumSDWAPatternsFound;
1007void SIPeepholeSDWA::pseudoOpConvertToVOP2(MachineInstr &
MI,
1008 const GCNSubtarget &ST)
const {
1009 int Opc =
MI.getOpcode();
1010 assert((
Opc == AMDGPU::V_ADD_CO_U32_e64 ||
Opc == AMDGPU::V_SUB_CO_U32_e64) &&
1011 "Currently only handles V_ADD_CO_U32_e64 or V_SUB_CO_U32_e64");
1018 const MachineOperand *Sdst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst);
1024 MachineInstr &MISucc = *NextOp->
getParent();
1027 MachineOperand *CarryIn =
TII->getNamedOperand(MISucc, AMDGPU::OpName::src2);
1030 MachineOperand *CarryOut =
TII->getNamedOperand(MISucc, AMDGPU::OpName::sdst);
1047 if (
I->modifiesRegister(AMDGPU::VCC,
TRI))
1053 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst))
1054 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src0))
1055 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src1))
1058 MI.eraseFromParent();
1070void SIPeepholeSDWA::convertVcndmaskToVOP2(MachineInstr &
MI,
1071 const GCNSubtarget &ST)
const {
1072 assert(
MI.getOpcode() == AMDGPU::V_CNDMASK_B32_e64);
1080 const MachineOperand &CarryIn =
1081 *
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
1090 MCRegister
Vcc =
TRI->getVCC();
1095 LLVM_DEBUG(
dbgs() <<
"VCC not known to be dead before instruction\n");
1103 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst))
1104 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src0))
1105 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src1))
1107 TII->fixImplicitOperands(*Converted);
1110 MI.eraseFromParent();
1114bool isConvertibleToSDWA(MachineInstr &
MI,
1115 const GCNSubtarget &ST,
1116 const SIInstrInfo*
TII) {
1118 unsigned Opc =
MI.getOpcode();
1124 if (
Opc == AMDGPU::V_CNDMASK_B32_e64)
1134 if (!
ST.hasSDWAOmod() &&
TII->hasModifiersSet(
MI, AMDGPU::OpName::omod))
1138 if (!
ST.hasSDWASdst()) {
1139 const MachineOperand *SDst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst);
1140 if (SDst && (SDst->
getReg() != AMDGPU::VCC &&
1141 SDst->
getReg() != AMDGPU::VCC_LO))
1145 if (!
ST.hasSDWAOutModsVOPC() &&
1146 (
TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp) ||
1147 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod)))
1150 }
else if (
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst) ||
1151 !
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst)) {
1155 if (!
ST.hasSDWAMac() && (
Opc == AMDGPU::V_FMAC_F16_e32 ||
1156 Opc == AMDGPU::V_FMAC_F32_e32 ||
1157 Opc == AMDGPU::V_MAC_F16_e32 ||
1158 Opc == AMDGPU::V_MAC_F32_e32))
1162 if (
TII->pseudoToMCOpcode(
Opc) == -1 ||
1166 if (MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0)) {
1167 if (!
Src0->isReg() && !
Src0->isImm())
1171 if (MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1)) {
1172 if (!
Src1->isReg() && !
Src1->isImm())
1180MachineInstr *SIPeepholeSDWA::createSDWAVersion(MachineInstr &
MI) {
1181 unsigned Opcode =
MI.getOpcode();
1185 if (SDWAOpcode == -1)
1187 assert(SDWAOpcode != -1);
1189 const MCInstrDesc &SDWADesc =
TII->get(SDWAOpcode);
1192 MachineInstrBuilder SDWAInst =
1197 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1201 }
else if ((Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst))) {
1206 SDWAInst.
addReg(
TRI->getVCC(), RegState::Define);
1211 MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
1214 if (
auto *
Mod =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers))
1218 SDWAInst.
add(*Src0);
1221 MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
1225 if (
auto *
Mod =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers))
1229 SDWAInst.
add(*Src1);
1232 if (SDWAOpcode == AMDGPU::V_FMAC_F16_sdwa ||
1233 SDWAOpcode == AMDGPU::V_FMAC_F32_sdwa ||
1234 SDWAOpcode == AMDGPU::V_MAC_F16_sdwa ||
1235 SDWAOpcode == AMDGPU::V_MAC_F32_sdwa) {
1237 MachineOperand *
Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
1239 SDWAInst.
add(*Src2);
1244 MachineOperand *Clamp =
TII->getNamedOperand(
MI, AMDGPU::OpName::clamp);
1246 SDWAInst.
add(*Clamp);
1253 MachineOperand *OMod =
TII->getNamedOperand(
MI, AMDGPU::OpName::omod);
1255 SDWAInst.
add(*OMod);
1263 SDWAInst.
addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1266 SDWAInst.
addImm(AMDGPU::SDWA::DstUnused::UNUSED_PAD);
1269 SDWAInst.
addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1273 SDWAInst.
addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1277 MachineInstr *Ret = SDWAInst.
getInstr();
1278 TII->fixImplicitOperands(*Ret);
1282bool SIPeepholeSDWA::convertToSDWA(MachineInstr &
MI,
1283 const SDWAOperandsVector &SDWAOperands) {
1286 MachineInstr *SDWAInst;
1287 if (
TII->isSDWA(
MI.getOpcode())) {
1291 SDWAInst =
MI.
getMF()->CloneMachineInstr(&
MI);
1292 MI.getParent()->
insert(
MI.getIterator(), SDWAInst);
1294 SDWAInst = createSDWAVersion(
MI);
1298 bool Converted =
false;
1299 for (
auto &Operand : SDWAOperands) {
1311 if (PotentialMatches.count(Operand->getParentInst()) == 0)
1312 Converted |= Operand->convertToSDWA(*SDWAInst,
TII);
1320 ConvertedInstructions.
push_back(SDWAInst);
1322 ++NumSDWAInstructionsPeepholed;
1324 MI.eraseFromParent();
1330void SIPeepholeSDWA::legalizeScalarOperands(MachineInstr &
MI,
1331 const GCNSubtarget &ST)
const {
1332 const MCInstrDesc &
Desc =
TII->get(
MI.getOpcode());
1333 unsigned ConstantBusCount = 0;
1334 for (MachineOperand &
Op :
MI.explicit_uses()) {
1336 if (
TRI->isVGPR(*
MRI,
Op.getReg()))
1339 if (
ST.hasSDWAScalar() && ConstantBusCount == 0) {
1343 }
else if (!
Op.isImm())
1346 unsigned I =
Op.getOperandNo();
1348 if (!OpRC || !
TRI->isVSSuperClass(OpRC))
1353 TII->get(AMDGPU::V_MOV_B32_e32), VGPR);
1355 Copy.addImm(
Op.getImm());
1356 else if (
Op.isReg())
1358 Op.ChangeToRegister(VGPR,
false);
1364bool SIPeepholeSDWA::splitLshlOrForSDWA(MachineBasicBlock &
MBB) {
1366 MachineInstr *LshlOr;
1367 MachineInstr *AndMI;
1369 MachineOperand *ValSrc;
1373 for (MachineInstr &
MI :
MBB) {
1374 if (
MI.getOpcode() != AMDGPU::V_LSHL_OR_B32_e64)
1377 MachineOperand *Shift =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
1378 std::optional<int64_t> ShiftImm = foldToImm(*Shift);
1379 if (!ShiftImm || *ShiftImm != 16)
1382 MachineOperand *
Hi =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
1383 MachineOperand *
Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
1385 if (!
Hi->isReg() || !
Src2->isReg() || !
Src2->getReg().isVirtual())
1394 std::optional<std::pair<MachineOperand *, SdwaSel>>
Mask =
1395 matchAndMask(*AndMI);
1398 MachineOperand *ValSrc =
Mask->first;
1405 for (
const Candidate &
C : Candidates) {
1406 MachineOperand *Dst =
TII->getNamedOperand(*
C.LshlOr, AMDGPU::OpName::vdst);
1409 BuildMI(*
C.LshlOr->getParent(), *
C.LshlOr,
C.LshlOr->getDebugLoc(),
1410 TII->get(AMDGPU::V_LSHLREV_B32_e64), ShiftReg)
1416 BuildMI(*
C.LshlOr->getParent(), *
C.LshlOr,
C.LshlOr->getDebugLoc(),
1417 TII->get(AMDGPU::V_OR_B32_sdwa))
1430 C.AndMI->eraseFromParent();
1433 return !Candidates.empty();
1440 return SIPeepholeSDWA().run(MF);
1450 TRI =
ST.getRegisterInfo();
1451 TII =
ST.getInstrInfo();
1455 for (MachineBasicBlock &
MBB : MF) {
1458 Ret |= splitLshlOrForSDWA(
MBB);
1464 matchSDWAOperands(
MBB);
1465 for (
const auto &OperandPair : SDWAOperands) {
1466 const auto &Operand = OperandPair.second;
1467 MachineInstr *PotentialMI = Operand->potentialToConvert(
TII, ST);
1472 case AMDGPU::V_ADD_CO_U32_e64:
1473 case AMDGPU::V_SUB_CO_U32_e64:
1474 pseudoOpConvertToVOP2(*PotentialMI, ST);
1476 case AMDGPU::V_CNDMASK_B32_e64:
1477 convertVcndmaskToVOP2(*PotentialMI, ST);
1481 SDWAOperands.clear();
1484 matchSDWAOperands(
MBB);
1486 for (
const auto &OperandPair : SDWAOperands) {
1487 const auto &Operand = OperandPair.second;
1488 MachineInstr *PotentialMI =
1489 Operand->potentialToConvert(
TII, ST, &PotentialMatches);
1491 if (PotentialMI && isConvertibleToSDWA(*PotentialMI, ST,
TII))
1492 PotentialMatches[PotentialMI].push_back(Operand.get());
1495 for (
auto &PotentialPair : PotentialMatches) {
1496 MachineInstr &PotentialMI = *PotentialPair.first;
1497 convertToSDWA(PotentialMI, PotentialPair.second);
1500 PotentialMatches.clear();
1501 SDWAOperands.clear();
1507 while (!ConvertedInstructions.
empty())
1508 legalizeScalarOperands(*ConvertedInstructions.
pop_back_val(), ST);
MachineInstrBuilder & UseMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
AMD GCN specific subclass of TargetSubtarget.
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
MachineRegisterInfo & MRI
static MachineOperand * findSingleRegDef(const MachineOperand *Reg, const MachineRegisterInfo *MRI)
static void copyRegOperand(MachineOperand &To, const MachineOperand &From)
static MachineOperand * findSingleRegUse(const MachineOperand *Reg, const MachineRegisterInfo *MRI)
static bool isSameReg(const MachineOperand &LHS, const MachineOperand &RHS)
static bool canCombineOpSel(const MachineInstr &MI, const SIInstrInfo *TII, AMDGPU::OpName SrcOpName, AMDGPU::OpName SrcSelOpName, MachineOperand *Op, SdwaSel OpSel)
Verify that Op is the same register as the operand of the SDWA instruction MI named by SrcOpName and ...
static std::optional< SdwaSel > combineSdwaSrcSel(SdwaSel Sel, SdwaSel OperandSel)
Combine an SDWA source instruction's existing source selection Sel with the SDWA selection OperandSel...
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Represents analyses that only rely on functions' control flow.
bool hasOptNone() const
Do not optimize this function (-O0).
LLVM_ABI LivenessQueryResult computeRegisterLiveness(const TargetRegisterInfo *TRI, MCRegister Reg, const_iterator Before, unsigned Neighborhood=10) const
Return whether (physical) register Reg has been defined and not killed as of just before Before.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
LivenessQueryResult
Possible outcome of a register liveness query to computeRegisterLiveness()
@ LQR_Dead
Register is known to be fully dead.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
LLVM_ABI void substituteRegister(Register FromReg, Register ToReg, unsigned SubIdx, const TargetRegisterInfo &RegInfo)
Replace all occurrences of FromReg with ToReg:SubIdx, properly composing subreg indices where necessa...
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
MachineOperand class - Representation of each machine instruction operand.
void setSubReg(unsigned subReg)
unsigned getSubReg() const
void setImm(int64_t immVal)
bool isReg() const
isReg - Tests if this is a MO_Register operand.
void setIsDead(bool Val=true)
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
void setIsKill(bool Val=true)
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
void setIsUndef(bool Val=true)
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
iterator_range< def_iterator > def_operands(Register Reg) const
This class implements a map that also provides access to all stored values in a deterministic order.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
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()
This class implements an extremely fast bulk output stream that can only output to a stream.
@ VGPR
Address space for VGPRs.
LLVM_READONLY bool hasNamedOperand(uint32_t Opcode, OpName NamedIdx)
LLVM_READONLY int32_t getVOPe32(uint32_t Opcode)
LLVM_READONLY int32_t getSDWAOp(uint32_t Opcode)
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.
NodeAddr< DefNode * > Def
unsigned getOpcode(const VPValue *V)
Return the instruction opcode for the recipe defining V or 0 for unsupported recipes and VPValues not...
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
constexpr RegState getKillRegState(bool B)
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
DWARFExpression::Operation Op
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
char & SIPeepholeSDWALegacyID
MCRegisterClass TargetRegisterClass