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())
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) {
608 for (MachineOperand &MO :
MI.uses()) {
611 getMRI()->clearKillFlags(MO.getReg());
615 MI.getParent()->remove(&
MI);
616 getParentInst()->getParent()->insert(getParentInst(), &
MI);
619 MachineInstrBuilder MIB(*
MI.getMF(),
MI);
620 MIB.addReg(getPreservedOperand()->
getReg(),
621 RegState::ImplicitKill,
622 getPreservedOperand()->getSubReg());
625 MI.tieOperands(AMDGPU::getNamedOperandIdx(
MI.getOpcode(), AMDGPU::OpName::vdst),
626 MI.getNumOperands() - 1);
629 return SDWADstOperand::convertToSDWA(
MI,
TII);
632bool SDWADstPreserveOperand::canCombineSelections(
const MachineInstr &
MI,
633 const SIInstrInfo *
TII) {
635 assert(
TII->getNamedImmOperand(
MI, AMDGPU::OpName::dst_sel) == getDstSel());
639std::optional<int64_t>
640SIPeepholeSDWA::foldToImm(
const MachineOperand &
Op)
const {
648 for (
const MachineOperand &Def : MRI->
def_operands(
Op.getReg())) {
652 const MachineInstr *DefInst =
Def.getParent();
653 if (!
TII->isFoldableCopy(*DefInst))
656 const MachineOperand &Copied = DefInst->
getOperand(1);
667std::optional<std::pair<MachineOperand *, SdwaSel>>
668SIPeepholeSDWA::matchAndMask(MachineInstr &
MI)
const {
669 if (
MI.getOpcode() != AMDGPU::V_AND_B32_e32 &&
670 MI.getOpcode() != AMDGPU::V_AND_B32_e64)
673 MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
674 MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
675 MachineOperand *ValSrc =
Src1;
676 std::optional<int64_t>
Imm = foldToImm(*Src0);
678 Imm = foldToImm(*Src1);
681 if (!
Imm || (*
Imm != 0x0000ffff && *
Imm != 0x000000ff))
687bool SIPeepholeSDWA::isSDWAWithDstSel(
const MachineInstr &Inst)
const {
688 return TII->isSDWA(Inst) &&
692std::unique_ptr<SDWAOperand>
693SIPeepholeSDWA::matchSDWAOperand(MachineInstr &
MI) {
694 unsigned Opcode =
MI.getOpcode();
696 case AMDGPU::V_LSHRREV_B32_e32:
697 case AMDGPU::V_ASHRREV_I32_e32:
698 case AMDGPU::V_LSHLREV_B32_e32:
699 case AMDGPU::V_LSHRREV_B32_e64:
700 case AMDGPU::V_ASHRREV_I32_e64:
701 case AMDGPU::V_LSHLREV_B32_e64: {
710 MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
711 auto Imm = foldToImm(*Src0);
715 if (*
Imm != 16 && *
Imm != 24)
718 MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
719 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
720 if (!
Src1->isReg() ||
Src1->getReg().isPhysical() ||
721 Dst->getReg().isPhysical())
724 if (Opcode == AMDGPU::V_LSHLREV_B32_e32 ||
725 Opcode == AMDGPU::V_LSHLREV_B32_e64) {
726 return std::make_unique<SDWADstOperand>(
729 return std::make_unique<SDWASrcOperand>(
731 Opcode != AMDGPU::V_LSHRREV_B32_e32 &&
732 Opcode != AMDGPU::V_LSHRREV_B32_e64);
736 case AMDGPU::V_LSHRREV_B16_e32:
737 case AMDGPU::V_LSHLREV_B16_e32:
738 case AMDGPU::V_LSHRREV_B16_e64:
739 case AMDGPU::V_LSHRREV_B16_opsel_e64:
740 case AMDGPU::V_LSHLREV_B16_opsel_e64:
741 case AMDGPU::V_LSHLREV_B16_e64: {
750 MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
751 auto Imm = foldToImm(*Src0);
755 MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
756 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
758 if (!
Src1->isReg() ||
Src1->getReg().isPhysical() ||
759 Dst->getReg().isPhysical())
762 if (Opcode == AMDGPU::V_LSHLREV_B16_e32 ||
763 Opcode == AMDGPU::V_LSHLREV_B16_opsel_e64 ||
764 Opcode == AMDGPU::V_LSHLREV_B16_e64)
766 return std::make_unique<SDWASrcOperand>(Src1, Dst,
BYTE_1,
false,
false,
771 case AMDGPU::V_BFE_I32_e64:
772 case AMDGPU::V_BFE_U32_e64: {
787 MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
788 auto Offset = foldToImm(*Src1);
792 MachineOperand *
Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
793 auto Width = foldToImm(*Src2);
799 if (*
Offset == 0 && *Width == 8)
801 else if (*
Offset == 0 && *Width == 16)
803 else if (*
Offset == 0 && *Width == 32)
805 else if (*
Offset == 8 && *Width == 8)
807 else if (*
Offset == 16 && *Width == 8)
809 else if (*
Offset == 16 && *Width == 16)
811 else if (*
Offset == 24 && *Width == 8)
816 MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
817 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
819 if (!
Src0->isReg() ||
Src0->getReg().isPhysical() ||
820 Dst->getReg().isPhysical())
823 return std::make_unique<SDWASrcOperand>(
824 Src0, Dst, SrcSel,
false,
false, Opcode != AMDGPU::V_BFE_U32_e64);
827 case AMDGPU::V_AND_B32_e32:
828 case AMDGPU::V_AND_B32_e64: {
832 auto Mask = matchAndMask(
MI);
835 MachineOperand *ValSrc =
Mask->first;
837 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
840 Dst->getReg().isPhysical())
843 return std::make_unique<SDWASrcOperand>(ValSrc, Dst,
Mask->second);
846 case AMDGPU::V_OR_B32_e32:
847 case AMDGPU::V_OR_B32_e64: {
858 std::optional<std::pair<MachineOperand *, MachineOperand *>>;
859 auto CheckOROperandsForSDWA =
860 [&](
const MachineOperand *Op1,
const MachineOperand *Op2) -> CheckRetType {
861 if (!Op1 || !Op1->
isReg() || !Op2 || !Op2->isReg())
862 return CheckRetType(std::nullopt);
866 return CheckRetType(std::nullopt);
868 MachineInstr *Op1Inst = Op1Def->
getParent();
869 if (!isSDWAWithDstSel(*Op1Inst))
870 return CheckRetType(std::nullopt);
874 return CheckRetType(std::nullopt);
876 return CheckRetType(std::pair(Op1Def, Op2Def));
879 MachineOperand *OrSDWA =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
880 MachineOperand *OrOther =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
881 assert(OrSDWA && OrOther);
882 auto Res = CheckOROperandsForSDWA(OrSDWA, OrOther);
884 OrSDWA =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
885 OrOther =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
886 assert(OrSDWA && OrOther);
887 Res = CheckOROperandsForSDWA(OrSDWA, OrOther);
892 MachineOperand *OrSDWADef = Res->first;
893 MachineOperand *OrOtherDef = Res->second;
894 assert(OrSDWADef && OrOtherDef);
896 MachineInstr *SDWAInst = OrSDWADef->
getParent();
897 MachineInstr *OtherInst = OrOtherDef->
getParent();
919 if (!isSDWAWithDstSel(*OtherInst))
923 TII->getNamedImmOperand(*SDWAInst, AMDGPU::OpName::dst_sel));
925 TII->getNamedImmOperand(*OtherInst, AMDGPU::OpName::dst_sel));
927 bool DstSelAgree =
false;
930 (OtherDstSel ==
BYTE_3) ||
934 (OtherDstSel ==
BYTE_1) ||
938 (OtherDstSel ==
BYTE_2) ||
939 (OtherDstSel ==
BYTE_3) ||
943 (OtherDstSel ==
BYTE_2) ||
944 (OtherDstSel ==
BYTE_3) ||
948 (OtherDstSel ==
BYTE_1) ||
949 (OtherDstSel ==
BYTE_3) ||
953 (OtherDstSel ==
BYTE_1) ||
954 (OtherDstSel ==
BYTE_2) ||
957 default: DstSelAgree =
false;
965 TII->getNamedImmOperand(*OtherInst, AMDGPU::OpName::dst_unused));
966 if (OtherDstUnused != DstUnused::UNUSED_PAD)
970 MachineOperand *OrDst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
973 return std::make_unique<SDWADstPreserveOperand>(
974 OrDst, OrSDWADef, OrOtherDef, DstSel);
979 return std::unique_ptr<SDWAOperand>(
nullptr);
989void SIPeepholeSDWA::matchSDWAOperands(MachineBasicBlock &
MBB) {
990 for (MachineInstr &
MI :
MBB) {
991 if (
auto Operand = matchSDWAOperand(
MI)) {
993 SDWAOperands[&
MI] = std::move(Operand);
994 ++NumSDWAPatternsFound;
1017void SIPeepholeSDWA::pseudoOpConvertToVOP2(MachineInstr &
MI,
1018 const GCNSubtarget &ST)
const {
1019 int Opc =
MI.getOpcode();
1020 assert((
Opc == AMDGPU::V_ADD_CO_U32_e64 ||
Opc == AMDGPU::V_SUB_CO_U32_e64) &&
1021 "Currently only handles V_ADD_CO_U32_e64 or V_SUB_CO_U32_e64");
1024 if (!
TII->canShrink(
MI, *MRI))
1028 const MachineOperand *Sdst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst);
1034 MachineInstr &MISucc = *NextOp->
getParent();
1037 MachineOperand *CarryIn =
TII->getNamedOperand(MISucc, AMDGPU::OpName::src2);
1040 MachineOperand *CarryOut =
TII->getNamedOperand(MISucc, AMDGPU::OpName::sdst);
1057 if (
I->modifiesRegister(AMDGPU::VCC,
TRI))
1063 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst))
1064 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src0))
1065 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src1))
1068 MI.eraseFromParent();
1080void SIPeepholeSDWA::convertVcndmaskToVOP2(MachineInstr &
MI,
1081 const GCNSubtarget &ST)
const {
1082 assert(
MI.getOpcode() == AMDGPU::V_CNDMASK_B32_e64);
1085 if (!
TII->canShrink(
MI, *MRI)) {
1090 const MachineOperand &CarryIn =
1091 *
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
1093 MachineInstr *CarryDef = MRI->
getVRegDef(CarryReg);
1100 MCRegister
Vcc =
TRI->getVCC();
1105 LLVM_DEBUG(
dbgs() <<
"VCC not known to be dead before instruction\n");
1113 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst))
1114 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src0))
1115 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src1))
1117 TII->fixImplicitOperands(*Converted);
1120 MI.eraseFromParent();
1124bool isConvertibleToSDWA(MachineInstr &
MI,
1125 const GCNSubtarget &ST,
1126 const SIInstrInfo*
TII) {
1128 unsigned Opc =
MI.getOpcode();
1134 if (
Opc == AMDGPU::V_CNDMASK_B32_e64)
1144 if (!
ST.hasSDWAOmod() &&
TII->hasModifiersSet(
MI, AMDGPU::OpName::omod))
1148 if (!
ST.hasSDWASdst()) {
1149 const MachineOperand *SDst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst);
1150 if (SDst && (SDst->
getReg() != AMDGPU::VCC &&
1151 SDst->
getReg() != AMDGPU::VCC_LO))
1155 if (!
ST.hasSDWAOutModsVOPC() &&
1156 (
TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp) ||
1157 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod)))
1160 }
else if (
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst) ||
1161 !
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst)) {
1165 if (!
ST.hasSDWAMac() && (
Opc == AMDGPU::V_FMAC_F16_e32 ||
1166 Opc == AMDGPU::V_FMAC_F32_e32 ||
1167 Opc == AMDGPU::V_MAC_F16_e32 ||
1168 Opc == AMDGPU::V_MAC_F32_e32))
1172 if (
TII->pseudoToMCOpcode(
Opc) == -1 ||
1176 if (MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0)) {
1177 if (!
Src0->isReg() && !
Src0->isImm())
1181 if (MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1)) {
1182 if (!
Src1->isReg() && !
Src1->isImm())
1190MachineInstr *SIPeepholeSDWA::createSDWAVersion(MachineInstr &
MI) {
1191 unsigned Opcode =
MI.getOpcode();
1195 if (SDWAOpcode == -1)
1197 assert(SDWAOpcode != -1);
1199 const MCInstrDesc &SDWADesc =
TII->get(SDWAOpcode);
1202 MachineInstrBuilder SDWAInst =
1207 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1211 }
else if ((Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst))) {
1216 SDWAInst.
addReg(
TRI->getVCC(), RegState::Define);
1221 MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
1224 if (
auto *
Mod =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers))
1228 SDWAInst.
add(*Src0);
1231 MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
1235 if (
auto *
Mod =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers))
1239 SDWAInst.
add(*Src1);
1242 if (SDWAOpcode == AMDGPU::V_FMAC_F16_sdwa ||
1243 SDWAOpcode == AMDGPU::V_FMAC_F32_sdwa ||
1244 SDWAOpcode == AMDGPU::V_MAC_F16_sdwa ||
1245 SDWAOpcode == AMDGPU::V_MAC_F32_sdwa) {
1247 MachineOperand *
Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
1249 SDWAInst.
add(*Src2);
1254 MachineOperand *Clamp =
TII->getNamedOperand(
MI, AMDGPU::OpName::clamp);
1256 SDWAInst.
add(*Clamp);
1263 MachineOperand *OMod =
TII->getNamedOperand(
MI, AMDGPU::OpName::omod);
1265 SDWAInst.
add(*OMod);
1273 SDWAInst.
addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1276 SDWAInst.
addImm(AMDGPU::SDWA::DstUnused::UNUSED_PAD);
1279 SDWAInst.
addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1283 SDWAInst.
addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1287 MachineInstr *Ret = SDWAInst.
getInstr();
1288 TII->fixImplicitOperands(*Ret);
1292bool SIPeepholeSDWA::convertToSDWA(MachineInstr &
MI,
1293 const SDWAOperandsVector &SDWAOperands) {
1296 MachineInstr *SDWAInst;
1297 if (
TII->isSDWA(
MI.getOpcode())) {
1301 SDWAInst =
MI.
getMF()->CloneMachineInstr(&
MI);
1302 MI.getParent()->
insert(
MI.getIterator(), SDWAInst);
1304 SDWAInst = createSDWAVersion(
MI);
1308 bool Converted =
false;
1309 for (
auto &Operand : SDWAOperands) {
1321 if (PotentialMatches.count(Operand->getParentInst()) == 0)
1322 Converted |= Operand->convertToSDWA(*SDWAInst,
TII);
1330 ConvertedInstructions.
push_back(SDWAInst);
1331 for (MachineOperand &MO : SDWAInst->
uses()) {
1338 ++NumSDWAInstructionsPeepholed;
1340 MI.eraseFromParent();
1346void SIPeepholeSDWA::legalizeScalarOperands(MachineInstr &
MI,
1347 const GCNSubtarget &ST)
const {
1348 const MCInstrDesc &
Desc =
TII->get(
MI.getOpcode());
1349 unsigned ConstantBusCount = 0;
1350 for (MachineOperand &
Op :
MI.explicit_uses()) {
1352 if (
TRI->isVGPR(*MRI,
Op.getReg()))
1355 if (
ST.hasSDWAScalar() && ConstantBusCount == 0) {
1359 }
else if (!
Op.isImm())
1362 unsigned I =
Op.getOperandNo();
1364 if (!OpRC || !
TRI->isVSSuperClass(OpRC))
1369 TII->get(AMDGPU::V_MOV_B32_e32), VGPR);
1371 Copy.addImm(
Op.getImm());
1372 else if (
Op.isReg())
1374 Op.ChangeToRegister(VGPR,
false);
1380bool SIPeepholeSDWA::splitLshlOrForSDWA(MachineBasicBlock &
MBB) {
1382 MachineInstr *LshlOr;
1383 MachineInstr *AndMI;
1385 MachineOperand *ValSrc;
1389 for (MachineInstr &
MI :
MBB) {
1390 if (
MI.getOpcode() != AMDGPU::V_LSHL_OR_B32_e64)
1393 MachineOperand *Shift =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
1394 std::optional<int64_t> ShiftImm = foldToImm(*Shift);
1395 if (!ShiftImm || *ShiftImm != 16)
1398 MachineOperand *
Hi =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
1399 MachineOperand *
Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
1401 if (!
Hi->isReg() || !
Src2->isReg() || !
Src2->getReg().isVirtual())
1410 std::optional<std::pair<MachineOperand *, SdwaSel>>
Mask =
1411 matchAndMask(*AndMI);
1414 MachineOperand *ValSrc =
Mask->first;
1421 for (
const Candidate &
C : Candidates) {
1422 MachineOperand *Dst =
TII->getNamedOperand(*
C.LshlOr, AMDGPU::OpName::vdst);
1425 BuildMI(*
C.LshlOr->getParent(), *
C.LshlOr,
C.LshlOr->getDebugLoc(),
1426 TII->get(AMDGPU::V_LSHLREV_B32_e64), ShiftReg)
1432 BuildMI(*
C.LshlOr->getParent(), *
C.LshlOr,
C.LshlOr->getDebugLoc(),
1433 TII->get(AMDGPU::V_OR_B32_sdwa))
1446 C.LshlOr->eraseFromParent();
1447 C.AndMI->eraseFromParent();
1450 return !Candidates.empty();
1457 return SIPeepholeSDWA().run(MF);
1467 TRI =
ST.getRegisterInfo();
1468 TII =
ST.getInstrInfo();
1472 for (MachineBasicBlock &
MBB : MF) {
1475 Ret |= splitLshlOrForSDWA(
MBB);
1481 matchSDWAOperands(
MBB);
1482 for (
const auto &OperandPair : SDWAOperands) {
1483 const auto &Operand = OperandPair.second;
1484 MachineInstr *PotentialMI = Operand->potentialToConvert(
TII, ST);
1489 case AMDGPU::V_ADD_CO_U32_e64:
1490 case AMDGPU::V_SUB_CO_U32_e64:
1491 pseudoOpConvertToVOP2(*PotentialMI, ST);
1493 case AMDGPU::V_CNDMASK_B32_e64:
1494 convertVcndmaskToVOP2(*PotentialMI, ST);
1498 SDWAOperands.clear();
1501 matchSDWAOperands(
MBB);
1503 for (
const auto &OperandPair : SDWAOperands) {
1504 const auto &Operand = OperandPair.second;
1505 MachineInstr *PotentialMI =
1506 Operand->potentialToConvert(
TII, ST, &PotentialMatches);
1508 if (PotentialMI && isConvertibleToSDWA(*PotentialMI, ST,
TII))
1509 PotentialMatches[PotentialMI].push_back(Operand.get());
1512 for (
auto &PotentialPair : PotentialMatches) {
1513 MachineInstr &PotentialMI = *PotentialPair.first;
1514 convertToSDWA(PotentialMI, PotentialPair.second);
1517 PotentialMatches.clear();
1518 SDWAOperands.clear();
1524 while (!ConvertedInstructions.
empty())
1525 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)
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...
mop_range uses()
Returns all operands which may be register uses.
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 void clearKillFlags(Register Reg) const
clearKillFlags - Iterate over all the uses of the given register and clear the kill flag from the Mac...
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 MachineOperand * getOneNonDBGUse(Register RegNo) const
If the register has a single non-Debug use, returns it; otherwise returns nullptr.
MachineOperand * getOneDef(Register Reg) const
Returns the defining operand if there is exactly one operand defining 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