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 {
255 std::optional<ANDMaskResult> getANDMaskRegOperand(
MachineInstr &AndMI)
const;
261 bool foldInstOperand(
MachineInstr &
MI,
const FoldableDef &OpToFold)
const;
263 bool foldCopyToAGPRRegSequence(
MachineInstr *CopyMI)
const;
270 std::pair<const MachineOperand *, int> isOMod(
const MachineInstr &
MI)
const;
280 SIFoldOperandsImpl() =
default;
295 &getAnalysis<MachineLoopInfoWrapperPass>().getLI();
296 return SIFoldOperandsImpl().run(MF, MLI);
299 StringRef getPassName()
const override {
return "SI Fold Operands"; }
321char SIFoldOperandsLegacy::ID = 0;
330 TRI.getSubRegisterClass(RC, MO.getSubReg()))
338 case AMDGPU::V_MAC_F32_e64:
339 return AMDGPU::V_MAD_F32_e64;
340 case AMDGPU::V_MAC_F16_e64:
341 return AMDGPU::V_MAD_F16_e64;
342 case AMDGPU::V_FMAC_F32_e64:
343 return AMDGPU::V_FMA_F32_e64;
344 case AMDGPU::V_FMAC_F16_e64:
345 return AMDGPU::V_FMA_F16_gfx9_e64;
346 case AMDGPU::V_FMAC_F16_t16_e64:
347 return AMDGPU::V_FMA_F16_gfx9_t16_e64;
348 case AMDGPU::V_FMAC_F16_fake16_e64:
349 return AMDGPU::V_FMA_F16_gfx9_fake16_e64;
350 case AMDGPU::V_FMAC_LEGACY_F32_e64:
351 return AMDGPU::V_FMA_LEGACY_F32_e64;
352 case AMDGPU::V_FMAC_F64_e64:
353 return AMDGPU::V_FMA_F64_e64;
355 return AMDGPU::INSTRUCTION_LIST_END;
361 const FoldableDef &OpToFold)
const {
362 if (!OpToFold.isFI())
365 const unsigned Opc =
UseMI.getOpcode();
367 case AMDGPU::S_ADD_I32:
368 case AMDGPU::S_ADD_U32:
369 case AMDGPU::V_ADD_U32_e32:
370 case AMDGPU::V_ADD_CO_U32_e32:
374 return UseMI.getOperand(OpNo == 1 ? 2 : 1).isImm() &&
376 case AMDGPU::V_ADD_U32_e64:
377 case AMDGPU::V_ADD_CO_U32_e64:
378 return UseMI.getOperand(OpNo == 2 ? 3 : 2).isImm() &&
385 return OpNo == AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::vaddr);
389 int SIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::saddr);
393 int VIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::vaddr);
394 return OpNo == VIdx && SIdx == -1;
400bool SIFoldOperandsImpl::foldCopyToVGPROfScalarAddOfFrameIndex(
405 if (
TRI->isVGPR(*
MRI, DstReg) &&
TRI->isSGPRReg(*
MRI, SrcReg) &&
408 if (!Def ||
Def->getNumOperands() != 4)
411 MachineOperand *
Src0 = &
Def->getOperand(1);
412 MachineOperand *
Src1 = &
Def->getOperand(2);
423 const bool UseVOP3 = !
Src0->isImm() ||
TII->isInlineConstant(*Src0);
424 unsigned NewOp = convertToVALUOp(
Def->getOpcode(), UseVOP3);
425 if (NewOp == AMDGPU::INSTRUCTION_LIST_END ||
426 !
Def->getOperand(3).isDead())
429 MachineBasicBlock *
MBB =
Def->getParent();
431 if (NewOp != AMDGPU::V_ADD_CO_U32_e32) {
432 MachineInstrBuilder
Add =
435 if (
Add->getDesc().getNumDefs() == 2) {
437 Add.addDef(CarryOutReg, RegState::Dead);
441 Add.add(*Src0).add(*Src1).setMIFlags(
Def->getFlags());
445 Def->eraseFromParent();
446 MI.eraseFromParent();
450 assert(NewOp == AMDGPU::V_ADD_CO_U32_e32);
461 Def->eraseFromParent();
462 MI.eraseFromParent();
470bool SIFoldOperandsImpl::canUseImmWithOpSel(
const MachineInstr *
MI,
472 int64_t ImmVal)
const {
478 const MachineOperand &Old =
MI->getOperand(UseOpNo);
479 int OpNo =
MI->getOperandNo(&Old);
481 unsigned Opcode =
MI->getOpcode();
482 uint8_t OpType =
TII->get(Opcode).operands()[OpNo].OperandType;
496 static_cast<uint16_t
>(ImmVal) !=
static_cast<uint16_t
>(ImmVal >> 16))
504bool SIFoldOperandsImpl::tryFoldImmWithOpSel(MachineInstr *
MI,
unsigned UseOpNo,
505 int64_t ImmVal)
const {
506 MachineOperand &Old =
MI->getOperand(UseOpNo);
507 unsigned Opcode =
MI->getOpcode();
508 int OpNo =
MI->getOperandNo(&Old);
509 uint8_t OpType =
TII->get(Opcode).operands()[OpNo].OperandType;
511 bool BF16FromUpperFP32 = ST->hasBF16InlineConstFromUpperFP32() &&
525 AMDGPU::OpName ModName = AMDGPU::OpName::NUM_OPERAND_NAMES;
526 unsigned SrcIdx = ~0;
527 if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src0)) {
528 ModName = AMDGPU::OpName::src0_modifiers;
530 }
else if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src1)) {
531 ModName = AMDGPU::OpName::src1_modifiers;
533 }
else if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src2)) {
534 ModName = AMDGPU::OpName::src2_modifiers;
537 assert(ModName != AMDGPU::OpName::NUM_OPERAND_NAMES);
538 int ModIdx = AMDGPU::getNamedOperandIdx(Opcode, ModName);
539 MachineOperand &
Mod =
MI->getOperand(ModIdx);
540 unsigned ModVal =
Mod.getImm();
546 uint32_t
Imm = (
static_cast<uint32_t
>(ImmHi) << 16) | ImmLo;
551 auto tryFoldToInline = [&](uint32_t
Imm) ->
bool {
552 uint16_t
Lo =
static_cast<uint16_t
>(
Imm);
553 uint16_t
Hi =
static_cast<uint16_t
>(
Imm >> 16);
555 if (BF16FromUpperFP32) {
567 uint32_t
Bits = IsBF16 ?
static_cast<uint32_t
>(
C) << 16
568 : static_cast<uint32_t>(NewImm);
569 uint16_t ReadLo =
static_cast<uint16_t
>(
Bits);
570 uint16_t ReadHi =
static_cast<uint16_t
>(
Bits >> 16);
574 if ((
Lo != ReadLo &&
Lo != ReadHi) || (
Hi != ReadLo &&
Hi != ReadHi))
582 Mod.setImm(NewModVal);
597 Mod.setImm(NewModVal);
602 if (
static_cast<int16_t
>(
Lo) < 0) {
603 int32_t SExt =
static_cast<int16_t
>(
Lo);
605 Mod.setImm(NewModVal);
620 uint32_t Swapped = (
static_cast<uint32_t
>(
Lo) << 16) |
Hi;
631 if (tryFoldToInline(
Imm))
640 bool IsUAdd = Opcode == AMDGPU::V_PK_ADD_U16;
641 bool IsUSub = Opcode == AMDGPU::V_PK_SUB_U16;
642 if (SrcIdx == 1 && (IsUAdd || IsUSub)) {
644 AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::clamp);
645 bool Clamp =
MI->getOperand(ClampIdx).getImm() != 0;
648 uint16_t NegLo = -
static_cast<uint16_t
>(
Imm);
649 uint16_t NegHi = -
static_cast<uint16_t
>(
Imm >> 16);
650 uint32_t NegImm = (
static_cast<uint32_t
>(NegHi) << 16) | NegLo;
652 if (tryFoldToInline(NegImm)) {
654 IsUAdd ? AMDGPU::V_PK_SUB_U16 : AMDGPU::V_PK_ADD_U16;
655 MI->setDesc(
TII->get(NegOpcode));
664bool SIFoldOperandsImpl::updateOperand(FoldCandidate &Fold)
const {
665 MachineInstr *
MI = Fold.UseMI;
666 MachineOperand &Old =
MI->getOperand(Fold.UseOpNo);
669 std::optional<int64_t> ImmVal;
671 ImmVal = Fold.Def.getEffectiveImmVal();
673 if (ImmVal && canUseImmWithOpSel(Fold.UseMI, Fold.UseOpNo, *ImmVal)) {
674 if (tryFoldImmWithOpSel(Fold.UseMI, Fold.UseOpNo, *ImmVal))
680 int OpNo =
MI->getOperandNo(&Old);
681 if (!
TII->isOperandLegal(*
MI, OpNo, &New))
688 if ((Fold.isImm() || Fold.isFI() || Fold.isGlobal()) && Fold.needsShrink()) {
696 int Op32 = Fold.ShrinkOpcode;
697 MachineOperand &Dst0 =
MI->getOperand(0);
698 MachineOperand &Dst1 =
MI->getOperand(1);
706 MachineInstr *Inst32 =
TII->buildShrunkInst(*
MI, Op32);
708 if (HaveNonDbgCarryUse) {
711 .
addReg(AMDGPU::VCC, RegState::Kill);
725 for (
unsigned I =
MI->getNumOperands() - 1;
I > 0; --
I)
726 MI->removeOperand(
I);
727 MI->setDesc(
TII->get(AMDGPU::IMPLICIT_DEF));
730 TII->commuteInstruction(*Inst32,
false);
734 assert(!Fold.needsShrink() &&
"not handled");
739 if (NewMFMAOpc == -1)
741 MI->setDesc(
TII->get(NewMFMAOpc));
742 MI->untieRegOperand(0);
743 const MCInstrDesc &MCID =
MI->getDesc();
744 for (
unsigned I = 0;
I <
MI->getNumDefs(); ++
I)
746 MI->getOperand(
I).setIsEarlyClobber(
true);
751 int OpNo =
MI->getOperandNo(&Old);
752 if (!
TII->isOperandLegal(*
MI, OpNo, &New))
755 if (ST->hasBF16InlineConstFromUpperFP32() &&
757 AMDGPU::getNamedOperandIdx(
MI->getOpcode(), AMDGPU::OpName::src0)) {
758 unsigned Opcode =
MI->getOpcode();
759 uint8_t OpType =
TII->get(Opcode).operands()[OpNo].OperandType;
762 TII->isInlineConstant(*ImmVal, OpType)) {
765 AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src0_modifiers);
768 MachineOperand &ModOp =
MI->getOperand(Mod0);
779 if (Fold.isGlobal()) {
780 Old.
ChangeToGA(Fold.Def.OpToFold->getGlobal(),
781 Fold.Def.OpToFold->getOffset(),
782 Fold.Def.OpToFold->getTargetFlags());
791 MachineOperand *
New = Fold.Def.OpToFold;
795 TII->getRegClass(
MI->getDesc(), Fold.UseOpNo)) {
797 TRI->getRegClassForReg(*
MRI,
New->getReg());
800 if (
New->getSubReg()) {
802 TRI->getMatchingSuperRegClass(NewRC, OpRC,
New->getSubReg());
808 if (
New->getReg().isVirtual() &&
811 <<
TRI->getRegClassName(ConstrainRC) <<
'\n');
820 if (
New->getReg().isPhysical()) {
828 if (
MI->isBundledWithPred()) {
830 for (MachineOperand &MO : Header.operands()) {
831 if (MO.getReg() == OldReg) {
832 MO.setReg(
New->getReg());
833 MO.setSubReg(
New->getSubReg());
842 FoldCandidate &&Entry) {
844 for (FoldCandidate &Fold : FoldList)
845 if (Fold.UseMI == Entry.UseMI && Fold.UseOpNo == Entry.UseOpNo)
847 LLVM_DEBUG(
dbgs() <<
"Append " << (Entry.Commuted ?
"commuted" :
"normal")
848 <<
" operand " << Entry.UseOpNo <<
"\n " << *Entry.UseMI);
854 const FoldableDef &FoldOp,
855 bool Commuted =
false,
int ShrinkOp = -1) {
857 FoldCandidate(
MI, OpNo, FoldOp, Commuted, ShrinkOp));
865 if (!ST->hasPKF32InstsReplicatingLower32BitsOfScalarInput())
875 const FoldableDef &OpToFold) {
876 assert(OpToFold.isImm() &&
"Expected immediate operand");
877 uint64_t ImmVal = OpToFold.getEffectiveImmVal().value();
883bool SIFoldOperandsImpl::tryAddToFoldList(
884 SmallVectorImpl<FoldCandidate> &FoldList, MachineInstr *
MI,
unsigned OpNo,
885 const FoldableDef &OpToFold)
const {
886 const unsigned Opc =
MI->getOpcode();
888 auto tryToFoldAsFMAAKorMK = [&]() {
889 if (!OpToFold.isImm())
892 const bool TryAK = OpNo == 3;
893 const unsigned NewOpc = TryAK ? AMDGPU::S_FMAAK_F32 : AMDGPU::S_FMAMK_F32;
894 MI->setDesc(
TII->get(NewOpc));
897 bool FoldAsFMAAKorMK =
898 tryAddToFoldList(FoldList,
MI, TryAK ? 3 : 2, OpToFold);
899 if (FoldAsFMAAKorMK) {
901 MI->untieRegOperand(3);
904 MachineOperand &Op1 =
MI->getOperand(1);
905 MachineOperand &Op2 =
MI->getOperand(2);
922 bool IsLegal = OpToFold.isOperandLegal(*
TII, *
MI, OpNo);
923 if (!IsLegal && OpToFold.isImm()) {
924 if (std::optional<int64_t> ImmVal = OpToFold.getEffectiveImmVal())
925 IsLegal = canUseImmWithOpSel(
MI, OpNo, *ImmVal);
931 if (NewOpc != AMDGPU::INSTRUCTION_LIST_END) {
934 MI->setDesc(
TII->get(NewOpc));
939 bool FoldAsMAD = tryAddToFoldList(FoldList,
MI, OpNo, OpToFold);
941 MI->untieRegOperand(OpNo);
945 MI->removeOperand(
MI->getNumExplicitOperands() - 1);
951 if (
Opc == AMDGPU::S_FMAC_F32 && OpNo == 3) {
952 if (tryToFoldAsFMAAKorMK())
958 if ((
Opc == AMDGPU::S_FMAAK_F32 ||
Opc == AMDGPU::S_FMAMK_F32) &&
960 std::optional<int64_t> ImmVal = OpToFold.getEffectiveImmVal();
961 if (ImmVal && !
TII->isInlineConstant(*
MI, OpNo, *ImmVal)) {
962 unsigned ImmIdx =
Opc == AMDGPU::S_FMAAK_F32 ? 3 : 2;
963 MachineOperand &OpImm =
MI->getOperand(ImmIdx);
964 if (!OpImm.
isReg() &&
965 TII->isInlineConstant(*
MI,
MI->getOperand(OpNo), OpImm))
966 return tryToFoldAsFMAAKorMK();
971 if (OpToFold.isImm()) {
973 if (
Opc == AMDGPU::S_SETREG_B32)
974 ImmOpc = AMDGPU::S_SETREG_IMM32_B32;
975 else if (
Opc == AMDGPU::S_SETREG_B32_mode)
976 ImmOpc = AMDGPU::S_SETREG_IMM32_B32_mode;
978 MI->setDesc(
TII->get(ImmOpc));
987 bool CanCommute =
TII->findCommutedOpIndices(*
MI, OpNo, CommuteOpNo);
991 MachineOperand &
Op =
MI->getOperand(OpNo);
992 MachineOperand &CommutedOp =
MI->getOperand(CommuteOpNo);
998 if (!
Op.isReg() || !CommutedOp.
isReg())
1003 if (
Op.isReg() && CommutedOp.
isReg() &&
1004 (
Op.getReg() == CommutedOp.
getReg() &&
1008 if (!
TII->commuteInstruction(*
MI,
false, OpNo, CommuteOpNo))
1012 if (!OpToFold.isOperandLegal(*
TII, *
MI, CommuteOpNo)) {
1013 if ((
Opc != AMDGPU::V_ADD_CO_U32_e64 &&
Opc != AMDGPU::V_SUB_CO_U32_e64 &&
1014 Opc != AMDGPU::V_SUBREV_CO_U32_e64) ||
1015 (!OpToFold.isImm() && !OpToFold.isFI() && !OpToFold.isGlobal())) {
1016 TII->commuteInstruction(*
MI,
false, OpNo, CommuteOpNo);
1022 MachineOperand &OtherOp =
MI->getOperand(OpNo);
1023 if (!OtherOp.
isReg() ||
1030 unsigned MaybeCommutedOpc =
MI->getOpcode();
1044 if (
Opc == AMDGPU::S_FMAC_F32 &&
1045 (OpNo != 1 || !
MI->getOperand(1).isIdenticalTo(
MI->getOperand(2)))) {
1046 if (tryToFoldAsFMAAKorMK())
1052 if (OpToFold.isImm() &&
1061bool SIFoldOperandsImpl::isUseSafeToFold(
const MachineInstr &
MI,
1062 const MachineOperand &UseMO)
const {
1064 return !
TII->isSDWA(
MI);
1071 if (
MI.modifiesRegister(
TRI.getExec(), &
TRI))
1079bool SIFoldOperandsImpl::isTemporallyDivergentUse(
1080 const FoldableDef &OpToFold,
const MachineInstr &
UseMI)
const {
1081 if (!OpToFold.isReg())
1083 const MachineInstr *
DefMI = OpToFold.DefMI;
1086 !
TRI->isSGPRReg(*
MRI, OpToFold.getReg()))
1098 SubDef &&
TII.isFoldableCopy(*SubDef);
1099 SubDef =
MRI.getVRegDef(
Sub->getReg())) {
1100 unsigned SrcIdx =
TII.getFoldableCopySrcIdx(*SubDef);
1109 if (
SrcOp.getSubReg())
1117 MachineInstr &RegSeq,
1118 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs)
const {
1134 else if (!
TRI->getCommonSubClass(RC, OpRC))
1139 Defs.emplace_back(&SrcOp, SubRegIdx);
1144 if (DefSrc && (DefSrc->
isReg() || DefSrc->
isImm())) {
1145 Defs.emplace_back(DefSrc, SubRegIdx);
1149 Defs.emplace_back(&SrcOp, SubRegIdx);
1159 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs,
1162 if (!Def || !
Def->isRegSequence())
1165 return getRegSeqInit(*Def, Defs);
1168std::pair<int64_t, const TargetRegisterClass *>
1169SIFoldOperandsImpl::isRegSeqSplat(MachineInstr &RegSeq)
const {
1175 bool TryToMatchSplat64 =
false;
1177 std::optional<int64_t>
Imm;
1178 for (
unsigned I = 0,
E = Defs.
size();
I !=
E; ++
I) {
1179 const MachineOperand *
Op = Defs[
I].first;
1183 if (!Def ||
Def->isImplicitDef())
1189 int64_t SubImm =
Op->getImm();
1195 if (
Imm != SubImm) {
1196 if (
I == 1 && (
E & 1) == 0) {
1199 TryToMatchSplat64 =
true;
1207 if (!TryToMatchSplat64) {
1209 return {*
Imm, SrcRC};
1216 for (
unsigned I = 0,
E = Defs.
size();
I !=
E;
I += 2) {
1217 const MachineOperand *Op0 = Defs[
I].first;
1218 const MachineOperand *Op1 = Defs[
I + 1].first;
1223 unsigned SubReg0 = Defs[
I].second;
1224 unsigned SubReg1 = Defs[
I + 1].second;
1228 if (
TRI->getChannelFromSubReg(SubReg0) + 1 !=
1229 TRI->getChannelFromSubReg(SubReg1))
1232 if (
TRI->getSubRegIdxSize(SubReg0) != 32)
1237 SplatVal64 = MergedVal;
1238 else if (SplatVal64 != MergedVal)
1245 return {SplatVal64, RC64};
1248bool SIFoldOperandsImpl::tryFoldRegSeqSplat(
1249 MachineInstr *
UseMI,
unsigned UseOpIdx, int64_t SplatVal,
1252 if (UseOpIdx >=
Desc.getNumOperands())
1259 int16_t RCID =
TII->getOpRegClassID(
Desc.operands()[UseOpIdx]);
1268 if (SplatVal != 0 && SplatVal != -1) {
1272 uint8_t OpTy =
Desc.operands()[UseOpIdx].OperandType;
1279 OpRC =
TRI->getSubRegisterClass(OpRC, AMDGPU::sub0);
1286 OpRC =
TRI->getSubRegisterClass(OpRC, AMDGPU::sub0_sub1);
1292 if (!
TRI->getCommonSubClass(OpRC, SplatRC))
1297 if (!
TII->isOperandLegal(*
UseMI, UseOpIdx, &TmpOp))
1303bool SIFoldOperandsImpl::tryToFoldACImm(
1304 const FoldableDef &OpToFold, MachineInstr *
UseMI,
unsigned UseOpIdx,
1305 SmallVectorImpl<FoldCandidate> &FoldList)
const {
1307 if (UseOpIdx >=
Desc.getNumOperands())
1314 if (OpToFold.isImm() && OpToFold.isOperandLegal(*
TII, *
UseMI, UseOpIdx)) {
1325bool SIFoldOperandsImpl::foldOperand(
1326 FoldableDef OpToFold, MachineInstr *
UseMI,
int UseOpIdx,
1327 SmallVectorImpl<FoldCandidate> &FoldList,
1328 SmallVectorImpl<MachineInstr *> &CopiesToReplace)
const {
1332 if (!isUseSafeToFold(*
UseMI, *UseOp))
1335 if (isTemporallyDivergentUse(OpToFold, *
UseMI))
1339 if (UseOp->
isReg() && OpToFold.isReg()) {
1343 if (UseOp->
getSubReg() != AMDGPU::NoSubRegister &&
1345 !
TRI->isSGPRReg(*
MRI, OpToFold.getReg())))
1358 std::tie(SplatVal, SplatRC) = isRegSeqSplat(*
UseMI);
1363 for (
unsigned I = 0;
I != UsesToProcess.size(); ++
I) {
1364 MachineOperand *RSUse = UsesToProcess[
I];
1365 MachineInstr *RSUseMI = RSUse->
getParent();
1375 if (tryFoldRegSeqSplat(RSUseMI, OpNo, SplatVal, SplatRC)) {
1376 FoldableDef SplatDef(SplatVal, SplatRC);
1384 if (RSUse->
getSubReg() != RegSeqDstSubReg)
1390 FoldList, CopiesToReplace);
1396 if (tryToFoldACImm(OpToFold,
UseMI, UseOpIdx, FoldList))
1399 if (frameIndexMayFold(*
UseMI, UseOpIdx, OpToFold)) {
1404 if (
TII->getNamedOperand(*
UseMI, AMDGPU::OpName::srsrc)->getReg() !=
1410 MachineOperand &SOff =
1411 *
TII->getNamedOperand(*
UseMI, AMDGPU::OpName::soffset);
1422 TII->getNamedOperand(*
UseMI, AMDGPU::OpName::cpol)->getImm();
1437 bool FoldingImmLike =
1438 OpToFold.isImm() || OpToFold.isFI() || OpToFold.isGlobal();
1457 for (
unsigned MovOp :
1458 {AMDGPU::S_MOV_B32, AMDGPU::V_MOV_B32_e32, AMDGPU::S_MOV_B64,
1459 AMDGPU::V_MOV_B64_PSEUDO, AMDGPU::V_MOV_B16_t16_e64,
1460 AMDGPU::V_ACCVGPR_WRITE_B32_e64, AMDGPU::AV_MOV_B32_IMM_PSEUDO,
1461 AMDGPU::AV_MOV_B64_IMM_PSEUDO}) {
1462 const MCInstrDesc &MovDesc =
TII->get(MovOp);
1472 const int SrcIdx = MovOp == AMDGPU::V_MOV_B16_t16_e64 ? 2 : 1;
1474 int16_t RegClassID =
TII->getOpRegClassID(MovDesc.
operands()[SrcIdx]);
1475 if (RegClassID != -1) {
1479 MovSrcRC =
TRI->getMatchingSuperRegClass(SrcRC, MovSrcRC, UseSubReg);
1483 if (MovOp == AMDGPU::AV_MOV_B32_IMM_PSEUDO &&
1484 (!OpToFold.isImm() ||
1485 !
TII->isImmOperandLegal(MovDesc, SrcIdx,
1486 *OpToFold.getEffectiveImmVal())))
1499 if (!OpToFold.isImm() ||
1500 !
TII->isImmOperandLegal(MovDesc, 1, *OpToFold.getEffectiveImmVal()))
1506 while (ImpOpI != ImpOpE) {
1513 if (MovOp == AMDGPU::V_MOV_B16_t16_e64) {
1515 MachineOperand NewSrcOp(SrcOp);
1537 LLVM_DEBUG(
dbgs() <<
"Folding " << *OpToFold.OpToFold <<
"\n into "
1542 unsigned SubRegIdx = OpToFold.getSubReg();
1547 TRI->isSGPRReg(*
MRI,
UseReg) && SubRegIdx != AMDGPU::NoSubRegister) {
1550 unsigned Channel =
TRI->getChannelFromSubReg(SubRegIdx);
1552 SubRegIdx =
TRI->getRegSizeInBits(*UseRC) == 32
1553 ? AMDGPU::NoSubRegister
1559 OpToFold.OpToFold->setIsKill(
false);
1562 if (foldCopyToAGPRRegSequence(
UseMI))
1567 if (UseOpc == AMDGPU::V_READFIRSTLANE_B32 ||
1568 (UseOpc == AMDGPU::V_READLANE_B32 &&
1570 AMDGPU::getNamedOperandIdx(UseOpc, AMDGPU::OpName::src0))) {
1575 if (FoldingImmLike) {
1578 *OpToFold.DefMI, *
UseMI))
1584 if (OpToFold.isImm()) {
1586 *OpToFold.getEffectiveImmVal());
1587 }
else if (OpToFold.isFI())
1590 assert(OpToFold.isGlobal());
1592 OpToFold.OpToFold->getOffset(),
1593 OpToFold.OpToFold->getTargetFlags());
1599 if (OpToFold.isReg() &&
TRI->isSGPRReg(*
MRI, OpToFold.getReg())) {
1602 *OpToFold.DefMI, *
UseMI))
1624 UseDesc.
operands()[UseOpIdx].RegClass == -1)
1632 Changed |= tryAddToFoldList(FoldList,
UseMI, UseOpIdx, OpToFold);
1639 case AMDGPU::S_ADD_I32:
1640 case AMDGPU::S_ADD_U32:
1643 case AMDGPU::S_SUB_I32:
1644 case AMDGPU::S_SUB_U32:
1647 case AMDGPU::V_AND_B32_e64:
1648 case AMDGPU::V_AND_B32_e32:
1649 case AMDGPU::S_AND_B32:
1652 case AMDGPU::V_OR_B32_e64:
1653 case AMDGPU::V_OR_B32_e32:
1654 case AMDGPU::S_OR_B32:
1657 case AMDGPU::V_XOR_B32_e64:
1658 case AMDGPU::V_XOR_B32_e32:
1659 case AMDGPU::S_XOR_B32:
1662 case AMDGPU::S_XNOR_B32:
1665 case AMDGPU::S_NAND_B32:
1668 case AMDGPU::S_NOR_B32:
1671 case AMDGPU::S_ANDN2_B32:
1674 case AMDGPU::S_ORN2_B32:
1677 case AMDGPU::V_LSHL_B32_e64:
1678 case AMDGPU::V_LSHL_B32_e32:
1679 case AMDGPU::S_LSHL_B32:
1681 Result =
LHS << (
RHS & 31);
1683 case AMDGPU::V_LSHLREV_B32_e64:
1684 case AMDGPU::V_LSHLREV_B32_e32:
1685 Result =
RHS << (
LHS & 31);
1687 case AMDGPU::V_LSHR_B32_e64:
1688 case AMDGPU::V_LSHR_B32_e32:
1689 case AMDGPU::S_LSHR_B32:
1690 Result =
LHS >> (
RHS & 31);
1692 case AMDGPU::V_LSHRREV_B32_e64:
1693 case AMDGPU::V_LSHRREV_B32_e32:
1694 Result =
RHS >> (
LHS & 31);
1696 case AMDGPU::V_ASHR_I32_e64:
1697 case AMDGPU::V_ASHR_I32_e32:
1698 case AMDGPU::S_ASHR_I32:
1699 Result =
static_cast<int32_t
>(
LHS) >> (
RHS & 31);
1701 case AMDGPU::V_ASHRREV_I32_e64:
1702 case AMDGPU::V_ASHRREV_I32_e32:
1703 Result =
static_cast<int32_t
>(
RHS) >> (
LHS & 31);
1711 return IsScalar ? AMDGPU::S_MOV_B32 : AMDGPU::V_MOV_B32_e32;
1717bool SIFoldOperandsImpl::tryConstantFoldOp(MachineInstr *
MI)
const {
1718 if (!
MI->allImplicitDefsAreDead())
1721 unsigned Opc =
MI->getOpcode();
1724 if (
Opc == AMDGPU::V_LSHL_ADD_U32_e64) {
1725 int DataIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src0);
1726 int AddIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
1727 std::optional<int64_t> Addend =
1728 TII->getImmOrMaterializedImm(*
MRI,
MI->getOperand(AddIdx));
1730 if (Addend &&
static_cast<uint32_t
>(*Addend) == 0) {
1731 MachineOperand
Data =
MI->getOperand(DataIdx);
1732 MI->removeOperand(AddIdx);
1733 MI->removeOperand(DataIdx);
1734 MI->addOperand(*MF,
Data);
1735 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::V_LSHLREV_B32_e64));
1740 int Src0Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src0);
1744 MachineOperand *
Src0 = &
MI->getOperand(Src0Idx);
1745 std::optional<int64_t> Src0Imm =
TII->getImmOrMaterializedImm(*
MRI, *Src0);
1747 if ((
Opc == AMDGPU::V_NOT_B32_e64 ||
Opc == AMDGPU::V_NOT_B32_e32 ||
1748 Opc == AMDGPU::S_NOT_B32) &&
1750 MI->getOperand(1).ChangeToImmediate(~*Src0Imm);
1751 TII->mutateAndCleanupImplicit(
1756 int Src1Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src1);
1760 MachineOperand *
Src1 = &
MI->getOperand(Src1Idx);
1761 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*
MRI, *Src1);
1763 if (!Src0Imm && !Src1Imm)
1769 if (Src0Imm && Src1Imm) {
1774 bool IsSGPR =
TRI->isSGPRReg(*
MRI,
MI->getOperand(0).getReg());
1778 MI->getOperand(Src0Idx).ChangeToImmediate(NewImm);
1779 MI->removeOperand(Src1Idx);
1786 if (
Opc == AMDGPU::S_SUB_I32 ||
Opc == AMDGPU::S_SUB_U32) {
1787 if (Src1Imm &&
static_cast<int32_t
>(*Src1Imm) == 0) {
1789 MI->removeOperand(Src1Idx);
1790 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1796 if (!
MI->isCommutable())
1799 if (Src0Imm && !Src1Imm) {
1805 int32_t Src1Val =
static_cast<int32_t
>(*Src1Imm);
1806 if (
Opc == AMDGPU::S_ADD_I32 ||
Opc == AMDGPU::S_ADD_U32) {
1809 MI->removeOperand(Src1Idx);
1810 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1816 if (
Opc == AMDGPU::V_OR_B32_e64 ||
1817 Opc == AMDGPU::V_OR_B32_e32 ||
1818 Opc == AMDGPU::S_OR_B32) {
1821 MI->removeOperand(Src1Idx);
1822 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1823 }
else if (Src1Val == -1) {
1825 MI->removeOperand(Src0Idx);
1826 TII->mutateAndCleanupImplicit(
1834 if (
Opc == AMDGPU::V_AND_B32_e64 ||
Opc == AMDGPU::V_AND_B32_e32 ||
1835 Opc == AMDGPU::S_AND_B32) {
1838 MI->removeOperand(Src0Idx);
1839 TII->mutateAndCleanupImplicit(
1841 }
else if (Src1Val == -1) {
1843 MI->removeOperand(Src1Idx);
1844 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1851 if (
Opc == AMDGPU::V_XOR_B32_e64 ||
Opc == AMDGPU::V_XOR_B32_e32 ||
1852 Opc == AMDGPU::S_XOR_B32) {
1855 MI->removeOperand(Src1Idx);
1856 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1865bool SIFoldOperandsImpl::tryFoldCndMask(MachineInstr &
MI)
const {
1866 unsigned Opc =
MI.getOpcode();
1867 if (
Opc != AMDGPU::V_CNDMASK_B32_e32 &&
Opc != AMDGPU::V_CNDMASK_B32_e64 &&
1868 Opc != AMDGPU::S_CSELECT_B32 &&
Opc != AMDGPU::S_CSELECT_B64)
1871 MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
1872 MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
1873 if (!
Src1->isIdenticalTo(*Src0)) {
1874 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*
MRI, *Src1);
1878 std::optional<int64_t> Src0Imm =
TII->getImmOrMaterializedImm(*
MRI, *Src0);
1879 if (!Src0Imm || *Src0Imm != *Src1Imm)
1884 AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src1_modifiers);
1886 AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src0_modifiers);
1887 if ((Src1ModIdx != -1 &&
MI.getOperand(Src1ModIdx).getImm() != 0) ||
1888 (Src0ModIdx != -1 &&
MI.getOperand(Src0ModIdx).getImm() != 0))
1892 if (
Src0->isReg()) {
1893 NewOpc = AMDGPU::COPY;
1896 case AMDGPU::S_CSELECT_B32:
1897 NewOpc = AMDGPU::S_MOV_B32;
1899 case AMDGPU::S_CSELECT_B64:
1900 NewOpc = AMDGPU::S_MOV_B64;
1903 NewOpc = AMDGPU::V_MOV_B32_e32;
1909 int Src2Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
1911 MI.removeOperand(Src2Idx);
1912 MI.removeOperand(AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src1));
1913 if (Src1ModIdx != -1)
1914 MI.removeOperand(Src1ModIdx);
1915 if (Src0ModIdx != -1)
1916 MI.removeOperand(Src0ModIdx);
1917 TII->mutateAndCleanupImplicit(
MI,
TII->get(NewOpc));
1924std::optional<SIFoldOperandsImpl::ANDMaskResult>
1925SIFoldOperandsImpl::getANDMaskRegOperand(MachineInstr &AndMI)
const {
1927 if (
Opc != AMDGPU::V_AND_B32_e64 &&
Opc != AMDGPU::V_AND_B32_e32 &&
1928 Opc != AMDGPU::S_AND_B32)
1929 return std::nullopt;
1931 std::optional<int64_t> MaskImm =
1940 return std::nullopt;
1946 AMDGPU::OpName::src0_modifiers, AMDGPU::OpName::src1_modifiers,
1947 AMDGPU::OpName::src2_modifiers, AMDGPU::OpName::op_sel};
1958 switch (
MI.getOpcode()) {
1959 case AMDGPU::V_MAD_U16_gfx9_e64:
1960 LegacyOpc = AMDGPU::V_MAD_U16_e64;
1962 case AMDGPU::V_MAD_I16_gfx9_e64:
1963 LegacyOpc = AMDGPU::V_MAD_I16_e64;
1970 if (
MI.getOperand(AMDGPU::getNamedOperandIdx(
MI.getOpcode(),
OpName))
1989bool SIFoldOperandsImpl::tryFoldRedundantAND(MachineInstr &ChildMI)
const {
1994 std::optional<ANDMaskResult> ChildResult = getANDMaskRegOperand(ChildMI);
1998 if (!ChildResult->Reg.isVirtual())
2005 int64_t ParentMask = 0;
2006 unsigned LegacyOpc = 0;
2007 std::optional<ANDMaskResult> ParentResult = getANDMaskRegOperand(*ParentMI);
2010 ParentMask = ParentResult->Mask;
2013 ParentMask = 0xffff;
2017 ParentMask = 0xffff;
2023 if ((ParentMask & ChildResult->Mask) != ParentMask)
2039 TII->mutateAndCleanupImplicit(*ParentMI,
TII->get(LegacyOpc));
2053bool SIFoldOperandsImpl::tryFoldAndExec(MachineInstr &
MI)
const {
2059 if (!
MI.allImplicitDefsAreDead())
2063 unsigned ExecIdx = 0;
2064 for (
unsigned I : {1u, 2u}) {
2065 const MachineOperand &MO =
MI.getOperand(
I);
2071 MachineOperand &Src =
MI.getOperand(3 - ExecIdx);
2072 if (!Src.isReg() || !Src.getReg().isVirtual() || Src.getSubReg())
2076 if (!
TII->isMaskedByExec(SrcReg,
MI, *
MRI))
2094 MI.eraseFromParent();
2098bool SIFoldOperandsImpl::foldInstOperand(MachineInstr &
MI,
2099 const FoldableDef &OpToFold)
const {
2103 SmallVector<MachineInstr *, 4> CopiesToReplace;
2105 MachineOperand &Dst =
MI.getOperand(0);
2110 for (
auto *U : UsesToProcess) {
2111 MachineInstr *
UseMI =
U->getParent();
2113 FoldableDef SubOpToFold = OpToFold.getWithSubReg(*
TRI,
U->getSubReg());
2118 if (CopiesToReplace.
empty() && FoldList.
empty())
2122 for (MachineInstr *Copy : CopiesToReplace)
2123 Copy->addImplicitDefUseOperands(*MF);
2125 SetVector<MachineInstr *> ConstantFoldCandidates;
2126 for (FoldCandidate &Fold : FoldList) {
2127 assert(!Fold.isReg() || Fold.Def.OpToFold);
2128 if (Fold.isReg() && Fold.getReg().isVirtual()) {
2130 const MachineInstr *
DefMI = Fold.Def.DefMI;
2137 <<
static_cast<int>(Fold.UseOpNo) <<
" of "
2141 ConstantFoldCandidates.
insert(Fold.UseMI);
2143 }
else if (Fold.Commuted) {
2145 TII->commuteInstruction(*Fold.UseMI,
false);
2149 for (MachineInstr *
MI : ConstantFoldCandidates) {
2150 if (tryConstantFoldOp(
MI)) {
2160bool SIFoldOperandsImpl::foldCopyToAGPRRegSequence(MachineInstr *CopyMI)
const {
2167 if (!
TRI->isAGPRClass(DefRC))
2179 DenseMap<TargetInstrInfo::RegSubRegPair, Register> VGPRCopies;
2188 unsigned NumFoldable = 0;
2190 for (
unsigned I = 1;
I != NumRegSeqOperands;
I += 2) {
2207 DefRC, &AMDGPU::AGPR_32RegClass, SubRegIdx);
2227 TRI->getMatchingSuperRegClass(DefRC, InputRC, SubRegIdx);
2238 if (NumFoldable == 0)
2241 CopyMI->
setDesc(
TII->get(AMDGPU::REG_SEQUENCE));
2245 for (
auto [Def, DestSubIdx] : NewDefs) {
2246 if (!
Def->isReg()) {
2250 BuildMI(
MBB, CopyMI,
DL,
TII->get(AMDGPU::V_ACCVGPR_WRITE_B32_e64), Tmp)
2255 Def->setIsKill(
false);
2257 Register &VGPRCopy = VGPRCopies[Src];
2260 TRI->getSubRegisterClass(UseRC, DestSubIdx);
2285 B.addImm(DestSubIdx);
2292bool SIFoldOperandsImpl::tryFoldFoldableCopy(
2293 MachineInstr &
MI, MachineOperand *&CurrentKnownM0Val)
const {
2297 if (DstReg == AMDGPU::M0) {
2298 MachineOperand &NewM0Val =
MI.getOperand(1);
2299 if (CurrentKnownM0Val && CurrentKnownM0Val->
isIdenticalTo(NewM0Val)) {
2300 MI.eraseFromParent();
2311 MachineOperand *OpToFoldPtr;
2312 if (
MI.getOpcode() == AMDGPU::V_MOV_B16_t16_e64) {
2314 if (
TII->hasAnyModifiersSet(
MI))
2316 OpToFoldPtr = &
MI.getOperand(2);
2318 OpToFoldPtr = &
MI.getOperand(1);
2319 MachineOperand &OpToFold = *OpToFoldPtr;
2323 if (!FoldingImm && !OpToFold.
isReg())
2328 !
TRI->isConstantPhysReg(OpToFold.
getReg()))
2357 if (
MI.getOpcode() == AMDGPU::COPY && OpToFold.
isReg() &&
2359 if (DstRC == &AMDGPU::SReg_32RegClass &&
2361 if (!
TRI->getMatchingSuperRegClass(DstRC, &AMDGPU::SGPR_LO16RegClass,
2370 if (OpToFold.
isReg() &&
MI.isCopy() && !
MI.getOperand(1).getSubReg()) {
2371 if (foldCopyToAGPRRegSequence(&
MI))
2375 FoldableDef
Def(OpToFold, DstRC);
2376 bool Changed = foldInstOperand(
MI, Def);
2383 auto *InstToErase = &
MI;
2385 auto &SrcOp = InstToErase->getOperand(1);
2387 InstToErase->eraseFromParent();
2389 InstToErase =
nullptr;
2393 if (!InstToErase || !
TII->isFoldableCopy(*InstToErase))
2397 if (InstToErase && InstToErase->isRegSequence() &&
2399 InstToErase->eraseFromParent();
2409 return OpToFold.
isReg() &&
2410 foldCopyToVGPROfScalarAddOfFrameIndex(DstReg, OpToFold.
getReg(),
MI);
2415const MachineOperand *
2416SIFoldOperandsImpl::isClamp(
const MachineInstr &
MI)
const {
2417 unsigned Op =
MI.getOpcode();
2419 case AMDGPU::V_MAX_F32_e64:
2420 case AMDGPU::V_MAX_F16_e64:
2421 case AMDGPU::V_MAX_F16_t16_e64:
2422 case AMDGPU::V_MAX_F16_fake16_e64:
2423 case AMDGPU::V_MAX_F64_e64:
2424 case AMDGPU::V_MAX_NUM_F64_e64:
2425 case AMDGPU::V_PK_MAX_F16:
2426 case AMDGPU::V_MAX_BF16_PSEUDO_e64:
2427 case AMDGPU::V_PK_MAX_NUM_BF16: {
2428 if (
MI.mayRaiseFPException())
2431 if (!
TII->getNamedOperand(
MI, AMDGPU::OpName::clamp)->getImm())
2435 const MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2436 const MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2437 if (!
Src0->isReg() || !
Src1->isReg() ||
2438 Src0->getReg() !=
Src1->getReg() ||
2439 Src0->getSubReg() !=
Src1->getSubReg() ||
2440 Src0->getSubReg() != AMDGPU::NoSubRegister)
2444 if (
TII->hasModifiersSet(
MI, AMDGPU::OpName::omod))
2448 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers)->getImm();
2450 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers)->getImm();
2454 unsigned UnsetMods =
2455 (
Op == AMDGPU::V_PK_MAX_F16 ||
Op == AMDGPU::V_PK_MAX_NUM_BF16)
2458 if (Src0Mods != UnsetMods || Src1Mods != UnsetMods)
2468bool SIFoldOperandsImpl::tryFoldClamp(MachineInstr &
MI) {
2469 const MachineOperand *ClampSrc = isClamp(
MI);
2485 if (
Def->mayRaiseFPException())
2488 MachineOperand *DefClamp =
TII->getNamedOperand(*Def, AMDGPU::OpName::clamp);
2492 LLVM_DEBUG(
dbgs() <<
"Folding clamp " << *DefClamp <<
" into " << *Def);
2498 Register MIDstReg =
MI.getOperand(0).getReg();
2499 if (
TRI->isSGPRReg(*
MRI, DefReg)) {
2508 MI.eraseFromParent();
2513 if (
TII->convertToThreeAddress(*Def,
nullptr))
2514 Def->eraseFromParent();
2521 case AMDGPU::V_MUL_F64_e64:
2522 case AMDGPU::V_MUL_F64_pseudo_e64: {
2524 case 0x3fe0000000000000:
2526 case 0x4000000000000000:
2528 case 0x4010000000000000:
2534 case AMDGPU::V_MUL_F32_e64: {
2535 switch (
static_cast<uint32_t>(Val)) {
2546 case AMDGPU::V_MUL_F16_e64:
2547 case AMDGPU::V_MUL_F16_t16_e64:
2548 case AMDGPU::V_MUL_F16_fake16_e64: {
2549 switch (
static_cast<uint16_t>(Val)) {
2560 case AMDGPU::V_PK_MUL_BF16: {
2561 switch (
static_cast<uint16_t>(Val)) {
2580std::pair<const MachineOperand *, int>
2581SIFoldOperandsImpl::isOMod(
const MachineInstr &
MI)
const {
2582 unsigned Op =
MI.getOpcode();
2584 case AMDGPU::V_MUL_F64_e64:
2585 case AMDGPU::V_MUL_F64_pseudo_e64:
2586 case AMDGPU::V_MUL_F32_e64:
2587 case AMDGPU::V_MUL_F16_t16_e64:
2588 case AMDGPU::V_MUL_F16_fake16_e64:
2589 case AMDGPU::V_MUL_F16_e64: {
2591 if ((
Op == AMDGPU::V_MUL_F32_e64 &&
2593 ((
Op == AMDGPU::V_MUL_F64_e64 ||
Op == AMDGPU::V_MUL_F64_pseudo_e64 ||
2594 Op == AMDGPU::V_MUL_F16_e64 ||
Op == AMDGPU::V_MUL_F16_t16_e64 ||
2595 Op == AMDGPU::V_MUL_F16_fake16_e64) &&
2598 MI.mayRaiseFPException())
2601 const MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2602 const MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2605 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*
MRI, *Src1);
2611 TII->hasModifiersSet(
MI, AMDGPU::OpName::src0_modifiers) ||
2612 TII->hasModifiersSet(
MI, AMDGPU::OpName::src1_modifiers) ||
2613 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod) ||
2614 TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp))
2617 return {
Src0, OMod};
2619 case AMDGPU::V_ADD_F64_e64:
2620 case AMDGPU::V_ADD_F64_pseudo_e64:
2621 case AMDGPU::V_ADD_F32_e64:
2622 case AMDGPU::V_ADD_F16_e64:
2623 case AMDGPU::V_ADD_F16_t16_e64:
2624 case AMDGPU::V_ADD_F16_fake16_e64: {
2626 if ((
Op == AMDGPU::V_ADD_F32_e64 &&
2628 ((
Op == AMDGPU::V_ADD_F64_e64 ||
Op == AMDGPU::V_ADD_F64_pseudo_e64 ||
2629 Op == AMDGPU::V_ADD_F16_e64 ||
Op == AMDGPU::V_ADD_F16_t16_e64 ||
2630 Op == AMDGPU::V_ADD_F16_fake16_e64) &&
2635 const MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2636 const MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2639 Src0->getSubReg() ==
Src1->getSubReg() &&
2640 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::src0_modifiers) &&
2641 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::src1_modifiers) &&
2642 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp) &&
2643 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::omod))
2648 case AMDGPU::V_PK_MUL_BF16: {
2653 MI.mayRaiseFPException())
2656 const MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2657 const MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2660 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*
MRI, *Src1);
2664 int OMod =
getOModValue(AMDGPU::V_PK_MUL_BF16, *Src1Imm);
2671 const MachineOperand *Src0Mods =
2672 TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers);
2673 const MachineOperand *Src1Mods =
2674 TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers);
2677 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod) ||
2678 TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp))
2681 return {
Src0, OMod};
2683 case AMDGPU::V_PK_ADD_BF16: {
2689 const MachineOperand *
Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2690 const MachineOperand *
Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2692 if (!
Src0->isReg() || !
Src1->isReg() ||
Src0->getReg() !=
Src1->getReg() ||
2693 Src0->getSubReg() !=
Src1->getSubReg())
2697 const MachineOperand *Src0Mods =
2698 TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers);
2699 const MachineOperand *Src1Mods =
2700 TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers);
2703 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod) ||
2704 TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp))
2715bool SIFoldOperandsImpl::tryFoldOMod(MachineInstr &
MI) {
2716 const MachineOperand *RegOp;
2718 std::tie(RegOp, OMod) = isOMod(
MI);
2720 RegOp->
getSubReg() != AMDGPU::NoSubRegister ||
2725 Register OModSrcReg =
Def->getOperand(0).getReg();
2729 if (
Def->isRegSequence() &&
Def->getNumOperands() == 5 &&
2730 Def->getOperand(2).getImm() == AMDGPU::lo16) {
2732 bool CanLookThrough =
true;
2735 CanLookThrough =
false;
2737 if (CanLookThrough) {
2748 MachineOperand *DefOMod =
TII->getNamedOperand(*Def, AMDGPU::OpName::omod);
2752 if (
Def->mayRaiseFPException())
2757 if (
TII->hasModifiersSet(*Def, AMDGPU::OpName::clamp))
2764 MI.eraseFromParent();
2769 if (
TII->convertToThreeAddress(*Def,
nullptr))
2770 Def->eraseFromParent();
2777bool SIFoldOperandsImpl::tryFoldSGPRSplatRegSequence(MachineInstr &
MI) {
2780 if (!ST->hasPackedFP64SingleSGPROps() && !ST->hasPackedU64SingleSGPROps())
2787 if (!
TRI->isSGPRClass(RegClass) ||
TRI->getRegSizeInBits(*RegClass) != 128)
2791 if (!getRegSeqInit(Defs,
Reg))
2795 if (Defs.
size() <= 1)
2798 const auto &[FirstOp,
_] = Defs.
front();
2799 if (!FirstOp->isReg())
2802 Register FirstReg = FirstOp->getReg();
2803 unsigned FirstSubReg = FirstOp->getSubReg();
2806 if (!
TRI->isSGPRClass(FirstRegClass))
2811 const auto &[
Op,
_] =
Def;
2812 return Op->isReg() &&
Op->getReg() == FirstReg &&
2813 Op->getSubReg() == FirstSubReg;
2825 MachineInstrBuilder
RS =
BuildMI(*
MI.getParent(),
MI,
MI.getDebugLoc(),
2826 TII->get(AMDGPU::REG_SEQUENCE), NewDst);
2829 FirstOp->setIsKill(
false);
2831 RS.addImm(Defs[0].second);
2836 for (
unsigned i = 1; i < Defs.
size(); ++i) {
2837 RS.addReg(UndefReg, RegState::Undef);
2838 RS.addImm(Defs[i].second);
2847 MI.eraseFromParent();
2853bool SIFoldOperandsImpl::tryFoldRegSequence(MachineInstr &
MI) {
2857 if (tryFoldSGPRSplatRegSequence(
MI))
2860 auto Reg =
MI.getOperand(0).getReg();
2862 if (!ST->hasGFX90AInsts() || !
TRI->isVGPR(*
MRI,
Reg) ||
2867 if (!getRegSeqInit(Defs,
Reg))
2870 for (
auto &[
Op, SubIdx] : Defs) {
2873 if (
TRI->isAGPR(*
MRI,
Op->getReg()))
2884 MachineInstr *
UseMI =
Op->getParent();
2893 if (
Op->getSubReg())
2899 if (!OpRC || !
TRI->isVectorSuperClass(OpRC))
2905 TII->get(AMDGPU::REG_SEQUENCE), Dst);
2907 for (
auto &[Def, SubIdx] : Defs) {
2908 Def->setIsKill(
false);
2920 if (!
TII->isOperandLegal(*
UseMI, OpIdx,
Op)) {
2922 RS->eraseFromParent();
2931 MI.eraseFromParent();
2939 Register &OutReg,
unsigned &OutSubReg) {
2949 if (
TRI.isAGPR(
MRI, CopySrcReg)) {
2950 OutReg = CopySrcReg;
2959 if (!CopySrcDef || !CopySrcDef->
isCopy())
2966 OtherCopySrc.
getSubReg() != AMDGPU::NoSubRegister ||
2967 !
TRI.isAGPR(
MRI, OtherCopySrcReg))
2970 OutReg = OtherCopySrcReg;
3004bool SIFoldOperandsImpl::tryFoldPhiAGPR(MachineInstr &
PHI) {
3008 if (!
TRI->isVGPR(*
MRI, PhiOut))
3014 for (
unsigned K = 1;
K <
PHI.getNumExplicitOperands();
K += 2) {
3015 MachineOperand &MO =
PHI.getOperand(K);
3017 if (!Copy || !
Copy->isCopy())
3021 unsigned AGPRRegMask = AMDGPU::NoSubRegister;
3026 if (
const auto *SubRC =
TRI->getSubRegisterClass(CopyInRC, AGPRRegMask))
3037 bool IsAGPR32 = (ARC == &AMDGPU::AGPR_32RegClass);
3041 for (
unsigned K = 1;
K <
PHI.getNumExplicitOperands();
K += 2) {
3042 MachineOperand &MO =
PHI.getOperand(K);
3046 MachineBasicBlock *InsertMBB =
nullptr;
3049 unsigned CopyOpc = AMDGPU::COPY;
3054 if (
Def->isCopy()) {
3056 unsigned AGPRSubReg = AMDGPU::NoSubRegister;
3069 MachineOperand &CopyIn =
Def->getOperand(1);
3072 CopyOpc = AMDGPU::V_ACCVGPR_WRITE_B32_e64;
3075 InsertMBB =
Def->getParent();
3083 MachineInstr *
MI =
BuildMI(*InsertMBB, InsertPt,
PHI.getDebugLoc(),
3084 TII->get(CopyOpc), NewReg)
3094 PHI.getOperand(0).setReg(NewReg);
3100 TII->get(AMDGPU::COPY), PhiOut)
3108bool SIFoldOperandsImpl::tryFoldLoad(MachineInstr &
MI) {
3110 if (!ST->hasGFX90AInsts() ||
MI.getNumExplicitDefs() != 1)
3113 MachineOperand &
Def =
MI.getOperand(0);
3130 while (!
Users.empty()) {
3131 const MachineInstr *
I =
Users.pop_back_val();
3132 if (!
I->isCopy() && !
I->isRegSequence())
3134 Register DstReg =
I->getOperand(0).getReg();
3138 if (
TRI->isAGPR(*
MRI, DstReg))
3142 Users.push_back(&U);
3147 if (!
TII->isOperandLegal(
MI, 0, &Def)) {
3152 while (!MoveRegs.
empty()) {
3194bool SIFoldOperandsImpl::tryOptimizeAGPRPhis(MachineBasicBlock &
MBB) {
3197 if (ST->hasGFX90AInsts())
3201 DenseMap<std::pair<Register, unsigned>, std::vector<MachineOperand *>>
3204 for (
auto &
MI :
MBB) {
3208 if (!
TRI->isAGPR(*
MRI,
MI.getOperand(0).getReg()))
3211 for (
unsigned K = 1;
K <
MI.getNumOperands();
K += 2) {
3212 MachineOperand &PhiMO =
MI.getOperand(K);
3222 for (
const auto &[Entry, MOs] : RegToMO) {
3223 if (MOs.size() == 1)
3228 MachineBasicBlock *DefMBB =
Def->getParent();
3235 MachineInstr *VGPRCopy =
3237 TII->get(AMDGPU::V_ACCVGPR_READ_B32_e64), TempVGPR)
3243 TII->get(AMDGPU::COPY), TempAGPR)
3247 for (MachineOperand *MO : MOs) {
3259bool SIFoldOperandsImpl::run(
MachineFunction &MF,
const MachineLoopInfo *MLI) {
3265 MFI = MF.
getInfo<SIMachineFunctionInfo>();
3276 MachineOperand *CurrentKnownM0Val =
nullptr;
3284 if (tryConstantFoldOp(&
MI)) {
3289 if (tryFoldRedundantAND(
MI)) {
3294 if (tryFoldAndExec(
MI)) {
3299 if (
MI.isRegSequence() && tryFoldRegSequence(
MI)) {
3304 if (
MI.isPHI() && tryFoldPhiAGPR(
MI)) {
3309 if (
MI.mayLoad() && tryFoldLoad(
MI)) {
3314 if (
TII->isFoldableCopy(
MI)) {
3315 Changed |= tryFoldFoldableCopy(
MI, CurrentKnownM0Val);
3320 if (CurrentKnownM0Val &&
MI.modifiesRegister(AMDGPU::M0,
TRI))
3321 CurrentKnownM0Val =
nullptr;
3341 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 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.