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>>
73 bool convertToSDWA(
MachineInstr &
MI,
const SDWAOperandsVector &SDWAOperands);
85 SIPeepholeSDWALegacy() : MachineFunctionPass(ID) {}
87 StringRef getPassName()
const override {
return "SI Peephole SDWA"; }
89 bool runOnMachineFunction(MachineFunction &MF)
override;
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; }
163 uint64_t getSrcMods(
const SIInstrInfo *
TII,
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))
693 return std::make_pair(ValSrc, *Imm == 0x0000ffff ?
WORD_0 :
BYTE_0);
696std::unique_ptr<SDWAOperand>
697SIPeepholeSDWA::matchSDWAOperand(MachineInstr &
MI) {
698 unsigned Opcode =
MI.getOpcode();
700 case AMDGPU::V_LSHRREV_B32_e32:
701 case AMDGPU::V_ASHRREV_I32_e32:
702 case AMDGPU::V_LSHLREV_B32_e32:
703 case AMDGPU::V_LSHRREV_B32_e64:
704 case AMDGPU::V_ASHRREV_I32_e64:
705 case AMDGPU::V_LSHLREV_B32_e64: {
714 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
715 auto Imm = foldToImm(*Src0);
719 if (*Imm != 16 && *Imm != 24)
722 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
723 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
725 Dst->getReg().isPhysical())
728 if (Opcode == AMDGPU::V_LSHLREV_B32_e32 ||
729 Opcode == AMDGPU::V_LSHLREV_B32_e64) {
730 return std::make_unique<SDWADstOperand>(
733 return std::make_unique<SDWASrcOperand>(
735 Opcode != AMDGPU::V_LSHRREV_B32_e32 &&
736 Opcode != AMDGPU::V_LSHRREV_B32_e64);
740 case AMDGPU::V_LSHRREV_B16_e32:
741 case AMDGPU::V_LSHLREV_B16_e32:
742 case AMDGPU::V_LSHRREV_B16_e64:
743 case AMDGPU::V_LSHRREV_B16_opsel_e64:
744 case AMDGPU::V_LSHLREV_B16_opsel_e64:
745 case AMDGPU::V_LSHLREV_B16_e64: {
754 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
755 auto Imm = foldToImm(*Src0);
756 if (!Imm || *Imm != 8)
759 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
760 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
763 Dst->getReg().isPhysical())
766 if (Opcode == AMDGPU::V_LSHLREV_B16_e32 ||
767 Opcode == AMDGPU::V_LSHLREV_B16_opsel_e64 ||
768 Opcode == AMDGPU::V_LSHLREV_B16_e64)
770 return std::make_unique<SDWASrcOperand>(Src1, Dst,
BYTE_1,
false,
false,
775 case AMDGPU::V_BFE_I32_e64:
776 case AMDGPU::V_BFE_U32_e64: {
791 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
792 auto Offset = foldToImm(*Src1);
796 MachineOperand *Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
797 auto Width = foldToImm(*Src2);
803 if (*
Offset == 0 && *Width == 8)
805 else if (*
Offset == 0 && *Width == 16)
807 else if (*
Offset == 0 && *Width == 32)
809 else if (*
Offset == 8 && *Width == 8)
811 else if (*
Offset == 16 && *Width == 8)
813 else if (*
Offset == 16 && *Width == 16)
815 else if (*
Offset == 24 && *Width == 8)
820 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
821 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
824 Dst->getReg().isPhysical())
827 return std::make_unique<SDWASrcOperand>(
828 Src0, Dst, SrcSel,
false,
false, Opcode != AMDGPU::V_BFE_U32_e64);
831 case AMDGPU::V_AND_B32_e32:
832 case AMDGPU::V_AND_B32_e64: {
836 auto Mask = matchAndMask(
MI);
839 MachineOperand *ValSrc =
Mask->first;
841 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
844 Dst->getReg().isPhysical())
847 return std::make_unique<SDWASrcOperand>(ValSrc, Dst,
Mask->second);
850 case AMDGPU::V_OR_B32_e32:
851 case AMDGPU::V_OR_B32_e64: {
862 std::optional<std::pair<MachineOperand *, MachineOperand *>>;
863 auto CheckOROperandsForSDWA =
864 [&](
const MachineOperand *Op1,
const MachineOperand *Op2) -> CheckRetType {
865 if (!Op1 || !Op1->
isReg() || !Op2 || !Op2->isReg())
866 return CheckRetType(std::nullopt);
870 return CheckRetType(std::nullopt);
872 MachineInstr *Op1Inst = Op1Def->
getParent();
873 if (!
TII->isSDWA(*Op1Inst))
874 return CheckRetType(std::nullopt);
878 return CheckRetType(std::nullopt);
880 return CheckRetType(std::pair(Op1Def, Op2Def));
883 MachineOperand *OrSDWA =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
884 MachineOperand *OrOther =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
885 assert(OrSDWA && OrOther);
886 auto Res = CheckOROperandsForSDWA(OrSDWA, OrOther);
888 OrSDWA =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
889 OrOther =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
890 assert(OrSDWA && OrOther);
891 Res = CheckOROperandsForSDWA(OrSDWA, OrOther);
896 MachineOperand *OrSDWADef = Res->first;
897 MachineOperand *OrOtherDef = Res->second;
898 assert(OrSDWADef && OrOtherDef);
900 MachineInstr *SDWAInst = OrSDWADef->
getParent();
901 MachineInstr *OtherInst = OrOtherDef->
getParent();
923 if (!
TII->isSDWA(*OtherInst))
927 TII->getNamedImmOperand(*SDWAInst, AMDGPU::OpName::dst_sel));
929 TII->getNamedImmOperand(*OtherInst, AMDGPU::OpName::dst_sel));
931 bool DstSelAgree =
false;
934 (OtherDstSel ==
BYTE_3) ||
938 (OtherDstSel ==
BYTE_1) ||
942 (OtherDstSel ==
BYTE_2) ||
943 (OtherDstSel ==
BYTE_3) ||
947 (OtherDstSel ==
BYTE_2) ||
948 (OtherDstSel ==
BYTE_3) ||
952 (OtherDstSel ==
BYTE_1) ||
953 (OtherDstSel ==
BYTE_3) ||
957 (OtherDstSel ==
BYTE_1) ||
958 (OtherDstSel ==
BYTE_2) ||
961 default: DstSelAgree =
false;
969 TII->getNamedImmOperand(*OtherInst, AMDGPU::OpName::dst_unused));
970 if (OtherDstUnused != DstUnused::UNUSED_PAD)
974 MachineOperand *OrDst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
977 return std::make_unique<SDWADstPreserveOperand>(
978 OrDst, OrSDWADef, OrOtherDef, DstSel);
983 return std::unique_ptr<SDWAOperand>(
nullptr);
993void SIPeepholeSDWA::matchSDWAOperands(MachineBasicBlock &
MBB) {
994 for (MachineInstr &
MI :
MBB) {
995 if (
auto Operand = matchSDWAOperand(
MI)) {
997 SDWAOperands[&
MI] = std::move(Operand);
998 ++NumSDWAPatternsFound;
1021void SIPeepholeSDWA::pseudoOpConvertToVOP2(MachineInstr &
MI,
1022 const GCNSubtarget &ST)
const {
1023 int Opc =
MI.getOpcode();
1024 assert((
Opc == AMDGPU::V_ADD_CO_U32_e64 ||
Opc == AMDGPU::V_SUB_CO_U32_e64) &&
1025 "Currently only handles V_ADD_CO_U32_e64 or V_SUB_CO_U32_e64");
1028 if (!
TII->canShrink(
MI, *MRI))
1032 const MachineOperand *Sdst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst);
1038 MachineInstr &MISucc = *NextOp->
getParent();
1041 MachineOperand *CarryIn =
TII->getNamedOperand(MISucc, AMDGPU::OpName::src2);
1044 MachineOperand *CarryOut =
TII->getNamedOperand(MISucc, AMDGPU::OpName::sdst);
1051 MachineBasicBlock &
MBB = *
MI.getParent();
1059 if (
I->modifiesRegister(AMDGPU::VCC,
TRI))
1065 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst))
1066 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src0))
1067 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src1))
1070 MI.eraseFromParent();
1082void SIPeepholeSDWA::convertVcndmaskToVOP2(MachineInstr &
MI,
1083 const GCNSubtarget &ST)
const {
1084 assert(
MI.getOpcode() == AMDGPU::V_CNDMASK_B32_e64);
1087 if (!
TII->canShrink(
MI, *MRI)) {
1092 const MachineOperand &CarryIn =
1093 *
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
1095 MachineInstr *CarryDef = MRI->
getVRegDef(CarryReg);
1102 MCRegister
Vcc =
TRI->getVCC();
1103 MachineBasicBlock &
MBB = *
MI.getParent();
1107 LLVM_DEBUG(
dbgs() <<
"VCC not known to be dead before instruction\n");
1115 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst))
1116 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src0))
1117 .
add(*
TII->getNamedOperand(
MI, AMDGPU::OpName::src1))
1119 TII->fixImplicitOperands(*Converted);
1122 MI.eraseFromParent();
1126bool isConvertibleToSDWA(MachineInstr &
MI,
1127 const GCNSubtarget &ST,
1128 const SIInstrInfo*
TII) {
1130 unsigned Opc =
MI.getOpcode();
1136 if (
Opc == AMDGPU::V_CNDMASK_B32_e64)
1146 if (!
ST.hasSDWAOmod() &&
TII->hasModifiersSet(
MI, AMDGPU::OpName::omod))
1150 if (!
ST.hasSDWASdst()) {
1151 const MachineOperand *SDst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst);
1152 if (SDst && (SDst->
getReg() != AMDGPU::VCC &&
1153 SDst->
getReg() != AMDGPU::VCC_LO))
1157 if (!
ST.hasSDWAOutModsVOPC() &&
1158 (
TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp) ||
1159 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod)))
1162 }
else if (
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst) ||
1163 !
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst)) {
1167 if (!
ST.hasSDWAMac() && (
Opc == AMDGPU::V_FMAC_F16_e32 ||
1168 Opc == AMDGPU::V_FMAC_F32_e32 ||
1169 Opc == AMDGPU::V_MAC_F16_e32 ||
1170 Opc == AMDGPU::V_MAC_F32_e32))
1174 if (
TII->pseudoToMCOpcode(
Opc) == -1)
1177 if (MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0)) {
1182 if (MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1)) {
1191MachineInstr *SIPeepholeSDWA::createSDWAVersion(MachineInstr &
MI) {
1192 unsigned Opcode =
MI.getOpcode();
1196 if (SDWAOpcode == -1)
1198 assert(SDWAOpcode != -1);
1200 const MCInstrDesc &SDWADesc =
TII->get(SDWAOpcode);
1203 MachineInstrBuilder SDWAInst =
1208 MachineOperand *Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1212 }
else if ((Dst =
TII->getNamedOperand(
MI, AMDGPU::OpName::sdst))) {
1217 SDWAInst.
addReg(
TRI->getVCC(), RegState::Define);
1222 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
1225 if (
auto *
Mod =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers))
1229 SDWAInst.
add(*Src0);
1232 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
1236 if (
auto *
Mod =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers))
1240 SDWAInst.
add(*Src1);
1243 if (SDWAOpcode == AMDGPU::V_FMAC_F16_sdwa ||
1244 SDWAOpcode == AMDGPU::V_FMAC_F32_sdwa ||
1245 SDWAOpcode == AMDGPU::V_MAC_F16_sdwa ||
1246 SDWAOpcode == AMDGPU::V_MAC_F32_sdwa) {
1248 MachineOperand *Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
1250 SDWAInst.
add(*Src2);
1255 MachineOperand *Clamp =
TII->getNamedOperand(
MI, AMDGPU::OpName::clamp);
1257 SDWAInst.
add(*Clamp);
1264 MachineOperand *OMod =
TII->getNamedOperand(
MI, AMDGPU::OpName::omod);
1266 SDWAInst.
add(*OMod);
1274 SDWAInst.
addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1277 SDWAInst.
addImm(AMDGPU::SDWA::DstUnused::UNUSED_PAD);
1280 SDWAInst.
addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1284 SDWAInst.
addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1288 MachineInstr *Ret = SDWAInst.
getInstr();
1289 TII->fixImplicitOperands(*Ret);
1293bool SIPeepholeSDWA::convertToSDWA(MachineInstr &
MI,
1294 const SDWAOperandsVector &SDWAOperands) {
1297 MachineInstr *SDWAInst;
1298 if (
TII->isSDWA(
MI.getOpcode())) {
1302 SDWAInst =
MI.getMF()->CloneMachineInstr(&
MI);
1303 MI.getParent()->insert(
MI.getIterator(), SDWAInst);
1305 SDWAInst = createSDWAVersion(
MI);
1309 bool Converted =
false;
1310 for (
auto &Operand : SDWAOperands) {
1322 if (PotentialMatches.count(Operand->getParentInst()) == 0)
1323 Converted |= Operand->convertToSDWA(*SDWAInst,
TII);
1331 ConvertedInstructions.
push_back(SDWAInst);
1332 for (MachineOperand &MO : SDWAInst->
uses()) {
1339 ++NumSDWAInstructionsPeepholed;
1341 MI.eraseFromParent();
1347void SIPeepholeSDWA::legalizeScalarOperands(MachineInstr &
MI,
1348 const GCNSubtarget &ST)
const {
1349 const MCInstrDesc &
Desc =
TII->get(
MI.getOpcode());
1350 unsigned ConstantBusCount = 0;
1351 for (MachineOperand &
Op :
MI.explicit_uses()) {
1353 if (
TRI->isVGPR(*MRI,
Op.getReg()))
1356 if (
ST.hasSDWAScalar() && ConstantBusCount == 0) {
1360 }
else if (!
Op.isImm())
1363 unsigned I =
Op.getOperandNo();
1365 if (!OpRC || !
TRI->isVSSuperClass(OpRC))
1370 TII->get(AMDGPU::V_MOV_B32_e32), VGPR);
1372 Copy.addImm(
Op.getImm());
1373 else if (
Op.isReg())
1375 Op.ChangeToRegister(VGPR,
false);
1381bool SIPeepholeSDWA::splitLshlOrForSDWA(MachineBasicBlock &
MBB) {
1383 MachineInstr *LshlOr;
1384 MachineInstr *AndMI;
1386 MachineOperand *ValSrc;
1390 for (MachineInstr &
MI :
MBB) {
1391 if (
MI.getOpcode() != AMDGPU::V_LSHL_OR_B32_e64)
1394 MachineOperand *Shift =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
1395 std::optional<int64_t> ShiftImm = foldToImm(*Shift);
1396 if (!ShiftImm || *ShiftImm != 16)
1399 MachineOperand *
Hi =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
1400 MachineOperand *Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
1411 std::optional<std::pair<MachineOperand *, SdwaSel>>
Mask =
1412 matchAndMask(*AndMI);
1415 MachineOperand *ValSrc =
Mask->first;
1422 for (
const Candidate &
C : Candidates) {
1423 MachineOperand *Dst =
TII->getNamedOperand(*
C.LshlOr, AMDGPU::OpName::vdst);
1426 BuildMI(*
C.LshlOr->getParent(), *
C.LshlOr,
C.LshlOr->getDebugLoc(),
1427 TII->get(AMDGPU::V_LSHLREV_B32_e64), ShiftReg)
1433 BuildMI(*
C.LshlOr->getParent(), *
C.LshlOr,
C.LshlOr->getDebugLoc(),
1434 TII->get(AMDGPU::V_OR_B32_sdwa))
1447 C.LshlOr->eraseFromParent();
1448 C.AndMI->eraseFromParent();
1451 return !Candidates.empty();
1454bool SIPeepholeSDWALegacy::runOnMachineFunction(MachineFunction &MF) {
1458 return SIPeepholeSDWA().run(MF);
1461bool SIPeepholeSDWA::run(MachineFunction &MF) {
1468 TRI =
ST.getRegisterInfo();
1469 TII =
ST.getInstrInfo();
1473 for (MachineBasicBlock &
MBB : MF) {
1476 Ret |= splitLshlOrForSDWA(
MBB);
1482 matchSDWAOperands(
MBB);
1483 for (
const auto &OperandPair : SDWAOperands) {
1484 const auto &Operand = OperandPair.second;
1485 MachineInstr *PotentialMI = Operand->potentialToConvert(
TII, ST);
1490 case AMDGPU::V_ADD_CO_U32_e64:
1491 case AMDGPU::V_SUB_CO_U32_e64:
1492 pseudoOpConvertToVOP2(*PotentialMI, ST);
1494 case AMDGPU::V_CNDMASK_B32_e64:
1495 convertVcndmaskToVOP2(*PotentialMI, ST);
1499 SDWAOperands.clear();
1502 matchSDWAOperands(
MBB);
1504 for (
const auto &OperandPair : SDWAOperands) {
1505 const auto &Operand = OperandPair.second;
1506 MachineInstr *PotentialMI =
1507 Operand->potentialToConvert(
TII, ST, &PotentialMatches);
1509 if (PotentialMI && isConvertibleToSDWA(*PotentialMI, ST,
TII))
1510 PotentialMatches[PotentialMI].push_back(Operand.get());
1513 for (
auto &PotentialPair : PotentialMatches) {
1514 MachineInstr &PotentialMI = *PotentialPair.first;
1515 convertToSDWA(PotentialMI, PotentialPair.second);
1518 PotentialMatches.clear();
1519 SDWAOperands.clear();
1525 while (!ConvertedInstructions.
empty())
1526 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.
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 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