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 {
553 uint16_t
Lo =
static_cast<uint16_t
>(
Imm);
554 uint16_t
Hi =
static_cast<uint16_t
>(
Imm >> 16);
556 if (BF16FromUpperFP32) {
568 uint32_t
Bits = IsBF16 ?
static_cast<uint32_t
>(
C) << 16
569 : static_cast<uint32_t>(NewImm);
570 uint16_t ReadLo =
static_cast<uint16_t
>(
Bits);
571 uint16_t ReadHi =
static_cast<uint16_t
>(
Bits >> 16);
575 if ((
Lo != ReadLo &&
Lo != ReadHi) || (
Hi != ReadLo &&
Hi != ReadHi))
583 Mod.setImm(NewModVal);
598 Mod.setImm(NewModVal);
603 if (
static_cast<int16_t
>(
Lo) < 0) {
604 int32_t SExt =
static_cast<int16_t
>(
Lo);
606 Mod.setImm(NewModVal);
621 uint32_t Swapped = (
static_cast<uint32_t
>(
Lo) << 16) |
Hi;
632 if (tryFoldToInline(
Imm))
641 bool IsUAdd = Opcode == AMDGPU::V_PK_ADD_U16;
642 bool IsUSub = Opcode == AMDGPU::V_PK_SUB_U16;
643 if (SrcIdx == 1 && (IsUAdd || IsUSub)) {
645 AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::clamp);
646 bool Clamp =
MI->getOperand(ClampIdx).getImm() != 0;
649 uint16_t NegLo = -
static_cast<uint16_t
>(
Imm);
650 uint16_t NegHi = -
static_cast<uint16_t
>(
Imm >> 16);
651 uint32_t NegImm = (
static_cast<uint32_t
>(NegHi) << 16) | NegLo;
653 if (tryFoldToInline(NegImm)) {
655 IsUAdd ? AMDGPU::V_PK_SUB_U16 : AMDGPU::V_PK_ADD_U16;
656 MI->setDesc(
TII->get(NegOpcode));
665bool SIFoldOperandsImpl::updateOperand(FoldCandidate &Fold)
const {
666 MachineInstr *
MI = Fold.UseMI;
667 MachineOperand &Old =
MI->getOperand(Fold.UseOpNo);
670 std::optional<int64_t> ImmVal;
672 ImmVal = Fold.Def.getEffectiveImmVal();
674 if (ImmVal && canUseImmWithOpSel(Fold.UseMI, Fold.UseOpNo, *ImmVal)) {
675 if (tryFoldImmWithOpSel(Fold.UseMI, Fold.UseOpNo, *ImmVal))
681 int OpNo =
MI->getOperandNo(&Old);
682 if (!
TII->isOperandLegal(*
MI, OpNo, &New))
689 if ((Fold.isImm() || Fold.isFI() || Fold.isGlobal()) && Fold.needsShrink()) {
697 int Op32 = Fold.ShrinkOpcode;
698 MachineOperand &Dst0 =
MI->getOperand(0);
699 MachineOperand &Dst1 =
MI->getOperand(1);
707 MachineInstr *Inst32 =
TII->buildShrunkInst(*
MI, Op32);
709 if (HaveNonDbgCarryUse) {
712 .
addReg(AMDGPU::VCC, RegState::Kill);
726 for (
unsigned I =
MI->getNumOperands() - 1;
I > 0; --
I)
727 MI->removeOperand(
I);
728 MI->setDesc(
TII->get(AMDGPU::IMPLICIT_DEF));
731 TII->commuteInstruction(*Inst32,
false);
735 assert(!Fold.needsShrink() &&
"not handled");
740 if (NewMFMAOpc == -1)
742 MI->setDesc(
TII->get(NewMFMAOpc));
743 MI->untieRegOperand(0);
744 const MCInstrDesc &MCID =
MI->getDesc();
745 for (
unsigned I = 0;
I <
MI->getNumDefs(); ++
I)
747 MI->getOperand(
I).setIsEarlyClobber(
true);
752 int OpNo =
MI->getOperandNo(&Old);
753 if (!
TII->isOperandLegal(*
MI, OpNo, &New))
756 if (ST->hasBF16InlineConstFromUpperFP32() &&
758 AMDGPU::getNamedOperandIdx(
MI->getOpcode(), AMDGPU::OpName::src0)) {
759 unsigned Opcode =
MI->getOpcode();
760 uint8_t OpType =
TII->get(Opcode).operands()[OpNo].OperandType;
763 TII->isInlineConstant(*ImmVal, OpType)) {
766 AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src0_modifiers);
769 MachineOperand &ModOp =
MI->getOperand(Mod0);
780 if (Fold.isGlobal()) {
781 Old.
ChangeToGA(Fold.Def.OpToFold->getGlobal(),
782 Fold.Def.OpToFold->getOffset(),
783 Fold.Def.OpToFold->getTargetFlags());
792 MachineOperand *
New = Fold.Def.OpToFold;
796 TII->getRegClass(
MI->getDesc(), Fold.UseOpNo)) {
798 TRI->getRegClassForReg(*
MRI,
New->getReg());
801 if (
New->getSubReg()) {
803 TRI->getMatchingSuperRegClass(NewRC, OpRC,
New->getSubReg());
809 if (
New->getReg().isVirtual() &&
812 <<
TRI->getRegClassName(ConstrainRC) <<
'\n');
821 if (
New->getReg().isPhysical()) {
829 if (
MI->isBundledWithPred()) {
831 for (MachineOperand &MO : Header.operands()) {
832 if (MO.getReg() == OldReg) {
833 MO.setReg(
New->getReg());
834 MO.setSubReg(
New->getSubReg());
843 FoldCandidate &&Entry) {
845 for (FoldCandidate &Fold : FoldList)
846 if (Fold.UseMI == Entry.UseMI && Fold.UseOpNo == Entry.UseOpNo)
848 LLVM_DEBUG(
dbgs() <<
"Append " << (Entry.Commuted ?
"commuted" :
"normal")
849 <<
" operand " << Entry.UseOpNo <<
"\n " << *Entry.UseMI);
855 const FoldableDef &FoldOp,
856 bool Commuted =
false,
int ShrinkOp = -1) {
858 FoldCandidate(
MI, OpNo, FoldOp, Commuted, ShrinkOp));
866 if (!ST->hasPKF32InstsReplicatingLower32BitsOfScalarInput())
876 const FoldableDef &OpToFold) {
877 assert(OpToFold.isImm() &&
"Expected immediate operand");
878 uint64_t ImmVal = OpToFold.getEffectiveImmVal().value();
884bool SIFoldOperandsImpl::tryAddToFoldList(
885 SmallVectorImpl<FoldCandidate> &FoldList, MachineInstr *
MI,
unsigned OpNo,
886 const FoldableDef &OpToFold)
const {
887 const unsigned Opc =
MI->getOpcode();
889 auto tryToFoldAsFMAAKorMK = [&]() {
890 if (!OpToFold.isImm())
893 const bool TryAK = OpNo == 3;
894 const unsigned NewOpc = TryAK ? AMDGPU::S_FMAAK_F32 : AMDGPU::S_FMAMK_F32;
895 MI->setDesc(
TII->get(NewOpc));
898 bool FoldAsFMAAKorMK =
899 tryAddToFoldList(FoldList,
MI, TryAK ? 3 : 2, OpToFold);
900 if (FoldAsFMAAKorMK) {
902 MI->untieRegOperand(3);
905 MachineOperand &Op1 =
MI->getOperand(1);
906 MachineOperand &Op2 =
MI->getOperand(2);
923 bool IsLegal = OpToFold.isOperandLegal(*
TII, *
MI, OpNo);
924 if (!IsLegal && OpToFold.isImm()) {
925 if (std::optional<int64_t> ImmVal = OpToFold.getEffectiveImmVal())
926 IsLegal = canUseImmWithOpSel(
MI, OpNo, *ImmVal);
932 if (NewOpc != AMDGPU::INSTRUCTION_LIST_END) {
935 MI->setDesc(
TII->get(NewOpc));
940 bool FoldAsMAD = tryAddToFoldList(FoldList,
MI, OpNo, OpToFold);
942 MI->untieRegOperand(OpNo);
946 MI->removeOperand(
MI->getNumExplicitOperands() - 1);
952 if (
Opc == AMDGPU::S_FMAC_F32 && OpNo == 3) {
953 if (tryToFoldAsFMAAKorMK())
959 if ((
Opc == AMDGPU::S_FMAAK_F32 ||
Opc == AMDGPU::S_FMAMK_F32) &&
961 std::optional<int64_t> ImmVal = OpToFold.getEffectiveImmVal();
962 if (ImmVal && !
TII->isInlineConstant(*
MI, OpNo, *ImmVal)) {
963 unsigned ImmIdx =
Opc == AMDGPU::S_FMAAK_F32 ? 3 : 2;
964 MachineOperand &OpImm =
MI->getOperand(ImmIdx);
965 if (!OpImm.
isReg() &&
966 TII->isInlineConstant(*
MI,
MI->getOperand(OpNo), OpImm))
967 return tryToFoldAsFMAAKorMK();
972 if (OpToFold.isImm()) {
974 if (
Opc == AMDGPU::S_SETREG_B32)
975 ImmOpc = AMDGPU::S_SETREG_IMM32_B32;
976 else if (
Opc == AMDGPU::S_SETREG_B32_mode)
977 ImmOpc = AMDGPU::S_SETREG_IMM32_B32_mode;
979 MI->setDesc(
TII->get(ImmOpc));
988 bool CanCommute =
TII->findCommutedOpIndices(*
MI, OpNo, CommuteOpNo);
992 MachineOperand &
Op =
MI->getOperand(OpNo);
993 MachineOperand &CommutedOp =
MI->getOperand(CommuteOpNo);
999 if (!
Op.isReg() || !CommutedOp.
isReg())
1004 if (
Op.isReg() && CommutedOp.
isReg() &&
1005 (
Op.getReg() == CommutedOp.
getReg() &&
1009 if (!
TII->commuteInstruction(*
MI,
false, OpNo, CommuteOpNo))
1013 if (!OpToFold.isOperandLegal(*
TII, *
MI, CommuteOpNo)) {
1014 if ((
Opc != AMDGPU::V_ADD_CO_U32_e64 &&
Opc != AMDGPU::V_SUB_CO_U32_e64 &&
1015 Opc != AMDGPU::V_SUBREV_CO_U32_e64) ||
1016 (!OpToFold.isImm() && !OpToFold.isFI() && !OpToFold.isGlobal())) {
1017 TII->commuteInstruction(*
MI,
false, OpNo, CommuteOpNo);
1023 MachineOperand &OtherOp =
MI->getOperand(OpNo);
1024 if (!OtherOp.
isReg() ||
1031 unsigned MaybeCommutedOpc =
MI->getOpcode();
1045 if (
Opc == AMDGPU::S_FMAC_F32 &&
1046 (OpNo != 1 || !
MI->getOperand(1).isIdenticalTo(
MI->getOperand(2)))) {
1047 if (tryToFoldAsFMAAKorMK())
1053 if (OpToFold.isImm() &&
1062bool SIFoldOperandsImpl::isUseSafeToFold(
const MachineInstr &
MI,
1063 const MachineOperand &UseMO)
const {
1065 return !
TII->isSDWA(
MI);
1072 if (
MI.modifiesRegister(
TRI.getExec(), &
TRI))
1080bool SIFoldOperandsImpl::isTemporallyDivergentUse(
1081 const FoldableDef &OpToFold,
const MachineInstr &
UseMI)
const {
1082 if (!OpToFold.isReg())
1084 const MachineInstr *
DefMI = OpToFold.DefMI;
1087 !
TRI->isSGPRReg(*
MRI, OpToFold.getReg()))
1099 SubDef &&
TII.isFoldableCopy(*SubDef);
1100 SubDef =
MRI.getVRegDef(
Sub->getReg())) {
1101 unsigned SrcIdx =
TII.getFoldableCopySrcIdx(*SubDef);
1110 if (
SrcOp.getSubReg())
1118 MachineInstr &RegSeq,
1119 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs)
const {
1135 else if (!
TRI->getCommonSubClass(RC, OpRC))
1140 Defs.emplace_back(&SrcOp, SubRegIdx);
1145 if (DefSrc && (DefSrc->
isReg() || DefSrc->
isImm())) {
1146 Defs.emplace_back(DefSrc, SubRegIdx);
1150 Defs.emplace_back(&SrcOp, SubRegIdx);
1160 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs,
1163 if (!Def || !
Def->isRegSequence())
1166 return getRegSeqInit(*Def, Defs);
1169std::pair<int64_t, const TargetRegisterClass *>
1170SIFoldOperandsImpl::isRegSeqSplat(MachineInstr &RegSeq)
const {
1176 bool TryToMatchSplat64 =
false;
1178 std::optional<int64_t>
Imm;
1179 for (
unsigned I = 0,
E = Defs.
size();
I !=
E; ++
I) {
1180 const MachineOperand *
Op = Defs[
I].first;
1184 if (!Def ||
Def->isImplicitDef())
1190 int64_t SubImm =
Op->getImm();
1196 if (
Imm != SubImm) {
1197 if (
I == 1 && (
E & 1) == 0) {
1200 TryToMatchSplat64 =
true;
1208 if (!TryToMatchSplat64) {
1210 return {*
Imm, SrcRC};
1217 for (
unsigned I = 0,
E = Defs.
size();
I !=
E;
I += 2) {
1218 const MachineOperand *Op0 = Defs[
I].first;
1219 const MachineOperand *Op1 = Defs[
I + 1].first;
1224 unsigned SubReg0 = Defs[
I].second;
1225 unsigned SubReg1 = Defs[
I + 1].second;
1229 if (
TRI->getChannelFromSubReg(SubReg0) + 1 !=
1230 TRI->getChannelFromSubReg(SubReg1))
1233 if (
TRI->getSubRegIdxSize(SubReg0) != 32)
1238 SplatVal64 = MergedVal;
1239 else if (SplatVal64 != MergedVal)
1246 return {SplatVal64, RC64};
1249bool SIFoldOperandsImpl::tryFoldRegSeqSplat(
1250 MachineInstr *
UseMI,
unsigned UseOpIdx, int64_t SplatVal,
1253 if (UseOpIdx >=
Desc.getNumOperands())
1260 int16_t RCID =
TII->getOpRegClassID(
Desc.operands()[UseOpIdx]);
1269 if (SplatVal != 0 && SplatVal != -1) {
1273 uint8_t OpTy =
Desc.operands()[UseOpIdx].OperandType;
1280 OpRC =
TRI->getSubRegisterClass(OpRC, AMDGPU::sub0);
1287 OpRC =
TRI->getSubRegisterClass(OpRC, AMDGPU::sub0_sub1);
1293 if (!
TRI->getCommonSubClass(OpRC, SplatRC))
1298 if (!
TII->isOperandLegal(*
UseMI, UseOpIdx, &TmpOp))
1304bool SIFoldOperandsImpl::tryToFoldACImm(
1305 const FoldableDef &OpToFold, MachineInstr *
UseMI,
unsigned UseOpIdx,
1306 SmallVectorImpl<FoldCandidate> &FoldList)
const {
1308 if (UseOpIdx >=
Desc.getNumOperands())
1315 if (OpToFold.isImm() && OpToFold.isOperandLegal(*
TII, *
UseMI, UseOpIdx)) {
1326bool SIFoldOperandsImpl::foldOperand(
1327 FoldableDef OpToFold, MachineInstr *
UseMI,
int UseOpIdx,
1328 SmallVectorImpl<FoldCandidate> &FoldList,
1329 SmallVectorImpl<MachineInstr *> &CopiesToReplace)
const {
1333 if (!isUseSafeToFold(*
UseMI, *UseOp))
1336 if (isTemporallyDivergentUse(OpToFold, *
UseMI))
1340 if (UseOp->
isReg() && OpToFold.isReg()) {
1344 if (UseOp->
getSubReg() != AMDGPU::NoSubRegister &&
1346 !
TRI->isSGPRReg(*
MRI, OpToFold.getReg())))
1359 std::tie(SplatVal, SplatRC) = isRegSeqSplat(*
UseMI);
1364 for (
unsigned I = 0;
I != UsesToProcess.size(); ++
I) {
1365 MachineOperand *RSUse = UsesToProcess[
I];
1366 MachineInstr *RSUseMI = RSUse->
getParent();
1376 if (tryFoldRegSeqSplat(RSUseMI, OpNo, SplatVal, SplatRC)) {
1377 FoldableDef SplatDef(SplatVal, SplatRC);
1385 if (RSUse->
getSubReg() != RegSeqDstSubReg)
1391 FoldList, CopiesToReplace);
1397 if (tryToFoldACImm(OpToFold,
UseMI, UseOpIdx, FoldList))
1400 if (frameIndexMayFold(*
UseMI, UseOpIdx, OpToFold)) {
1405 if (
TII->getNamedOperand(*
UseMI, AMDGPU::OpName::srsrc)->getReg() !=
1411 MachineOperand &SOff =
1412 *
TII->getNamedOperand(*
UseMI, AMDGPU::OpName::soffset);
1423 TII->getNamedOperand(*
UseMI, AMDGPU::OpName::cpol)->getImm();
1438 bool FoldingImmLike =
1439 OpToFold.isImm() || OpToFold.isFI() || OpToFold.isGlobal();
1458 for (
unsigned MovOp :
1459 {AMDGPU::S_MOV_B32, AMDGPU::V_MOV_B32_e32, AMDGPU::S_MOV_B64,
1460 AMDGPU::V_MOV_B64_PSEUDO, AMDGPU::V_MOV_B16_t16_e64,
1461 AMDGPU::V_ACCVGPR_WRITE_B32_e64, AMDGPU::AV_MOV_B32_IMM_PSEUDO,
1462 AMDGPU::AV_MOV_B64_IMM_PSEUDO}) {
1463 const MCInstrDesc &MovDesc =
TII->get(MovOp);
1473 const int SrcIdx = MovOp == AMDGPU::V_MOV_B16_t16_e64 ? 2 : 1;
1475 int16_t RegClassID =
TII->getOpRegClassID(MovDesc.
operands()[SrcIdx]);
1476 if (RegClassID != -1) {
1480 MovSrcRC =
TRI->getMatchingSuperRegClass(SrcRC, MovSrcRC, UseSubReg);
1484 if (MovOp == AMDGPU::AV_MOV_B32_IMM_PSEUDO &&
1485 (!OpToFold.isImm() ||
1486 !
TII->isImmOperandLegal(MovDesc, SrcIdx,
1487 *OpToFold.getEffectiveImmVal())))
1500 if (!OpToFold.isImm() ||
1501 !
TII->isImmOperandLegal(MovDesc, 1, *OpToFold.getEffectiveImmVal()))
1507 while (ImpOpI != ImpOpE) {
1514 if (MovOp == AMDGPU::V_MOV_B16_t16_e64) {
1516 MachineOperand NewSrcOp(SrcOp);
1538 LLVM_DEBUG(
dbgs() <<
"Folding " << *OpToFold.OpToFold <<
"\n into "
1543 unsigned SubRegIdx = OpToFold.getSubReg();
1548 TRI->isSGPRReg(*
MRI,
UseReg) && SubRegIdx != AMDGPU::NoSubRegister) {
1551 unsigned Channel =
TRI->getChannelFromSubReg(SubRegIdx);
1553 SubRegIdx =
TRI->getRegSizeInBits(*UseRC) == 32
1554 ? AMDGPU::NoSubRegister
1560 OpToFold.OpToFold->setIsKill(
false);
1565 if (foldCopyToAGPRRegSequence(
UseMI))
1570 if (UseOpc == AMDGPU::V_READFIRSTLANE_B32 ||
1571 (UseOpc == AMDGPU::V_READLANE_B32 &&
1573 AMDGPU::getNamedOperandIdx(UseOpc, AMDGPU::OpName::src0))) {
1578 if (FoldingImmLike) {
1581 *OpToFold.DefMI, *
UseMI))
1587 if (OpToFold.isImm()) {
1589 *OpToFold.getEffectiveImmVal());
1590 }
else if (OpToFold.isFI())
1593 assert(OpToFold.isGlobal());
1595 OpToFold.OpToFold->getOffset(),
1596 OpToFold.OpToFold->getTargetFlags());
1602 if (OpToFold.isReg() &&
TRI->isSGPRReg(*
MRI, OpToFold.getReg())) {
1605 *OpToFold.DefMI, *
UseMI))
1627 UseDesc.
operands()[UseOpIdx].RegClass == -1)
1635 Changed |= tryAddToFoldList(FoldList,
UseMI, UseOpIdx, OpToFold);
1642 case AMDGPU::S_ADD_I32:
1643 case AMDGPU::S_ADD_U32:
1646 case AMDGPU::S_SUB_I32:
1647 case AMDGPU::S_SUB_U32:
1650 case AMDGPU::V_AND_B32_e64:
1651 case AMDGPU::V_AND_B32_e32:
1652 case AMDGPU::S_AND_B32:
1655 case AMDGPU::V_OR_B32_e64:
1656 case AMDGPU::V_OR_B32_e32:
1657 case AMDGPU::S_OR_B32:
1660 case AMDGPU::V_XOR_B32_e64:
1661 case AMDGPU::V_XOR_B32_e32:
1662 case AMDGPU::S_XOR_B32:
1665 case AMDGPU::S_XNOR_B32:
1668 case AMDGPU::S_NAND_B32:
1671 case AMDGPU::S_NOR_B32:
1674 case AMDGPU::S_ANDN2_B32:
1677 case AMDGPU::S_ORN2_B32:
1680 case AMDGPU::V_LSHL_B32_e64:
1681 case AMDGPU::V_LSHL_B32_e32:
1682 case AMDGPU::S_LSHL_B32:
1684 Result =
LHS << (
RHS & 31);
1686 case AMDGPU::V_LSHLREV_B32_e64:
1687 case AMDGPU::V_LSHLREV_B32_e32:
1688 Result =
RHS << (
LHS & 31);
1690 case AMDGPU::V_LSHR_B32_e64:
1691 case AMDGPU::V_LSHR_B32_e32:
1692 case AMDGPU::S_LSHR_B32:
1693 Result =
LHS >> (
RHS & 31);
1695 case AMDGPU::V_LSHRREV_B32_e64:
1696 case AMDGPU::V_LSHRREV_B32_e32:
1697 Result =
RHS >> (
LHS & 31);
1699 case AMDGPU::V_ASHR_I32_e64:
1700 case AMDGPU::V_ASHR_I32_e32:
1701 case AMDGPU::S_ASHR_I32:
1702 Result =
static_cast<int32_t
>(
LHS) >> (
RHS & 31);
1704 case AMDGPU::V_ASHRREV_I32_e64:
1705 case AMDGPU::V_ASHRREV_I32_e32:
1706 Result =
static_cast<int32_t
>(
RHS) >> (
LHS & 31);
1714 return IsScalar ? AMDGPU::S_MOV_B32 : AMDGPU::V_MOV_B32_e32;
1720bool SIFoldOperandsImpl::tryConstantFoldOp(MachineInstr *
MI)
const {
1721 if (!
MI->allImplicitDefsAreDead())
1724 unsigned Opc =
MI->getOpcode();
1726 int Src0Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src0);
1730 MachineOperand *
Src0 = &
MI->getOperand(Src0Idx);
1731 std::optional<int64_t> Src0Imm =
TII->getImmOrMaterializedImm(*
MRI, *Src0);
1733 if ((
Opc == AMDGPU::V_NOT_B32_e64 ||
Opc == AMDGPU::V_NOT_B32_e32 ||
1734 Opc == AMDGPU::S_NOT_B32) &&
1736 MI->getOperand(1).ChangeToImmediate(~*Src0Imm);
1737 TII->mutateAndCleanupImplicit(
1742 int Src1Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src1);
1746 MachineOperand *
Src1 = &
MI->getOperand(Src1Idx);
1747 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*
MRI, *Src1);
1749 if (!Src0Imm && !Src1Imm)
1755 if (Src0Imm && Src1Imm) {
1760 bool IsSGPR =
TRI->isSGPRReg(*
MRI,
MI->getOperand(0).getReg());
1764 MI->getOperand(Src0Idx).ChangeToImmediate(NewImm);
1765 MI->removeOperand(Src1Idx);
1772 if (
Opc == AMDGPU::S_SUB_I32 ||
Opc == AMDGPU::S_SUB_U32) {
1773 if (Src1Imm &&
static_cast<int32_t
>(*Src1Imm) == 0) {
1775 MI->removeOperand(Src1Idx);
1776 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1782 if (!
MI->isCommutable())
1785 if (Src0Imm && !Src1Imm) {
1791 int32_t Src1Val =
static_cast<int32_t
>(*Src1Imm);
1792 if (
Opc == AMDGPU::S_ADD_I32 ||
Opc == AMDGPU::S_ADD_U32) {
1795 MI->removeOperand(Src1Idx);
1796 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1802 if (
Opc == AMDGPU::V_OR_B32_e64 ||
1803 Opc == AMDGPU::V_OR_B32_e32 ||
1804 Opc == AMDGPU::S_OR_B32) {
1807 MI->removeOperand(Src1Idx);
1808 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1809 }
else if (Src1Val == -1) {
1811 MI->removeOperand(Src0Idx);
1812 TII->mutateAndCleanupImplicit(
1820 if (
Opc == AMDGPU::V_AND_B32_e64 ||
Opc == AMDGPU::V_AND_B32_e32 ||
1821 Opc == AMDGPU::S_AND_B32) {
1824 MI->removeOperand(Src0Idx);
1825 TII->mutateAndCleanupImplicit(
1827 }
else if (Src1Val == -1) {
1829 MI->removeOperand(Src1Idx);
1830 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1837 if (
Opc == AMDGPU::V_XOR_B32_e64 ||
Opc == AMDGPU::V_XOR_B32_e32 ||
1838 Opc == AMDGPU::S_XOR_B32) {
1841 MI->removeOperand(Src1Idx);
1842 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1851bool SIFoldOperandsImpl::tryFoldCndMask(MachineInstr &
MI)
const {
1852 unsigned Opc =
MI.getOpcode();
1853 if (
Opc != AMDGPU::V_CNDMASK_B32_e32 &&
Opc != AMDGPU::V_CNDMASK_B32_e64 &&
1854 Opc != AMDGPU::V_CNDMASK_B64_PSEUDO)
1857 MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
1858 MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
1859 if (!
Src1->isIdenticalTo(*Src0)) {
1860 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*
MRI, *Src1);
1864 std::optional<int64_t> Src0Imm =
TII->getImmOrMaterializedImm(*
MRI, *Src0);
1865 if (!Src0Imm || *Src0Imm != *Src1Imm)
1870 AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src1_modifiers);
1872 AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src0_modifiers);
1873 if ((Src1ModIdx != -1 &&
MI.getOperand(Src1ModIdx).getImm() != 0) ||
1874 (Src0ModIdx != -1 &&
MI.getOperand(Src0ModIdx).getImm() != 0))
1880 int Src2Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
1882 MI.removeOperand(Src2Idx);
1883 MI.removeOperand(AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src1));
1884 if (Src1ModIdx != -1)
1885 MI.removeOperand(Src1ModIdx);
1886 if (Src0ModIdx != -1)
1887 MI.removeOperand(Src0ModIdx);
1888 TII->mutateAndCleanupImplicit(
MI, NewDesc);
1895std::optional<SIFoldOperandsImpl::ANDMaskResult>
1896SIFoldOperandsImpl::getANDMaskRegOperand(MachineInstr &AndMI)
const {
1898 if (
Opc != AMDGPU::V_AND_B32_e64 &&
Opc != AMDGPU::V_AND_B32_e32 &&
1899 Opc != AMDGPU::S_AND_B32)
1900 return std::nullopt;
1902 std::optional<int64_t> MaskImm =
1911 return std::nullopt;
1917 AMDGPU::OpName::src0_modifiers, AMDGPU::OpName::src1_modifiers,
1918 AMDGPU::OpName::src2_modifiers, AMDGPU::OpName::op_sel};
1929 switch (
MI.getOpcode()) {
1930 case AMDGPU::V_MAD_U16_gfx9_e64:
1931 LegacyOpc = AMDGPU::V_MAD_U16_e64;
1933 case AMDGPU::V_MAD_I16_gfx9_e64:
1934 LegacyOpc = AMDGPU::V_MAD_I16_e64;
1941 if (
MI.getOperand(AMDGPU::getNamedOperandIdx(
MI.getOpcode(),
OpName))
1960bool SIFoldOperandsImpl::tryFoldRedundantAND(MachineInstr &ChildMI)
const {
1965 std::optional<ANDMaskResult> ChildResult = getANDMaskRegOperand(ChildMI);
1969 if (!ChildResult->Reg.isVirtual())
1976 int64_t ParentMask = 0;
1977 unsigned LegacyOpc = 0;
1978 std::optional<ANDMaskResult> ParentResult = getANDMaskRegOperand(*ParentMI);
1981 ParentMask = ParentResult->Mask;
1984 ParentMask = 0xffff;
1988 ParentMask = 0xffff;
1994 if ((ParentMask & ChildResult->Mask) != ParentMask)
2010 TII->mutateAndCleanupImplicit(*ParentMI,
TII->get(LegacyOpc));
2028bool SIFoldOperandsImpl::tryFoldAndExec(MachineInstr &
MI)
const {
2034 if (!
MI.allImplicitDefsAreDead())
2038 unsigned ExecIdx = 0;
2039 for (
unsigned I : {1u, 2u}) {
2040 const MachineOperand &MO =
MI.getOperand(
I);
2046 MachineOperand &Src =
MI.getOperand(3 - ExecIdx);
2047 if (!Src.isReg() || !Src.getReg().isVirtual() || Src.getSubReg())
2051 if (!
TII->isMaskedByExec(SrcReg,
MI, *
MRI))
2071 MI.eraseFromParent();
2075bool SIFoldOperandsImpl::foldInstOperand(MachineInstr &
MI,
2076 const FoldableDef &OpToFold)
const {
2080 SmallVector<MachineInstr *, 4> CopiesToReplace;
2082 MachineOperand &Dst =
MI.getOperand(0);
2087 for (
auto *U : UsesToProcess) {
2088 MachineInstr *
UseMI =
U->getParent();
2090 FoldableDef SubOpToFold = OpToFold.getWithSubReg(*
TRI,
U->getSubReg());
2095 if (CopiesToReplace.
empty() && FoldList.
empty())
2099 for (MachineInstr *Copy : CopiesToReplace)
2100 Copy->addImplicitDefUseOperands(*MF);
2102 SetVector<MachineInstr *> ConstantFoldCandidates;
2103 for (FoldCandidate &Fold : FoldList) {
2104 assert(!Fold.isReg() || Fold.Def.OpToFold);
2105 if (Fold.isReg() && Fold.getReg().isVirtual()) {
2107 const MachineInstr *
DefMI = Fold.Def.DefMI;
2115 assert(Fold.Def.OpToFold && Fold.isReg());
2122 <<
static_cast<int>(Fold.UseOpNo) <<
" of "
2126 ConstantFoldCandidates.
insert(Fold.UseMI);
2128 }
else if (Fold.Commuted) {
2130 TII->commuteInstruction(*Fold.UseMI,
false);
2134 for (MachineInstr *
MI : ConstantFoldCandidates) {
2135 if (tryConstantFoldOp(
MI)) {
2145bool SIFoldOperandsImpl::foldCopyToAGPRRegSequence(MachineInstr *CopyMI)
const {
2152 if (!
TRI->isAGPRClass(DefRC))
2164 DenseMap<TargetInstrInfo::RegSubRegPair, Register> VGPRCopies;
2173 unsigned NumFoldable = 0;
2175 for (
unsigned I = 1;
I != NumRegSeqOperands;
I += 2) {
2192 DefRC, &AMDGPU::AGPR_32RegClass, SubRegIdx);
2212 TRI->getMatchingSuperRegClass(DefRC, InputRC, SubRegIdx);
2223 if (NumFoldable == 0)
2226 CopyMI->
setDesc(
TII->get(AMDGPU::REG_SEQUENCE));
2230 for (
auto [Def, DestSubIdx] : NewDefs) {
2231 if (!
Def->isReg()) {
2235 BuildMI(
MBB, CopyMI,
DL,
TII->get(AMDGPU::V_ACCVGPR_WRITE_B32_e64), Tmp)
2240 Def->setIsKill(
false);
2242 Register &VGPRCopy = VGPRCopies[Src];
2245 TRI->getSubRegisterClass(UseRC, DestSubIdx);
2270 B.addImm(DestSubIdx);
2277bool SIFoldOperandsImpl::tryFoldFoldableCopy(
2278 MachineInstr &
MI, MachineOperand *&CurrentKnownM0Val)
const {
2282 if (DstReg == AMDGPU::M0) {
2283 MachineOperand &NewM0Val =
MI.getOperand(1);
2284 if (CurrentKnownM0Val && CurrentKnownM0Val->
isIdenticalTo(NewM0Val)) {
2285 MI.eraseFromParent();
2296 MachineOperand *OpToFoldPtr;
2297 if (
MI.getOpcode() == AMDGPU::V_MOV_B16_t16_e64) {
2299 if (
TII->hasAnyModifiersSet(
MI))
2301 OpToFoldPtr = &
MI.getOperand(2);
2303 OpToFoldPtr = &
MI.getOperand(1);
2304 MachineOperand &OpToFold = *OpToFoldPtr;
2308 if (!FoldingImm && !OpToFold.
isReg())
2313 !
TRI->isConstantPhysReg(OpToFold.
getReg()))
2342 if (
MI.getOpcode() == AMDGPU::COPY && OpToFold.
isReg() &&
2344 if (DstRC == &AMDGPU::SReg_32RegClass &&
2346 if (!
TRI->getMatchingSuperRegClass(DstRC, &AMDGPU::SGPR_LO16RegClass,
2355 if (OpToFold.
isReg() &&
MI.isCopy() && !
MI.getOperand(1).getSubReg()) {
2356 if (foldCopyToAGPRRegSequence(&
MI))
2360 FoldableDef
Def(OpToFold, DstRC);
2361 bool Changed = foldInstOperand(
MI, Def);
2368 auto *InstToErase = &
MI;
2370 auto &SrcOp = InstToErase->getOperand(1);
2372 InstToErase->eraseFromParent();
2374 InstToErase =
nullptr;
2378 if (!InstToErase || !
TII->isFoldableCopy(*InstToErase))
2382 if (InstToErase && InstToErase->isRegSequence() &&
2384 InstToErase->eraseFromParent();
2394 return OpToFold.
isReg() &&
2395 foldCopyToVGPROfScalarAddOfFrameIndex(DstReg, OpToFold.
getReg(),
MI);
2400const MachineOperand *
2401SIFoldOperandsImpl::isClamp(
const MachineInstr &
MI)
const {
2402 unsigned Op =
MI.getOpcode();
2404 case AMDGPU::V_MAX_F32_e64:
2405 case AMDGPU::V_MAX_F16_e64:
2406 case AMDGPU::V_MAX_F16_t16_e64:
2407 case AMDGPU::V_MAX_F16_fake16_e64:
2408 case AMDGPU::V_MAX_F64_e64:
2409 case AMDGPU::V_MAX_NUM_F64_e64:
2410 case AMDGPU::V_PK_MAX_F16:
2411 case AMDGPU::V_MAX_BF16_PSEUDO_e64:
2412 case AMDGPU::V_PK_MAX_NUM_BF16: {
2413 if (
MI.mayRaiseFPException())
2416 if (!
TII->getNamedOperand(
MI, AMDGPU::OpName::clamp)->getImm())
2420 const MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2421 const MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2422 if (!
Src0->isReg() || !
Src1->isReg() ||
2423 Src0->getReg() !=
Src1->getReg() ||
2424 Src0->getSubReg() !=
Src1->getSubReg() ||
2425 Src0->getSubReg() != AMDGPU::NoSubRegister)
2429 if (
TII->hasModifiersSet(
MI, AMDGPU::OpName::omod))
2433 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers)->getImm();
2435 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers)->getImm();
2439 unsigned UnsetMods =
2440 (
Op == AMDGPU::V_PK_MAX_F16 ||
Op == AMDGPU::V_PK_MAX_NUM_BF16)
2443 if (Src0Mods != UnsetMods || Src1Mods != UnsetMods)
2453bool SIFoldOperandsImpl::tryFoldClamp(MachineInstr &
MI) {
2454 const MachineOperand *ClampSrc = isClamp(
MI);
2470 if (
Def->mayRaiseFPException())
2473 MachineOperand *DefClamp =
TII->getNamedOperand(*Def, AMDGPU::OpName::clamp);
2477 LLVM_DEBUG(
dbgs() <<
"Folding clamp " << *DefClamp <<
" into " << *Def);
2483 Register MIDstReg =
MI.getOperand(0).getReg();
2484 if (
TRI->isSGPRReg(*
MRI, DefReg)) {
2493 MI.eraseFromParent();
2498 if (
TII->convertToThreeAddress(*Def,
nullptr))
2499 Def->eraseFromParent();
2506 case AMDGPU::V_MUL_F64_e64:
2507 case AMDGPU::V_MUL_F64_pseudo_e64: {
2509 case 0x3fe0000000000000:
2511 case 0x4000000000000000:
2513 case 0x4010000000000000:
2519 case AMDGPU::V_MUL_F32_e64: {
2520 switch (
static_cast<uint32_t>(Val)) {
2531 case AMDGPU::V_MUL_F16_e64:
2532 case AMDGPU::V_MUL_F16_t16_e64:
2533 case AMDGPU::V_MUL_F16_fake16_e64: {
2534 switch (
static_cast<uint16_t>(Val)) {
2545 case AMDGPU::V_PK_MUL_BF16: {
2546 switch (
static_cast<uint16_t>(Val)) {
2565std::pair<const MachineOperand *, int>
2566SIFoldOperandsImpl::isOMod(
const MachineInstr &
MI)
const {
2567 unsigned Op =
MI.getOpcode();
2569 case AMDGPU::V_MUL_F64_e64:
2570 case AMDGPU::V_MUL_F64_pseudo_e64:
2571 case AMDGPU::V_MUL_F32_e64:
2572 case AMDGPU::V_MUL_F16_t16_e64:
2573 case AMDGPU::V_MUL_F16_fake16_e64:
2574 case AMDGPU::V_MUL_F16_e64: {
2576 if ((
Op == AMDGPU::V_MUL_F32_e64 &&
2578 ((
Op == AMDGPU::V_MUL_F64_e64 ||
Op == AMDGPU::V_MUL_F64_pseudo_e64 ||
2579 Op == AMDGPU::V_MUL_F16_e64 ||
Op == AMDGPU::V_MUL_F16_t16_e64 ||
2580 Op == AMDGPU::V_MUL_F16_fake16_e64) &&
2583 MI.mayRaiseFPException())
2586 const MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2587 const MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2590 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*
MRI, *Src1);
2596 TII->hasModifiersSet(
MI, AMDGPU::OpName::src0_modifiers) ||
2597 TII->hasModifiersSet(
MI, AMDGPU::OpName::src1_modifiers) ||
2598 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod) ||
2599 TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp))
2602 return {
Src0, OMod};
2604 case AMDGPU::V_ADD_F64_e64:
2605 case AMDGPU::V_ADD_F64_pseudo_e64:
2606 case AMDGPU::V_ADD_F32_e64:
2607 case AMDGPU::V_ADD_F16_e64:
2608 case AMDGPU::V_ADD_F16_t16_e64:
2609 case AMDGPU::V_ADD_F16_fake16_e64: {
2611 if ((
Op == AMDGPU::V_ADD_F32_e64 &&
2613 ((
Op == AMDGPU::V_ADD_F64_e64 ||
Op == AMDGPU::V_ADD_F64_pseudo_e64 ||
2614 Op == AMDGPU::V_ADD_F16_e64 ||
Op == AMDGPU::V_ADD_F16_t16_e64 ||
2615 Op == AMDGPU::V_ADD_F16_fake16_e64) &&
2620 const MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2621 const MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2624 Src0->getSubReg() ==
Src1->getSubReg() &&
2625 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::src0_modifiers) &&
2626 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::src1_modifiers) &&
2627 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp) &&
2628 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::omod))
2633 case AMDGPU::V_PK_MUL_BF16: {
2638 MI.mayRaiseFPException())
2641 const MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2642 const MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2645 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*
MRI, *Src1);
2649 int OMod =
getOModValue(AMDGPU::V_PK_MUL_BF16, *Src1Imm);
2656 const MachineOperand *Src0Mods =
2657 TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers);
2658 const MachineOperand *Src1Mods =
2659 TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers);
2662 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod) ||
2663 TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp))
2666 return {
Src0, OMod};
2668 case AMDGPU::V_PK_ADD_BF16: {
2674 const MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2675 const MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2677 if (!
Src0->isReg() || !
Src1->isReg() ||
Src0->getReg() !=
Src1->getReg() ||
2678 Src0->getSubReg() !=
Src1->getSubReg())
2682 const MachineOperand *Src0Mods =
2683 TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers);
2684 const MachineOperand *Src1Mods =
2685 TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers);
2688 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod) ||
2689 TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp))
2700bool SIFoldOperandsImpl::tryFoldOMod(MachineInstr &
MI) {
2701 const MachineOperand *RegOp;
2703 std::tie(RegOp, OMod) = isOMod(
MI);
2705 RegOp->
getSubReg() != AMDGPU::NoSubRegister ||
2710 Register OModSrcReg =
Def->getOperand(0).getReg();
2714 if (
Def->isRegSequence() &&
Def->getNumOperands() == 5 &&
2715 Def->getOperand(2).getImm() == AMDGPU::lo16) {
2717 bool CanLookThrough =
true;
2720 CanLookThrough =
false;
2722 if (CanLookThrough) {
2733 MachineOperand *DefOMod =
TII->getNamedOperand(*Def, AMDGPU::OpName::omod);
2737 if (
Def->mayRaiseFPException())
2742 if (
TII->hasModifiersSet(*Def, AMDGPU::OpName::clamp))
2752 MI.eraseFromParent();
2757 if (
TII->convertToThreeAddress(*Def,
nullptr))
2758 Def->eraseFromParent();
2765bool SIFoldOperandsImpl::tryFoldSGPRSplatRegSequence(MachineInstr &
MI) {
2768 if (!ST->hasPackedFP64SingleSGPROps() && !ST->hasPackedU64SingleSGPROps())
2775 if (!
TRI->isSGPRClass(RegClass) ||
TRI->getRegSizeInBits(*RegClass) != 128)
2779 if (!getRegSeqInit(Defs,
Reg))
2783 if (Defs.
size() <= 1)
2786 const auto &[FirstOp,
_] = Defs.
front();
2787 if (!FirstOp->isReg())
2790 Register FirstReg = FirstOp->getReg();
2791 unsigned FirstSubReg = FirstOp->getSubReg();
2794 if (!
TRI->isSGPRClass(FirstRegClass))
2799 const auto &[
Op,
_] =
Def;
2800 return Op->isReg() &&
Op->getReg() == FirstReg &&
2801 Op->getSubReg() == FirstSubReg;
2813 MachineInstrBuilder
RS =
BuildMI(*
MI.getParent(),
MI,
MI.getDebugLoc(),
2814 TII->get(AMDGPU::REG_SEQUENCE), NewDst);
2817 FirstOp->setIsKill(
false);
2819 RS.addImm(Defs[0].second);
2824 for (
unsigned i = 1; i < Defs.
size(); ++i) {
2825 RS.addReg(UndefReg, RegState::Undef);
2826 RS.addImm(Defs[i].second);
2835 MI.eraseFromParent();
2841bool SIFoldOperandsImpl::tryFoldRegSequence(MachineInstr &
MI) {
2845 if (tryFoldSGPRSplatRegSequence(
MI))
2848 auto Reg =
MI.getOperand(0).getReg();
2850 if (!ST->hasGFX90AInsts() || !
TRI->isVGPR(*
MRI,
Reg) ||
2855 if (!getRegSeqInit(Defs,
Reg))
2858 for (
auto &[
Op, SubIdx] : Defs) {
2861 if (
TRI->isAGPR(*
MRI,
Op->getReg()))
2872 MachineInstr *
UseMI =
Op->getParent();
2881 if (
Op->getSubReg())
2887 if (!OpRC || !
TRI->isVectorSuperClass(OpRC))
2893 TII->get(AMDGPU::REG_SEQUENCE), Dst);
2895 for (
auto &[Def, SubIdx] : Defs) {
2896 Def->setIsKill(
false);
2908 if (!
TII->isOperandLegal(*
UseMI, OpIdx,
Op)) {
2910 RS->eraseFromParent();
2919 MI.eraseFromParent();
2927 Register &OutReg,
unsigned &OutSubReg) {
2937 if (
TRI.isAGPR(
MRI, CopySrcReg)) {
2938 OutReg = CopySrcReg;
2947 if (!CopySrcDef || !CopySrcDef->
isCopy())
2954 OtherCopySrc.
getSubReg() != AMDGPU::NoSubRegister ||
2955 !
TRI.isAGPR(
MRI, OtherCopySrcReg))
2958 OutReg = OtherCopySrcReg;
2992bool SIFoldOperandsImpl::tryFoldPhiAGPR(MachineInstr &
PHI) {
2996 if (!
TRI->isVGPR(*
MRI, PhiOut))
3002 for (
unsigned K = 1;
K <
PHI.getNumExplicitOperands();
K += 2) {
3003 MachineOperand &MO =
PHI.getOperand(K);
3005 if (!Copy || !
Copy->isCopy())
3009 unsigned AGPRRegMask = AMDGPU::NoSubRegister;
3014 if (
const auto *SubRC =
TRI->getSubRegisterClass(CopyInRC, AGPRRegMask))
3025 bool IsAGPR32 = (ARC == &AMDGPU::AGPR_32RegClass);
3029 for (
unsigned K = 1;
K <
PHI.getNumExplicitOperands();
K += 2) {
3030 MachineOperand &MO =
PHI.getOperand(K);
3034 MachineBasicBlock *InsertMBB =
nullptr;
3037 unsigned CopyOpc = AMDGPU::COPY;
3042 if (
Def->isCopy()) {
3044 unsigned AGPRSubReg = AMDGPU::NoSubRegister;
3057 MachineOperand &CopyIn =
Def->getOperand(1);
3060 CopyOpc = AMDGPU::V_ACCVGPR_WRITE_B32_e64;
3063 InsertMBB =
Def->getParent();
3071 MachineInstr *
MI =
BuildMI(*InsertMBB, InsertPt,
PHI.getDebugLoc(),
3072 TII->get(CopyOpc), NewReg)
3082 PHI.getOperand(0).setReg(NewReg);
3088 TII->get(AMDGPU::COPY), PhiOut)
3096bool SIFoldOperandsImpl::tryFoldLoad(MachineInstr &
MI) {
3098 if (!ST->hasGFX90AInsts() ||
MI.getNumExplicitDefs() != 1)
3101 MachineOperand &
Def =
MI.getOperand(0);
3118 while (!
Users.empty()) {
3119 const MachineInstr *
I =
Users.pop_back_val();
3120 if (!
I->isCopy() && !
I->isRegSequence())
3122 Register DstReg =
I->getOperand(0).getReg();
3126 if (
TRI->isAGPR(*
MRI, DstReg))
3130 Users.push_back(&U);
3135 if (!
TII->isOperandLegal(
MI, 0, &Def)) {
3140 while (!MoveRegs.
empty()) {
3182bool SIFoldOperandsImpl::tryOptimizeAGPRPhis(MachineBasicBlock &
MBB) {
3185 if (ST->hasGFX90AInsts())
3189 DenseMap<std::pair<Register, unsigned>, std::vector<MachineOperand *>>
3192 for (
auto &
MI :
MBB) {
3196 if (!
TRI->isAGPR(*
MRI,
MI.getOperand(0).getReg()))
3199 for (
unsigned K = 1;
K <
MI.getNumOperands();
K += 2) {
3200 MachineOperand &PhiMO =
MI.getOperand(K);
3210 for (
const auto &[Entry, MOs] : RegToMO) {
3211 if (MOs.size() == 1)
3216 MachineBasicBlock *DefMBB =
Def->getParent();
3223 MachineInstr *VGPRCopy =
3225 TII->get(AMDGPU::V_ACCVGPR_READ_B32_e64), TempVGPR)
3231 TII->get(AMDGPU::COPY), TempAGPR)
3235 for (MachineOperand *MO : MOs) {
3247bool SIFoldOperandsImpl::run(
MachineFunction &MF,
const MachineLoopInfo *MLI) {
3253 MFI = MF.
getInfo<SIMachineFunctionInfo>();
3264 MachineOperand *CurrentKnownM0Val =
nullptr;
3272 if (tryConstantFoldOp(&
MI)) {
3277 if (tryFoldRedundantAND(
MI)) {
3282 if (tryFoldAndExec(
MI)) {
3287 if (
MI.isRegSequence() && tryFoldRegSequence(
MI)) {
3292 if (
MI.isPHI() && tryFoldPhiAGPR(
MI)) {
3297 if (
MI.mayLoad() && tryFoldLoad(
MI)) {
3302 if (
TII->isFoldableCopy(
MI)) {
3303 Changed |= tryFoldFoldableCopy(
MI, CurrentKnownM0Val);
3308 if (CurrentKnownM0Val &&
MI.modifiesRegister(AMDGPU::M0,
TRI))
3309 CurrentKnownM0Val =
nullptr;
3329 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< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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)
MachineRegisterInfo & MRI
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 unsigned getZeroHi16LegacyOpcode(const GCNSubtarget &ST, const MachineInstr &MI)
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)
static constexpr AMDGPU::OpName OpSelOnlyOpNames[]
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(uint64_t Channel, uint64_t 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?
bool isInlinableLiteralBF16(int16_t Literal, bool HasInv2Pi, bool *IsBF16)
@ 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
auto reverse(ContainerTy &&C)
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)
constexpr int64_t SignExtend64(uint64_t x)
Sign-extend the number in the bottom B bits of X to a 64-bit integer.
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.