34#define DEBUG_TYPE "si-peephole-sdwa"
36STATISTIC(NumSDWAPatternsFound,
"Number of SDWA patterns found.");
38 "Number of instruction converted to SDWA.");
57 SDWAOperandsMap PotentialMatches;
68 bool convertToSDWA(
MachineInstr &
MI,
const SDWAOperandsVector &SDWAOperands);
79 SIPeepholeSDWALegacy() : MachineFunctionPass(ID) {}
81 StringRef getPassName()
const override {
return "SI Peephole SDWA"; }
83 bool runOnMachineFunction(MachineFunction &MF)
override;
85 void getAnalysisUsage(AnalysisUsage &AU)
const override {
96 MachineOperand *Target;
97 MachineOperand *Replaced;
101 virtual bool canCombineSelections(
const MachineInstr &
MI,
102 const SIInstrInfo *
TII) = 0;
105 SDWAOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp)
106 : Target(TargetOp), Replaced(ReplacedOp) {
108 assert(Replaced->isReg());
111 virtual ~SDWAOperand() =
default;
113 virtual MachineInstr *potentialToConvert(
const SIInstrInfo *
TII,
114 const GCNSubtarget &ST,
115 SDWAOperandsMap *PotentialMatches =
nullptr) = 0;
116 virtual bool convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII) = 0;
118 MachineOperand *getTargetOperand()
const {
return Target; }
119 MachineOperand *getReplacedOperand()
const {
return Replaced; }
120 MachineInstr *getParentInst()
const {
return Target->getParent(); }
122 MachineRegisterInfo *getMRI()
const {
123 return &getParentInst()->getMF()->getRegInfo();
126#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
127 virtual void print(raw_ostream& OS)
const = 0;
132class SDWASrcOperand :
public SDWAOperand {
140 SDWASrcOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp,
141 SdwaSel SrcSel_ =
DWORD,
bool Abs_ =
false,
bool Neg_ =
false,
143 : SDWAOperand(TargetOp, ReplacedOp), SrcSel(SrcSel_), Abs(Abs_),
144 Neg(Neg_), Sext(Sext_) {}
146 MachineInstr *potentialToConvert(
const SIInstrInfo *
TII,
147 const GCNSubtarget &ST,
148 SDWAOperandsMap *PotentialMatches =
nullptr)
override;
149 bool convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII)
override;
150 bool canCombineSelections(
const MachineInstr &
MI,
151 const SIInstrInfo *
TII)
override;
153 SdwaSel getSrcSel()
const {
return SrcSel; }
154 bool getAbs()
const {
return Abs; }
155 bool getNeg()
const {
return Neg; }
156 bool getSext()
const {
return Sext; }
158 uint64_t getSrcMods(
const SIInstrInfo *
TII,
159 const MachineOperand *SrcOp)
const;
161#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
162 void print(raw_ostream& OS)
const override;
166class SDWADstOperand :
public SDWAOperand {
172 SDWADstOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp,
174 : SDWAOperand(TargetOp, ReplacedOp), DstSel(DstSel_), DstUn(DstUn_) {}
176 MachineInstr *potentialToConvert(
const SIInstrInfo *
TII,
177 const GCNSubtarget &ST,
178 SDWAOperandsMap *PotentialMatches =
nullptr)
override;
179 bool convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII)
override;
180 bool canCombineSelections(
const MachineInstr &
MI,
181 const SIInstrInfo *
TII)
override;
183 SdwaSel getDstSel()
const {
return DstSel; }
184 DstUnused getDstUnused()
const {
return DstUn; }
186#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
187 void print(raw_ostream& OS)
const override;
191class SDWADstPreserveOperand :
public SDWADstOperand {
193 MachineOperand *Preserve;
196 SDWADstPreserveOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp,
199 Preserve(PreserveOp) {}
201 bool convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII)
override;
202 bool canCombineSelections(
const MachineInstr &
MI,
203 const SIInstrInfo *
TII)
override;
205 MachineOperand *getPreservedOperand()
const {
return Preserve; }
207#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
208 void print(raw_ostream& OS)
const override;
217char SIPeepholeSDWALegacy::
ID = 0;
222 return new SIPeepholeSDWALegacy();
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())
314 if (Sel == SdwaSel::DWORD)
317 if (Sel == OperandSel || OperandSel == SdwaSel::DWORD)
320 if (Sel == SdwaSel::WORD_1 || Sel == SdwaSel::BYTE_2 ||
321 Sel == SdwaSel::BYTE_3)
324 if (OperandSel == SdwaSel::WORD_0)
327 if (OperandSel == SdwaSel::WORD_1) {
328 if (Sel == SdwaSel::BYTE_0)
329 return SdwaSel::BYTE_2;
330 if (Sel == SdwaSel::BYTE_1)
331 return SdwaSel::BYTE_3;
332 if (Sel == SdwaSel::WORD_0)
333 return SdwaSel::WORD_1;
339uint64_t SDWASrcOperand::getSrcMods(
const SIInstrInfo *
TII,
340 const MachineOperand *SrcOp)
const {
343 if (
TII->getNamedOperand(*
MI, AMDGPU::OpName::src0) == SrcOp) {
344 if (
auto *
Mod =
TII->getNamedOperand(*
MI, AMDGPU::OpName::src0_modifiers)) {
345 Mods =
Mod->getImm();
347 }
else if (
TII->getNamedOperand(*
MI, AMDGPU::OpName::src1) == SrcOp) {
348 if (
auto *
Mod =
TII->getNamedOperand(*
MI, AMDGPU::OpName::src1_modifiers)) {
349 Mods =
Mod->getImm();
354 "Float and integer src modifiers can't be set simultaneously");
364MachineInstr *SDWASrcOperand::potentialToConvert(
const SIInstrInfo *
TII,
365 const GCNSubtarget &ST,
366 SDWAOperandsMap *PotentialMatches) {
367 if (PotentialMatches !=
nullptr) {
369 MachineOperand *
Reg = getReplacedOperand();
370 if (!
Reg->isReg() || !
Reg->isDef())
373 for (MachineInstr &
UseMI : getMRI()->use_nodbg_instructions(
Reg->getReg()))
375 if (!isConvertibleToSDWA(
UseMI, ST,
TII) ||
381 for (MachineOperand &UseMO : getMRI()->use_nodbg_operands(
Reg->getReg())) {
385 SDWAOperandsMap &potentialMatchesMap = *PotentialMatches;
386 MachineInstr *
UseMI = UseMO.getParent();
387 potentialMatchesMap[
UseMI].push_back(
this);
394 MachineOperand *PotentialMO =
findSingleRegUse(getReplacedOperand(), getMRI());
398 MachineInstr *Parent = PotentialMO->
getParent();
400 return canCombineSelections(*Parent,
TII) ? Parent :
nullptr;
403bool SDWASrcOperand::convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII) {
404 assert((!Sext || !
TII->getSubtarget().zeroesHigh16BitsOfDest(
406 "Cannot use sign-extension with instruction that zeroes high bits");
407 switch (
MI.getOpcode()) {
408 case AMDGPU::V_CVT_F32_FP8_sdwa:
409 case AMDGPU::V_CVT_F32_BF8_sdwa:
410 case AMDGPU::V_CVT_PK_F32_FP8_sdwa:
411 case AMDGPU::V_CVT_PK_F32_BF8_sdwa:
414 case AMDGPU::V_CNDMASK_B32_sdwa:
433 bool IsPreserveSrc =
false;
434 MachineOperand *Src =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
435 MachineOperand *SrcSel =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0_sel);
436 MachineOperand *SrcMods =
437 TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers);
438 assert(Src && (Src->isReg() || Src->isImm()));
439 if (!
isSameReg(*Src, *getReplacedOperand())) {
441 Src =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
442 SrcSel =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_sel);
443 SrcMods =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers);
446 !
isSameReg(*Src, *getReplacedOperand())) {
453 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
455 TII->getNamedOperand(
MI, AMDGPU::OpName::dst_unused);
458 DstUnused->getImm() == AMDGPU::SDWA::DstUnused::UNUSED_PRESERVE) {
464 TII->getNamedImmOperand(
MI, AMDGPU::OpName::dst_sel));
465 if (DstSel == AMDGPU::SDWA::SdwaSel::WORD_1 &&
466 getSrcSel() == AMDGPU::SDWA::SdwaSel::WORD_0) {
467 IsPreserveSrc =
true;
468 auto DstIdx = AMDGPU::getNamedOperandIdx(
MI.getOpcode(),
469 AMDGPU::OpName::vdst);
470 auto TiedIdx =
MI.findTiedOperandIdx(DstIdx);
471 Src = &
MI.getOperand(TiedIdx);
480 assert(Src && Src->isReg());
482 if ((
MI.getOpcode() == AMDGPU::V_FMAC_F16_sdwa ||
483 MI.getOpcode() == AMDGPU::V_FMAC_F32_sdwa ||
484 MI.getOpcode() == AMDGPU::V_MAC_F16_sdwa ||
485 MI.getOpcode() == AMDGPU::V_MAC_F32_sdwa) &&
486 !
isSameReg(*Src, *getReplacedOperand())) {
493 (IsPreserveSrc || (SrcSel && SrcMods)));
496 if (!IsPreserveSrc) {
501 getTargetOperand()->setIsKill(
false);
508 AMDGPU::OpName SrcSelOpName,
SdwaSel OpSel) {
521 AMDGPU::OpName SrcOpName,
533bool SDWASrcOperand::canCombineSelections(
const MachineInstr &
MI,
534 const SIInstrInfo *
TII) {
535 if (!
TII->isSDWA(
MI.getOpcode()))
538 using namespace AMDGPU;
541 getReplacedOperand(), getSrcSel()) &&
543 getReplacedOperand(), getSrcSel());
546MachineInstr *SDWADstOperand::potentialToConvert(
const SIInstrInfo *
TII,
547 const GCNSubtarget &ST,
548 SDWAOperandsMap *PotentialMatches) {
551 MachineRegisterInfo *MRI = getMRI();
552 MachineInstr *ParentMI = getParentInst();
560 if (&UseInst != ParentMI)
564 MachineInstr *Parent = PotentialMO->
getParent();
565 return canCombineSelections(*Parent,
TII) ? Parent :
nullptr;
568bool SDWADstOperand::convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII) {
571 if ((
MI.getOpcode() == AMDGPU::V_FMAC_F16_sdwa ||
572 MI.getOpcode() == AMDGPU::V_FMAC_F32_sdwa ||
573 MI.getOpcode() == AMDGPU::V_MAC_F16_sdwa ||
574 MI.getOpcode() == AMDGPU::V_MAC_F32_sdwa) &&
580 MachineOperand *Operand =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
583 isSameReg(*Operand, *getReplacedOperand()));
585 MachineOperand *DstSel=
TII->getNamedOperand(
MI, AMDGPU::OpName::dst_sel);
591 MachineOperand *
DstUnused=
TII->getNamedOperand(
MI, AMDGPU::OpName::dst_unused);
597 getParentInst()->eraseFromParent();
601bool SDWADstOperand::canCombineSelections(
const MachineInstr &
MI,
602 const SIInstrInfo *
TII) {
603 if (!
TII->isSDWA(
MI.getOpcode()))
609bool SDWADstPreserveOperand::convertToSDWA(MachineInstr &
MI,
610 const SIInstrInfo *
TII) {
614 for (MachineOperand &MO :
MI.uses()) {
617 getMRI()->clearKillFlags(MO.getReg());
621 MI.getParent()->remove(&
MI);
622 getParentInst()->getParent()->insert(getParentInst(), &
MI);
625 MachineInstrBuilder MIB(*
MI.getMF(),
MI);
626 MIB.addReg(getPreservedOperand()->
getReg(),
627 RegState::ImplicitKill,
628 getPreservedOperand()->getSubReg());
631 MI.tieOperands(AMDGPU::getNamedOperandIdx(
MI.getOpcode(), AMDGPU::OpName::vdst),
632 MI.getNumOperands() - 1);
635 return SDWADstOperand::convertToSDWA(
MI,
TII);
638bool SDWADstPreserveOperand::canCombineSelections(
const MachineInstr &
MI,
639 const SIInstrInfo *
TII) {
640 return SDWADstOperand::canCombineSelections(
MI,
TII);
643std::optional<int64_t>
644SIPeepholeSDWA::foldToImm(
const MachineOperand &
Op)
const {
652 for (
const MachineOperand &Def : MRI->
def_operands(
Op.getReg())) {
656 const MachineInstr *DefInst =
Def.getParent();
657 if (!
TII->isFoldableCopy(*DefInst))
660 const MachineOperand &Copied = DefInst->
getOperand(1);
671std::unique_ptr<SDWAOperand>
672SIPeepholeSDWA::matchSDWAOperand(MachineInstr &
MI) {
673 unsigned Opcode =
MI.getOpcode();
675 case AMDGPU::V_LSHRREV_B32_e32:
676 case AMDGPU::V_ASHRREV_I32_e32:
677 case AMDGPU::V_LSHLREV_B32_e32:
678 case AMDGPU::V_LSHRREV_B32_e64:
679 case AMDGPU::V_ASHRREV_I32_e64:
680 case AMDGPU::V_LSHLREV_B32_e64: {
689 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
690 auto Imm = foldToImm(*Src0);
694 if (*Imm != 16 && *Imm != 24)
697 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
698 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
700 Dst->getReg().isPhysical())
703 if (Opcode == AMDGPU::V_LSHLREV_B32_e32 ||
704 Opcode == AMDGPU::V_LSHLREV_B32_e64) {
705 return std::make_unique<SDWADstOperand>(
708 return std::make_unique<SDWASrcOperand>(
710 Opcode != AMDGPU::V_LSHRREV_B32_e32 &&
711 Opcode != AMDGPU::V_LSHRREV_B32_e64);
715 case AMDGPU::V_LSHRREV_B16_e32:
716 case AMDGPU::V_LSHLREV_B16_e32:
717 case AMDGPU::V_LSHRREV_B16_e64:
718 case AMDGPU::V_LSHRREV_B16_opsel_e64:
719 case AMDGPU::V_LSHLREV_B16_opsel_e64:
720 case AMDGPU::V_LSHLREV_B16_e64: {
729 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
730 auto Imm = foldToImm(*Src0);
731 if (!Imm || *Imm != 8)
734 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
735 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
738 Dst->getReg().isPhysical())
741 if (Opcode == AMDGPU::V_LSHLREV_B16_e32 ||
742 Opcode == AMDGPU::V_LSHLREV_B16_opsel_e64 ||
743 Opcode == AMDGPU::V_LSHLREV_B16_e64)
745 return std::make_unique<SDWASrcOperand>(Src1, Dst,
BYTE_1,
false,
false,
750 case AMDGPU::V_BFE_I32_e64:
751 case AMDGPU::V_BFE_U32_e64: {
766 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
767 auto Offset = foldToImm(*Src1);
771 MachineOperand *Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
772 auto Width = foldToImm(*Src2);
778 if (*
Offset == 0 && *Width == 8)
780 else if (*
Offset == 0 && *Width == 16)
782 else if (*
Offset == 0 && *Width == 32)
784 else if (*
Offset == 8 && *Width == 8)
786 else if (*
Offset == 16 && *Width == 8)
788 else if (*
Offset == 16 && *Width == 16)
790 else if (*
Offset == 24 && *Width == 8)
795 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
796 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
799 Dst->getReg().isPhysical())
802 return std::make_unique<SDWASrcOperand>(
803 Src0, Dst, SrcSel,
false,
false, Opcode != AMDGPU::V_BFE_U32_e64);
806 case AMDGPU::V_AND_B32_e32:
807 case AMDGPU::V_AND_B32_e64: {
812 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
813 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
815 auto Imm = foldToImm(*Src0);
818 Imm = foldToImm(*Src1);
822 if (!Imm || (*Imm != 0x0000ffff && *Imm != 0x000000ff))
825 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
827 if (!ValSrc->isReg() || ValSrc->getReg().isPhysical() ||
828 Dst->getReg().isPhysical())
831 return std::make_unique<SDWASrcOperand>(
835 case AMDGPU::V_OR_B32_e32:
836 case AMDGPU::V_OR_B32_e64: {
847 std::optional<std::pair<MachineOperand *, MachineOperand *>>;
848 auto CheckOROperandsForSDWA =
849 [&](
const MachineOperand *Op1,
const MachineOperand *Op2) -> CheckRetType {
850 if (!Op1 || !Op1->
isReg() || !Op2 || !Op2->isReg())
851 return CheckRetType(std::nullopt);
855 return CheckRetType(std::nullopt);
857 MachineInstr *Op1Inst = Op1Def->
getParent();
858 if (!
TII->isSDWA(*Op1Inst))
859 return CheckRetType(std::nullopt);
863 return CheckRetType(std::nullopt);
865 return CheckRetType(std::pair(Op1Def, Op2Def));
868 MachineOperand *OrSDWA =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
869 MachineOperand *OrOther =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
870 assert(OrSDWA && OrOther);
871 auto Res = CheckOROperandsForSDWA(OrSDWA, OrOther);
873 OrSDWA =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
874 OrOther =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
875 assert(OrSDWA && OrOther);
876 Res = CheckOROperandsForSDWA(OrSDWA, OrOther);
881 MachineOperand *OrSDWADef = Res->first;
882 MachineOperand *OrOtherDef = Res->second;
883 assert(OrSDWADef && OrOtherDef);
885 MachineInstr *SDWAInst = OrSDWADef->
getParent();
886 MachineInstr *OtherInst = OrOtherDef->
getParent();
908 if (!
TII->isSDWA(*OtherInst))
912 TII->getNamedImmOperand(*SDWAInst, AMDGPU::OpName::dst_sel));
914 TII->getNamedImmOperand(*OtherInst, AMDGPU::OpName::dst_sel));
916 bool DstSelAgree =
false;
919 (OtherDstSel ==
BYTE_3) ||
923 (OtherDstSel ==
BYTE_1) ||
927 (OtherDstSel ==
BYTE_2) ||
928 (OtherDstSel ==
BYTE_3) ||
932 (OtherDstSel ==
BYTE_2) ||
933 (OtherDstSel ==
BYTE_3) ||
937 (OtherDstSel ==
BYTE_1) ||
938 (OtherDstSel ==
BYTE_3) ||
942 (OtherDstSel ==
BYTE_1) ||
943 (OtherDstSel ==
BYTE_2) ||
946 default: DstSelAgree =
false;
954 TII->getNamedImmOperand(*OtherInst, AMDGPU::OpName::dst_unused));
955 if (OtherDstUnused != DstUnused::UNUSED_PAD)
959 MachineOperand *OrDst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
962 return std::make_unique<SDWADstPreserveOperand>(
963 OrDst, OrSDWADef, OrOtherDef, DstSel);
968 return std::unique_ptr<SDWAOperand>(
nullptr);
978void SIPeepholeSDWA::matchSDWAOperands(MachineBasicBlock &
MBB) {
979 for (MachineInstr &
MI :
MBB) {
980 if (
auto Operand = matchSDWAOperand(
MI)) {
982 SDWAOperands[&
MI] = std::move(Operand);
983 ++NumSDWAPatternsFound;
1006void SIPeepholeSDWA::pseudoOpConvertToVOP2(MachineInstr &
MI,
1007 const GCNSubtarget &ST)
const {
1008 int Opc =
MI.getOpcode();
1009 assert((
Opc == AMDGPU::V_ADD_CO_U32_e64 ||
Opc == AMDGPU::V_SUB_CO_U32_e64) &&
1010 "Currently only handles V_ADD_CO_U32_e64 or V_SUB_CO_U32_e64");
1013 if (!
TII->canShrink(
MI, *MRI))
1017 const MachineOperand *Sdst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst);
1023 MachineInstr &MISucc = *NextOp->
getParent();
1026 MachineOperand *CarryIn =
TII->getNamedOperand(MISucc, AMDGPU::OpName::src2);
1029 MachineOperand *CarryOut =
TII->getNamedOperand(MISucc, AMDGPU::OpName::sdst);
1036 MachineBasicBlock &
MBB = *
MI.getParent();
1044 if (
I->modifiesRegister(AMDGPU::VCC,
TRI))
1050 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst))
1051 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src0))
1052 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src1))
1055 MI.eraseFromParent();
1067void SIPeepholeSDWA::convertVcndmaskToVOP2(MachineInstr &
MI,
1068 const GCNSubtarget &ST)
const {
1069 assert(
MI.getOpcode() == AMDGPU::V_CNDMASK_B32_e64);
1072 if (!
TII->canShrink(
MI, *MRI)) {
1077 const MachineOperand &CarryIn =
1078 *
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
1080 MachineInstr *CarryDef = MRI->
getVRegDef(CarryReg);
1087 MCRegister
Vcc =
TRI->getVCC();
1088 MachineBasicBlock &
MBB = *
MI.getParent();
1092 LLVM_DEBUG(
dbgs() <<
"VCC not known to be dead before instruction\n");
1100 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst))
1101 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src0))
1102 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src1))
1104 TII->fixImplicitOperands(*Converted);
1107 MI.eraseFromParent();
1111bool isConvertibleToSDWA(MachineInstr &
MI,
1112 const GCNSubtarget &ST,
1113 const SIInstrInfo*
TII) {
1115 unsigned Opc =
MI.getOpcode();
1121 if (
Opc == AMDGPU::V_CNDMASK_B32_e64)
1131 if (!
ST.hasSDWAOmod() &&
TII->hasModifiersSet(
MI, AMDGPU::OpName::omod))
1135 if (!
ST.hasSDWASdst()) {
1136 const MachineOperand *SDst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst);
1137 if (SDst && (SDst->
getReg() != AMDGPU::VCC &&
1138 SDst->
getReg() != AMDGPU::VCC_LO))
1142 if (!
ST.hasSDWAOutModsVOPC() &&
1143 (
TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp) ||
1144 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod)))
1147 }
else if (
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst) ||
1148 !
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst)) {
1152 if (!
ST.hasSDWAMac() && (
Opc == AMDGPU::V_FMAC_F16_e32 ||
1153 Opc == AMDGPU::V_FMAC_F32_e32 ||
1154 Opc == AMDGPU::V_MAC_F16_e32 ||
1155 Opc == AMDGPU::V_MAC_F32_e32))
1159 if (
TII->pseudoToMCOpcode(
Opc) == -1)
1162 if (MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0)) {
1167 if (MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1)) {
1176MachineInstr *SIPeepholeSDWA::createSDWAVersion(MachineInstr &
MI) {
1177 unsigned Opcode =
MI.getOpcode();
1181 if (SDWAOpcode == -1)
1183 assert(SDWAOpcode != -1);
1185 const MCInstrDesc &SDWADesc =
TII->get(SDWAOpcode);
1188 MachineInstrBuilder SDWAInst =
1193 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1197 }
else if ((Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst))) {
1202 SDWAInst.
addReg(
TRI->getVCC(), RegState::Define);
1207 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
1210 if (
auto *
Mod =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers))
1214 SDWAInst.
add(*Src0);
1217 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
1221 if (
auto *
Mod =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers))
1225 SDWAInst.
add(*Src1);
1228 if (SDWAOpcode == AMDGPU::V_FMAC_F16_sdwa ||
1229 SDWAOpcode == AMDGPU::V_FMAC_F32_sdwa ||
1230 SDWAOpcode == AMDGPU::V_MAC_F16_sdwa ||
1231 SDWAOpcode == AMDGPU::V_MAC_F32_sdwa) {
1233 MachineOperand *Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
1235 SDWAInst.
add(*Src2);
1240 MachineOperand *Clamp =
TII->getNamedOperand(
MI, AMDGPU::OpName::clamp);
1242 SDWAInst.
add(*Clamp);
1249 MachineOperand *OMod =
TII->getNamedOperand(
MI, AMDGPU::OpName::omod);
1251 SDWAInst.
add(*OMod);
1259 SDWAInst.
addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1262 SDWAInst.
addImm(AMDGPU::SDWA::DstUnused::UNUSED_PAD);
1265 SDWAInst.
addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1269 SDWAInst.
addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1273 MachineInstr *Ret = SDWAInst.
getInstr();
1274 TII->fixImplicitOperands(*Ret);
1278bool SIPeepholeSDWA::convertToSDWA(MachineInstr &
MI,
1279 const SDWAOperandsVector &SDWAOperands) {
1282 MachineInstr *SDWAInst;
1283 if (
TII->isSDWA(
MI.getOpcode())) {
1287 SDWAInst =
MI.getMF()->CloneMachineInstr(&
MI);
1288 MI.getParent()->insert(
MI.getIterator(), SDWAInst);
1290 SDWAInst = createSDWAVersion(
MI);
1294 bool Converted =
false;
1295 for (
auto &Operand : SDWAOperands) {
1307 if (PotentialMatches.count(Operand->getParentInst()) == 0)
1308 Converted |= Operand->convertToSDWA(*SDWAInst,
TII);
1316 ConvertedInstructions.
push_back(SDWAInst);
1317 for (MachineOperand &MO : SDWAInst->
uses()) {
1324 ++NumSDWAInstructionsPeepholed;
1326 MI.eraseFromParent();
1332void SIPeepholeSDWA::legalizeScalarOperands(MachineInstr &
MI,
1333 const GCNSubtarget &ST)
const {
1334 const MCInstrDesc &
Desc =
TII->get(
MI.getOpcode());
1335 unsigned ConstantBusCount = 0;
1336 for (MachineOperand &
Op :
MI.explicit_uses()) {
1338 if (
TRI->isVGPR(*MRI,
Op.getReg()))
1341 if (
ST.hasSDWAScalar() && ConstantBusCount == 0) {
1345 }
else if (!
Op.isImm())
1348 unsigned I =
Op.getOperandNo();
1350 if (!OpRC || !
TRI->isVSSuperClass(OpRC))
1355 TII->get(AMDGPU::V_MOV_B32_e32), VGPR);
1357 Copy.addImm(
Op.getImm());
1358 else if (
Op.isReg())
1360 Op.ChangeToRegister(VGPR,
false);
1364bool SIPeepholeSDWALegacy::runOnMachineFunction(MachineFunction &MF) {
1368 return SIPeepholeSDWA().run(MF);
1371bool SIPeepholeSDWA::run(MachineFunction &MF) {
1378 TRI =
ST.getRegisterInfo();
1379 TII =
ST.getInstrInfo();
1383 for (MachineBasicBlock &
MBB : MF) {
1390 matchSDWAOperands(
MBB);
1391 for (
const auto &OperandPair : SDWAOperands) {
1392 const auto &Operand = OperandPair.second;
1393 MachineInstr *PotentialMI = Operand->potentialToConvert(
TII, ST);
1398 case AMDGPU::V_ADD_CO_U32_e64:
1399 case AMDGPU::V_SUB_CO_U32_e64:
1400 pseudoOpConvertToVOP2(*PotentialMI, ST);
1402 case AMDGPU::V_CNDMASK_B32_e64:
1403 convertVcndmaskToVOP2(*PotentialMI, ST);
1407 SDWAOperands.clear();
1410 matchSDWAOperands(
MBB);
1412 for (
const auto &OperandPair : SDWAOperands) {
1413 const auto &Operand = OperandPair.second;
1414 MachineInstr *PotentialMI =
1415 Operand->potentialToConvert(
TII, ST, &PotentialMatches);
1417 if (PotentialMI && isConvertibleToSDWA(*PotentialMI, ST,
TII))
1418 PotentialMatches[PotentialMI].push_back(Operand.get());
1421 for (
auto &PotentialPair : PotentialMatches) {
1422 MachineInstr &PotentialMI = *PotentialPair.first;
1423 convertToSDWA(PotentialMI, PotentialPair.second);
1426 PotentialMatches.clear();
1427 SDWAOperands.clear();
1433 while (!ConvertedInstructions.
empty())
1434 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< 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)
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
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.
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.
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.
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 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.
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)
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
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.
DWARFExpression::Operation Op
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
char & SIPeepholeSDWALegacyID
MCRegisterClass TargetRegisterClass