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; }
164 const MachineOperand *SrcOp)
const;
166#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
167 void print(raw_ostream& OS)
const override;
171class SDWADstOperand :
public SDWAOperand {
177 SDWADstOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp,
179 : SDWAOperand(TargetOp, ReplacedOp), DstSel(DstSel_), DstUn(DstUn_) {}
181 MachineInstr *potentialToConvert(
const SIInstrInfo *
TII,
182 const GCNSubtarget &ST,
183 SDWAOperandsMap *PotentialMatches =
nullptr)
override;
184 bool convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII)
override;
185 bool canCombineSelections(
const MachineInstr &
MI,
186 const SIInstrInfo *
TII)
override;
188 SdwaSel getDstSel()
const {
return DstSel; }
189 DstUnused getDstUnused()
const {
return DstUn; }
191#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
192 void print(raw_ostream& OS)
const override;
196class SDWADstPreserveOperand :
public SDWADstOperand {
198 MachineOperand *Preserve;
201 SDWADstPreserveOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp,
204 Preserve(PreserveOp) {}
206 bool convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII)
override;
207 bool canCombineSelections(
const MachineInstr &
MI,
208 const SIInstrInfo *
TII)
override;
210 MachineOperand *getPreservedOperand()
const {
return Preserve; }
212#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
213 void print(raw_ostream& OS)
const override;
222char SIPeepholeSDWALegacy::ID = 0;
227 return new SIPeepholeSDWALegacy();
230#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
233 case BYTE_0: OS <<
"BYTE_0";
break;
234 case BYTE_1: OS <<
"BYTE_1";
break;
235 case BYTE_2: OS <<
"BYTE_2";
break;
236 case BYTE_3: OS <<
"BYTE_3";
break;
237 case WORD_0: OS <<
"WORD_0";
break;
238 case WORD_1: OS <<
"WORD_1";
break;
239 case DWORD: OS <<
"DWORD";
break;
255 OS <<
"SDWA src: " << *getTargetOperand()
256 <<
" src_sel:" << getSrcSel()
257 <<
" abs:" << getAbs() <<
" neg:" << getNeg()
258 <<
" sext:" << getSext() <<
'\n';
262void SDWADstOperand::print(raw_ostream& OS)
const {
263 OS <<
"SDWA dst: " << *getTargetOperand()
264 <<
" dst_sel:" << getDstSel()
265 <<
" dst_unused:" << getDstUnused() <<
'\n';
269void SDWADstPreserveOperand::print(raw_ostream& OS)
const {
270 OS <<
"SDWA preserve dst: " << *getTargetOperand()
271 <<
" dst_sel:" << getDstSel()
272 <<
" preserve:" << *getPreservedOperand() <<
'\n';
290 return LHS.isReg() &&
292 LHS.getReg() ==
RHS.getReg() &&
293 LHS.getSubReg() ==
RHS.getSubReg();
298 if (!
Reg->isReg() || !
Reg->isDef())
319 if (Sel == SdwaSel::DWORD)
322 if (Sel == OperandSel || OperandSel == SdwaSel::DWORD)
325 if (Sel == SdwaSel::WORD_1 || Sel == SdwaSel::BYTE_2 ||
326 Sel == SdwaSel::BYTE_3)
329 if (OperandSel == SdwaSel::WORD_0)
332 if (OperandSel == SdwaSel::WORD_1) {
333 if (Sel == SdwaSel::BYTE_0)
334 return SdwaSel::BYTE_2;
335 if (Sel == SdwaSel::BYTE_1)
336 return SdwaSel::BYTE_3;
337 if (Sel == SdwaSel::WORD_0)
338 return SdwaSel::WORD_1;
344uint64_t SDWASrcOperand::getSrcMods(
const SIInstrInfo *
TII,
345 const MachineOperand *SrcOp)
const {
348 if (
TII->getNamedOperand(*
MI, AMDGPU::OpName::src0) == SrcOp) {
349 if (
auto *
Mod =
TII->getNamedOperand(*
MI, AMDGPU::OpName::src0_modifiers)) {
350 Mods =
Mod->getImm();
352 }
else if (
TII->getNamedOperand(*
MI, AMDGPU::OpName::src1) == SrcOp) {
353 if (
auto *
Mod =
TII->getNamedOperand(*
MI, AMDGPU::OpName::src1_modifiers)) {
354 Mods =
Mod->getImm();
359 "Float and integer src modifiers can't be set simultaneously");
369MachineInstr *SDWASrcOperand::potentialToConvert(
const SIInstrInfo *
TII,
370 const GCNSubtarget &ST,
371 SDWAOperandsMap *PotentialMatches) {
372 if (PotentialMatches !=
nullptr) {
374 MachineOperand *
Reg = getReplacedOperand();
375 if (!
Reg->isReg() || !
Reg->isDef())
378 for (MachineInstr &
UseMI : getMRI()->use_nodbg_instructions(
Reg->getReg()))
380 if (!isConvertibleToSDWA(
UseMI, ST,
TII) ||
386 for (MachineOperand &UseMO : getMRI()->use_nodbg_operands(
Reg->getReg())) {
390 SDWAOperandsMap &potentialMatchesMap = *PotentialMatches;
391 MachineInstr *
UseMI = UseMO.getParent();
392 potentialMatchesMap[
UseMI].push_back(
this);
399 MachineOperand *PotentialMO =
findSingleRegUse(getReplacedOperand(), getMRI());
403 MachineInstr *Parent = PotentialMO->
getParent();
405 return canCombineSelections(*Parent,
TII) ? Parent :
nullptr;
408bool SDWASrcOperand::convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII) {
409 assert((!Sext || !
TII->getSubtarget().zeroesHigh16BitsOfDest(
411 "Cannot use sign-extension with instruction that zeroes high bits");
412 switch (
MI.getOpcode()) {
413 case AMDGPU::V_CVT_F32_FP8_sdwa:
414 case AMDGPU::V_CVT_F32_BF8_sdwa:
415 case AMDGPU::V_CVT_PK_F32_FP8_sdwa:
416 case AMDGPU::V_CVT_PK_F32_BF8_sdwa:
419 case AMDGPU::V_CNDMASK_B32_sdwa:
438 bool IsPreserveSrc =
false;
439 MachineOperand *Src =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
440 MachineOperand *SrcSel =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0_sel);
441 MachineOperand *SrcMods =
442 TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers);
443 assert(Src && (Src->isReg() || Src->isImm()));
444 if (!
isSameReg(*Src, *getReplacedOperand())) {
446 Src =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
447 SrcSel =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_sel);
448 SrcMods =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers);
451 !
isSameReg(*Src, *getReplacedOperand())) {
458 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
460 TII->getNamedOperand(
MI, AMDGPU::OpName::dst_unused);
463 DstUnused->getImm() == AMDGPU::SDWA::DstUnused::UNUSED_PRESERVE) {
469 TII->getNamedImmOperand(
MI, AMDGPU::OpName::dst_sel));
470 if (DstSel == AMDGPU::SDWA::SdwaSel::WORD_1 &&
471 getSrcSel() == AMDGPU::SDWA::SdwaSel::WORD_0) {
472 IsPreserveSrc =
true;
473 auto DstIdx = AMDGPU::getNamedOperandIdx(
MI.getOpcode(),
474 AMDGPU::OpName::vdst);
475 auto TiedIdx =
MI.findTiedOperandIdx(DstIdx);
476 Src = &
MI.getOperand(TiedIdx);
485 assert(Src && Src->isReg());
487 if ((
MI.getOpcode() == AMDGPU::V_FMAC_F16_sdwa ||
488 MI.getOpcode() == AMDGPU::V_FMAC_F32_sdwa ||
489 MI.getOpcode() == AMDGPU::V_MAC_F16_sdwa ||
490 MI.getOpcode() == AMDGPU::V_MAC_F32_sdwa) &&
491 !
isSameReg(*Src, *getReplacedOperand())) {
498 (IsPreserveSrc || (SrcSel && SrcMods)));
501 if (!IsPreserveSrc) {
506 getTargetOperand()->setIsKill(
false);
513 AMDGPU::OpName SrcSelOpName,
SdwaSel OpSel) {
526 AMDGPU::OpName SrcOpName,
538bool SDWASrcOperand::canCombineSelections(
const MachineInstr &
MI,
539 const SIInstrInfo *
TII) {
540 if (!
TII->isSDWA(
MI.getOpcode()))
543 using namespace AMDGPU;
546 getReplacedOperand(), getSrcSel()) &&
548 getReplacedOperand(), getSrcSel());
551MachineInstr *SDWADstOperand::potentialToConvert(
const SIInstrInfo *
TII,
552 const GCNSubtarget &ST,
553 SDWAOperandsMap *PotentialMatches) {
556 MachineRegisterInfo *MRI = getMRI();
557 MachineInstr *ParentMI = getParentInst();
565 if (&UseInst != ParentMI)
569 MachineInstr *Parent = PotentialMO->
getParent();
570 return canCombineSelections(*Parent,
TII) ? Parent :
nullptr;
573bool SDWADstOperand::convertToSDWA(MachineInstr &
MI,
const SIInstrInfo *
TII) {
576 if ((
MI.getOpcode() == AMDGPU::V_FMAC_F16_sdwa ||
577 MI.getOpcode() == AMDGPU::V_FMAC_F32_sdwa ||
578 MI.getOpcode() == AMDGPU::V_MAC_F16_sdwa ||
579 MI.getOpcode() == AMDGPU::V_MAC_F32_sdwa) &&
585 MachineOperand *Operand =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
588 isSameReg(*Operand, *getReplacedOperand()));
590 MachineOperand *DstSel=
TII->getNamedOperand(
MI, AMDGPU::OpName::dst_sel);
596 MachineOperand *
DstUnused=
TII->getNamedOperand(
MI, AMDGPU::OpName::dst_unused);
602 getParentInst()->eraseFromParent();
606bool SDWADstOperand::canCombineSelections(
const MachineInstr &
MI,
607 const SIInstrInfo *
TII) {
608 if (!
TII->isSDWA(
MI.getOpcode()))
614bool SDWADstPreserveOperand::convertToSDWA(MachineInstr &
MI,
615 const SIInstrInfo *
TII) {
619 for (MachineOperand &MO :
MI.uses()) {
622 getMRI()->clearKillFlags(MO.getReg());
626 MI.getParent()->remove(&
MI);
627 getParentInst()->getParent()->insert(getParentInst(), &
MI);
630 MachineInstrBuilder MIB(*
MI.getMF(),
MI);
631 MIB.addReg(getPreservedOperand()->
getReg(),
632 RegState::ImplicitKill,
633 getPreservedOperand()->getSubReg());
636 MI.tieOperands(AMDGPU::getNamedOperandIdx(
MI.getOpcode(), AMDGPU::OpName::vdst),
637 MI.getNumOperands() - 1);
640 return SDWADstOperand::convertToSDWA(
MI,
TII);
643bool SDWADstPreserveOperand::canCombineSelections(
const MachineInstr &
MI,
644 const SIInstrInfo *
TII) {
645 return SDWADstOperand::canCombineSelections(
MI,
TII);
648std::optional<int64_t>
649SIPeepholeSDWA::foldToImm(
const MachineOperand &
Op)
const {
657 for (
const MachineOperand &Def : MRI->
def_operands(
Op.getReg())) {
661 const MachineInstr *DefInst =
Def.getParent();
662 if (!
TII->isFoldableCopy(*DefInst))
665 const MachineOperand &Copied = DefInst->
getOperand(1);
676std::optional<std::pair<MachineOperand *, SdwaSel>>
677SIPeepholeSDWA::matchAndMask(MachineInstr &
MI)
const {
678 if (
MI.getOpcode() != AMDGPU::V_AND_B32_e32 &&
679 MI.getOpcode() != AMDGPU::V_AND_B32_e64)
682 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
683 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
684 MachineOperand *ValSrc = Src1;
685 std::optional<int64_t>
Imm = foldToImm(*Src0);
687 Imm = foldToImm(*Src1);
690 if (!
Imm || (*
Imm != 0x0000ffff && *
Imm != 0x000000ff))
696bool SIPeepholeSDWA::isSDWAWithDstSel(
const MachineInstr &Inst)
const {
697 return TII->isSDWA(Inst) &&
701std::unique_ptr<SDWAOperand>
702SIPeepholeSDWA::matchSDWAOperand(MachineInstr &
MI) {
703 unsigned Opcode =
MI.getOpcode();
705 case AMDGPU::V_LSHRREV_B32_e32:
706 case AMDGPU::V_ASHRREV_I32_e32:
707 case AMDGPU::V_LSHLREV_B32_e32:
708 case AMDGPU::V_LSHRREV_B32_e64:
709 case AMDGPU::V_ASHRREV_I32_e64:
710 case AMDGPU::V_LSHLREV_B32_e64: {
719 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
720 auto Imm = foldToImm(*Src0);
724 if (*
Imm != 16 && *
Imm != 24)
727 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
728 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
730 Dst->getReg().isPhysical())
733 if (Opcode == AMDGPU::V_LSHLREV_B32_e32 ||
734 Opcode == AMDGPU::V_LSHLREV_B32_e64) {
735 return std::make_unique<SDWADstOperand>(
738 return std::make_unique<SDWASrcOperand>(
740 Opcode != AMDGPU::V_LSHRREV_B32_e32 &&
741 Opcode != AMDGPU::V_LSHRREV_B32_e64);
745 case AMDGPU::V_LSHRREV_B16_e32:
746 case AMDGPU::V_LSHLREV_B16_e32:
747 case AMDGPU::V_LSHRREV_B16_e64:
748 case AMDGPU::V_LSHRREV_B16_opsel_e64:
749 case AMDGPU::V_LSHLREV_B16_opsel_e64:
750 case AMDGPU::V_LSHLREV_B16_e64: {
759 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
760 auto Imm = foldToImm(*Src0);
764 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
765 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
768 Dst->getReg().isPhysical())
771 if (Opcode == AMDGPU::V_LSHLREV_B16_e32 ||
772 Opcode == AMDGPU::V_LSHLREV_B16_opsel_e64 ||
773 Opcode == AMDGPU::V_LSHLREV_B16_e64)
775 return std::make_unique<SDWASrcOperand>(Src1, Dst,
BYTE_1,
false,
false,
780 case AMDGPU::V_BFE_I32_e64:
781 case AMDGPU::V_BFE_U32_e64: {
796 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
797 auto Offset = foldToImm(*Src1);
801 MachineOperand *Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
802 auto Width = foldToImm(*Src2);
808 if (*
Offset == 0 && *Width == 8)
810 else if (*
Offset == 0 && *Width == 16)
812 else if (*
Offset == 0 && *Width == 32)
814 else if (*
Offset == 8 && *Width == 8)
816 else if (*
Offset == 16 && *Width == 8)
818 else if (*
Offset == 16 && *Width == 16)
820 else if (*
Offset == 24 && *Width == 8)
825 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
826 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
829 Dst->getReg().isPhysical())
832 return std::make_unique<SDWASrcOperand>(
833 Src0, Dst, SrcSel,
false,
false, Opcode != AMDGPU::V_BFE_U32_e64);
836 case AMDGPU::V_AND_B32_e32:
837 case AMDGPU::V_AND_B32_e64: {
841 auto Mask = matchAndMask(
MI);
844 MachineOperand *ValSrc =
Mask->first;
846 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
849 Dst->getReg().isPhysical())
852 return std::make_unique<SDWASrcOperand>(ValSrc, Dst,
Mask->second);
855 case AMDGPU::V_OR_B32_e32:
856 case AMDGPU::V_OR_B32_e64: {
867 std::optional<std::pair<MachineOperand *, MachineOperand *>>;
868 auto CheckOROperandsForSDWA =
869 [&](
const MachineOperand *Op1,
const MachineOperand *Op2) -> CheckRetType {
870 if (!Op1 || !Op1->
isReg() || !Op2 || !Op2->isReg())
871 return CheckRetType(std::nullopt);
875 return CheckRetType(std::nullopt);
877 MachineInstr *Op1Inst = Op1Def->
getParent();
878 if (!isSDWAWithDstSel(*Op1Inst))
879 return CheckRetType(std::nullopt);
883 return CheckRetType(std::nullopt);
885 return CheckRetType(std::pair(Op1Def, Op2Def));
888 MachineOperand *OrSDWA =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
889 MachineOperand *OrOther =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
890 assert(OrSDWA && OrOther);
891 auto Res = CheckOROperandsForSDWA(OrSDWA, OrOther);
893 OrSDWA =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
894 OrOther =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
895 assert(OrSDWA && OrOther);
896 Res = CheckOROperandsForSDWA(OrSDWA, OrOther);
901 MachineOperand *OrSDWADef = Res->first;
902 MachineOperand *OrOtherDef = Res->second;
903 assert(OrSDWADef && OrOtherDef);
905 MachineInstr *SDWAInst = OrSDWADef->
getParent();
906 MachineInstr *OtherInst = OrOtherDef->
getParent();
928 if (!isSDWAWithDstSel(*OtherInst))
932 TII->getNamedImmOperand(*SDWAInst, AMDGPU::OpName::dst_sel));
934 TII->getNamedImmOperand(*OtherInst, AMDGPU::OpName::dst_sel));
936 bool DstSelAgree =
false;
939 (OtherDstSel ==
BYTE_3) ||
943 (OtherDstSel ==
BYTE_1) ||
947 (OtherDstSel ==
BYTE_2) ||
948 (OtherDstSel ==
BYTE_3) ||
952 (OtherDstSel ==
BYTE_2) ||
953 (OtherDstSel ==
BYTE_3) ||
957 (OtherDstSel ==
BYTE_1) ||
958 (OtherDstSel ==
BYTE_3) ||
962 (OtherDstSel ==
BYTE_1) ||
963 (OtherDstSel ==
BYTE_2) ||
966 default: DstSelAgree =
false;
974 TII->getNamedImmOperand(*OtherInst, AMDGPU::OpName::dst_unused));
975 if (OtherDstUnused != DstUnused::UNUSED_PAD)
979 MachineOperand *OrDst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
982 return std::make_unique<SDWADstPreserveOperand>(
983 OrDst, OrSDWADef, OrOtherDef, DstSel);
988 return std::unique_ptr<SDWAOperand>(
nullptr);
998void SIPeepholeSDWA::matchSDWAOperands(MachineBasicBlock &
MBB) {
999 for (MachineInstr &
MI :
MBB) {
1000 if (
auto Operand = matchSDWAOperand(
MI)) {
1002 SDWAOperands[&
MI] = std::move(Operand);
1003 ++NumSDWAPatternsFound;
1026void SIPeepholeSDWA::pseudoOpConvertToVOP2(MachineInstr &
MI,
1027 const GCNSubtarget &ST)
const {
1028 int Opc =
MI.getOpcode();
1029 assert((
Opc == AMDGPU::V_ADD_CO_U32_e64 ||
Opc == AMDGPU::V_SUB_CO_U32_e64) &&
1030 "Currently only handles V_ADD_CO_U32_e64 or V_SUB_CO_U32_e64");
1033 if (!
TII->canShrink(
MI, *MRI))
1037 const MachineOperand *Sdst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst);
1043 MachineInstr &MISucc = *NextOp->
getParent();
1046 MachineOperand *CarryIn =
TII->getNamedOperand(MISucc, AMDGPU::OpName::src2);
1049 MachineOperand *CarryOut =
TII->getNamedOperand(MISucc, AMDGPU::OpName::sdst);
1064 if (
I->modifiesRegister(AMDGPU::VCC,
TRI))
1070 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst))
1071 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src0))
1072 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src1))
1075 MI.eraseFromParent();
1087void SIPeepholeSDWA::convertVcndmaskToVOP2(MachineInstr &
MI,
1088 const GCNSubtarget &ST)
const {
1089 assert(
MI.getOpcode() == AMDGPU::V_CNDMASK_B32_e64);
1092 if (!
TII->canShrink(
MI, *MRI)) {
1097 const MachineOperand &CarryIn =
1098 *
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
1100 MachineInstr *CarryDef = MRI->
getVRegDef(CarryReg);
1107 MCRegister
Vcc =
TRI->getVCC();
1112 LLVM_DEBUG(
dbgs() <<
"VCC not known to be dead before instruction\n");
1120 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst))
1121 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src0))
1122 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src1))
1124 TII->fixImplicitOperands(*Converted);
1127 MI.eraseFromParent();
1131bool isConvertibleToSDWA(MachineInstr &
MI,
1132 const GCNSubtarget &ST,
1133 const SIInstrInfo*
TII) {
1135 unsigned Opc =
MI.getOpcode();
1141 if (
Opc == AMDGPU::V_CNDMASK_B32_e64)
1151 if (!
ST.hasSDWAOmod() &&
TII->hasModifiersSet(
MI, AMDGPU::OpName::omod))
1155 if (!
ST.hasSDWASdst()) {
1156 const MachineOperand *SDst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst);
1157 if (SDst && (SDst->
getReg() != AMDGPU::VCC &&
1158 SDst->
getReg() != AMDGPU::VCC_LO))
1162 if (!
ST.hasSDWAOutModsVOPC() &&
1163 (
TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp) ||
1164 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod)))
1167 }
else if (
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst) ||
1168 !
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst)) {
1172 if (!
ST.hasSDWAMac() && (
Opc == AMDGPU::V_FMAC_F16_e32 ||
1173 Opc == AMDGPU::V_FMAC_F32_e32 ||
1174 Opc == AMDGPU::V_MAC_F16_e32 ||
1175 Opc == AMDGPU::V_MAC_F32_e32))
1179 if (
TII->pseudoToMCOpcode(
Opc) == -1 ||
1183 if (MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0)) {
1188 if (MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1)) {
1197MachineInstr *SIPeepholeSDWA::createSDWAVersion(MachineInstr &
MI) {
1198 unsigned Opcode =
MI.getOpcode();
1202 if (SDWAOpcode == -1)
1204 assert(SDWAOpcode != -1);
1206 const MCInstrDesc &SDWADesc =
TII->get(SDWAOpcode);
1209 MachineInstrBuilder SDWAInst =
1214 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1218 }
else if ((Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst))) {
1223 SDWAInst.
addReg(
TRI->getVCC(), RegState::Define);
1228 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
1231 if (
auto *
Mod =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers))
1235 SDWAInst.
add(*Src0);
1238 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
1242 if (
auto *
Mod =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers))
1246 SDWAInst.
add(*Src1);
1249 if (SDWAOpcode == AMDGPU::V_FMAC_F16_sdwa ||
1250 SDWAOpcode == AMDGPU::V_FMAC_F32_sdwa ||
1251 SDWAOpcode == AMDGPU::V_MAC_F16_sdwa ||
1252 SDWAOpcode == AMDGPU::V_MAC_F32_sdwa) {
1254 MachineOperand *Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
1256 SDWAInst.
add(*Src2);
1261 MachineOperand *Clamp =
TII->getNamedOperand(
MI, AMDGPU::OpName::clamp);
1263 SDWAInst.
add(*Clamp);
1270 MachineOperand *OMod =
TII->getNamedOperand(
MI, AMDGPU::OpName::omod);
1272 SDWAInst.
add(*OMod);
1280 SDWAInst.
addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1283 SDWAInst.
addImm(AMDGPU::SDWA::DstUnused::UNUSED_PAD);
1286 SDWAInst.
addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1290 SDWAInst.
addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1294 MachineInstr *Ret = SDWAInst.
getInstr();
1295 TII->fixImplicitOperands(*Ret);
1299bool SIPeepholeSDWA::convertToSDWA(MachineInstr &
MI,
1300 const SDWAOperandsVector &SDWAOperands) {
1303 MachineInstr *SDWAInst;
1304 if (
TII->isSDWA(
MI.getOpcode())) {
1308 SDWAInst =
MI.
getMF()->CloneMachineInstr(&
MI);
1309 MI.getParent()->
insert(
MI.getIterator(), SDWAInst);
1311 SDWAInst = createSDWAVersion(
MI);
1315 bool Converted =
false;
1316 for (
auto &Operand : SDWAOperands) {
1328 if (PotentialMatches.count(Operand->getParentInst()) == 0)
1329 Converted |= Operand->convertToSDWA(*SDWAInst,
TII);
1337 ConvertedInstructions.
push_back(SDWAInst);
1338 for (MachineOperand &MO : SDWAInst->
uses()) {
1345 ++NumSDWAInstructionsPeepholed;
1347 MI.eraseFromParent();
1353void SIPeepholeSDWA::legalizeScalarOperands(MachineInstr &
MI,
1354 const GCNSubtarget &ST)
const {
1355 const MCInstrDesc &
Desc =
TII->get(
MI.getOpcode());
1356 unsigned ConstantBusCount = 0;
1357 for (MachineOperand &
Op :
MI.explicit_uses()) {
1359 if (
TRI->isVGPR(*MRI,
Op.getReg()))
1362 if (
ST.hasSDWAScalar() && ConstantBusCount == 0) {
1366 }
else if (!
Op.isImm())
1369 unsigned I =
Op.getOperandNo();
1371 if (!OpRC || !
TRI->isVSSuperClass(OpRC))
1376 TII->get(AMDGPU::V_MOV_B32_e32), VGPR);
1378 Copy.addImm(
Op.getImm());
1379 else if (
Op.isReg())
1381 Op.ChangeToRegister(VGPR,
false);
1387bool SIPeepholeSDWA::splitLshlOrForSDWA(MachineBasicBlock &
MBB) {
1389 MachineInstr *LshlOr;
1390 MachineInstr *AndMI;
1392 MachineOperand *ValSrc;
1396 for (MachineInstr &
MI :
MBB) {
1397 if (
MI.getOpcode() != AMDGPU::V_LSHL_OR_B32_e64)
1400 MachineOperand *Shift =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
1401 std::optional<int64_t> ShiftImm = foldToImm(*Shift);
1402 if (!ShiftImm || *ShiftImm != 16)
1405 MachineOperand *
Hi =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
1406 MachineOperand *Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
1417 std::optional<std::pair<MachineOperand *, SdwaSel>>
Mask =
1418 matchAndMask(*AndMI);
1421 MachineOperand *ValSrc =
Mask->first;
1428 for (
const Candidate &
C : Candidates) {
1429 MachineOperand *Dst =
TII->getNamedOperand(*
C.LshlOr, AMDGPU::OpName::vdst);
1432 BuildMI(*
C.LshlOr->getParent(), *
C.LshlOr,
C.LshlOr->getDebugLoc(),
1433 TII->get(AMDGPU::V_LSHLREV_B32_e64), ShiftReg)
1439 BuildMI(*
C.LshlOr->getParent(), *
C.LshlOr,
C.LshlOr->getDebugLoc(),
1440 TII->get(AMDGPU::V_OR_B32_sdwa))
1453 C.LshlOr->eraseFromParent();
1454 C.AndMI->eraseFromParent();
1457 return !Candidates.empty();
1464 return SIPeepholeSDWA().run(MF);
1474 TRI =
ST.getRegisterInfo();
1475 TII =
ST.getInstrInfo();
1479 for (MachineBasicBlock &
MBB : MF) {
1482 Ret |= splitLshlOrForSDWA(
MBB);
1488 matchSDWAOperands(
MBB);
1489 for (
const auto &OperandPair : SDWAOperands) {
1490 const auto &Operand = OperandPair.second;
1491 MachineInstr *PotentialMI = Operand->potentialToConvert(
TII, ST);
1496 case AMDGPU::V_ADD_CO_U32_e64:
1497 case AMDGPU::V_SUB_CO_U32_e64:
1498 pseudoOpConvertToVOP2(*PotentialMI, ST);
1500 case AMDGPU::V_CNDMASK_B32_e64:
1501 convertVcndmaskToVOP2(*PotentialMI, ST);
1505 SDWAOperands.clear();
1508 matchSDWAOperands(
MBB);
1510 for (
const auto &OperandPair : SDWAOperands) {
1511 const auto &Operand = OperandPair.second;
1512 MachineInstr *PotentialMI =
1513 Operand->potentialToConvert(
TII, ST, &PotentialMatches);
1515 if (PotentialMI && isConvertibleToSDWA(*PotentialMI, ST,
TII))
1516 PotentialMatches[PotentialMI].push_back(Operand.get());
1519 for (
auto &PotentialPair : PotentialMatches) {
1520 MachineInstr &PotentialMI = *PotentialPair.first;
1521 convertToSDWA(PotentialMI, PotentialPair.second);
1524 PotentialMatches.clear();
1525 SDWAOperands.clear();
1531 while (!ConvertedInstructions.
empty())
1532 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 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