34#define DEBUG_TYPE "si-peephole-sdwa"
36STATISTIC(NumSDWAPatternsFound,
"Number of SDWA patterns found.");
38 "Number of instruction converted to SDWA.");
57 SDWAOperandsMap PotentialMatches;
64 std::optional<std::pair<MachineOperand *, AMDGPU::SDWA::SdwaSel>>
76 bool convertToSDWA(
MachineInstr &
MI,
const SDWAOperandsVector &SDWAOperands);
88 SIPeepholeSDWALegacy() : MachineFunctionPass(ID) {}
90 StringRef getPassName()
const override {
return "SI Peephole SDWA"; }
94 void getAnalysisUsage(AnalysisUsage &AU)
const override {
104 MachineOperand *Target;
105 MachineOperand *Replaced;
109 virtual bool canCombineSelections(
const MachineInstr &
MI,
110 const SIInstrInfo *
TII) = 0;
113 SDWAOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp)
114 : Target(TargetOp), Replaced(ReplacedOp) {
116 assert(Replaced->isReg());
119 virtual ~SDWAOperand() =
default;
121 virtual MachineInstr *potentialToConvert(
const SIInstrInfo *
TII,
122 const GCNSubtarget &ST,
123 SDWAOperandsMap *PotentialMatches =
nullptr) = 0;
124 virtual bool convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII) = 0;
126 MachineOperand *getTargetOperand()
const {
return Target; }
127 MachineOperand *getReplacedOperand()
const {
return Replaced; }
128 MachineInstr *getParentInst()
const {
return Target->getParent(); }
130 MachineRegisterInfo *getMRI()
const {
131 return &getParentInst()->getMF()->getRegInfo();
134#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
135 virtual void print(raw_ostream& OS)
const = 0;
140class SDWASrcOperand :
public SDWAOperand {
148 SDWASrcOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp,
149 SdwaSel SrcSel_ =
DWORD,
bool Abs_ =
false,
bool Neg_ =
false,
151 : SDWAOperand(TargetOp, ReplacedOp), SrcSel(SrcSel_), Abs(Abs_),
152 Neg(Neg_), Sext(Sext_) {}
154 MachineInstr *potentialToConvert(
const SIInstrInfo *
TII,
155 const GCNSubtarget &ST,
156 SDWAOperandsMap *PotentialMatches =
nullptr)
override;
157 bool convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII)
override;
158 bool canCombineSelections(
const MachineInstr &
MI,
159 const SIInstrInfo *
TII)
override;
161 SdwaSel getSrcSel()
const {
return SrcSel; }
162 bool getAbs()
const {
return Abs; }
163 bool getNeg()
const {
return Neg; }
164 bool getSext()
const {
return Sext; }
167 const MachineOperand *SrcOp)
const;
169#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
170 void print(raw_ostream& OS)
const override;
174class SDWADstOperand :
public SDWAOperand {
180 SDWADstOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp,
182 : SDWAOperand(TargetOp, ReplacedOp), DstSel(DstSel_), DstUn(DstUn_) {}
184 MachineInstr *potentialToConvert(
const SIInstrInfo *
TII,
185 const GCNSubtarget &ST,
186 SDWAOperandsMap *PotentialMatches =
nullptr)
override;
187 bool convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII)
override;
188 bool canCombineSelections(
const MachineInstr &
MI,
189 const SIInstrInfo *
TII)
override;
191 SdwaSel getDstSel()
const {
return DstSel; }
192 DstUnused getDstUnused()
const {
return DstUn; }
194#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
195 void print(raw_ostream& OS)
const override;
199class SDWADstPreserveOperand :
public SDWADstOperand {
201 MachineOperand *Preserve;
204 SDWADstPreserveOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp,
207 Preserve(PreserveOp) {}
209 bool convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII)
override;
210 bool canCombineSelections(
const MachineInstr &
MI,
211 const SIInstrInfo *
TII)
override;
213 MachineOperand *getPreservedOperand()
const {
return Preserve; }
215#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
216 void print(raw_ostream& OS)
const override;
225char SIPeepholeSDWALegacy::ID = 0;
230 return new SIPeepholeSDWALegacy();
233#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
236 case BYTE_0: OS <<
"BYTE_0";
break;
237 case BYTE_1: OS <<
"BYTE_1";
break;
238 case BYTE_2: OS <<
"BYTE_2";
break;
239 case BYTE_3: OS <<
"BYTE_3";
break;
240 case WORD_0: OS <<
"WORD_0";
break;
241 case WORD_1: OS <<
"WORD_1";
break;
242 case DWORD: OS <<
"DWORD";
break;
258 OS <<
"SDWA src: " << *getTargetOperand()
259 <<
" src_sel:" << getSrcSel()
260 <<
" abs:" << getAbs() <<
" neg:" << getNeg()
261 <<
" sext:" << getSext() <<
'\n';
265void SDWADstOperand::print(raw_ostream& OS)
const {
266 OS <<
"SDWA dst: " << *getTargetOperand()
267 <<
" dst_sel:" << getDstSel()
268 <<
" dst_unused:" << getDstUnused() <<
'\n';
272void SDWADstPreserveOperand::print(raw_ostream& OS)
const {
273 OS <<
"SDWA preserve dst: " << *getTargetOperand()
274 <<
" dst_sel:" << getDstSel()
275 <<
" preserve:" << *getPreservedOperand() <<
'\n';
293 return LHS.isReg() &&
295 LHS.getReg() ==
RHS.getReg() &&
296 LHS.getSubReg() ==
RHS.getSubReg();
301 if (!
Reg->isReg() || !
Reg->isDef())
322 if (Sel == SdwaSel::DWORD)
325 if (Sel == OperandSel || OperandSel == SdwaSel::DWORD)
328 if (Sel == SdwaSel::WORD_1 || Sel == SdwaSel::BYTE_2 ||
329 Sel == SdwaSel::BYTE_3)
332 if (OperandSel == SdwaSel::WORD_0)
335 if (OperandSel == SdwaSel::WORD_1) {
336 if (Sel == SdwaSel::BYTE_0)
337 return SdwaSel::BYTE_2;
338 if (Sel == SdwaSel::BYTE_1)
339 return SdwaSel::BYTE_3;
340 if (Sel == SdwaSel::WORD_0)
341 return SdwaSel::WORD_1;
347uint64_t SDWASrcOperand::getSrcMods(
const SIInstrInfo *
TII,
348 const MachineOperand *SrcOp)
const {
351 if (
TII->getNamedOperand(*
MI, AMDGPU::OpName::src0) == SrcOp) {
352 if (
auto *
Mod =
TII->getNamedOperand(*
MI, AMDGPU::OpName::src0_modifiers)) {
353 Mods =
Mod->getImm();
355 }
else if (
TII->getNamedOperand(*
MI, AMDGPU::OpName::src1) == SrcOp) {
356 if (
auto *
Mod =
TII->getNamedOperand(*
MI, AMDGPU::OpName::src1_modifiers)) {
357 Mods =
Mod->getImm();
362 "Float and integer src modifiers can't be set simultaneously");
372MachineInstr *SDWASrcOperand::potentialToConvert(
const SIInstrInfo *
TII,
373 const GCNSubtarget &ST,
374 SDWAOperandsMap *PotentialMatches) {
375 if (PotentialMatches !=
nullptr) {
377 MachineOperand *
Reg = getReplacedOperand();
378 if (!
Reg->isReg() || !
Reg->isDef())
381 for (MachineInstr &
UseMI : getMRI()->use_nodbg_instructions(
Reg->getReg()))
383 if (!isConvertibleToSDWA(
UseMI, ST,
TII) ||
389 for (MachineOperand &UseMO : getMRI()->use_nodbg_operands(
Reg->getReg())) {
393 SDWAOperandsMap &potentialMatchesMap = *PotentialMatches;
394 MachineInstr *
UseMI = UseMO.getParent();
395 potentialMatchesMap[
UseMI].push_back(
this);
402 MachineOperand *PotentialMO =
findSingleRegUse(getReplacedOperand(), getMRI());
406 MachineInstr *Parent = PotentialMO->
getParent();
408 return canCombineSelections(*Parent,
TII) ? Parent :
nullptr;
411bool SDWASrcOperand::convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII) {
412 assert((!Sext || !
TII->getSubtarget().zeroesHigh16BitsOfDest(
414 "Cannot use sign-extension with instruction that zeroes high bits");
415 switch (
MI.getOpcode()) {
416 case AMDGPU::V_CVT_F32_FP8_sdwa:
417 case AMDGPU::V_CVT_F32_BF8_sdwa:
418 case AMDGPU::V_CVT_PK_F32_FP8_sdwa:
419 case AMDGPU::V_CVT_PK_F32_BF8_sdwa:
422 case AMDGPU::V_CNDMASK_B32_sdwa:
441 bool IsPreserveSrc =
false;
442 MachineOperand *Src =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
443 MachineOperand *SrcSel =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0_sel);
444 MachineOperand *SrcMods =
445 TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers);
446 assert(Src && (Src->isReg() || Src->isImm()));
447 if (!
isSameReg(*Src, *getReplacedOperand())) {
449 Src =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
450 SrcSel =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_sel);
451 SrcMods =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers);
454 !
isSameReg(*Src, *getReplacedOperand())) {
461 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
463 TII->getNamedOperand(
MI, AMDGPU::OpName::dst_unused);
466 DstUnused->getImm() == AMDGPU::SDWA::DstUnused::UNUSED_PRESERVE) {
472 TII->getNamedImmOperand(
MI, AMDGPU::OpName::dst_sel));
473 if (DstSel == AMDGPU::SDWA::SdwaSel::WORD_1 &&
474 getSrcSel() == AMDGPU::SDWA::SdwaSel::WORD_0) {
475 IsPreserveSrc =
true;
476 auto DstIdx = AMDGPU::getNamedOperandIdx(
MI.getOpcode(),
477 AMDGPU::OpName::vdst);
478 auto TiedIdx =
MI.findTiedOperandIdx(DstIdx);
479 Src = &
MI.getOperand(TiedIdx);
488 assert(Src && Src->isReg());
490 if ((
MI.getOpcode() == AMDGPU::V_FMAC_F16_sdwa ||
491 MI.getOpcode() == AMDGPU::V_FMAC_F32_sdwa ||
492 MI.getOpcode() == AMDGPU::V_MAC_F16_sdwa ||
493 MI.getOpcode() == AMDGPU::V_MAC_F32_sdwa) &&
494 !
isSameReg(*Src, *getReplacedOperand())) {
501 (IsPreserveSrc || (SrcSel && SrcMods)));
504 if (!IsPreserveSrc) {
509 getTargetOperand()->setIsKill(
false);
516 AMDGPU::OpName SrcSelOpName,
SdwaSel OpSel) {
529 AMDGPU::OpName SrcOpName,
541bool SDWASrcOperand::canCombineSelections(
const MachineInstr &
MI,
542 const SIInstrInfo *
TII) {
543 if (!
TII->isSDWA(
MI.getOpcode()))
546 using namespace AMDGPU;
549 getReplacedOperand(), getSrcSel()) &&
551 getReplacedOperand(), getSrcSel());
554MachineInstr *SDWADstOperand::potentialToConvert(
const SIInstrInfo *
TII,
555 const GCNSubtarget &ST,
556 SDWAOperandsMap *PotentialMatches) {
559 MachineRegisterInfo *MRI = getMRI();
560 MachineInstr *ParentMI = getParentInst();
568 if (&UseInst != ParentMI)
572 MachineInstr *Parent = PotentialMO->
getParent();
573 return canCombineSelections(*Parent,
TII) ? Parent :
nullptr;
576bool SDWADstOperand::convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII) {
579 if ((
MI.getOpcode() == AMDGPU::V_FMAC_F16_sdwa ||
580 MI.getOpcode() == AMDGPU::V_FMAC_F32_sdwa ||
581 MI.getOpcode() == AMDGPU::V_MAC_F16_sdwa ||
582 MI.getOpcode() == AMDGPU::V_MAC_F32_sdwa) &&
588 MachineOperand *Operand =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
591 isSameReg(*Operand, *getReplacedOperand()));
593 MachineOperand *DstSel=
TII->getNamedOperand(
MI, AMDGPU::OpName::dst_sel);
599 MachineOperand *
DstUnused=
TII->getNamedOperand(
MI, AMDGPU::OpName::dst_unused);
605 getParentInst()->eraseFromParent();
609bool SDWADstOperand::canCombineSelections(
const MachineInstr &
MI,
610 const SIInstrInfo *
TII) {
611 if (!
TII->isSDWA(
MI.getOpcode()))
617bool SDWADstPreserveOperand::convertToSDWA(MachineInstr &
MI,
618 const SIInstrInfo *
TII) {
622 for (MachineOperand &MO :
MI.uses()) {
625 getMRI()->clearKillFlags(MO.getReg());
629 MI.getParent()->remove(&
MI);
630 getParentInst()->getParent()->insert(getParentInst(), &
MI);
633 MachineInstrBuilder MIB(*
MI.getMF(),
MI);
634 MIB.addReg(getPreservedOperand()->
getReg(),
635 RegState::ImplicitKill,
636 getPreservedOperand()->getSubReg());
639 MI.tieOperands(AMDGPU::getNamedOperandIdx(
MI.getOpcode(), AMDGPU::OpName::vdst),
640 MI.getNumOperands() - 1);
643 return SDWADstOperand::convertToSDWA(
MI,
TII);
646bool SDWADstPreserveOperand::canCombineSelections(
const MachineInstr &
MI,
647 const SIInstrInfo *
TII) {
648 return SDWADstOperand::canCombineSelections(
MI,
TII);
651std::optional<int64_t>
652SIPeepholeSDWA::foldToImm(
const MachineOperand &
Op)
const {
660 for (
const MachineOperand &Def : MRI->
def_operands(
Op.getReg())) {
664 const MachineInstr *DefInst =
Def.getParent();
665 if (!
TII->isFoldableCopy(*DefInst))
668 const MachineOperand &Copied = DefInst->
getOperand(1);
679std::optional<std::pair<MachineOperand *, SdwaSel>>
680SIPeepholeSDWA::matchAndMask(MachineInstr &
MI)
const {
681 if (
MI.getOpcode() != AMDGPU::V_AND_B32_e32 &&
682 MI.getOpcode() != AMDGPU::V_AND_B32_e64)
685 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
686 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
687 MachineOperand *ValSrc = Src1;
688 std::optional<int64_t>
Imm = foldToImm(*Src0);
690 Imm = foldToImm(*Src1);
693 if (!
Imm || (*
Imm != 0x0000ffff && *
Imm != 0x000000ff))
699bool SIPeepholeSDWA::isSDWAWithDstSel(
const MachineInstr &Inst)
const {
700 return TII->isSDWA(Inst) &&
704std::unique_ptr<SDWAOperand>
705SIPeepholeSDWA::matchSDWAOperand(MachineInstr &
MI) {
706 unsigned Opcode =
MI.getOpcode();
708 case AMDGPU::V_LSHRREV_B32_e32:
709 case AMDGPU::V_ASHRREV_I32_e32:
710 case AMDGPU::V_LSHLREV_B32_e32:
711 case AMDGPU::V_LSHRREV_B32_e64:
712 case AMDGPU::V_ASHRREV_I32_e64:
713 case AMDGPU::V_LSHLREV_B32_e64: {
722 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
723 auto Imm = foldToImm(*Src0);
727 if (*
Imm != 16 && *
Imm != 24)
730 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
731 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
733 Dst->getReg().isPhysical())
736 if (Opcode == AMDGPU::V_LSHLREV_B32_e32 ||
737 Opcode == AMDGPU::V_LSHLREV_B32_e64) {
738 return std::make_unique<SDWADstOperand>(
741 return std::make_unique<SDWASrcOperand>(
743 Opcode != AMDGPU::V_LSHRREV_B32_e32 &&
744 Opcode != AMDGPU::V_LSHRREV_B32_e64);
748 case AMDGPU::V_LSHRREV_B16_e32:
749 case AMDGPU::V_LSHLREV_B16_e32:
750 case AMDGPU::V_LSHRREV_B16_e64:
751 case AMDGPU::V_LSHRREV_B16_opsel_e64:
752 case AMDGPU::V_LSHLREV_B16_opsel_e64:
753 case AMDGPU::V_LSHLREV_B16_e64: {
762 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
763 auto Imm = foldToImm(*Src0);
767 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
768 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
771 Dst->getReg().isPhysical())
774 if (Opcode == AMDGPU::V_LSHLREV_B16_e32 ||
775 Opcode == AMDGPU::V_LSHLREV_B16_opsel_e64 ||
776 Opcode == AMDGPU::V_LSHLREV_B16_e64)
778 return std::make_unique<SDWASrcOperand>(Src1, Dst,
BYTE_1,
false,
false,
783 case AMDGPU::V_BFE_I32_e64:
784 case AMDGPU::V_BFE_U32_e64: {
799 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
800 auto Offset = foldToImm(*Src1);
804 MachineOperand *Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
805 auto Width = foldToImm(*Src2);
811 if (*
Offset == 0 && *Width == 8)
813 else if (*
Offset == 0 && *Width == 16)
815 else if (*
Offset == 0 && *Width == 32)
817 else if (*
Offset == 8 && *Width == 8)
819 else if (*
Offset == 16 && *Width == 8)
821 else if (*
Offset == 16 && *Width == 16)
823 else if (*
Offset == 24 && *Width == 8)
828 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
829 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
832 Dst->getReg().isPhysical())
835 return std::make_unique<SDWASrcOperand>(
836 Src0, Dst, SrcSel,
false,
false, Opcode != AMDGPU::V_BFE_U32_e64);
839 case AMDGPU::V_AND_B32_e32:
840 case AMDGPU::V_AND_B32_e64: {
844 auto Mask = matchAndMask(
MI);
847 MachineOperand *ValSrc =
Mask->first;
849 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
852 Dst->getReg().isPhysical())
855 return std::make_unique<SDWASrcOperand>(ValSrc, Dst,
Mask->second);
858 case AMDGPU::V_OR_B32_e32:
859 case AMDGPU::V_OR_B32_e64: {
870 std::optional<std::pair<MachineOperand *, MachineOperand *>>;
871 auto CheckOROperandsForSDWA =
872 [&](
const MachineOperand *Op1,
const MachineOperand *Op2) -> CheckRetType {
873 if (!Op1 || !Op1->
isReg() || !Op2 || !Op2->isReg())
874 return CheckRetType(std::nullopt);
878 return CheckRetType(std::nullopt);
880 MachineInstr *Op1Inst = Op1Def->
getParent();
881 if (!isSDWAWithDstSel(*Op1Inst))
882 return CheckRetType(std::nullopt);
886 return CheckRetType(std::nullopt);
888 return CheckRetType(std::pair(Op1Def, Op2Def));
891 MachineOperand *OrSDWA =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
892 MachineOperand *OrOther =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
893 assert(OrSDWA && OrOther);
894 auto Res = CheckOROperandsForSDWA(OrSDWA, OrOther);
896 OrSDWA =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
897 OrOther =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
898 assert(OrSDWA && OrOther);
899 Res = CheckOROperandsForSDWA(OrSDWA, OrOther);
904 MachineOperand *OrSDWADef = Res->first;
905 MachineOperand *OrOtherDef = Res->second;
906 assert(OrSDWADef && OrOtherDef);
908 MachineInstr *SDWAInst = OrSDWADef->
getParent();
909 MachineInstr *OtherInst = OrOtherDef->
getParent();
931 if (!isSDWAWithDstSel(*OtherInst))
935 TII->getNamedImmOperand(*SDWAInst, AMDGPU::OpName::dst_sel));
937 TII->getNamedImmOperand(*OtherInst, AMDGPU::OpName::dst_sel));
939 bool DstSelAgree =
false;
942 (OtherDstSel ==
BYTE_3) ||
946 (OtherDstSel ==
BYTE_1) ||
950 (OtherDstSel ==
BYTE_2) ||
951 (OtherDstSel ==
BYTE_3) ||
955 (OtherDstSel ==
BYTE_2) ||
956 (OtherDstSel ==
BYTE_3) ||
960 (OtherDstSel ==
BYTE_1) ||
961 (OtherDstSel ==
BYTE_3) ||
965 (OtherDstSel ==
BYTE_1) ||
966 (OtherDstSel ==
BYTE_2) ||
969 default: DstSelAgree =
false;
977 TII->getNamedImmOperand(*OtherInst, AMDGPU::OpName::dst_unused));
978 if (OtherDstUnused != DstUnused::UNUSED_PAD)
982 MachineOperand *OrDst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
985 return std::make_unique<SDWADstPreserveOperand>(
986 OrDst, OrSDWADef, OrOtherDef, DstSel);
991 return std::unique_ptr<SDWAOperand>(
nullptr);
1001void SIPeepholeSDWA::matchSDWAOperands(MachineBasicBlock &
MBB) {
1002 for (MachineInstr &
MI :
MBB) {
1003 if (
auto Operand = matchSDWAOperand(
MI)) {
1005 SDWAOperands[&
MI] = std::move(Operand);
1006 ++NumSDWAPatternsFound;
1029void SIPeepholeSDWA::pseudoOpConvertToVOP2(MachineInstr &
MI,
1030 const GCNSubtarget &ST)
const {
1031 int Opc =
MI.getOpcode();
1032 assert((
Opc == AMDGPU::V_ADD_CO_U32_e64 ||
Opc == AMDGPU::V_SUB_CO_U32_e64) &&
1033 "Currently only handles V_ADD_CO_U32_e64 or V_SUB_CO_U32_e64");
1036 if (!
TII->canShrink(
MI, *MRI))
1040 const MachineOperand *Sdst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst);
1046 MachineInstr &MISucc = *NextOp->
getParent();
1049 MachineOperand *CarryIn =
TII->getNamedOperand(MISucc, AMDGPU::OpName::src2);
1052 MachineOperand *CarryOut =
TII->getNamedOperand(MISucc, AMDGPU::OpName::sdst);
1067 if (
I->modifiesRegister(AMDGPU::VCC,
TRI))
1073 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst))
1074 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src0))
1075 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src1))
1078 MI.eraseFromParent();
1090void SIPeepholeSDWA::convertVcndmaskToVOP2(MachineInstr &
MI,
1091 const GCNSubtarget &ST)
const {
1092 assert(
MI.getOpcode() == AMDGPU::V_CNDMASK_B32_e64);
1095 if (!
TII->canShrink(
MI, *MRI)) {
1100 const MachineOperand &CarryIn =
1101 *
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
1103 MachineInstr *CarryDef = MRI->
getVRegDef(CarryReg);
1110 MCRegister
Vcc =
TRI->getVCC();
1115 LLVM_DEBUG(
dbgs() <<
"VCC not known to be dead before instruction\n");
1123 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst))
1124 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src0))
1125 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src1))
1127 TII->fixImplicitOperands(*Converted);
1130 MI.eraseFromParent();
1134bool isConvertibleToSDWA(MachineInstr &
MI,
1135 const GCNSubtarget &ST,
1136 const SIInstrInfo*
TII) {
1138 unsigned Opc =
MI.getOpcode();
1144 if (
Opc == AMDGPU::V_CNDMASK_B32_e64)
1154 if (!
ST.hasSDWAOmod() &&
TII->hasModifiersSet(
MI, AMDGPU::OpName::omod))
1158 if (!
ST.hasSDWASdst()) {
1159 const MachineOperand *SDst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst);
1160 if (SDst && (SDst->
getReg() != AMDGPU::VCC &&
1161 SDst->
getReg() != AMDGPU::VCC_LO))
1165 if (!
ST.hasSDWAOutModsVOPC() &&
1166 (
TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp) ||
1167 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod)))
1170 }
else if (
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst) ||
1171 !
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst)) {
1175 if (!
ST.hasSDWAMac() && (
Opc == AMDGPU::V_FMAC_F16_e32 ||
1176 Opc == AMDGPU::V_FMAC_F32_e32 ||
1177 Opc == AMDGPU::V_MAC_F16_e32 ||
1178 Opc == AMDGPU::V_MAC_F32_e32))
1182 if (
TII->pseudoToMCOpcode(
Opc) == -1)
1185 if (MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0)) {
1190 if (MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1)) {
1199MachineInstr *SIPeepholeSDWA::createSDWAVersion(MachineInstr &
MI) {
1200 unsigned Opcode =
MI.getOpcode();
1204 if (SDWAOpcode == -1)
1206 assert(SDWAOpcode != -1);
1208 const MCInstrDesc &SDWADesc =
TII->get(SDWAOpcode);
1211 MachineInstrBuilder SDWAInst =
1216 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1220 }
else if ((Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst))) {
1225 SDWAInst.
addReg(
TRI->getVCC(), RegState::Define);
1230 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
1233 if (
auto *
Mod =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers))
1237 SDWAInst.
add(*Src0);
1240 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
1244 if (
auto *
Mod =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers))
1248 SDWAInst.
add(*Src1);
1251 if (SDWAOpcode == AMDGPU::V_FMAC_F16_sdwa ||
1252 SDWAOpcode == AMDGPU::V_FMAC_F32_sdwa ||
1253 SDWAOpcode == AMDGPU::V_MAC_F16_sdwa ||
1254 SDWAOpcode == AMDGPU::V_MAC_F32_sdwa) {
1256 MachineOperand *Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
1258 SDWAInst.
add(*Src2);
1263 MachineOperand *Clamp =
TII->getNamedOperand(
MI, AMDGPU::OpName::clamp);
1265 SDWAInst.
add(*Clamp);
1272 MachineOperand *OMod =
TII->getNamedOperand(
MI, AMDGPU::OpName::omod);
1274 SDWAInst.
add(*OMod);
1282 SDWAInst.
addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1285 SDWAInst.
addImm(AMDGPU::SDWA::DstUnused::UNUSED_PAD);
1288 SDWAInst.
addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1292 SDWAInst.
addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1296 MachineInstr *Ret = SDWAInst.
getInstr();
1297 TII->fixImplicitOperands(*Ret);
1301bool SIPeepholeSDWA::convertToSDWA(MachineInstr &
MI,
1302 const SDWAOperandsVector &SDWAOperands) {
1305 MachineInstr *SDWAInst;
1306 if (
TII->isSDWA(
MI.getOpcode())) {
1310 SDWAInst =
MI.
getMF()->CloneMachineInstr(&
MI);
1311 MI.getParent()->
insert(
MI.getIterator(), SDWAInst);
1313 SDWAInst = createSDWAVersion(
MI);
1317 bool Converted =
false;
1318 for (
auto &Operand : SDWAOperands) {
1330 if (PotentialMatches.count(Operand->getParentInst()) == 0)
1331 Converted |= Operand->convertToSDWA(*SDWAInst,
TII);
1339 ConvertedInstructions.
push_back(SDWAInst);
1340 for (MachineOperand &MO : SDWAInst->
uses()) {
1347 ++NumSDWAInstructionsPeepholed;
1349 MI.eraseFromParent();
1355void SIPeepholeSDWA::legalizeScalarOperands(MachineInstr &
MI,
1356 const GCNSubtarget &ST)
const {
1357 const MCInstrDesc &
Desc =
TII->get(
MI.getOpcode());
1358 unsigned ConstantBusCount = 0;
1359 for (MachineOperand &
Op :
MI.explicit_uses()) {
1361 if (
TRI->isVGPR(*MRI,
Op.getReg()))
1364 if (
ST.hasSDWAScalar() && ConstantBusCount == 0) {
1368 }
else if (!
Op.isImm())
1371 unsigned I =
Op.getOperandNo();
1373 if (!OpRC || !
TRI->isVSSuperClass(OpRC))
1378 TII->get(AMDGPU::V_MOV_B32_e32), VGPR);
1380 Copy.addImm(
Op.getImm());
1381 else if (
Op.isReg())
1383 Op.ChangeToRegister(VGPR,
false);
1389bool SIPeepholeSDWA::splitLshlOrForSDWA(MachineBasicBlock &
MBB) {
1391 MachineInstr *LshlOr;
1392 MachineInstr *AndMI;
1394 MachineOperand *ValSrc;
1398 for (MachineInstr &
MI :
MBB) {
1399 if (
MI.getOpcode() != AMDGPU::V_LSHL_OR_B32_e64)
1402 MachineOperand *Shift =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
1403 std::optional<int64_t> ShiftImm = foldToImm(*Shift);
1404 if (!ShiftImm || *ShiftImm != 16)
1407 MachineOperand *
Hi =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
1408 MachineOperand *Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
1419 std::optional<std::pair<MachineOperand *, SdwaSel>>
Mask =
1420 matchAndMask(*AndMI);
1423 MachineOperand *ValSrc =
Mask->first;
1430 for (
const Candidate &
C : Candidates) {
1431 MachineOperand *Dst =
TII->getNamedOperand(*
C.LshlOr, AMDGPU::OpName::vdst);
1434 BuildMI(*
C.LshlOr->getParent(), *
C.LshlOr,
C.LshlOr->getDebugLoc(),
1435 TII->get(AMDGPU::V_LSHLREV_B32_e64), ShiftReg)
1441 BuildMI(*
C.LshlOr->getParent(), *
C.LshlOr,
C.LshlOr->getDebugLoc(),
1442 TII->get(AMDGPU::V_OR_B32_sdwa))
1455 C.LshlOr->eraseFromParent();
1456 C.AndMI->eraseFromParent();
1459 return !Candidates.empty();
1466 return SIPeepholeSDWA().run(MF);
1476 TRI =
ST.getRegisterInfo();
1477 TII =
ST.getInstrInfo();
1481 for (MachineBasicBlock &
MBB : MF) {
1484 Ret |= splitLshlOrForSDWA(
MBB);
1490 matchSDWAOperands(
MBB);
1491 for (
const auto &OperandPair : SDWAOperands) {
1492 const auto &Operand = OperandPair.second;
1493 MachineInstr *PotentialMI = Operand->potentialToConvert(
TII, ST);
1498 case AMDGPU::V_ADD_CO_U32_e64:
1499 case AMDGPU::V_SUB_CO_U32_e64:
1500 pseudoOpConvertToVOP2(*PotentialMI, ST);
1502 case AMDGPU::V_CNDMASK_B32_e64:
1503 convertVcndmaskToVOP2(*PotentialMI, ST);
1507 SDWAOperands.clear();
1510 matchSDWAOperands(
MBB);
1512 for (
const auto &OperandPair : SDWAOperands) {
1513 const auto &Operand = OperandPair.second;
1514 MachineInstr *PotentialMI =
1515 Operand->potentialToConvert(
TII, ST, &PotentialMatches);
1517 if (PotentialMI && isConvertibleToSDWA(*PotentialMI, ST,
TII))
1518 PotentialMatches[PotentialMI].push_back(Operand.get());
1521 for (
auto &PotentialPair : PotentialMatches) {
1522 MachineInstr &PotentialMI = *PotentialPair.first;
1523 convertToSDWA(PotentialMI, PotentialPair.second);
1526 PotentialMatches.clear();
1527 SDWAOperands.clear();
1533 while (!ConvertedInstructions.
empty())
1534 legalizeScalarOperands(*ConvertedInstructions.
pop_back_val(), ST);
MachineInstrBuilder & UseMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Provides AMDGPU specific target descriptions.
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
This file implements a map that provides insertion order iteration.
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 std::optional< SdwaSel > combineSdwaSel(SdwaSel Sel, SdwaSel OperandSel)
Combine an SDWA instruction's existing SDWA selection Sel with the SDWA selection OperandSel of its o...
static bool isSameReg(const MachineOperand &LHS, const MachineOperand &RHS)
static bool canCombineOpSel(const MachineInstr &MI, const SIInstrInfo *TII, AMDGPU::OpName SrcSelOpName, SdwaSel OpSel)
Verify that the SDWA selection operand SrcSelOpName of the SDWA instruction MI can be combined with t...
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.
FunctionPass class - This class is used to implement most global optimizations.
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.
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 isVirtual() const
Return true if the specified register number is in the virtual register namespace.
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.
LLVM_READONLY bool hasNamedOperand(uint64_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
FunctionPass * createSIPeepholeSDWALegacyPass()
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