25#define DEBUG_TYPE "si-fold-operands"
46 unsigned DefSubReg = AMDGPU::NoSubRegister;
51 FoldableDef() =
delete;
53 unsigned DefSubReg = AMDGPU::NoSubRegister)
54 : DefRC(DefRC), DefSubReg(DefSubReg), Kind(FoldOp.
getType()) {
57 ImmToFold = FoldOp.
getImm();
58 }
else if (FoldOp.
isFI()) {
59 FrameIndexToFold = FoldOp.
getIndex();
69 unsigned DefSubReg = AMDGPU::NoSubRegister)
70 : ImmToFold(FoldImm), DefRC(DefRC), DefSubReg(DefSubReg),
75 FoldableDef Copy(*
this);
76 Copy.DefSubReg =
TRI.composeSubRegIndices(DefSubReg, SubReg);
84 return OpToFold->getReg();
87 unsigned getSubReg()
const {
89 return OpToFold->getSubReg();
100 return FrameIndexToFold;
108 std::optional<int64_t> getEffectiveImmVal()
const {
116 unsigned OpIdx)
const {
119 std::optional<int64_t> ImmToFold = getEffectiveImmVal();
126 return TII.isOperandLegal(
MI, OpIdx, &TmpOp);
129 if (DefSubReg != AMDGPU::NoSubRegister)
132 return TII.isOperandLegal(
MI, OpIdx, &TmpOp);
137 if (DefSubReg != AMDGPU::NoSubRegister)
139 return TII.isOperandLegal(
MI, OpIdx, OpToFold);
146struct FoldCandidate {
154 bool Commuted =
false,
int ShrinkOp = -1)
155 :
UseMI(
MI), Def(Def), ShrinkOpcode(ShrinkOp), UseOpNo(OpNo),
156 Commuted(Commuted) {}
158 bool isFI()
const {
return Def.isFI(); }
162 return Def.FrameIndexToFold;
165 bool isImm()
const {
return Def.isImm(); }
167 bool isReg()
const {
return Def.isReg(); }
171 bool isGlobal()
const {
return Def.isGlobal(); }
173 bool needsShrink()
const {
return ShrinkOpcode != -1; }
176class SIFoldOperandsImpl {
187 const FoldableDef &OpToFold)
const;
190 unsigned convertToVALUOp(
unsigned Opc,
bool UseVOP3 =
false)
const {
192 case AMDGPU::S_ADD_I32: {
193 if (ST->hasAddNoCarryInsts())
194 return UseVOP3 ? AMDGPU::V_ADD_U32_e64 : AMDGPU::V_ADD_U32_e32;
195 return UseVOP3 ? AMDGPU::V_ADD_CO_U32_e64 : AMDGPU::V_ADD_CO_U32_e32;
197 case AMDGPU::S_OR_B32:
198 return UseVOP3 ? AMDGPU::V_OR_B32_e64 : AMDGPU::V_OR_B32_e32;
199 case AMDGPU::S_AND_B32:
200 return UseVOP3 ? AMDGPU::V_AND_B32_e64 : AMDGPU::V_AND_B32_e32;
201 case AMDGPU::S_MUL_I32:
202 return AMDGPU::V_MUL_LO_U32_e64;
204 return AMDGPU::INSTRUCTION_LIST_END;
208 bool foldCopyToVGPROfScalarAddOfFrameIndex(
Register DstReg,
Register SrcReg,
214 int64_t ImmVal)
const;
218 int64_t ImmVal)
const;
222 const FoldableDef &OpToFold)
const;
225 bool isTemporallyDivergentUse(
const FoldableDef &OpToFold,
233 getRegSeqInit(
SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs,
236 std::pair<int64_t, const TargetRegisterClass *>
250 struct ANDMaskResult {
256 std::optional<ANDMaskResult> getANDMaskRegOperand(
MachineInstr &AndMI)
const;
262 bool foldInstOperand(
MachineInstr &
MI,
const FoldableDef &OpToFold)
const;
264 bool foldCopyToAGPRRegSequence(
MachineInstr *CopyMI)
const;
271 std::pair<const MachineOperand *, int> isOMod(
const MachineInstr &
MI)
const;
281 SIFoldOperandsImpl() =
default;
296 &getAnalysis<MachineLoopInfoWrapperPass>().getLI();
297 return SIFoldOperandsImpl().run(MF, MLI);
300 StringRef getPassName()
const override {
return "SI Fold Operands"; }
322char SIFoldOperandsLegacy::ID = 0;
331 TRI.getSubRegisterClass(RC, MO.getSubReg()))
339 case AMDGPU::V_MAC_F32_e64:
340 return AMDGPU::V_MAD_F32_e64;
341 case AMDGPU::V_MAC_F16_e64:
342 return AMDGPU::V_MAD_F16_e64;
343 case AMDGPU::V_FMAC_F32_e64:
344 return AMDGPU::V_FMA_F32_e64;
345 case AMDGPU::V_FMAC_F16_e64:
346 return AMDGPU::V_FMA_F16_gfx9_e64;
347 case AMDGPU::V_FMAC_F16_t16_e64:
348 return AMDGPU::V_FMA_F16_gfx9_t16_e64;
349 case AMDGPU::V_FMAC_F16_fake16_e64:
350 return AMDGPU::V_FMA_F16_gfx9_fake16_e64;
351 case AMDGPU::V_FMAC_LEGACY_F32_e64:
352 return AMDGPU::V_FMA_LEGACY_F32_e64;
353 case AMDGPU::V_FMAC_F64_e64:
354 return AMDGPU::V_FMA_F64_e64;
356 return AMDGPU::INSTRUCTION_LIST_END;
362 const FoldableDef &OpToFold)
const {
363 if (!OpToFold.isFI())
366 const unsigned Opc =
UseMI.getOpcode();
368 case AMDGPU::S_ADD_I32:
369 case AMDGPU::S_ADD_U32:
370 case AMDGPU::V_ADD_U32_e32:
371 case AMDGPU::V_ADD_CO_U32_e32:
375 return UseMI.getOperand(OpNo == 1 ? 2 : 1).isImm() &&
377 case AMDGPU::V_ADD_U32_e64:
378 case AMDGPU::V_ADD_CO_U32_e64:
379 return UseMI.getOperand(OpNo == 2 ? 3 : 2).isImm() &&
386 return OpNo == AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::vaddr);
390 int SIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::saddr);
394 int VIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::vaddr);
395 return OpNo == VIdx && SIdx == -1;
401bool SIFoldOperandsImpl::foldCopyToVGPROfScalarAddOfFrameIndex(
406 if (
TRI->isVGPR(*MRI, DstReg) &&
TRI->isSGPRReg(*MRI, SrcReg) &&
409 if (!Def ||
Def->getNumOperands() != 4)
412 MachineOperand *
Src0 = &
Def->getOperand(1);
413 MachineOperand *
Src1 = &
Def->getOperand(2);
424 const bool UseVOP3 = !
Src0->isImm() ||
TII->isInlineConstant(*Src0);
425 unsigned NewOp = convertToVALUOp(
Def->getOpcode(), UseVOP3);
426 if (NewOp == AMDGPU::INSTRUCTION_LIST_END ||
427 !
Def->getOperand(3).isDead())
430 MachineBasicBlock *
MBB =
Def->getParent();
432 if (NewOp != AMDGPU::V_ADD_CO_U32_e32) {
433 MachineInstrBuilder
Add =
436 if (
Add->getDesc().getNumDefs() == 2) {
438 Add.addDef(CarryOutReg, RegState::Dead);
442 Add.add(*Src0).add(*Src1).setMIFlags(
Def->getFlags());
446 Def->eraseFromParent();
447 MI.eraseFromParent();
451 assert(NewOp == AMDGPU::V_ADD_CO_U32_e32);
462 Def->eraseFromParent();
463 MI.eraseFromParent();
471bool SIFoldOperandsImpl::canUseImmWithOpSel(
const MachineInstr *
MI,
473 int64_t ImmVal)
const {
479 const MachineOperand &Old =
MI->getOperand(UseOpNo);
480 int OpNo =
MI->getOperandNo(&Old);
482 unsigned Opcode =
MI->getOpcode();
483 uint8_t OpType =
TII->get(Opcode).operands()[OpNo].OperandType;
497 static_cast<uint16_t
>(ImmVal) !=
static_cast<uint16_t
>(ImmVal >> 16))
505bool SIFoldOperandsImpl::tryFoldImmWithOpSel(MachineInstr *
MI,
unsigned UseOpNo,
506 int64_t ImmVal)
const {
507 MachineOperand &Old =
MI->getOperand(UseOpNo);
508 unsigned Opcode =
MI->getOpcode();
509 int OpNo =
MI->getOperandNo(&Old);
510 uint8_t OpType =
TII->get(Opcode).operands()[OpNo].OperandType;
512 bool BF16FromUpperFP32 = ST->hasBF16InlineConstFromUpperFP32() &&
526 AMDGPU::OpName ModName = AMDGPU::OpName::NUM_OPERAND_NAMES;
527 unsigned SrcIdx = ~0;
528 if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src0)) {
529 ModName = AMDGPU::OpName::src0_modifiers;
531 }
else if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src1)) {
532 ModName = AMDGPU::OpName::src1_modifiers;
534 }
else if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src2)) {
535 ModName = AMDGPU::OpName::src2_modifiers;
538 assert(ModName != AMDGPU::OpName::NUM_OPERAND_NAMES);
539 int ModIdx = AMDGPU::getNamedOperandIdx(Opcode, ModName);
540 MachineOperand &
Mod =
MI->getOperand(ModIdx);
541 unsigned ModVal =
Mod.getImm();
547 uint32_t
Imm = (
static_cast<uint32_t
>(ImmHi) << 16) | ImmLo;
552 auto tryFoldToInline = [&](uint32_t
Imm) ->
bool {
561 uint16_t
Lo =
static_cast<uint16_t
>(
Imm);
562 uint16_t
Hi =
static_cast<uint16_t
>(
Imm >> 16);
568 if (BF16FromUpperFP32)
570 Mod.setImm(NewModVal);
575 if (!BF16FromUpperFP32 &&
static_cast<int16_t
>(
Lo) < 0) {
576 int32_t SExt =
static_cast<int16_t
>(
Lo);
578 Mod.setImm(NewModVal);
593 uint32_t Swapped = (
static_cast<uint32_t
>(
Lo) << 16) |
Hi;
594 if (!BF16FromUpperFP32 &&
605 if (tryFoldToInline(
Imm))
614 bool IsUAdd = Opcode == AMDGPU::V_PK_ADD_U16;
615 bool IsUSub = Opcode == AMDGPU::V_PK_SUB_U16;
616 if (SrcIdx == 1 && (IsUAdd || IsUSub)) {
618 AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::clamp);
619 bool Clamp =
MI->getOperand(ClampIdx).getImm() != 0;
622 uint16_t NegLo = -
static_cast<uint16_t
>(
Imm);
623 uint16_t NegHi = -
static_cast<uint16_t
>(
Imm >> 16);
624 uint32_t NegImm = (
static_cast<uint32_t
>(NegHi) << 16) | NegLo;
626 if (tryFoldToInline(NegImm)) {
628 IsUAdd ? AMDGPU::V_PK_SUB_U16 : AMDGPU::V_PK_ADD_U16;
629 MI->setDesc(
TII->get(NegOpcode));
638bool SIFoldOperandsImpl::updateOperand(FoldCandidate &Fold)
const {
639 MachineInstr *
MI = Fold.UseMI;
640 MachineOperand &Old =
MI->getOperand(Fold.UseOpNo);
643 std::optional<int64_t> ImmVal;
645 ImmVal = Fold.Def.getEffectiveImmVal();
647 if (ImmVal && canUseImmWithOpSel(Fold.UseMI, Fold.UseOpNo, *ImmVal)) {
648 if (tryFoldImmWithOpSel(Fold.UseMI, Fold.UseOpNo, *ImmVal))
654 int OpNo =
MI->getOperandNo(&Old);
655 if (!
TII->isOperandLegal(*
MI, OpNo, &New))
662 if ((Fold.isImm() || Fold.isFI() || Fold.isGlobal()) && Fold.needsShrink()) {
670 int Op32 = Fold.ShrinkOpcode;
671 MachineOperand &Dst0 =
MI->getOperand(0);
672 MachineOperand &Dst1 =
MI->getOperand(1);
680 MachineInstr *Inst32 =
TII->buildShrunkInst(*
MI, Op32);
682 if (HaveNonDbgCarryUse) {
685 .
addReg(AMDGPU::VCC, RegState::Kill);
699 for (
unsigned I =
MI->getNumOperands() - 1;
I > 0; --
I)
700 MI->removeOperand(
I);
701 MI->setDesc(
TII->get(AMDGPU::IMPLICIT_DEF));
704 TII->commuteInstruction(*Inst32,
false);
708 assert(!Fold.needsShrink() &&
"not handled");
713 if (NewMFMAOpc == -1)
715 MI->setDesc(
TII->get(NewMFMAOpc));
716 MI->untieRegOperand(0);
717 const MCInstrDesc &MCID =
MI->getDesc();
718 for (
unsigned I = 0;
I <
MI->getNumDefs(); ++
I)
720 MI->getOperand(
I).setIsEarlyClobber(
true);
725 int OpNo =
MI->getOperandNo(&Old);
726 if (!
TII->isOperandLegal(*
MI, OpNo, &New))
729 if (ST->hasBF16InlineConstFromUpperFP32() &&
731 AMDGPU::getNamedOperandIdx(
MI->getOpcode(), AMDGPU::OpName::src0)) {
732 unsigned Opcode =
MI->getOpcode();
733 uint8_t OpType =
TII->get(Opcode).operands()[OpNo].OperandType;
736 TII->isInlineConstant(*ImmVal, OpType)) {
739 AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src0_modifiers);
742 MachineOperand &ModOp =
MI->getOperand(Mod0);
753 if (Fold.isGlobal()) {
754 Old.
ChangeToGA(Fold.Def.OpToFold->getGlobal(),
755 Fold.Def.OpToFold->getOffset(),
756 Fold.Def.OpToFold->getTargetFlags());
765 MachineOperand *
New = Fold.Def.OpToFold;
769 TII->getRegClass(
MI->getDesc(), Fold.UseOpNo)) {
771 TRI->getRegClassForReg(*MRI,
New->getReg());
774 if (
New->getSubReg()) {
776 TRI->getMatchingSuperRegClass(NewRC, OpRC,
New->getSubReg());
782 if (
New->getReg().isVirtual() &&
785 <<
TRI->getRegClassName(ConstrainRC) <<
'\n');
792 if (Old.
getSubReg() == AMDGPU::lo16 &&
TRI->isSGPRReg(*MRI,
New->getReg()))
794 if (
New->getReg().isPhysical()) {
802 if (
MI->isBundledWithPred()) {
804 for (MachineOperand &MO : Header.operands()) {
805 if (MO.getReg() == OldReg) {
806 MO.setReg(
New->getReg());
807 MO.setSubReg(
New->getSubReg());
816 FoldCandidate &&Entry) {
818 for (FoldCandidate &Fold : FoldList)
819 if (Fold.UseMI == Entry.UseMI && Fold.UseOpNo == Entry.UseOpNo)
821 LLVM_DEBUG(
dbgs() <<
"Append " << (Entry.Commuted ?
"commuted" :
"normal")
822 <<
" operand " << Entry.UseOpNo <<
"\n " << *Entry.UseMI);
828 const FoldableDef &FoldOp,
829 bool Commuted =
false,
int ShrinkOp = -1) {
831 FoldCandidate(
MI, OpNo, FoldOp, Commuted, ShrinkOp));
839 if (!ST->hasPKF32InstsReplicatingLower32BitsOfScalarInput())
849 const FoldableDef &OpToFold) {
850 assert(OpToFold.isImm() &&
"Expected immediate operand");
851 uint64_t ImmVal = OpToFold.getEffectiveImmVal().value();
857bool SIFoldOperandsImpl::tryAddToFoldList(
858 SmallVectorImpl<FoldCandidate> &FoldList, MachineInstr *
MI,
unsigned OpNo,
859 const FoldableDef &OpToFold)
const {
860 const unsigned Opc =
MI->getOpcode();
862 auto tryToFoldAsFMAAKorMK = [&]() {
863 if (!OpToFold.isImm())
866 const bool TryAK = OpNo == 3;
867 const unsigned NewOpc = TryAK ? AMDGPU::S_FMAAK_F32 : AMDGPU::S_FMAMK_F32;
868 MI->setDesc(
TII->get(NewOpc));
871 bool FoldAsFMAAKorMK =
872 tryAddToFoldList(FoldList,
MI, TryAK ? 3 : 2, OpToFold);
873 if (FoldAsFMAAKorMK) {
875 MI->untieRegOperand(3);
878 MachineOperand &Op1 =
MI->getOperand(1);
879 MachineOperand &Op2 =
MI->getOperand(2);
896 bool IsLegal = OpToFold.isOperandLegal(*
TII, *
MI, OpNo);
897 if (!IsLegal && OpToFold.isImm()) {
898 if (std::optional<int64_t> ImmVal = OpToFold.getEffectiveImmVal())
899 IsLegal = canUseImmWithOpSel(
MI, OpNo, *ImmVal);
905 if (NewOpc != AMDGPU::INSTRUCTION_LIST_END) {
908 MI->setDesc(
TII->get(NewOpc));
913 bool FoldAsMAD = tryAddToFoldList(FoldList,
MI, OpNo, OpToFold);
915 MI->untieRegOperand(OpNo);
919 MI->removeOperand(
MI->getNumExplicitOperands() - 1);
925 if (
Opc == AMDGPU::S_FMAC_F32 && OpNo == 3) {
926 if (tryToFoldAsFMAAKorMK())
932 if ((
Opc == AMDGPU::S_FMAAK_F32 ||
Opc == AMDGPU::S_FMAMK_F32) &&
934 std::optional<int64_t> ImmVal = OpToFold.getEffectiveImmVal();
935 if (ImmVal && !
TII->isInlineConstant(*
MI, OpNo, *ImmVal)) {
936 unsigned ImmIdx =
Opc == AMDGPU::S_FMAAK_F32 ? 3 : 2;
937 MachineOperand &OpImm =
MI->getOperand(ImmIdx);
938 if (!OpImm.
isReg() &&
939 TII->isInlineConstant(*
MI,
MI->getOperand(OpNo), OpImm))
940 return tryToFoldAsFMAAKorMK();
945 if (OpToFold.isImm()) {
947 if (
Opc == AMDGPU::S_SETREG_B32)
948 ImmOpc = AMDGPU::S_SETREG_IMM32_B32;
949 else if (
Opc == AMDGPU::S_SETREG_B32_mode)
950 ImmOpc = AMDGPU::S_SETREG_IMM32_B32_mode;
952 MI->setDesc(
TII->get(ImmOpc));
961 bool CanCommute =
TII->findCommutedOpIndices(*
MI, OpNo, CommuteOpNo);
965 MachineOperand &
Op =
MI->getOperand(OpNo);
966 MachineOperand &CommutedOp =
MI->getOperand(CommuteOpNo);
972 if (!
Op.isReg() || !CommutedOp.
isReg())
977 if (
Op.isReg() && CommutedOp.
isReg() &&
978 (
Op.getReg() == CommutedOp.
getReg() &&
982 if (!
TII->commuteInstruction(*
MI,
false, OpNo, CommuteOpNo))
986 if (!OpToFold.isOperandLegal(*
TII, *
MI, CommuteOpNo)) {
987 if ((
Opc != AMDGPU::V_ADD_CO_U32_e64 &&
Opc != AMDGPU::V_SUB_CO_U32_e64 &&
988 Opc != AMDGPU::V_SUBREV_CO_U32_e64) ||
989 (!OpToFold.isImm() && !OpToFold.isFI() && !OpToFold.isGlobal())) {
990 TII->commuteInstruction(*
MI,
false, OpNo, CommuteOpNo);
996 MachineOperand &OtherOp =
MI->getOperand(OpNo);
997 if (!OtherOp.
isReg() ||
1004 unsigned MaybeCommutedOpc =
MI->getOpcode();
1018 if (
Opc == AMDGPU::S_FMAC_F32 &&
1019 (OpNo != 1 || !
MI->getOperand(1).isIdenticalTo(
MI->getOperand(2)))) {
1020 if (tryToFoldAsFMAAKorMK())
1026 if (OpToFold.isImm() &&
1035bool SIFoldOperandsImpl::isUseSafeToFold(
const MachineInstr &
MI,
1036 const MachineOperand &UseMO)
const {
1038 return !
TII->isSDWA(
MI);
1045 if (
MI.modifiesRegister(
TRI.getExec(), &
TRI))
1053bool SIFoldOperandsImpl::isTemporallyDivergentUse(
1054 const FoldableDef &OpToFold,
const MachineInstr &
UseMI)
const {
1055 if (!OpToFold.isReg())
1057 const MachineInstr *
DefMI = OpToFold.DefMI;
1060 !
TRI->isSGPRReg(*MRI, OpToFold.getReg()))
1072 SubDef &&
TII.isFoldableCopy(*SubDef);
1074 unsigned SrcIdx =
TII.getFoldableCopySrcIdx(*SubDef);
1083 if (
SrcOp.getSubReg())
1091 MachineInstr &RegSeq,
1092 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs)
const {
1108 else if (!
TRI->getCommonSubClass(RC, OpRC))
1113 Defs.emplace_back(&SrcOp, SubRegIdx);
1118 if (DefSrc && (DefSrc->
isReg() || DefSrc->
isImm())) {
1119 Defs.emplace_back(DefSrc, SubRegIdx);
1123 Defs.emplace_back(&SrcOp, SubRegIdx);
1133 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs,
1136 if (!Def || !
Def->isRegSequence())
1139 return getRegSeqInit(*Def, Defs);
1142std::pair<int64_t, const TargetRegisterClass *>
1143SIFoldOperandsImpl::isRegSeqSplat(MachineInstr &RegSeq)
const {
1149 bool TryToMatchSplat64 =
false;
1151 std::optional<int64_t>
Imm;
1152 for (
unsigned I = 0,
E = Defs.
size();
I !=
E; ++
I) {
1153 const MachineOperand *
Op = Defs[
I].first;
1157 if (!Def ||
Def->isImplicitDef())
1163 int64_t SubImm =
Op->getImm();
1169 if (
Imm != SubImm) {
1170 if (
I == 1 && (
E & 1) == 0) {
1173 TryToMatchSplat64 =
true;
1181 if (!TryToMatchSplat64) {
1183 return {*
Imm, SrcRC};
1190 for (
unsigned I = 0,
E = Defs.
size();
I !=
E;
I += 2) {
1191 const MachineOperand *Op0 = Defs[
I].first;
1192 const MachineOperand *Op1 = Defs[
I + 1].first;
1197 unsigned SubReg0 = Defs[
I].second;
1198 unsigned SubReg1 = Defs[
I + 1].second;
1202 if (
TRI->getChannelFromSubReg(SubReg0) + 1 !=
1203 TRI->getChannelFromSubReg(SubReg1))
1206 if (
TRI->getSubRegIdxSize(SubReg0) != 32)
1211 SplatVal64 = MergedVal;
1212 else if (SplatVal64 != MergedVal)
1219 return {SplatVal64, RC64};
1222bool SIFoldOperandsImpl::tryFoldRegSeqSplat(
1223 MachineInstr *
UseMI,
unsigned UseOpIdx, int64_t SplatVal,
1226 if (UseOpIdx >=
Desc.getNumOperands())
1233 int16_t RCID =
TII->getOpRegClassID(
Desc.operands()[UseOpIdx]);
1242 if (SplatVal != 0 && SplatVal != -1) {
1246 uint8_t OpTy =
Desc.operands()[UseOpIdx].OperandType;
1253 OpRC =
TRI->getSubRegisterClass(OpRC, AMDGPU::sub0);
1260 OpRC =
TRI->getSubRegisterClass(OpRC, AMDGPU::sub0_sub1);
1266 if (!
TRI->getCommonSubClass(OpRC, SplatRC))
1271 if (!
TII->isOperandLegal(*
UseMI, UseOpIdx, &TmpOp))
1277bool SIFoldOperandsImpl::tryToFoldACImm(
1278 const FoldableDef &OpToFold, MachineInstr *
UseMI,
unsigned UseOpIdx,
1279 SmallVectorImpl<FoldCandidate> &FoldList)
const {
1281 if (UseOpIdx >=
Desc.getNumOperands())
1288 if (OpToFold.isImm() && OpToFold.isOperandLegal(*
TII, *
UseMI, UseOpIdx)) {
1299bool SIFoldOperandsImpl::foldOperand(
1300 FoldableDef OpToFold, MachineInstr *
UseMI,
int UseOpIdx,
1301 SmallVectorImpl<FoldCandidate> &FoldList,
1302 SmallVectorImpl<MachineInstr *> &CopiesToReplace)
const {
1306 if (!isUseSafeToFold(*
UseMI, *UseOp))
1309 if (isTemporallyDivergentUse(OpToFold, *
UseMI))
1313 if (UseOp->
isReg() && OpToFold.isReg()) {
1317 if (UseOp->
getSubReg() != AMDGPU::NoSubRegister &&
1319 !
TRI->isSGPRReg(*MRI, OpToFold.getReg())))
1332 std::tie(SplatVal, SplatRC) = isRegSeqSplat(*
UseMI);
1337 for (
unsigned I = 0;
I != UsesToProcess.size(); ++
I) {
1338 MachineOperand *RSUse = UsesToProcess[
I];
1339 MachineInstr *RSUseMI = RSUse->
getParent();
1349 if (tryFoldRegSeqSplat(RSUseMI, OpNo, SplatVal, SplatRC)) {
1350 FoldableDef SplatDef(SplatVal, SplatRC);
1358 if (RSUse->
getSubReg() != RegSeqDstSubReg)
1364 FoldList, CopiesToReplace);
1370 if (tryToFoldACImm(OpToFold,
UseMI, UseOpIdx, FoldList))
1373 if (frameIndexMayFold(*
UseMI, UseOpIdx, OpToFold)) {
1378 if (
TII->getNamedOperand(*
UseMI, AMDGPU::OpName::srsrc)->getReg() !=
1384 MachineOperand &SOff =
1385 *
TII->getNamedOperand(*
UseMI, AMDGPU::OpName::soffset);
1396 TII->getNamedOperand(*
UseMI, AMDGPU::OpName::cpol)->getImm();
1411 bool FoldingImmLike =
1412 OpToFold.isImm() || OpToFold.isFI() || OpToFold.isGlobal();
1431 for (
unsigned MovOp :
1432 {AMDGPU::S_MOV_B32, AMDGPU::V_MOV_B32_e32, AMDGPU::S_MOV_B64,
1433 AMDGPU::V_MOV_B64_PSEUDO, AMDGPU::V_MOV_B16_t16_e64,
1434 AMDGPU::V_ACCVGPR_WRITE_B32_e64, AMDGPU::AV_MOV_B32_IMM_PSEUDO,
1435 AMDGPU::AV_MOV_B64_IMM_PSEUDO}) {
1436 const MCInstrDesc &MovDesc =
TII->get(MovOp);
1446 const int SrcIdx = MovOp == AMDGPU::V_MOV_B16_t16_e64 ? 2 : 1;
1448 int16_t RegClassID =
TII->getOpRegClassID(MovDesc.
operands()[SrcIdx]);
1449 if (RegClassID != -1) {
1453 MovSrcRC =
TRI->getMatchingSuperRegClass(SrcRC, MovSrcRC, UseSubReg);
1457 if (MovOp == AMDGPU::AV_MOV_B32_IMM_PSEUDO &&
1458 (!OpToFold.isImm() ||
1459 !
TII->isImmOperandLegal(MovDesc, SrcIdx,
1460 *OpToFold.getEffectiveImmVal())))
1473 if (!OpToFold.isImm() ||
1474 !
TII->isImmOperandLegal(MovDesc, 1, *OpToFold.getEffectiveImmVal()))
1480 while (ImpOpI != ImpOpE) {
1487 if (MovOp == AMDGPU::V_MOV_B16_t16_e64) {
1489 MachineOperand NewSrcOp(SrcOp);
1511 LLVM_DEBUG(
dbgs() <<
"Folding " << *OpToFold.OpToFold <<
"\n into "
1516 unsigned SubRegIdx = OpToFold.getSubReg();
1521 TRI->isSGPRReg(*MRI,
UseReg) && SubRegIdx != AMDGPU::NoSubRegister) {
1524 unsigned Channel =
TRI->getChannelFromSubReg(SubRegIdx);
1526 SubRegIdx =
TRI->getRegSizeInBits(*UseRC) == 32
1527 ? AMDGPU::NoSubRegister
1533 OpToFold.OpToFold->setIsKill(
false);
1538 if (foldCopyToAGPRRegSequence(
UseMI))
1543 if (UseOpc == AMDGPU::V_READFIRSTLANE_B32 ||
1544 (UseOpc == AMDGPU::V_READLANE_B32 &&
1546 AMDGPU::getNamedOperandIdx(UseOpc, AMDGPU::OpName::src0))) {
1551 if (FoldingImmLike) {
1554 *OpToFold.DefMI, *
UseMI))
1560 if (OpToFold.isImm()) {
1562 *OpToFold.getEffectiveImmVal());
1563 }
else if (OpToFold.isFI())
1566 assert(OpToFold.isGlobal());
1568 OpToFold.OpToFold->getOffset(),
1569 OpToFold.OpToFold->getTargetFlags());
1575 if (OpToFold.isReg() &&
TRI->isSGPRReg(*MRI, OpToFold.getReg())) {
1578 *OpToFold.DefMI, *
UseMI))
1600 UseDesc.
operands()[UseOpIdx].RegClass == -1)
1608 Changed |= tryAddToFoldList(FoldList,
UseMI, UseOpIdx, OpToFold);
1615 case AMDGPU::S_ADD_I32:
1616 case AMDGPU::S_ADD_U32:
1619 case AMDGPU::S_SUB_I32:
1620 case AMDGPU::S_SUB_U32:
1623 case AMDGPU::V_AND_B32_e64:
1624 case AMDGPU::V_AND_B32_e32:
1625 case AMDGPU::S_AND_B32:
1628 case AMDGPU::V_OR_B32_e64:
1629 case AMDGPU::V_OR_B32_e32:
1630 case AMDGPU::S_OR_B32:
1633 case AMDGPU::V_XOR_B32_e64:
1634 case AMDGPU::V_XOR_B32_e32:
1635 case AMDGPU::S_XOR_B32:
1638 case AMDGPU::S_XNOR_B32:
1641 case AMDGPU::S_NAND_B32:
1644 case AMDGPU::S_NOR_B32:
1647 case AMDGPU::S_ANDN2_B32:
1650 case AMDGPU::S_ORN2_B32:
1653 case AMDGPU::V_LSHL_B32_e64:
1654 case AMDGPU::V_LSHL_B32_e32:
1655 case AMDGPU::S_LSHL_B32:
1657 Result =
LHS << (
RHS & 31);
1659 case AMDGPU::V_LSHLREV_B32_e64:
1660 case AMDGPU::V_LSHLREV_B32_e32:
1661 Result =
RHS << (
LHS & 31);
1663 case AMDGPU::V_LSHR_B32_e64:
1664 case AMDGPU::V_LSHR_B32_e32:
1665 case AMDGPU::S_LSHR_B32:
1666 Result =
LHS >> (
RHS & 31);
1668 case AMDGPU::V_LSHRREV_B32_e64:
1669 case AMDGPU::V_LSHRREV_B32_e32:
1670 Result =
RHS >> (
LHS & 31);
1672 case AMDGPU::V_ASHR_I32_e64:
1673 case AMDGPU::V_ASHR_I32_e32:
1674 case AMDGPU::S_ASHR_I32:
1675 Result =
static_cast<int32_t
>(
LHS) >> (
RHS & 31);
1677 case AMDGPU::V_ASHRREV_I32_e64:
1678 case AMDGPU::V_ASHRREV_I32_e32:
1679 Result =
static_cast<int32_t
>(
RHS) >> (
LHS & 31);
1687 return IsScalar ? AMDGPU::S_MOV_B32 : AMDGPU::V_MOV_B32_e32;
1693bool SIFoldOperandsImpl::tryConstantFoldOp(MachineInstr *
MI)
const {
1694 if (!
MI->allImplicitDefsAreDead())
1697 unsigned Opc =
MI->getOpcode();
1699 int Src0Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src0);
1703 MachineOperand *
Src0 = &
MI->getOperand(Src0Idx);
1704 std::optional<int64_t> Src0Imm =
TII->getImmOrMaterializedImm(*MRI, *Src0);
1706 if ((
Opc == AMDGPU::V_NOT_B32_e64 ||
Opc == AMDGPU::V_NOT_B32_e32 ||
1707 Opc == AMDGPU::S_NOT_B32) &&
1709 MI->getOperand(1).ChangeToImmediate(~*Src0Imm);
1710 TII->mutateAndCleanupImplicit(
1715 int Src1Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src1);
1719 MachineOperand *
Src1 = &
MI->getOperand(Src1Idx);
1720 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*MRI, *Src1);
1722 if (!Src0Imm && !Src1Imm)
1728 if (Src0Imm && Src1Imm) {
1733 bool IsSGPR =
TRI->isSGPRReg(*MRI,
MI->getOperand(0).getReg());
1737 MI->getOperand(Src0Idx).ChangeToImmediate(NewImm);
1738 MI->removeOperand(Src1Idx);
1745 if (
Opc == AMDGPU::S_SUB_I32 ||
Opc == AMDGPU::S_SUB_U32) {
1746 if (Src1Imm &&
static_cast<int32_t
>(*Src1Imm) == 0) {
1748 MI->removeOperand(Src1Idx);
1749 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1755 if (!
MI->isCommutable())
1758 if (Src0Imm && !Src1Imm) {
1764 int32_t Src1Val =
static_cast<int32_t
>(*Src1Imm);
1765 if (
Opc == AMDGPU::S_ADD_I32 ||
Opc == AMDGPU::S_ADD_U32) {
1768 MI->removeOperand(Src1Idx);
1769 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1775 if (
Opc == AMDGPU::V_OR_B32_e64 ||
1776 Opc == AMDGPU::V_OR_B32_e32 ||
1777 Opc == AMDGPU::S_OR_B32) {
1780 MI->removeOperand(Src1Idx);
1781 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1782 }
else if (Src1Val == -1) {
1784 MI->removeOperand(Src0Idx);
1785 TII->mutateAndCleanupImplicit(
1793 if (
Opc == AMDGPU::V_AND_B32_e64 ||
Opc == AMDGPU::V_AND_B32_e32 ||
1794 Opc == AMDGPU::S_AND_B32) {
1797 MI->removeOperand(Src0Idx);
1798 TII->mutateAndCleanupImplicit(
1800 }
else if (Src1Val == -1) {
1802 MI->removeOperand(Src1Idx);
1803 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1810 if (
Opc == AMDGPU::V_XOR_B32_e64 ||
Opc == AMDGPU::V_XOR_B32_e32 ||
1811 Opc == AMDGPU::S_XOR_B32) {
1814 MI->removeOperand(Src1Idx);
1815 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1824bool SIFoldOperandsImpl::tryFoldCndMask(MachineInstr &
MI)
const {
1825 unsigned Opc =
MI.getOpcode();
1826 if (
Opc != AMDGPU::V_CNDMASK_B32_e32 &&
Opc != AMDGPU::V_CNDMASK_B32_e64 &&
1827 Opc != AMDGPU::V_CNDMASK_B64_PSEUDO)
1830 MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
1831 MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
1832 if (!
Src1->isIdenticalTo(*Src0)) {
1833 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*MRI, *Src1);
1837 std::optional<int64_t> Src0Imm =
TII->getImmOrMaterializedImm(*MRI, *Src0);
1838 if (!Src0Imm || *Src0Imm != *Src1Imm)
1843 AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src1_modifiers);
1845 AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src0_modifiers);
1846 if ((Src1ModIdx != -1 &&
MI.getOperand(Src1ModIdx).getImm() != 0) ||
1847 (Src0ModIdx != -1 &&
MI.getOperand(Src0ModIdx).getImm() != 0))
1853 int Src2Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
1855 MI.removeOperand(Src2Idx);
1856 MI.removeOperand(AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src1));
1857 if (Src1ModIdx != -1)
1858 MI.removeOperand(Src1ModIdx);
1859 if (Src0ModIdx != -1)
1860 MI.removeOperand(Src0ModIdx);
1861 TII->mutateAndCleanupImplicit(
MI, NewDesc);
1868std::optional<SIFoldOperandsImpl::ANDMaskResult>
1869SIFoldOperandsImpl::getANDMaskRegOperand(MachineInstr &AndMI)
const {
1871 if (
Opc != AMDGPU::V_AND_B32_e64 &&
Opc != AMDGPU::V_AND_B32_e32 &&
1872 Opc != AMDGPU::S_AND_B32)
1873 return std::nullopt;
1875 std::optional<int64_t> MaskImm =
1880 MaskImm =
TII->getImmOrMaterializedImm(*MRI, AndMI.
getOperand(2));
1884 return std::nullopt;
1897bool SIFoldOperandsImpl::tryFoldRedundantAND(MachineInstr &ChildMI)
const {
1902 std::optional<ANDMaskResult> ChildResult = getANDMaskRegOperand(ChildMI);
1906 if (!ChildResult->Reg.isVirtual())
1909 MachineInstr *ParentMI = MRI->
getVRegDef(ChildResult->Reg);
1913 int64_t ParentMask = 0;
1914 std::optional<ANDMaskResult> ParentResult = getANDMaskRegOperand(*ParentMI);
1917 ParentMask = ParentResult->Mask;
1920 ParentMask = 0xffff;
1926 if ((ParentMask & ChildResult->Mask) != ParentMask)
1953bool SIFoldOperandsImpl::tryFoldAndExec(MachineInstr &
MI)
const {
1959 if (!
MI.allImplicitDefsAreDead())
1963 unsigned ExecIdx = 0;
1964 for (
unsigned I : {1u, 2u}) {
1965 const MachineOperand &MO =
MI.getOperand(
I);
1971 MachineOperand &Src =
MI.getOperand(3 - ExecIdx);
1972 if (!Src.isReg() || !Src.getReg().isVirtual() || Src.getSubReg())
1976 if (!
TII->isMaskedByExec(SrcReg,
MI, *MRI))
1996 MI.eraseFromParent();
2000bool SIFoldOperandsImpl::foldInstOperand(MachineInstr &
MI,
2001 const FoldableDef &OpToFold)
const {
2005 SmallVector<MachineInstr *, 4> CopiesToReplace;
2007 MachineOperand &Dst =
MI.getOperand(0);
2012 for (
auto *U : UsesToProcess) {
2013 MachineInstr *
UseMI =
U->getParent();
2015 FoldableDef SubOpToFold = OpToFold.getWithSubReg(*
TRI,
U->getSubReg());
2020 if (CopiesToReplace.
empty() && FoldList.
empty())
2024 for (MachineInstr *Copy : CopiesToReplace)
2025 Copy->addImplicitDefUseOperands(*MF);
2027 SetVector<MachineInstr *> ConstantFoldCandidates;
2028 for (FoldCandidate &Fold : FoldList) {
2029 assert(!Fold.isReg() || Fold.Def.OpToFold);
2030 if (Fold.isReg() && Fold.getReg().isVirtual()) {
2032 const MachineInstr *
DefMI = Fold.Def.DefMI;
2040 assert(Fold.Def.OpToFold && Fold.isReg());
2047 <<
static_cast<int>(Fold.UseOpNo) <<
" of "
2051 ConstantFoldCandidates.
insert(Fold.UseMI);
2053 }
else if (Fold.Commuted) {
2055 TII->commuteInstruction(*Fold.UseMI,
false);
2059 for (MachineInstr *
MI : ConstantFoldCandidates) {
2060 if (tryConstantFoldOp(
MI)) {
2070bool SIFoldOperandsImpl::foldCopyToAGPRRegSequence(MachineInstr *CopyMI)
const {
2077 if (!
TRI->isAGPRClass(DefRC))
2089 DenseMap<TargetInstrInfo::RegSubRegPair, Register> VGPRCopies;
2098 unsigned NumFoldable = 0;
2100 for (
unsigned I = 1;
I != NumRegSeqOperands;
I += 2) {
2117 DefRC, &AMDGPU::AGPR_32RegClass, SubRegIdx);
2137 TRI->getMatchingSuperRegClass(DefRC, InputRC, SubRegIdx);
2148 if (NumFoldable == 0)
2151 CopyMI->
setDesc(
TII->get(AMDGPU::REG_SEQUENCE));
2155 for (
auto [Def, DestSubIdx] : NewDefs) {
2156 if (!
Def->isReg()) {
2160 BuildMI(
MBB, CopyMI,
DL,
TII->get(AMDGPU::V_ACCVGPR_WRITE_B32_e64), Tmp)
2165 Def->setIsKill(
false);
2167 Register &VGPRCopy = VGPRCopies[Src];
2170 TRI->getSubRegisterClass(UseRC, DestSubIdx);
2195 B.addImm(DestSubIdx);
2202bool SIFoldOperandsImpl::tryFoldFoldableCopy(
2203 MachineInstr &
MI, MachineOperand *&CurrentKnownM0Val)
const {
2207 if (DstReg == AMDGPU::M0) {
2208 MachineOperand &NewM0Val =
MI.getOperand(1);
2209 if (CurrentKnownM0Val && CurrentKnownM0Val->
isIdenticalTo(NewM0Val)) {
2210 MI.eraseFromParent();
2221 MachineOperand *OpToFoldPtr;
2222 if (
MI.getOpcode() == AMDGPU::V_MOV_B16_t16_e64) {
2224 if (
TII->hasAnyModifiersSet(
MI))
2226 OpToFoldPtr = &
MI.getOperand(2);
2228 OpToFoldPtr = &
MI.getOperand(1);
2229 MachineOperand &OpToFold = *OpToFoldPtr;
2233 if (!FoldingImm && !OpToFold.
isReg())
2238 !
TRI->isConstantPhysReg(OpToFold.
getReg()))
2267 if (
MI.getOpcode() == AMDGPU::COPY && OpToFold.
isReg() &&
2269 if (DstRC == &AMDGPU::SReg_32RegClass &&
2271 if (!
TRI->getMatchingSuperRegClass(DstRC, &AMDGPU::SGPR_LO16RegClass,
2280 if (OpToFold.
isReg() &&
MI.isCopy() && !
MI.getOperand(1).getSubReg()) {
2281 if (foldCopyToAGPRRegSequence(&
MI))
2285 FoldableDef
Def(OpToFold, DstRC);
2286 bool Changed = foldInstOperand(
MI, Def);
2293 auto *InstToErase = &
MI;
2295 auto &SrcOp = InstToErase->getOperand(1);
2297 InstToErase->eraseFromParent();
2299 InstToErase =
nullptr;
2303 if (!InstToErase || !
TII->isFoldableCopy(*InstToErase))
2307 if (InstToErase && InstToErase->isRegSequence() &&
2309 InstToErase->eraseFromParent();
2319 return OpToFold.
isReg() &&
2320 foldCopyToVGPROfScalarAddOfFrameIndex(DstReg, OpToFold.
getReg(),
MI);
2325const MachineOperand *
2326SIFoldOperandsImpl::isClamp(
const MachineInstr &
MI)
const {
2327 unsigned Op =
MI.getOpcode();
2329 case AMDGPU::V_MAX_F32_e64:
2330 case AMDGPU::V_MAX_F16_e64:
2331 case AMDGPU::V_MAX_F16_t16_e64:
2332 case AMDGPU::V_MAX_F16_fake16_e64:
2333 case AMDGPU::V_MAX_F64_e64:
2334 case AMDGPU::V_MAX_NUM_F64_e64:
2335 case AMDGPU::V_PK_MAX_F16:
2336 case AMDGPU::V_MAX_BF16_PSEUDO_e64:
2337 case AMDGPU::V_PK_MAX_NUM_BF16: {
2338 if (
MI.mayRaiseFPException())
2341 if (!
TII->getNamedOperand(
MI, AMDGPU::OpName::clamp)->getImm())
2345 const MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2346 const MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2347 if (!
Src0->isReg() || !
Src1->isReg() ||
2348 Src0->getReg() !=
Src1->getReg() ||
2349 Src0->getSubReg() !=
Src1->getSubReg() ||
2350 Src0->getSubReg() != AMDGPU::NoSubRegister)
2354 if (
TII->hasModifiersSet(
MI, AMDGPU::OpName::omod))
2358 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers)->getImm();
2360 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers)->getImm();
2364 unsigned UnsetMods =
2365 (
Op == AMDGPU::V_PK_MAX_F16 ||
Op == AMDGPU::V_PK_MAX_NUM_BF16)
2368 if (Src0Mods != UnsetMods || Src1Mods != UnsetMods)
2378bool SIFoldOperandsImpl::tryFoldClamp(MachineInstr &
MI) {
2379 const MachineOperand *ClampSrc = isClamp(
MI);
2395 if (
Def->mayRaiseFPException())
2398 MachineOperand *DefClamp =
TII->getNamedOperand(*Def, AMDGPU::OpName::clamp);
2402 LLVM_DEBUG(
dbgs() <<
"Folding clamp " << *DefClamp <<
" into " << *Def);
2408 Register MIDstReg =
MI.getOperand(0).getReg();
2409 if (
TRI->isSGPRReg(*MRI, DefReg)) {
2418 MI.eraseFromParent();
2423 if (
TII->convertToThreeAddress(*Def,
nullptr))
2424 Def->eraseFromParent();
2431 case AMDGPU::V_MUL_F64_e64:
2432 case AMDGPU::V_MUL_F64_pseudo_e64: {
2434 case 0x3fe0000000000000:
2436 case 0x4000000000000000:
2438 case 0x4010000000000000:
2444 case AMDGPU::V_MUL_F32_e64: {
2445 switch (
static_cast<uint32_t>(Val)) {
2456 case AMDGPU::V_MUL_F16_e64:
2457 case AMDGPU::V_MUL_F16_t16_e64:
2458 case AMDGPU::V_MUL_F16_fake16_e64: {
2459 switch (
static_cast<uint16_t>(Val)) {
2470 case AMDGPU::V_PK_MUL_BF16: {
2471 switch (
static_cast<uint16_t>(Val)) {
2490std::pair<const MachineOperand *, int>
2491SIFoldOperandsImpl::isOMod(
const MachineInstr &
MI)
const {
2492 unsigned Op =
MI.getOpcode();
2494 case AMDGPU::V_MUL_F64_e64:
2495 case AMDGPU::V_MUL_F64_pseudo_e64:
2496 case AMDGPU::V_MUL_F32_e64:
2497 case AMDGPU::V_MUL_F16_t16_e64:
2498 case AMDGPU::V_MUL_F16_fake16_e64:
2499 case AMDGPU::V_MUL_F16_e64: {
2501 if ((
Op == AMDGPU::V_MUL_F32_e64 &&
2503 ((
Op == AMDGPU::V_MUL_F64_e64 ||
Op == AMDGPU::V_MUL_F64_pseudo_e64 ||
2504 Op == AMDGPU::V_MUL_F16_e64 ||
Op == AMDGPU::V_MUL_F16_t16_e64 ||
2505 Op == AMDGPU::V_MUL_F16_fake16_e64) &&
2508 MI.mayRaiseFPException())
2511 const MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2512 const MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2515 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*MRI, *Src1);
2521 TII->hasModifiersSet(
MI, AMDGPU::OpName::src0_modifiers) ||
2522 TII->hasModifiersSet(
MI, AMDGPU::OpName::src1_modifiers) ||
2523 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod) ||
2524 TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp))
2527 return {
Src0, OMod};
2529 case AMDGPU::V_ADD_F64_e64:
2530 case AMDGPU::V_ADD_F64_pseudo_e64:
2531 case AMDGPU::V_ADD_F32_e64:
2532 case AMDGPU::V_ADD_F16_e64:
2533 case AMDGPU::V_ADD_F16_t16_e64:
2534 case AMDGPU::V_ADD_F16_fake16_e64: {
2536 if ((
Op == AMDGPU::V_ADD_F32_e64 &&
2538 ((
Op == AMDGPU::V_ADD_F64_e64 ||
Op == AMDGPU::V_ADD_F64_pseudo_e64 ||
2539 Op == AMDGPU::V_ADD_F16_e64 ||
Op == AMDGPU::V_ADD_F16_t16_e64 ||
2540 Op == AMDGPU::V_ADD_F16_fake16_e64) &&
2545 const MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2546 const MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2549 Src0->getSubReg() ==
Src1->getSubReg() &&
2550 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::src0_modifiers) &&
2551 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::src1_modifiers) &&
2552 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp) &&
2553 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::omod))
2558 case AMDGPU::V_PK_MUL_BF16: {
2563 MI.mayRaiseFPException())
2566 const MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2567 const MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2570 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*MRI, *Src1);
2574 int OMod =
getOModValue(AMDGPU::V_PK_MUL_BF16, *Src1Imm);
2581 const MachineOperand *Src0Mods =
2582 TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers);
2583 const MachineOperand *Src1Mods =
2584 TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers);
2587 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod) ||
2588 TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp))
2591 return {
Src0, OMod};
2593 case AMDGPU::V_PK_ADD_BF16: {
2599 const MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2600 const MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2602 if (!
Src0->isReg() || !
Src1->isReg() ||
Src0->getReg() !=
Src1->getReg() ||
2603 Src0->getSubReg() !=
Src1->getSubReg())
2607 const MachineOperand *Src0Mods =
2608 TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers);
2609 const MachineOperand *Src1Mods =
2610 TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers);
2613 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod) ||
2614 TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp))
2625bool SIFoldOperandsImpl::tryFoldOMod(MachineInstr &
MI) {
2626 const MachineOperand *RegOp;
2628 std::tie(RegOp, OMod) = isOMod(
MI);
2630 RegOp->
getSubReg() != AMDGPU::NoSubRegister ||
2635 Register OModSrcReg =
Def->getOperand(0).getReg();
2639 if (
Def->isRegSequence() &&
Def->getNumOperands() == 5 &&
2640 Def->getOperand(2).getImm() == AMDGPU::lo16) {
2642 bool CanLookThrough =
true;
2643 MachineInstr *Hi16Def = MRI->
getVRegDef(
Def->getOperand(3).getReg());
2645 CanLookThrough =
false;
2647 if (CanLookThrough) {
2658 MachineOperand *DefOMod =
TII->getNamedOperand(*Def, AMDGPU::OpName::omod);
2662 if (
Def->mayRaiseFPException())
2667 if (
TII->hasModifiersSet(*Def, AMDGPU::OpName::clamp))
2677 MI.eraseFromParent();
2682 if (
TII->convertToThreeAddress(*Def,
nullptr))
2683 Def->eraseFromParent();
2690bool SIFoldOperandsImpl::tryFoldSGPRSplatRegSequence(MachineInstr &
MI) {
2693 if (!ST->hasPackedFP64SingleSGPROps() && !ST->hasPackedU64SingleSGPROps())
2700 if (!
TRI->isSGPRClass(RegClass) ||
TRI->getRegSizeInBits(*RegClass) != 128)
2704 if (!getRegSeqInit(Defs,
Reg))
2708 if (Defs.
size() <= 1)
2711 const auto &[FirstOp,
_] = Defs.
front();
2712 if (!FirstOp->isReg())
2715 Register FirstReg = FirstOp->getReg();
2716 unsigned FirstSubReg = FirstOp->getSubReg();
2719 if (!
TRI->isSGPRClass(FirstRegClass))
2724 const auto &[
Op,
_] =
Def;
2725 return Op->isReg() &&
Op->getReg() == FirstReg &&
2726 Op->getSubReg() == FirstSubReg;
2738 MachineInstrBuilder
RS =
BuildMI(*
MI.getParent(),
MI,
MI.getDebugLoc(),
2739 TII->get(AMDGPU::REG_SEQUENCE), NewDst);
2742 FirstOp->setIsKill(
false);
2744 RS.addImm(Defs[0].second);
2749 for (
unsigned i = 1; i < Defs.
size(); ++i) {
2750 RS.addReg(UndefReg, RegState::Undef);
2751 RS.addImm(Defs[i].second);
2760 MI.eraseFromParent();
2766bool SIFoldOperandsImpl::tryFoldRegSequence(MachineInstr &
MI) {
2770 if (tryFoldSGPRSplatRegSequence(
MI))
2773 auto Reg =
MI.getOperand(0).getReg();
2775 if (!ST->hasGFX90AInsts() || !
TRI->isVGPR(*MRI,
Reg) ||
2780 if (!getRegSeqInit(Defs,
Reg))
2783 for (
auto &[
Op, SubIdx] : Defs) {
2786 if (
TRI->isAGPR(*MRI,
Op->getReg()))
2789 const MachineInstr *SubDef = MRI->
getVRegDef(
Op->getReg());
2797 MachineInstr *
UseMI =
Op->getParent();
2806 if (
Op->getSubReg())
2812 if (!OpRC || !
TRI->isVectorSuperClass(OpRC))
2818 TII->get(AMDGPU::REG_SEQUENCE), Dst);
2820 for (
auto &[Def, SubIdx] : Defs) {
2821 Def->setIsKill(
false);
2822 if (
TRI->isAGPR(*MRI,
Def->getReg())) {
2833 if (!
TII->isOperandLegal(*
UseMI, OpIdx,
Op)) {
2835 RS->eraseFromParent();
2844 MI.eraseFromParent();
2852 Register &OutReg,
unsigned &OutSubReg) {
2862 if (
TRI.isAGPR(MRI, CopySrcReg)) {
2863 OutReg = CopySrcReg;
2872 if (!CopySrcDef || !CopySrcDef->
isCopy())
2879 OtherCopySrc.
getSubReg() != AMDGPU::NoSubRegister ||
2880 !
TRI.isAGPR(MRI, OtherCopySrcReg))
2883 OutReg = OtherCopySrcReg;
2917bool SIFoldOperandsImpl::tryFoldPhiAGPR(MachineInstr &
PHI) {
2921 if (!
TRI->isVGPR(*MRI, PhiOut))
2927 for (
unsigned K = 1;
K <
PHI.getNumExplicitOperands();
K += 2) {
2928 MachineOperand &MO =
PHI.getOperand(K);
2930 if (!Copy || !
Copy->isCopy())
2934 unsigned AGPRRegMask = AMDGPU::NoSubRegister;
2939 if (
const auto *SubRC =
TRI->getSubRegisterClass(CopyInRC, AGPRRegMask))
2950 bool IsAGPR32 = (ARC == &AMDGPU::AGPR_32RegClass);
2954 for (
unsigned K = 1;
K <
PHI.getNumExplicitOperands();
K += 2) {
2955 MachineOperand &MO =
PHI.getOperand(K);
2959 MachineBasicBlock *InsertMBB =
nullptr;
2962 unsigned CopyOpc = AMDGPU::COPY;
2967 if (
Def->isCopy()) {
2969 unsigned AGPRSubReg = AMDGPU::NoSubRegister;
2982 MachineOperand &CopyIn =
Def->getOperand(1);
2985 CopyOpc = AMDGPU::V_ACCVGPR_WRITE_B32_e64;
2988 InsertMBB =
Def->getParent();
2996 MachineInstr *
MI =
BuildMI(*InsertMBB, InsertPt,
PHI.getDebugLoc(),
2997 TII->get(CopyOpc), NewReg)
3007 PHI.getOperand(0).setReg(NewReg);
3013 TII->get(AMDGPU::COPY), PhiOut)
3021bool SIFoldOperandsImpl::tryFoldLoad(MachineInstr &
MI) {
3023 if (!ST->hasGFX90AInsts() ||
MI.getNumExplicitDefs() != 1)
3026 MachineOperand &
Def =
MI.getOperand(0);
3043 while (!
Users.empty()) {
3044 const MachineInstr *
I =
Users.pop_back_val();
3045 if (!
I->isCopy() && !
I->isRegSequence())
3047 Register DstReg =
I->getOperand(0).getReg();
3051 if (
TRI->isAGPR(*MRI, DstReg))
3055 Users.push_back(&U);
3060 if (!
TII->isOperandLegal(
MI, 0, &Def)) {
3065 while (!MoveRegs.
empty()) {
3107bool SIFoldOperandsImpl::tryOptimizeAGPRPhis(MachineBasicBlock &
MBB) {
3110 if (ST->hasGFX90AInsts())
3114 DenseMap<std::pair<Register, unsigned>, std::vector<MachineOperand *>>
3117 for (
auto &
MI :
MBB) {
3121 if (!
TRI->isAGPR(*MRI,
MI.getOperand(0).getReg()))
3124 for (
unsigned K = 1;
K <
MI.getNumOperands();
K += 2) {
3125 MachineOperand &PhiMO =
MI.getOperand(K);
3135 for (
const auto &[Entry, MOs] : RegToMO) {
3136 if (MOs.size() == 1)
3141 MachineBasicBlock *DefMBB =
Def->getParent();
3148 MachineInstr *VGPRCopy =
3150 TII->get(AMDGPU::V_ACCVGPR_READ_B32_e64), TempVGPR)
3156 TII->get(AMDGPU::COPY), TempAGPR)
3160 for (MachineOperand *MO : MOs) {
3172bool SIFoldOperandsImpl::run(
MachineFunction &MF,
const MachineLoopInfo *MLI) {
3178 MFI = MF.
getInfo<SIMachineFunctionInfo>();
3189 MachineOperand *CurrentKnownM0Val =
nullptr;
3197 if (tryConstantFoldOp(&
MI)) {
3202 if (tryFoldRedundantAND(
MI)) {
3207 if (tryFoldAndExec(
MI)) {
3212 if (
MI.isRegSequence() && tryFoldRegSequence(
MI)) {
3217 if (
MI.isPHI() && tryFoldPhiAGPR(
MI)) {
3222 if (
MI.mayLoad() && tryFoldLoad(
MI)) {
3227 if (
TII->isFoldableCopy(
MI)) {
3228 Changed |= tryFoldFoldableCopy(
MI, CurrentKnownM0Val);
3233 if (CurrentKnownM0Val &&
MI.modifiesRegister(AMDGPU::M0,
TRI))
3234 CurrentKnownM0Val =
nullptr;
3254 bool Changed = SIFoldOperandsImpl().run(MF, MLI);
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool updateOperand(Instruction *Inst, unsigned Idx, Instruction *Mat)
Updates the operand at Idx in instruction Inst with the result of instruction Mat.
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
AMD GCN specific subclass of TargetSubtarget.
static Register UseReg(const MachineOperand &MO)
const HexagonInstrInfo * TII
iv Induction Variable Users
Register const TargetRegisterInfo * TRI
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
static bool isReg(const MCInst &MI, unsigned OpNo)
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
static bool loopModifiesExec(const MachineLoop &L, const SIRegisterInfo &TRI)
static unsigned macToMad(unsigned Opc)
static bool isAGPRCopy(const SIRegisterInfo &TRI, const MachineRegisterInfo &MRI, const MachineInstr &Copy, Register &OutReg, unsigned &OutSubReg)
Checks whether Copy is a AGPR -> VGPR copy.
static void appendFoldCandidate(SmallVectorImpl< FoldCandidate > &FoldList, FoldCandidate &&Entry)
static const TargetRegisterClass * getRegOpRC(const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const MachineOperand &MO)
static bool evalBinaryInstruction(unsigned Opcode, int32_t &Result, uint32_t LHS, uint32_t RHS)
static int getOModValue(unsigned Opc, int64_t Val)
static unsigned getMovOpc(bool IsScalar)
static MachineOperand * lookUpCopyChain(const SIInstrInfo &TII, const MachineRegisterInfo &MRI, Register SrcReg)
static bool checkImmOpForPKF32InstrReplicatesLower32BitsOfScalarOperand(const FoldableDef &OpToFold)
static bool isPKF32InstrReplicatesLower32BitsOfScalarOperand(const GCNSubtarget *ST, MachineInstr *MI, unsigned OpNo)
Interface definition for SIInstrInfo.
Interface definition for SIRegisterInfo.
static int Lookup(ArrayRef< TableEntry > Table, unsigned Opcode)
static const LaneMaskConstants & get(const GCNSubtarget &ST)
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
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.
const SIInstrInfo * getInstrInfo() const override
bool hasDOTOpSelHazard() const
bool zeroesHigh16BitsOfDest(unsigned Opcode) const
Returns if the result of this instruction with a 16-bit result returned in a 32-bit register implicit...
const HexagonRegisterInfo & getRegisterInfo() const
bool contains(const LoopT *L) const
Return true if the specified loop is contained within this loop.
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
ArrayRef< MCOperandInfo > operands() const
int getOperandConstraint(unsigned OpNum, MCOI::OperandConstraint Constraint) const
Returns the value of the specified operand constraint if it is present.
bool isVariadic() const
Return true if this instruction can have a variable number of operands.
This holds information about one operand of a machine instruction, indicating the register class for ...
uint8_t OperandType
Information about the type of the operand.
bool hasSuperClassEq(const MCRegisterClass *RC) const
Returns true if RC is a super-class of or equal to this class.
bool contains(MCRegister Reg) const
contains - Return true if the specified register is included in this register class.
bool hasSubClassEq(const MCRegisterClass *RC) const
Returns true if RC is a sub-class of or equal to this class.
An RAII based helper class to modify MachineFunctionProperties when running pass.
LLVM_ABI iterator SkipPHIsLabelsAndDebug(iterator I, Register Reg=Register(), bool SkipPseudoOp=true)
Return the first instruction in MBB after I that is not a PHI, label or debug.
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.
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
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.
Properties which a MachineFunction may have at a given point in time.
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.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Register getReg(unsigned Idx) const
Get the register for the operand index.
const MachineInstrBuilder & setOperandDead(unsigned OpIdx) const
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool isImplicitDef() const
const MachineBasicBlock * getParent() const
bool readsRegister(Register Reg, const TargetRegisterInfo *TRI) const
Return true if the MachineInstr reads the specified register.
LLVM_ABI bool allImplicitDefsAreDead() const
Return true if all the implicit defs of this instruction are dead.
unsigned getNumOperands() const
Retuns the total number of operands.
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
unsigned getOperandNo(const_mop_iterator I) const
Returns the number of the operand iterator I points to.
LLVM_ABI unsigned getNumExplicitOperands() const
Returns the number of non-implicit operands.
mop_range implicit_operands()
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
void clearFlag(MIFlag Flag)
clearFlag - Clear a MI flag.
bool isRegSequence() const
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
MachineOperand * mop_iterator
iterator/begin/end - Iterate over all operands of a machine instruction.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
LLVM_ABI void removeOperand(unsigned OpNo)
Erase an operand from an instruction, leaving it with one fewer operand than it started with.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
Analysis pass that exposes the MachineLoopInfo for a machine function.
MachineOperand class - Representation of each machine instruction operand.
void setSubReg(unsigned subReg)
unsigned getSubReg() const
LLVM_ABI unsigned getOperandNo() const
Returns the index of this operand in the instruction that it belongs to.
LLVM_ABI void substVirtReg(Register Reg, unsigned SubIdx, const TargetRegisterInfo &)
substVirtReg - Substitute the current register with the virtual subregister Reg:SubReg.
LLVM_ABI void ChangeToFrameIndex(int Idx, unsigned TargetFlags=0)
Replace this operand with a frame index.
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.
LLVM_ABI void ChangeToImmediate(int64_t ImmVal, unsigned TargetFlags=0)
ChangeToImmediate - Replace this operand with a new immediate operand of the specified value.
LLVM_ABI void ChangeToGA(const GlobalValue *GV, int64_t Offset, unsigned TargetFlags=0)
ChangeToGA - Replace this operand with a new global address operand.
void setIsKill(bool Val=true)
LLVM_ABI void ChangeToRegister(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isDebug=false)
ChangeToRegister - Replace this operand with a new register operand of the specified value.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
LLVM_ABI void substPhysReg(MCRegister Reg, const TargetRegisterInfo &)
substPhysReg - Substitute the current register with the physical register Reg, taking any existing Su...
static MachineOperand CreateImm(int64_t Val)
bool isGlobal() const
isGlobal - Tests if this is a MO_GlobalAddress operand.
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
void setIsUndef(bool Val=true)
Register getReg() const
getReg - Returns the register number.
bool isFI() const
isFI - Tests if this is a MO_FrameIndex operand.
LLVM_ABI bool isIdenticalTo(const MachineOperand &Other) const
Returns true if this operand is identical to the specified operand except for liveness related flags ...
@ MO_Immediate
Immediate operand.
@ MO_GlobalAddress
Address of a global value.
@ MO_FrameIndex
Abstract Stack Frame Index.
@ MO_Register
Register operand.
static MachineOperand CreateFI(int Idx)
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.
use_nodbg_iterator use_nodbg_begin(Register RegNo) const
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual 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 ...
iterator_range< use_nodbg_iterator > use_nodbg_operands(Register Reg) const
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 Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
LLVM_ABI bool hasOneNonDBGUser(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug instruction using the specified regis...
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
void setRegAllocationHint(Register VReg, unsigned Type, Register PrefReg)
setRegAllocationHint - Specify a register allocation hint for the specified virtual register.
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
LLVM_ABI const TargetRegisterClass * constrainRegClass(Register Reg, const TargetRegisterClass *RC, unsigned MinNumRegs=0)
constrainRegClass - Constrain the register class of the specified virtual register to be a common sub...
LLVM_ABI void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Wrapper class representing virtual and physical registers.
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)
static bool hasSameClamp(const MachineInstr &A, const MachineInstr &B)
static std::optional< int64_t > extractSubregFromImm(int64_t ImmVal, unsigned SubRegIndex)
Return the extracted immediate value in a subregister use from a constant materialized in a super reg...
This class keeps track of the SPI_SP_INPUT_ADDR config register, which tells the hardware which inter...
Register getScratchRSrcReg() const
Returns the physical register reserved for use as the resource descriptor for scratch accesses.
SIModeRegisterDefaults getMode() const
static unsigned getSubRegFromChannel(unsigned Channel, unsigned NumRegs=1)
bool insert(const value_type &X)
Insert a new element into the SetVector.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
Represent a constant reference to a string, i.e.
static const unsigned CommuteAnyOperandIndex
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
bool isInlinableLiteralV216(uint32_t Literal, uint8_t OpType)
LLVM_READONLY int32_t getMFMAEarlyClobberOp(uint32_t Opcode)
bool isPackedSingleSGPR64BitInst(unsigned Opc)
The opcode is a packed 64-bit instruction which only reads low 64 bits of a scalar operand and propag...
LLVM_READONLY bool hasNamedOperand(uint32_t Opcode, OpName NamedIdx)
LLVM_READONLY int32_t getVOPe32(uint32_t Opcode)
constexpr bool isSISrcOperand(const MCOperandInfo &OpInfo)
Is this an AMDGPU specific source operand?
@ OPERAND_REG_INLINE_C_FP64
@ OPERAND_REG_INLINE_C_BF16
@ OPERAND_REG_INLINE_C_V2BF16
@ OPERAND_REG_IMM_V2INT64
@ OPERAND_REG_IMM_V2INT16
@ OPERAND_REG_INLINE_C_INT64
@ OPERAND_REG_IMM_NOINLINE_V2FP16
@ OPERAND_REG_INLINE_C_V2FP16
@ OPERAND_REG_INLINE_AC_INT32
Operands with an AccVGPR register or inline constant.
@ OPERAND_REG_INLINE_AC_FP32
@ OPERAND_REG_INLINE_C_FP32
@ OPERAND_REG_INLINE_C_INT32
@ OPERAND_REG_INLINE_C_V2INT16
@ OPERAND_REG_INLINE_AC_FP64
LLVM_READONLY int32_t getFlatScratchInstSSfromSV(uint32_t Opcode)
bool supportsScaleOffset(const MCInstrInfo &MII, unsigned Opcode)
constexpr bool isVOP3(const T &...O)
constexpr bool isMAI(const T &...O)
constexpr bool isSWMMAC(const T &...O)
constexpr bool isVOP3P(const T &...O)
constexpr bool isWMMA(const T &...O)
constexpr bool isDOT(const T &...O)
constexpr bool isPacked(const T &...O)
NodeAddr< DefNode * > Def
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
TargetInstrInfo::RegSubRegPair getRegSubRegPair(const MachineOperand &O)
Create RegSubRegPair from a register MachineOperand.
MachineBasicBlock::instr_iterator getBundleStart(MachineBasicBlock::instr_iterator I)
Returns an iterator to the first instruction in the bundle containing I.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool execMayBeModifiedBeforeUse(const MachineRegisterInfo &MRI, Register VReg, const MachineInstr &DefMI, const MachineInstr &UseMI)
Return false if EXEC is not changed between the def of VReg at DefMI and the use at UseMI.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
char & SIFoldOperandsLegacyID
constexpr uint32_t Hi_32(uint64_t Value)
Return the high 32 bits of a 64 bit value.
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...
constexpr uint32_t Lo_32(uint64_t Value)
Return the low 32 bits of a 64 bit value.
@ Sub
Subtraction of integers.
DWARFExpression::Operation Op
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
iterator_range< df_iterator< T > > depth_first(const T &G)
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
constexpr uint64_t Make_64(uint32_t High, uint32_t Low)
Make a 64-bit integer from a high / low pair of 32-bit integers.
MCRegisterClass TargetRegisterClass
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
@ PreserveSign
The sign of a flushed-to-zero number is preserved in the sign of 0.
DenormalModeKind Output
Denormal flushing mode for floating point instruction results in the default floating point environme...
DenormalMode FP64FP16Denormals
If this is set, neither input or output denormals are flushed for both f64 and f16/v2f16 instructions...
bool IEEE
Floating point opcodes that support exception flag gathering quiet and propagate signaling NaN inputs...
DenormalMode FP32Denormals
If this is set, neither input or output denormals are flushed for most f32 instructions.