24#define DEBUG_TYPE "si-fold-operands"
45 unsigned DefSubReg = AMDGPU::NoSubRegister;
50 FoldableDef() =
delete;
52 unsigned DefSubReg = AMDGPU::NoSubRegister)
53 : DefRC(DefRC), DefSubReg(DefSubReg), Kind(FoldOp.
getType()) {
56 ImmToFold = FoldOp.
getImm();
57 }
else if (FoldOp.
isFI()) {
58 FrameIndexToFold = FoldOp.
getIndex();
68 unsigned DefSubReg = AMDGPU::NoSubRegister)
69 : ImmToFold(FoldImm), DefRC(DefRC), DefSubReg(DefSubReg),
74 FoldableDef Copy(*
this);
75 Copy.DefSubReg =
TRI.composeSubRegIndices(DefSubReg, SubReg);
83 return OpToFold->getReg();
86 unsigned getSubReg()
const {
88 return OpToFold->getSubReg();
99 return FrameIndexToFold;
107 std::optional<int64_t> getEffectiveImmVal()
const {
115 unsigned OpIdx)
const {
118 std::optional<int64_t> ImmToFold = getEffectiveImmVal();
125 return TII.isOperandLegal(
MI, OpIdx, &TmpOp);
128 if (DefSubReg != AMDGPU::NoSubRegister)
131 return TII.isOperandLegal(
MI, OpIdx, &TmpOp);
136 if (DefSubReg != AMDGPU::NoSubRegister)
138 return TII.isOperandLegal(
MI, OpIdx, OpToFold);
145struct FoldCandidate {
153 bool Commuted =
false,
int ShrinkOp = -1)
154 :
UseMI(
MI), Def(Def), ShrinkOpcode(ShrinkOp), UseOpNo(OpNo),
155 Commuted(Commuted) {}
157 bool isFI()
const {
return Def.isFI(); }
161 return Def.FrameIndexToFold;
164 bool isImm()
const {
return Def.isImm(); }
166 bool isReg()
const {
return Def.isReg(); }
170 bool isGlobal()
const {
return Def.isGlobal(); }
172 bool needsShrink()
const {
return ShrinkOpcode != -1; }
175class SIFoldOperandsImpl {
186 const FoldableDef &OpToFold)
const;
189 unsigned convertToVALUOp(
unsigned Opc,
bool UseVOP3 =
false)
const {
191 case AMDGPU::S_ADD_I32: {
192 if (ST->hasAddNoCarryInsts())
193 return UseVOP3 ? AMDGPU::V_ADD_U32_e64 : AMDGPU::V_ADD_U32_e32;
194 return UseVOP3 ? AMDGPU::V_ADD_CO_U32_e64 : AMDGPU::V_ADD_CO_U32_e32;
196 case AMDGPU::S_OR_B32:
197 return UseVOP3 ? AMDGPU::V_OR_B32_e64 : AMDGPU::V_OR_B32_e32;
198 case AMDGPU::S_AND_B32:
199 return UseVOP3 ? AMDGPU::V_AND_B32_e64 : AMDGPU::V_AND_B32_e32;
200 case AMDGPU::S_MUL_I32:
201 return AMDGPU::V_MUL_LO_U32_e64;
203 return AMDGPU::INSTRUCTION_LIST_END;
207 bool foldCopyToVGPROfScalarAddOfFrameIndex(
Register DstReg,
Register SrcReg,
213 int64_t ImmVal)
const;
217 int64_t ImmVal)
const;
221 const FoldableDef &OpToFold)
const;
224 bool isTemporallyDivergentUse(
const FoldableDef &OpToFold,
232 getRegSeqInit(
SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs,
235 std::pair<int64_t, const TargetRegisterClass *>
249 struct ANDMaskResult {
255 std::optional<ANDMaskResult> getANDMaskRegOperand(
MachineInstr &AndMI)
const;
260 bool foldInstOperand(
MachineInstr &
MI,
const FoldableDef &OpToFold)
const;
262 bool foldCopyToAGPRRegSequence(
MachineInstr *CopyMI)
const;
269 std::pair<const MachineOperand *, int> isOMod(
const MachineInstr &
MI)
const;
279 SIFoldOperandsImpl() =
default;
294 &getAnalysis<MachineLoopInfoWrapperPass>().getLI();
295 return SIFoldOperandsImpl().run(MF, MLI);
298 StringRef getPassName()
const override {
return "SI Fold Operands"; }
320char SIFoldOperandsLegacy::ID = 0;
329 TRI.getSubRegisterClass(RC, MO.getSubReg()))
337 case AMDGPU::V_MAC_F32_e64:
338 return AMDGPU::V_MAD_F32_e64;
339 case AMDGPU::V_MAC_F16_e64:
340 return AMDGPU::V_MAD_F16_e64;
341 case AMDGPU::V_FMAC_F32_e64:
342 return AMDGPU::V_FMA_F32_e64;
343 case AMDGPU::V_FMAC_F16_e64:
344 return AMDGPU::V_FMA_F16_gfx9_e64;
345 case AMDGPU::V_FMAC_F16_t16_e64:
346 return AMDGPU::V_FMA_F16_gfx9_t16_e64;
347 case AMDGPU::V_FMAC_F16_fake16_e64:
348 return AMDGPU::V_FMA_F16_gfx9_fake16_e64;
349 case AMDGPU::V_FMAC_LEGACY_F32_e64:
350 return AMDGPU::V_FMA_LEGACY_F32_e64;
351 case AMDGPU::V_FMAC_F64_e64:
352 return AMDGPU::V_FMA_F64_e64;
354 return AMDGPU::INSTRUCTION_LIST_END;
360 const FoldableDef &OpToFold)
const {
361 if (!OpToFold.isFI())
364 const unsigned Opc =
UseMI.getOpcode();
366 case AMDGPU::S_ADD_I32:
367 case AMDGPU::S_ADD_U32:
368 case AMDGPU::V_ADD_U32_e32:
369 case AMDGPU::V_ADD_CO_U32_e32:
373 return UseMI.getOperand(OpNo == 1 ? 2 : 1).isImm() &&
375 case AMDGPU::V_ADD_U32_e64:
376 case AMDGPU::V_ADD_CO_U32_e64:
377 return UseMI.getOperand(OpNo == 2 ? 3 : 2).isImm() &&
384 return OpNo == AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::vaddr);
388 int SIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::saddr);
392 int VIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::vaddr);
393 return OpNo == VIdx && SIdx == -1;
399bool SIFoldOperandsImpl::foldCopyToVGPROfScalarAddOfFrameIndex(
404 if (
TRI->isVGPR(*MRI, DstReg) &&
TRI->isSGPRReg(*MRI, SrcReg) &&
407 if (!Def ||
Def->getNumOperands() != 4)
410 MachineOperand *Src0 = &
Def->getOperand(1);
411 MachineOperand *Src1 = &
Def->getOperand(2);
422 const bool UseVOP3 = !Src0->
isImm() ||
TII->isInlineConstant(*Src0);
423 unsigned NewOp = convertToVALUOp(
Def->getOpcode(), UseVOP3);
424 if (NewOp == AMDGPU::INSTRUCTION_LIST_END ||
425 !
Def->getOperand(3).isDead())
428 MachineBasicBlock *
MBB =
Def->getParent();
430 if (NewOp != AMDGPU::V_ADD_CO_U32_e32) {
431 MachineInstrBuilder
Add =
434 if (
Add->getDesc().getNumDefs() == 2) {
436 Add.addDef(CarryOutReg, RegState::Dead);
440 Add.add(*Src0).add(*Src1).setMIFlags(
Def->getFlags());
444 Def->eraseFromParent();
445 MI.eraseFromParent();
449 assert(NewOp == AMDGPU::V_ADD_CO_U32_e32);
460 Def->eraseFromParent();
461 MI.eraseFromParent();
470 return new SIFoldOperandsLegacy();
473bool SIFoldOperandsImpl::canUseImmWithOpSel(
const MachineInstr *
MI,
475 int64_t ImmVal)
const {
482 int OpNo =
MI->getOperandNo(&Old);
484 unsigned Opcode =
MI->getOpcode();
485 uint8_t OpType =
TII->get(Opcode).operands()[OpNo].OperandType;
507bool SIFoldOperandsImpl::tryFoldImmWithOpSel(MachineInstr *
MI,
unsigned UseOpNo,
508 int64_t ImmVal)
const {
509 MachineOperand &Old =
MI->getOperand(UseOpNo);
510 unsigned Opcode =
MI->getOpcode();
511 int OpNo =
MI->getOperandNo(&Old);
512 uint8_t OpType =
TII->get(Opcode).operands()[OpNo].OperandType;
524 AMDGPU::OpName ModName = AMDGPU::OpName::NUM_OPERAND_NAMES;
525 unsigned SrcIdx = ~0;
526 if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src0)) {
527 ModName = AMDGPU::OpName::src0_modifiers;
529 }
else if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src1)) {
530 ModName = AMDGPU::OpName::src1_modifiers;
532 }
else if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src2)) {
533 ModName = AMDGPU::OpName::src2_modifiers;
536 assert(ModName != AMDGPU::OpName::NUM_OPERAND_NAMES);
537 int ModIdx = AMDGPU::getNamedOperandIdx(Opcode, ModName);
538 MachineOperand &
Mod =
MI->getOperand(ModIdx);
539 unsigned ModVal =
Mod.getImm();
545 uint32_t
Imm = (
static_cast<uint32_t
>(ImmHi) << 16) | ImmLo;
550 auto tryFoldToInline = [&](uint32_t
Imm) ->
bool {
559 uint16_t
Lo =
static_cast<uint16_t
>(
Imm);
560 uint16_t
Hi =
static_cast<uint16_t
>(
Imm >> 16);
566 if (ST->hasBF16InlineConstFromUpperFP32() &&
570 Mod.setImm(NewModVal);
575 if (
static_cast<int16_t
>(
Lo) < 0) {
576 int32_t SExt =
static_cast<int16_t
>(
Lo);
578 Mod.setImm(NewModVal);
593 uint32_t Swapped = (
static_cast<uint32_t
>(
Lo) << 16) |
Hi;
604 if (tryFoldToInline(
Imm))
613 bool IsUAdd = Opcode == AMDGPU::V_PK_ADD_U16;
614 bool IsUSub = Opcode == AMDGPU::V_PK_SUB_U16;
615 if (SrcIdx == 1 && (IsUAdd || IsUSub)) {
617 AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::clamp);
618 bool Clamp =
MI->getOperand(ClampIdx).getImm() != 0;
621 uint16_t NegLo = -
static_cast<uint16_t
>(
Imm);
622 uint16_t NegHi = -
static_cast<uint16_t
>(
Imm >> 16);
623 uint32_t NegImm = (
static_cast<uint32_t
>(NegHi) << 16) | NegLo;
625 if (tryFoldToInline(NegImm)) {
627 IsUAdd ? AMDGPU::V_PK_SUB_U16 : AMDGPU::V_PK_ADD_U16;
628 MI->setDesc(
TII->get(NegOpcode));
637bool SIFoldOperandsImpl::updateOperand(FoldCandidate &Fold)
const {
638 MachineInstr *
MI = Fold.UseMI;
639 MachineOperand &Old =
MI->getOperand(Fold.UseOpNo);
642 std::optional<int64_t> ImmVal;
644 ImmVal = Fold.Def.getEffectiveImmVal();
646 if (ImmVal && canUseImmWithOpSel(Fold.UseMI, Fold.UseOpNo, *ImmVal)) {
647 if (tryFoldImmWithOpSel(Fold.UseMI, Fold.UseOpNo, *ImmVal))
653 int OpNo =
MI->getOperandNo(&Old);
654 if (!
TII->isOperandLegal(*
MI, OpNo, &New))
660 if ((Fold.isImm() || Fold.isFI() || Fold.isGlobal()) && Fold.needsShrink()) {
668 int Op32 = Fold.ShrinkOpcode;
669 MachineOperand &Dst0 =
MI->getOperand(0);
670 MachineOperand &Dst1 =
MI->getOperand(1);
678 MachineInstr *Inst32 =
TII->buildShrunkInst(*
MI, Op32);
680 if (HaveNonDbgCarryUse) {
683 .
addReg(AMDGPU::VCC, RegState::Kill);
697 for (
unsigned I =
MI->getNumOperands() - 1;
I > 0; --
I)
698 MI->removeOperand(
I);
699 MI->setDesc(
TII->get(AMDGPU::IMPLICIT_DEF));
702 TII->commuteInstruction(*Inst32,
false);
706 assert(!Fold.needsShrink() &&
"not handled");
711 if (NewMFMAOpc == -1)
713 MI->setDesc(
TII->get(NewMFMAOpc));
714 MI->untieRegOperand(0);
715 const MCInstrDesc &MCID =
MI->getDesc();
716 for (
unsigned I = 0;
I <
MI->getNumDefs(); ++
I)
718 MI->getOperand(
I).setIsEarlyClobber(
true);
723 int OpNo =
MI->getOperandNo(&Old);
724 if (!
TII->isOperandLegal(*
MI, OpNo, &New))
727 if (ST->hasBF16InlineConstFromUpperFP32() &&
729 AMDGPU::getNamedOperandIdx(
MI->getOpcode(), AMDGPU::OpName::src0)) {
730 unsigned Opcode =
MI->getOpcode();
731 uint8_t OpType =
TII->get(Opcode).operands()[OpNo].OperandType;
734 TII->isInlineConstant(*ImmVal, OpType)) {
737 AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src0_modifiers);
740 MachineOperand &ModOp =
MI->getOperand(Mod0);
751 if (Fold.isGlobal()) {
752 Old.
ChangeToGA(Fold.Def.OpToFold->getGlobal(),
753 Fold.Def.OpToFold->getOffset(),
754 Fold.Def.OpToFold->getTargetFlags());
763 MachineOperand *
New = Fold.Def.OpToFold;
767 TII->getRegClass(
MI->getDesc(), Fold.UseOpNo)) {
769 TRI->getRegClassForReg(*MRI,
New->getReg());
772 if (
New->getSubReg()) {
774 TRI->getMatchingSuperRegClass(NewRC, OpRC,
New->getSubReg());
780 if (
New->getReg().isVirtual() &&
783 <<
TRI->getRegClassName(ConstrainRC) <<
'\n');
790 if (Old.
getSubReg() == AMDGPU::lo16 &&
TRI->isSGPRReg(*MRI,
New->getReg()))
792 if (
New->getReg().isPhysical()) {
800 if (
MI->isBundledWithPred()) {
802 for (MachineOperand &MO : Header.operands()) {
803 if (MO.getReg() == OldReg) {
804 MO.setReg(
New->getReg());
805 MO.setSubReg(
New->getSubReg());
814 FoldCandidate &&Entry) {
816 for (FoldCandidate &Fold : FoldList)
817 if (Fold.UseMI == Entry.UseMI && Fold.UseOpNo == Entry.UseOpNo)
819 LLVM_DEBUG(
dbgs() <<
"Append " << (Entry.Commuted ?
"commuted" :
"normal")
820 <<
" operand " << Entry.UseOpNo <<
"\n " << *Entry.UseMI);
826 const FoldableDef &FoldOp,
827 bool Commuted =
false,
int ShrinkOp = -1) {
829 FoldCandidate(
MI, OpNo, FoldOp, Commuted, ShrinkOp));
837 if (!ST->hasPKF32InstsReplicatingLower32BitsOfScalarInput())
847 const FoldableDef &OpToFold) {
848 assert(OpToFold.isImm() &&
"Expected immediate operand");
849 uint64_t ImmVal = OpToFold.getEffectiveImmVal().value();
855bool SIFoldOperandsImpl::tryAddToFoldList(
856 SmallVectorImpl<FoldCandidate> &FoldList, MachineInstr *
MI,
unsigned OpNo,
857 const FoldableDef &OpToFold)
const {
858 const unsigned Opc =
MI->getOpcode();
860 auto tryToFoldAsFMAAKorMK = [&]() {
861 if (!OpToFold.isImm())
864 const bool TryAK = OpNo == 3;
865 const unsigned NewOpc = TryAK ? AMDGPU::S_FMAAK_F32 : AMDGPU::S_FMAMK_F32;
866 MI->setDesc(
TII->get(NewOpc));
869 bool FoldAsFMAAKorMK =
870 tryAddToFoldList(FoldList,
MI, TryAK ? 3 : 2, OpToFold);
871 if (FoldAsFMAAKorMK) {
873 MI->untieRegOperand(3);
876 MachineOperand &Op1 =
MI->getOperand(1);
877 MachineOperand &Op2 =
MI->getOperand(2);
894 bool IsLegal = OpToFold.isOperandLegal(*
TII, *
MI, OpNo);
895 if (!IsLegal && OpToFold.isImm()) {
896 if (std::optional<int64_t> ImmVal = OpToFold.getEffectiveImmVal())
897 IsLegal = canUseImmWithOpSel(
MI, OpNo, *ImmVal);
903 if (NewOpc != AMDGPU::INSTRUCTION_LIST_END) {
906 MI->setDesc(
TII->get(NewOpc));
911 bool FoldAsMAD = tryAddToFoldList(FoldList,
MI, OpNo, OpToFold);
913 MI->untieRegOperand(OpNo);
917 MI->removeOperand(
MI->getNumExplicitOperands() - 1);
923 if (
Opc == AMDGPU::S_FMAC_F32 && OpNo == 3) {
924 if (tryToFoldAsFMAAKorMK())
930 if ((
Opc == AMDGPU::S_FMAAK_F32 ||
Opc == AMDGPU::S_FMAMK_F32) &&
932 std::optional<int64_t> ImmVal = OpToFold.getEffectiveImmVal();
933 if (ImmVal && !
TII->isInlineConstant(*
MI, OpNo, *ImmVal)) {
934 unsigned ImmIdx =
Opc == AMDGPU::S_FMAAK_F32 ? 3 : 2;
935 MachineOperand &OpImm =
MI->getOperand(ImmIdx);
936 if (!OpImm.
isReg() &&
937 TII->isInlineConstant(*
MI,
MI->getOperand(OpNo), OpImm))
938 return tryToFoldAsFMAAKorMK();
943 if (OpToFold.isImm()) {
945 if (
Opc == AMDGPU::S_SETREG_B32)
946 ImmOpc = AMDGPU::S_SETREG_IMM32_B32;
947 else if (
Opc == AMDGPU::S_SETREG_B32_mode)
948 ImmOpc = AMDGPU::S_SETREG_IMM32_B32_mode;
950 MI->setDesc(
TII->get(ImmOpc));
959 bool CanCommute =
TII->findCommutedOpIndices(*
MI, OpNo, CommuteOpNo);
963 MachineOperand &
Op =
MI->getOperand(OpNo);
964 MachineOperand &CommutedOp =
MI->getOperand(CommuteOpNo);
970 if (!
Op.isReg() || !CommutedOp.
isReg())
975 if (
Op.isReg() && CommutedOp.
isReg() &&
976 (
Op.getReg() == CommutedOp.
getReg() &&
980 if (!
TII->commuteInstruction(*
MI,
false, OpNo, CommuteOpNo))
984 if (!OpToFold.isOperandLegal(*
TII, *
MI, CommuteOpNo)) {
985 if ((
Opc != AMDGPU::V_ADD_CO_U32_e64 &&
Opc != AMDGPU::V_SUB_CO_U32_e64 &&
986 Opc != AMDGPU::V_SUBREV_CO_U32_e64) ||
987 (!OpToFold.isImm() && !OpToFold.isFI() && !OpToFold.isGlobal())) {
988 TII->commuteInstruction(*
MI,
false, OpNo, CommuteOpNo);
994 MachineOperand &OtherOp =
MI->getOperand(OpNo);
995 if (!OtherOp.
isReg() ||
1002 unsigned MaybeCommutedOpc =
MI->getOpcode();
1016 if (
Opc == AMDGPU::S_FMAC_F32 &&
1017 (OpNo != 1 || !
MI->getOperand(1).isIdenticalTo(
MI->getOperand(2)))) {
1018 if (tryToFoldAsFMAAKorMK())
1024 if (OpToFold.isImm() &&
1033bool SIFoldOperandsImpl::isUseSafeToFold(
const MachineInstr &
MI,
1034 const MachineOperand &UseMO)
const {
1036 return !
TII->isSDWA(
MI);
1043 if (
MI.modifiesRegister(
TRI.getExec(), &
TRI))
1051bool SIFoldOperandsImpl::isTemporallyDivergentUse(
1052 const FoldableDef &OpToFold,
const MachineInstr &
UseMI)
const {
1053 if (!OpToFold.isReg())
1055 const MachineInstr *
DefMI = OpToFold.DefMI;
1058 !
TRI->isSGPRReg(*MRI, OpToFold.getReg()))
1070 SubDef &&
TII.isFoldableCopy(*SubDef);
1072 unsigned SrcIdx =
TII.getFoldableCopySrcIdx(*SubDef);
1081 if (
SrcOp.getSubReg())
1089 MachineInstr &RegSeq,
1090 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs)
const {
1106 else if (!
TRI->getCommonSubClass(RC, OpRC))
1111 Defs.emplace_back(&SrcOp, SubRegIdx);
1116 if (DefSrc && (DefSrc->
isReg() || DefSrc->
isImm())) {
1117 Defs.emplace_back(DefSrc, SubRegIdx);
1121 Defs.emplace_back(&SrcOp, SubRegIdx);
1131 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs,
1134 if (!Def || !
Def->isRegSequence())
1137 return getRegSeqInit(*Def, Defs);
1140std::pair<int64_t, const TargetRegisterClass *>
1141SIFoldOperandsImpl::isRegSeqSplat(MachineInstr &RegSeq)
const {
1147 bool TryToMatchSplat64 =
false;
1149 std::optional<int64_t>
Imm;
1150 for (
unsigned I = 0,
E = Defs.
size();
I !=
E; ++
I) {
1151 const MachineOperand *
Op = Defs[
I].first;
1155 if (!Def ||
Def->isImplicitDef())
1161 int64_t SubImm =
Op->getImm();
1167 if (
Imm != SubImm) {
1168 if (
I == 1 && (
E & 1) == 0) {
1171 TryToMatchSplat64 =
true;
1179 if (!TryToMatchSplat64) {
1181 return {*
Imm, SrcRC};
1188 for (
unsigned I = 0,
E = Defs.
size();
I !=
E;
I += 2) {
1189 const MachineOperand *Op0 = Defs[
I].first;
1190 const MachineOperand *Op1 = Defs[
I + 1].first;
1195 unsigned SubReg0 = Defs[
I].second;
1196 unsigned SubReg1 = Defs[
I + 1].second;
1200 if (
TRI->getChannelFromSubReg(SubReg0) + 1 !=
1201 TRI->getChannelFromSubReg(SubReg1))
1204 if (
TRI->getSubRegIdxSize(SubReg0) != 32)
1209 SplatVal64 = MergedVal;
1210 else if (SplatVal64 != MergedVal)
1217 return {SplatVal64, RC64};
1220bool SIFoldOperandsImpl::tryFoldRegSeqSplat(
1221 MachineInstr *
UseMI,
unsigned UseOpIdx, int64_t SplatVal,
1224 if (UseOpIdx >=
Desc.getNumOperands())
1231 int16_t RCID =
TII->getOpRegClassID(
Desc.operands()[UseOpIdx]);
1240 if (SplatVal != 0 && SplatVal != -1) {
1244 uint8_t OpTy =
Desc.operands()[UseOpIdx].OperandType;
1251 OpRC =
TRI->getSubRegisterClass(OpRC, AMDGPU::sub0);
1258 OpRC =
TRI->getSubRegisterClass(OpRC, AMDGPU::sub0_sub1);
1264 if (!
TRI->getCommonSubClass(OpRC, SplatRC))
1269 if (!
TII->isOperandLegal(*
UseMI, UseOpIdx, &TmpOp))
1275bool SIFoldOperandsImpl::tryToFoldACImm(
1276 const FoldableDef &OpToFold, MachineInstr *
UseMI,
unsigned UseOpIdx,
1277 SmallVectorImpl<FoldCandidate> &FoldList)
const {
1279 if (UseOpIdx >=
Desc.getNumOperands())
1286 if (OpToFold.isImm() && OpToFold.isOperandLegal(*
TII, *
UseMI, UseOpIdx)) {
1297bool SIFoldOperandsImpl::foldOperand(
1298 FoldableDef OpToFold, MachineInstr *
UseMI,
int UseOpIdx,
1299 SmallVectorImpl<FoldCandidate> &FoldList,
1300 SmallVectorImpl<MachineInstr *> &CopiesToReplace)
const {
1304 if (!isUseSafeToFold(*
UseMI, *UseOp))
1307 if (isTemporallyDivergentUse(OpToFold, *
UseMI))
1311 if (UseOp->
isReg() && OpToFold.isReg()) {
1315 if (UseOp->
getSubReg() != AMDGPU::NoSubRegister &&
1317 !
TRI->isSGPRReg(*MRI, OpToFold.getReg())))
1330 std::tie(SplatVal, SplatRC) = isRegSeqSplat(*
UseMI);
1335 for (
unsigned I = 0;
I != UsesToProcess.size(); ++
I) {
1336 MachineOperand *RSUse = UsesToProcess[
I];
1337 MachineInstr *RSUseMI = RSUse->
getParent();
1347 if (tryFoldRegSeqSplat(RSUseMI, OpNo, SplatVal, SplatRC)) {
1348 FoldableDef SplatDef(SplatVal, SplatRC);
1356 if (RSUse->
getSubReg() != RegSeqDstSubReg)
1362 FoldList, CopiesToReplace);
1368 if (tryToFoldACImm(OpToFold,
UseMI, UseOpIdx, FoldList))
1371 if (frameIndexMayFold(*
UseMI, UseOpIdx, OpToFold)) {
1376 if (
TII->getNamedOperand(*
UseMI, AMDGPU::OpName::srsrc)->getReg() !=
1382 MachineOperand &SOff =
1383 *
TII->getNamedOperand(*
UseMI, AMDGPU::OpName::soffset);
1394 TII->getNamedOperand(*
UseMI, AMDGPU::OpName::cpol)->getImm();
1409 bool FoldingImmLike =
1410 OpToFold.isImm() || OpToFold.isFI() || OpToFold.isGlobal();
1429 for (
unsigned MovOp :
1430 {AMDGPU::S_MOV_B32, AMDGPU::V_MOV_B32_e32, AMDGPU::S_MOV_B64,
1431 AMDGPU::V_MOV_B64_PSEUDO, AMDGPU::V_MOV_B16_t16_e64,
1432 AMDGPU::V_ACCVGPR_WRITE_B32_e64, AMDGPU::AV_MOV_B32_IMM_PSEUDO,
1433 AMDGPU::AV_MOV_B64_IMM_PSEUDO}) {
1434 const MCInstrDesc &MovDesc =
TII->get(MovOp);
1444 const int SrcIdx = MovOp == AMDGPU::V_MOV_B16_t16_e64 ? 2 : 1;
1446 int16_t RegClassID =
TII->getOpRegClassID(MovDesc.
operands()[SrcIdx]);
1447 if (RegClassID != -1) {
1451 MovSrcRC =
TRI->getMatchingSuperRegClass(SrcRC, MovSrcRC, UseSubReg);
1455 if (MovOp == AMDGPU::AV_MOV_B32_IMM_PSEUDO &&
1456 (!OpToFold.isImm() ||
1457 !
TII->isImmOperandLegal(MovDesc, SrcIdx,
1458 *OpToFold.getEffectiveImmVal())))
1471 if (!OpToFold.isImm() ||
1472 !
TII->isImmOperandLegal(MovDesc, 1, *OpToFold.getEffectiveImmVal()))
1478 while (ImpOpI != ImpOpE) {
1485 if (MovOp == AMDGPU::V_MOV_B16_t16_e64) {
1487 MachineOperand NewSrcOp(SrcOp);
1509 LLVM_DEBUG(
dbgs() <<
"Folding " << *OpToFold.OpToFold <<
"\n into "
1514 unsigned SubRegIdx = OpToFold.getSubReg();
1519 TRI->isSGPRReg(*MRI,
UseReg) && SubRegIdx != AMDGPU::NoSubRegister) {
1522 unsigned Channel =
TRI->getChannelFromSubReg(SubRegIdx);
1524 SubRegIdx =
TRI->getRegSizeInBits(*UseRC) == 32
1525 ? AMDGPU::NoSubRegister
1531 OpToFold.OpToFold->setIsKill(
false);
1536 if (foldCopyToAGPRRegSequence(
UseMI))
1541 if (UseOpc == AMDGPU::V_READFIRSTLANE_B32 ||
1542 (UseOpc == AMDGPU::V_READLANE_B32 &&
1544 AMDGPU::getNamedOperandIdx(UseOpc, AMDGPU::OpName::src0))) {
1549 if (FoldingImmLike) {
1552 *OpToFold.DefMI, *
UseMI))
1558 if (OpToFold.isImm()) {
1560 *OpToFold.getEffectiveImmVal());
1561 }
else if (OpToFold.isFI())
1564 assert(OpToFold.isGlobal());
1566 OpToFold.OpToFold->getOffset(),
1567 OpToFold.OpToFold->getTargetFlags());
1573 if (OpToFold.isReg() &&
TRI->isSGPRReg(*MRI, OpToFold.getReg())) {
1576 *OpToFold.DefMI, *
UseMI))
1598 UseDesc.
operands()[UseOpIdx].RegClass == -1)
1606 Changed |= tryAddToFoldList(FoldList,
UseMI, UseOpIdx, OpToFold);
1613 case AMDGPU::S_ADD_I32:
1614 case AMDGPU::S_ADD_U32:
1617 case AMDGPU::S_SUB_I32:
1618 case AMDGPU::S_SUB_U32:
1621 case AMDGPU::V_AND_B32_e64:
1622 case AMDGPU::V_AND_B32_e32:
1623 case AMDGPU::S_AND_B32:
1626 case AMDGPU::V_OR_B32_e64:
1627 case AMDGPU::V_OR_B32_e32:
1628 case AMDGPU::S_OR_B32:
1631 case AMDGPU::V_XOR_B32_e64:
1632 case AMDGPU::V_XOR_B32_e32:
1633 case AMDGPU::S_XOR_B32:
1636 case AMDGPU::S_XNOR_B32:
1639 case AMDGPU::S_NAND_B32:
1642 case AMDGPU::S_NOR_B32:
1645 case AMDGPU::S_ANDN2_B32:
1648 case AMDGPU::S_ORN2_B32:
1651 case AMDGPU::V_LSHL_B32_e64:
1652 case AMDGPU::V_LSHL_B32_e32:
1653 case AMDGPU::S_LSHL_B32:
1655 Result =
LHS << (
RHS & 31);
1657 case AMDGPU::V_LSHLREV_B32_e64:
1658 case AMDGPU::V_LSHLREV_B32_e32:
1659 Result =
RHS << (
LHS & 31);
1661 case AMDGPU::V_LSHR_B32_e64:
1662 case AMDGPU::V_LSHR_B32_e32:
1663 case AMDGPU::S_LSHR_B32:
1664 Result =
LHS >> (
RHS & 31);
1666 case AMDGPU::V_LSHRREV_B32_e64:
1667 case AMDGPU::V_LSHRREV_B32_e32:
1668 Result =
RHS >> (
LHS & 31);
1670 case AMDGPU::V_ASHR_I32_e64:
1671 case AMDGPU::V_ASHR_I32_e32:
1672 case AMDGPU::S_ASHR_I32:
1673 Result =
static_cast<int32_t
>(
LHS) >> (
RHS & 31);
1675 case AMDGPU::V_ASHRREV_I32_e64:
1676 case AMDGPU::V_ASHRREV_I32_e32:
1677 Result =
static_cast<int32_t
>(
RHS) >> (
LHS & 31);
1685 return IsScalar ? AMDGPU::S_MOV_B32 : AMDGPU::V_MOV_B32_e32;
1691bool SIFoldOperandsImpl::tryConstantFoldOp(MachineInstr *
MI)
const {
1692 if (!
MI->allImplicitDefsAreDead())
1695 unsigned Opc =
MI->getOpcode();
1697 int Src0Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src0);
1701 MachineOperand *Src0 = &
MI->getOperand(Src0Idx);
1702 std::optional<int64_t> Src0Imm =
TII->getImmOrMaterializedImm(*MRI, *Src0);
1704 if ((
Opc == AMDGPU::V_NOT_B32_e64 ||
Opc == AMDGPU::V_NOT_B32_e32 ||
1705 Opc == AMDGPU::S_NOT_B32) &&
1707 MI->getOperand(1).ChangeToImmediate(~*Src0Imm);
1708 TII->mutateAndCleanupImplicit(
1713 int Src1Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src1);
1717 MachineOperand *Src1 = &
MI->getOperand(Src1Idx);
1718 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*MRI, *Src1);
1720 if (!Src0Imm && !Src1Imm)
1726 if (Src0Imm && Src1Imm) {
1731 bool IsSGPR =
TRI->isSGPRReg(*MRI,
MI->getOperand(0).getReg());
1735 MI->getOperand(Src0Idx).ChangeToImmediate(NewImm);
1736 MI->removeOperand(Src1Idx);
1743 if (
Opc == AMDGPU::S_SUB_I32 ||
Opc == AMDGPU::S_SUB_U32) {
1744 if (Src1Imm &&
static_cast<int32_t
>(*Src1Imm) == 0) {
1746 MI->removeOperand(Src1Idx);
1747 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1753 if (!
MI->isCommutable())
1756 if (Src0Imm && !Src1Imm) {
1762 int32_t Src1Val =
static_cast<int32_t
>(*Src1Imm);
1763 if (
Opc == AMDGPU::S_ADD_I32 ||
Opc == AMDGPU::S_ADD_U32) {
1766 MI->removeOperand(Src1Idx);
1767 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1773 if (
Opc == AMDGPU::V_OR_B32_e64 ||
1774 Opc == AMDGPU::V_OR_B32_e32 ||
1775 Opc == AMDGPU::S_OR_B32) {
1778 MI->removeOperand(Src1Idx);
1779 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1780 }
else if (Src1Val == -1) {
1782 MI->removeOperand(Src0Idx);
1783 TII->mutateAndCleanupImplicit(
1791 if (
Opc == AMDGPU::V_AND_B32_e64 ||
Opc == AMDGPU::V_AND_B32_e32 ||
1792 Opc == AMDGPU::S_AND_B32) {
1795 MI->removeOperand(Src0Idx);
1796 TII->mutateAndCleanupImplicit(
1798 }
else if (Src1Val == -1) {
1800 MI->removeOperand(Src1Idx);
1801 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1808 if (
Opc == AMDGPU::V_XOR_B32_e64 ||
Opc == AMDGPU::V_XOR_B32_e32 ||
1809 Opc == AMDGPU::S_XOR_B32) {
1812 MI->removeOperand(Src1Idx);
1813 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1822bool SIFoldOperandsImpl::tryFoldCndMask(MachineInstr &
MI)
const {
1823 unsigned Opc =
MI.getOpcode();
1824 if (
Opc != AMDGPU::V_CNDMASK_B32_e32 &&
Opc != AMDGPU::V_CNDMASK_B32_e64 &&
1825 Opc != AMDGPU::V_CNDMASK_B64_PSEUDO)
1828 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
1829 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
1831 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*MRI, *Src1);
1835 std::optional<int64_t> Src0Imm =
TII->getImmOrMaterializedImm(*MRI, *Src0);
1836 if (!Src0Imm || *Src0Imm != *Src1Imm)
1841 AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src1_modifiers);
1843 AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src0_modifiers);
1844 if ((Src1ModIdx != -1 &&
MI.getOperand(Src1ModIdx).getImm() != 0) ||
1845 (Src0ModIdx != -1 &&
MI.getOperand(Src0ModIdx).getImm() != 0))
1851 int Src2Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
1853 MI.removeOperand(Src2Idx);
1854 MI.removeOperand(AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src1));
1855 if (Src1ModIdx != -1)
1856 MI.removeOperand(Src1ModIdx);
1857 if (Src0ModIdx != -1)
1858 MI.removeOperand(Src0ModIdx);
1859 TII->mutateAndCleanupImplicit(
MI, NewDesc);
1866std::optional<SIFoldOperandsImpl::ANDMaskResult>
1867SIFoldOperandsImpl::getANDMaskRegOperand(MachineInstr &AndMI)
const {
1869 if (
Opc != AMDGPU::V_AND_B32_e64 &&
Opc != AMDGPU::V_AND_B32_e32 &&
1870 Opc != AMDGPU::S_AND_B32)
1871 return std::nullopt;
1873 std::optional<int64_t> MaskImm =
1878 MaskImm =
TII->getImmOrMaterializedImm(*MRI, AndMI.
getOperand(2));
1882 return std::nullopt;
1895bool SIFoldOperandsImpl::tryFoldRedundantAND(MachineInstr &ChildMI)
const {
1900 std::optional<ANDMaskResult> ChildResult = getANDMaskRegOperand(ChildMI);
1904 if (!ChildResult->Reg.isVirtual())
1907 MachineInstr *ParentMI = MRI->
getVRegDef(ChildResult->Reg);
1911 int64_t ParentMask = 0;
1912 std::optional<ANDMaskResult> ParentResult = getANDMaskRegOperand(*ParentMI);
1915 ParentMask = ParentResult->Mask;
1918 ParentMask = 0xffff;
1924 if ((ParentMask & ChildResult->Mask) != ParentMask)
1946bool SIFoldOperandsImpl::foldInstOperand(MachineInstr &
MI,
1947 const FoldableDef &OpToFold)
const {
1951 SmallVector<MachineInstr *, 4> CopiesToReplace;
1953 MachineOperand &Dst =
MI.getOperand(0);
1958 for (
auto *U : UsesToProcess) {
1959 MachineInstr *
UseMI =
U->getParent();
1961 FoldableDef SubOpToFold = OpToFold.getWithSubReg(*
TRI,
U->getSubReg());
1966 if (CopiesToReplace.
empty() && FoldList.
empty())
1970 for (MachineInstr *Copy : CopiesToReplace)
1971 Copy->addImplicitDefUseOperands(*MF);
1973 SetVector<MachineInstr *> ConstantFoldCandidates;
1974 for (FoldCandidate &Fold : FoldList) {
1975 assert(!Fold.isReg() || Fold.Def.OpToFold);
1976 if (Fold.isReg() && Fold.getReg().isVirtual()) {
1978 const MachineInstr *
DefMI = Fold.Def.DefMI;
1986 assert(Fold.Def.OpToFold && Fold.isReg());
1993 <<
static_cast<int>(Fold.UseOpNo) <<
" of "
1997 ConstantFoldCandidates.
insert(Fold.UseMI);
1999 }
else if (Fold.Commuted) {
2001 TII->commuteInstruction(*Fold.UseMI,
false);
2005 for (MachineInstr *
MI : ConstantFoldCandidates) {
2006 if (tryConstantFoldOp(
MI)) {
2016bool SIFoldOperandsImpl::foldCopyToAGPRRegSequence(MachineInstr *CopyMI)
const {
2023 if (!
TRI->isAGPRClass(DefRC))
2035 DenseMap<TargetInstrInfo::RegSubRegPair, Register> VGPRCopies;
2044 unsigned NumFoldable = 0;
2046 for (
unsigned I = 1;
I != NumRegSeqOperands;
I += 2) {
2063 DefRC, &AMDGPU::AGPR_32RegClass, SubRegIdx);
2083 TRI->getMatchingSuperRegClass(DefRC, InputRC, SubRegIdx);
2094 if (NumFoldable == 0)
2097 CopyMI->
setDesc(
TII->get(AMDGPU::REG_SEQUENCE));
2101 for (
auto [Def, DestSubIdx] : NewDefs) {
2102 if (!
Def->isReg()) {
2106 BuildMI(
MBB, CopyMI,
DL,
TII->get(AMDGPU::V_ACCVGPR_WRITE_B32_e64), Tmp)
2111 Def->setIsKill(
false);
2113 Register &VGPRCopy = VGPRCopies[Src];
2116 TRI->getSubRegisterClass(UseRC, DestSubIdx);
2141 B.addImm(DestSubIdx);
2148bool SIFoldOperandsImpl::tryFoldFoldableCopy(
2149 MachineInstr &
MI, MachineOperand *&CurrentKnownM0Val)
const {
2153 if (DstReg == AMDGPU::M0) {
2154 MachineOperand &NewM0Val =
MI.getOperand(1);
2155 if (CurrentKnownM0Val && CurrentKnownM0Val->
isIdenticalTo(NewM0Val)) {
2156 MI.eraseFromParent();
2167 MachineOperand *OpToFoldPtr;
2168 if (
MI.getOpcode() == AMDGPU::V_MOV_B16_t16_e64) {
2170 if (
TII->hasAnyModifiersSet(
MI))
2172 OpToFoldPtr = &
MI.getOperand(2);
2174 OpToFoldPtr = &
MI.getOperand(1);
2175 MachineOperand &OpToFold = *OpToFoldPtr;
2179 if (!FoldingImm && !OpToFold.
isReg())
2184 !
TRI->isConstantPhysReg(OpToFold.
getReg()))
2213 if (
MI.getOpcode() == AMDGPU::COPY && OpToFold.
isReg() &&
2215 if (DstRC == &AMDGPU::SReg_32RegClass &&
2217 if (!
TRI->getMatchingSuperRegClass(DstRC, &AMDGPU::SGPR_LO16RegClass,
2226 if (OpToFold.
isReg() &&
MI.isCopy() && !
MI.getOperand(1).getSubReg()) {
2227 if (foldCopyToAGPRRegSequence(&
MI))
2231 FoldableDef
Def(OpToFold, DstRC);
2232 bool Changed = foldInstOperand(
MI, Def);
2239 auto *InstToErase = &
MI;
2241 auto &SrcOp = InstToErase->getOperand(1);
2243 InstToErase->eraseFromParent();
2245 InstToErase =
nullptr;
2249 if (!InstToErase || !
TII->isFoldableCopy(*InstToErase))
2253 if (InstToErase && InstToErase->isRegSequence() &&
2255 InstToErase->eraseFromParent();
2265 return OpToFold.
isReg() &&
2266 foldCopyToVGPROfScalarAddOfFrameIndex(DstReg, OpToFold.
getReg(),
MI);
2271const MachineOperand *
2272SIFoldOperandsImpl::isClamp(
const MachineInstr &
MI)
const {
2273 unsigned Op =
MI.getOpcode();
2275 case AMDGPU::V_MAX_F32_e64:
2276 case AMDGPU::V_MAX_F16_e64:
2277 case AMDGPU::V_MAX_F16_t16_e64:
2278 case AMDGPU::V_MAX_F16_fake16_e64:
2279 case AMDGPU::V_MAX_F64_e64:
2280 case AMDGPU::V_MAX_NUM_F64_e64:
2281 case AMDGPU::V_PK_MAX_F16:
2282 case AMDGPU::V_MAX_BF16_PSEUDO_e64:
2283 case AMDGPU::V_PK_MAX_NUM_BF16: {
2284 if (
MI.mayRaiseFPException())
2287 if (!
TII->getNamedOperand(
MI, AMDGPU::OpName::clamp)->getImm())
2291 const MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2292 const MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2296 Src0->
getSubReg() != AMDGPU::NoSubRegister)
2300 if (
TII->hasModifiersSet(
MI, AMDGPU::OpName::omod))
2304 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers)->getImm();
2306 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers)->getImm();
2310 unsigned UnsetMods =
2311 (
Op == AMDGPU::V_PK_MAX_F16 ||
Op == AMDGPU::V_PK_MAX_NUM_BF16)
2314 if (Src0Mods != UnsetMods || Src1Mods != UnsetMods)
2324bool SIFoldOperandsImpl::tryFoldClamp(MachineInstr &
MI) {
2325 const MachineOperand *ClampSrc = isClamp(
MI);
2341 if (
Def->mayRaiseFPException())
2344 MachineOperand *DefClamp =
TII->getNamedOperand(*Def, AMDGPU::OpName::clamp);
2348 LLVM_DEBUG(
dbgs() <<
"Folding clamp " << *DefClamp <<
" into " << *Def);
2354 Register MIDstReg =
MI.getOperand(0).getReg();
2355 if (
TRI->isSGPRReg(*MRI, DefReg)) {
2364 MI.eraseFromParent();
2369 if (
TII->convertToThreeAddress(*Def,
nullptr,
nullptr))
2370 Def->eraseFromParent();
2377 case AMDGPU::V_MUL_F64_e64:
2378 case AMDGPU::V_MUL_F64_pseudo_e64: {
2380 case 0x3fe0000000000000:
2382 case 0x4000000000000000:
2384 case 0x4010000000000000:
2390 case AMDGPU::V_MUL_F32_e64: {
2391 switch (
static_cast<uint32_t>(Val)) {
2402 case AMDGPU::V_MUL_F16_e64:
2403 case AMDGPU::V_MUL_F16_t16_e64:
2404 case AMDGPU::V_MUL_F16_fake16_e64: {
2405 switch (
static_cast<uint16_t>(Val)) {
2416 case AMDGPU::V_PK_MUL_BF16: {
2417 switch (
static_cast<uint16_t>(Val)) {
2436std::pair<const MachineOperand *, int>
2437SIFoldOperandsImpl::isOMod(
const MachineInstr &
MI)
const {
2438 unsigned Op =
MI.getOpcode();
2440 case AMDGPU::V_MUL_F64_e64:
2441 case AMDGPU::V_MUL_F64_pseudo_e64:
2442 case AMDGPU::V_MUL_F32_e64:
2443 case AMDGPU::V_MUL_F16_t16_e64:
2444 case AMDGPU::V_MUL_F16_fake16_e64:
2445 case AMDGPU::V_MUL_F16_e64: {
2447 if ((
Op == AMDGPU::V_MUL_F32_e64 &&
2449 ((
Op == AMDGPU::V_MUL_F64_e64 ||
Op == AMDGPU::V_MUL_F64_pseudo_e64 ||
2450 Op == AMDGPU::V_MUL_F16_e64 ||
Op == AMDGPU::V_MUL_F16_t16_e64 ||
2451 Op == AMDGPU::V_MUL_F16_fake16_e64) &&
2454 MI.mayRaiseFPException())
2457 const MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2458 const MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2461 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*MRI, *Src1);
2467 TII->hasModifiersSet(
MI, AMDGPU::OpName::src0_modifiers) ||
2468 TII->hasModifiersSet(
MI, AMDGPU::OpName::src1_modifiers) ||
2469 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod) ||
2470 TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp))
2473 return {Src0, OMod};
2475 case AMDGPU::V_ADD_F64_e64:
2476 case AMDGPU::V_ADD_F64_pseudo_e64:
2477 case AMDGPU::V_ADD_F32_e64:
2478 case AMDGPU::V_ADD_F16_e64:
2479 case AMDGPU::V_ADD_F16_t16_e64:
2480 case AMDGPU::V_ADD_F16_fake16_e64: {
2482 if ((
Op == AMDGPU::V_ADD_F32_e64 &&
2484 ((
Op == AMDGPU::V_ADD_F64_e64 ||
Op == AMDGPU::V_ADD_F64_pseudo_e64 ||
2485 Op == AMDGPU::V_ADD_F16_e64 ||
Op == AMDGPU::V_ADD_F16_t16_e64 ||
2486 Op == AMDGPU::V_ADD_F16_fake16_e64) &&
2491 const MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2492 const MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2496 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::src0_modifiers) &&
2497 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::src1_modifiers) &&
2498 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp) &&
2499 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::omod))
2504 case AMDGPU::V_PK_MUL_BF16: {
2509 MI.mayRaiseFPException())
2512 const MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2513 const MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2516 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*MRI, *Src1);
2520 int OMod =
getOModValue(AMDGPU::V_PK_MUL_BF16, *Src1Imm);
2525 const MachineOperand *Src0Mods =
2526 TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers);
2527 const MachineOperand *Src1Mods =
2528 TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers);
2531 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod) ||
2532 TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp))
2535 return {Src0, OMod};
2537 case AMDGPU::V_PK_ADD_BF16: {
2543 const MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2544 const MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2551 const MachineOperand *Src0Mods =
2552 TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers);
2553 const MachineOperand *Src1Mods =
2554 TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers);
2557 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod) ||
2558 TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp))
2569bool SIFoldOperandsImpl::tryFoldOMod(MachineInstr &
MI) {
2570 const MachineOperand *RegOp;
2572 std::tie(RegOp, OMod) = isOMod(
MI);
2574 RegOp->
getSubReg() != AMDGPU::NoSubRegister ||
2579 Register OModSrcReg =
Def->getOperand(0).getReg();
2583 if (
Def->isRegSequence() &&
Def->getNumOperands() == 5 &&
2584 Def->getOperand(2).getImm() == AMDGPU::lo16) {
2586 bool CanLookThrough =
true;
2587 MachineInstr *Hi16Def = MRI->
getVRegDef(
Def->getOperand(3).getReg());
2589 CanLookThrough =
false;
2591 if (CanLookThrough) {
2602 MachineOperand *DefOMod =
TII->getNamedOperand(*Def, AMDGPU::OpName::omod);
2606 if (
Def->mayRaiseFPException())
2611 if (
TII->hasModifiersSet(*Def, AMDGPU::OpName::clamp))
2621 MI.eraseFromParent();
2626 if (
TII->convertToThreeAddress(*Def,
nullptr,
nullptr))
2627 Def->eraseFromParent();
2634bool SIFoldOperandsImpl::tryFoldSGPRSplatRegSequence(MachineInstr &
MI) {
2637 if (!ST->hasPackedFP64SingleSGPROps() && !ST->hasPackedU64SingleSGPROps())
2644 if (!
TRI->isSGPRClass(RegClass) ||
TRI->getRegSizeInBits(*RegClass) != 128)
2648 if (!getRegSeqInit(Defs,
Reg))
2652 if (Defs.
size() <= 1)
2655 const auto &[FirstOp,
_] = Defs.
front();
2656 if (!FirstOp->isReg())
2659 Register FirstReg = FirstOp->getReg();
2660 unsigned FirstSubReg = FirstOp->getSubReg();
2663 if (!
TRI->isSGPRClass(FirstRegClass))
2668 const auto &[
Op,
_] =
Def;
2669 return Op->isReg() &&
Op->getReg() == FirstReg &&
2670 Op->getSubReg() == FirstSubReg;
2682 MachineInstrBuilder
RS =
BuildMI(*
MI.getParent(),
MI,
MI.getDebugLoc(),
2683 TII->get(AMDGPU::REG_SEQUENCE), NewDst);
2686 FirstOp->setIsKill(
false);
2688 RS.addImm(Defs[0].second);
2693 for (
unsigned i = 1; i < Defs.
size(); ++i) {
2694 RS.addReg(UndefReg, RegState::Undef);
2695 RS.addImm(Defs[i].second);
2704 MI.eraseFromParent();
2710bool SIFoldOperandsImpl::tryFoldRegSequence(MachineInstr &
MI) {
2714 if (tryFoldSGPRSplatRegSequence(
MI))
2717 auto Reg =
MI.getOperand(0).getReg();
2719 if (!ST->hasGFX90AInsts() || !
TRI->isVGPR(*MRI,
Reg) ||
2724 if (!getRegSeqInit(Defs,
Reg))
2727 for (
auto &[
Op, SubIdx] : Defs) {
2730 if (
TRI->isAGPR(*MRI,
Op->getReg()))
2733 const MachineInstr *SubDef = MRI->
getVRegDef(
Op->getReg());
2741 MachineInstr *
UseMI =
Op->getParent();
2750 if (
Op->getSubReg())
2756 if (!OpRC || !
TRI->isVectorSuperClass(OpRC))
2762 TII->get(AMDGPU::REG_SEQUENCE), Dst);
2764 for (
auto &[Def, SubIdx] : Defs) {
2765 Def->setIsKill(
false);
2766 if (
TRI->isAGPR(*MRI,
Def->getReg())) {
2777 if (!
TII->isOperandLegal(*
UseMI, OpIdx,
Op)) {
2779 RS->eraseFromParent();
2788 MI.eraseFromParent();
2796 Register &OutReg,
unsigned &OutSubReg) {
2806 if (
TRI.isAGPR(MRI, CopySrcReg)) {
2807 OutReg = CopySrcReg;
2816 if (!CopySrcDef || !CopySrcDef->
isCopy())
2823 OtherCopySrc.
getSubReg() != AMDGPU::NoSubRegister ||
2824 !
TRI.isAGPR(MRI, OtherCopySrcReg))
2827 OutReg = OtherCopySrcReg;
2861bool SIFoldOperandsImpl::tryFoldPhiAGPR(MachineInstr &
PHI) {
2865 if (!
TRI->isVGPR(*MRI, PhiOut))
2871 for (
unsigned K = 1;
K <
PHI.getNumExplicitOperands();
K += 2) {
2872 MachineOperand &MO =
PHI.getOperand(K);
2874 if (!Copy || !
Copy->isCopy())
2878 unsigned AGPRRegMask = AMDGPU::NoSubRegister;
2883 if (
const auto *SubRC =
TRI->getSubRegisterClass(CopyInRC, AGPRRegMask))
2894 bool IsAGPR32 = (ARC == &AMDGPU::AGPR_32RegClass);
2898 for (
unsigned K = 1;
K <
PHI.getNumExplicitOperands();
K += 2) {
2899 MachineOperand &MO =
PHI.getOperand(K);
2903 MachineBasicBlock *InsertMBB =
nullptr;
2906 unsigned CopyOpc = AMDGPU::COPY;
2911 if (
Def->isCopy()) {
2913 unsigned AGPRSubReg = AMDGPU::NoSubRegister;
2926 MachineOperand &CopyIn =
Def->getOperand(1);
2929 CopyOpc = AMDGPU::V_ACCVGPR_WRITE_B32_e64;
2932 InsertMBB =
Def->getParent();
2940 MachineInstr *
MI =
BuildMI(*InsertMBB, InsertPt,
PHI.getDebugLoc(),
2941 TII->get(CopyOpc), NewReg)
2951 PHI.getOperand(0).setReg(NewReg);
2957 TII->get(AMDGPU::COPY), PhiOut)
2965bool SIFoldOperandsImpl::tryFoldLoad(MachineInstr &
MI) {
2967 if (!ST->hasGFX90AInsts() ||
MI.getNumExplicitDefs() != 1)
2970 MachineOperand &
Def =
MI.getOperand(0);
2987 while (!
Users.empty()) {
2988 const MachineInstr *
I =
Users.pop_back_val();
2989 if (!
I->isCopy() && !
I->isRegSequence())
2991 Register DstReg =
I->getOperand(0).getReg();
2995 if (
TRI->isAGPR(*MRI, DstReg))
2999 Users.push_back(&U);
3004 if (!
TII->isOperandLegal(
MI, 0, &Def)) {
3009 while (!MoveRegs.
empty()) {
3051bool SIFoldOperandsImpl::tryOptimizeAGPRPhis(MachineBasicBlock &
MBB) {
3054 if (ST->hasGFX90AInsts())
3058 DenseMap<std::pair<Register, unsigned>, std::vector<MachineOperand *>>
3061 for (
auto &
MI :
MBB) {
3065 if (!
TRI->isAGPR(*MRI,
MI.getOperand(0).getReg()))
3068 for (
unsigned K = 1;
K <
MI.getNumOperands();
K += 2) {
3069 MachineOperand &PhiMO =
MI.getOperand(K);
3079 for (
const auto &[Entry, MOs] : RegToMO) {
3080 if (MOs.size() == 1)
3085 MachineBasicBlock *DefMBB =
Def->getParent();
3092 MachineInstr *VGPRCopy =
3094 TII->get(AMDGPU::V_ACCVGPR_READ_B32_e64), TempVGPR)
3100 TII->get(AMDGPU::COPY), TempAGPR)
3104 for (MachineOperand *MO : MOs) {
3116bool SIFoldOperandsImpl::run(
MachineFunction &MF,
const MachineLoopInfo *MLI) {
3122 MFI = MF.
getInfo<SIMachineFunctionInfo>();
3133 MachineOperand *CurrentKnownM0Val =
nullptr;
3141 if (tryConstantFoldOp(&
MI)) {
3146 if (tryFoldRedundantAND(
MI)) {
3151 if (
MI.isRegSequence() && tryFoldRegSequence(
MI)) {
3156 if (
MI.isPHI() && tryFoldPhiAGPR(
MI)) {
3161 if (
MI.mayLoad() && tryFoldLoad(
MI)) {
3166 if (
TII->isFoldableCopy(
MI)) {
3167 Changed |= tryFoldFoldableCopy(
MI, CurrentKnownM0Val);
3172 if (CurrentKnownM0Val &&
MI.modifiesRegister(AMDGPU::M0,
TRI))
3173 CurrentKnownM0Val =
nullptr;
3193 bool Changed = SIFoldOperandsImpl().run(MF, MLI);
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool updateOperand(Instruction *Inst, unsigned Idx, Instruction *Mat)
Updates the operand at Idx in instruction Inst with the result of instruction Mat.
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
AMD GCN specific subclass of TargetSubtarget.
static Register UseReg(const MachineOperand &MO)
const HexagonInstrInfo * TII
iv Induction Variable Users
Register const TargetRegisterInfo * TRI
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
static bool isReg(const MCInst &MI, unsigned OpNo)
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
static bool loopModifiesExec(const MachineLoop &L, const SIRegisterInfo &TRI)
static unsigned macToMad(unsigned Opc)
static bool isAGPRCopy(const SIRegisterInfo &TRI, const MachineRegisterInfo &MRI, const MachineInstr &Copy, Register &OutReg, unsigned &OutSubReg)
Checks whether Copy is a AGPR -> VGPR copy.
static void appendFoldCandidate(SmallVectorImpl< FoldCandidate > &FoldList, FoldCandidate &&Entry)
static const TargetRegisterClass * getRegOpRC(const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const MachineOperand &MO)
static bool evalBinaryInstruction(unsigned Opcode, int32_t &Result, uint32_t LHS, uint32_t RHS)
static int getOModValue(unsigned Opc, int64_t Val)
static unsigned getMovOpc(bool IsScalar)
static MachineOperand * lookUpCopyChain(const SIInstrInfo &TII, const MachineRegisterInfo &MRI, Register SrcReg)
static bool checkImmOpForPKF32InstrReplicatesLower32BitsOfScalarOperand(const FoldableDef &OpToFold)
static bool isPKF32InstrReplicatesLower32BitsOfScalarOperand(const GCNSubtarget *ST, MachineInstr *MI, unsigned OpNo)
Interface definition for SIInstrInfo.
Interface definition for SIRegisterInfo.
static int Lookup(ArrayRef< TableEntry > Table, unsigned Opcode)
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.
FunctionPass class - This class is used to implement most global optimizations.
const SIInstrInfo * getInstrInfo() const override
bool hasDOTOpSelHazard() const
bool zeroesHigh16BitsOfDest(unsigned Opcode) const
Returns if the result of this instruction with a 16-bit result returned in a 32-bit register implicit...
const HexagonRegisterInfo & getRegisterInfo() const
bool contains(const LoopT *L) const
Return true if the specified loop is contained within this loop.
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
ArrayRef< MCOperandInfo > operands() const
int getOperandConstraint(unsigned OpNum, MCOI::OperandConstraint Constraint) const
Returns the value of the specified operand constraint if it is present.
bool isVariadic() const
Return true if this instruction can have a variable number of operands.
This holds information about one operand of a machine instruction, indicating the register class for ...
uint8_t OperandType
Information about the type of the operand.
bool hasSuperClassEq(const MCRegisterClass *RC) const
Returns true if RC is a super-class of or equal to this class.
bool contains(MCRegister Reg) const
contains - Return true if the specified register is included in this register class.
bool hasSubClassEq(const MCRegisterClass *RC) const
Returns true if RC is a sub-class of or equal to this class.
An RAII based helper class to modify MachineFunctionProperties when running pass.
LLVM_ABI iterator SkipPHIsLabelsAndDebug(iterator I, Register Reg=Register(), bool SkipPseudoOp=true)
Return the first instruction in MBB after I that is not a PHI, label or debug.
LLVM_ABI LivenessQueryResult computeRegisterLiveness(const TargetRegisterInfo *TRI, MCRegister Reg, const_iterator Before, unsigned Neighborhood=10) const
Return whether (physical) register Reg has been defined and not killed as of just before Before.
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
LivenessQueryResult
Possible outcome of a register liveness query to computeRegisterLiveness()
@ LQR_Dead
Register is known to be fully dead.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
Properties which a MachineFunction may have at a given point in time.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Register getReg(unsigned Idx) const
Get the register for the operand index.
const MachineInstrBuilder & setOperandDead(unsigned OpIdx) const
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool isImplicitDef() const
const MachineBasicBlock * getParent() const
bool readsRegister(Register Reg, const TargetRegisterInfo *TRI) const
Return true if the MachineInstr reads the specified register.
LLVM_ABI bool allImplicitDefsAreDead() const
Return true if all the implicit defs of this instruction are dead.
unsigned getNumOperands() const
Retuns the total number of operands.
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
unsigned getOperandNo(const_mop_iterator I) const
Returns the number of the operand iterator I points to.
LLVM_ABI unsigned getNumExplicitOperands() const
Returns the number of non-implicit operands.
mop_range implicit_operands()
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
void clearFlag(MIFlag Flag)
clearFlag - Clear a MI flag.
bool isRegSequence() const
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
MachineOperand * mop_iterator
iterator/begin/end - Iterate over all operands of a machine instruction.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
LLVM_ABI void removeOperand(unsigned OpNo)
Erase an operand from an instruction, leaving it with one fewer operand than it started with.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
Analysis pass that exposes the MachineLoopInfo for a machine function.
MachineOperand class - Representation of each machine instruction operand.
void setSubReg(unsigned subReg)
unsigned getSubReg() const
LLVM_ABI unsigned getOperandNo() const
Returns the index of this operand in the instruction that it belongs to.
LLVM_ABI void substVirtReg(Register Reg, unsigned SubIdx, const TargetRegisterInfo &)
substVirtReg - Substitute the current register with the virtual subregister Reg:SubReg.
LLVM_ABI void ChangeToFrameIndex(int Idx, unsigned TargetFlags=0)
Replace this operand with a frame index.
void setImm(int64_t immVal)
bool isReg() const
isReg - Tests if this is a MO_Register operand.
void setIsDead(bool Val=true)
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
LLVM_ABI void ChangeToImmediate(int64_t ImmVal, unsigned TargetFlags=0)
ChangeToImmediate - Replace this operand with a new immediate operand of the specified value.
LLVM_ABI void ChangeToGA(const GlobalValue *GV, int64_t Offset, unsigned TargetFlags=0)
ChangeToGA - Replace this operand with a new global address operand.
void setIsKill(bool Val=true)
LLVM_ABI void ChangeToRegister(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isDebug=false)
ChangeToRegister - Replace this operand with a new register operand of the specified value.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
LLVM_ABI void substPhysReg(MCRegister Reg, const TargetRegisterInfo &)
substPhysReg - Substitute the current register with the physical register Reg, taking any existing Su...
static MachineOperand CreateImm(int64_t Val)
bool isGlobal() const
isGlobal - Tests if this is a MO_GlobalAddress operand.
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
void setIsUndef(bool Val=true)
Register getReg() const
getReg - Returns the register number.
bool isFI() const
isFI - Tests if this is a MO_FrameIndex operand.
LLVM_ABI bool isIdenticalTo(const MachineOperand &Other) const
Returns true if this operand is identical to the specified operand except for liveness related flags ...
@ MO_Immediate
Immediate operand.
@ MO_GlobalAddress
Address of a global value.
@ MO_FrameIndex
Abstract Stack Frame Index.
@ MO_Register
Register operand.
static MachineOperand CreateFI(int Idx)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
use_nodbg_iterator use_nodbg_begin(Register RegNo) const
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI void clearKillFlags(Register Reg) const
clearKillFlags - Iterate over all the uses of the given register and clear the kill flag from the Mac...
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
iterator_range< use_nodbg_iterator > use_nodbg_operands(Register Reg) const
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
LLVM_ABI bool hasOneNonDBGUser(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug instruction using the specified regis...
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
void setRegAllocationHint(Register VReg, unsigned Type, Register PrefReg)
setRegAllocationHint - Specify a register allocation hint for the specified virtual register.
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
LLVM_ABI const TargetRegisterClass * constrainRegClass(Register Reg, const TargetRegisterClass *RC, unsigned MinNumRegs=0)
constrainRegClass - Constrain the register class of the specified virtual register to be a common sub...
LLVM_ABI void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Wrapper class representing virtual and physical registers.
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
static bool hasSameClamp(const MachineInstr &A, const MachineInstr &B)
static std::optional< int64_t > extractSubregFromImm(int64_t ImmVal, unsigned SubRegIndex)
Return the extracted immediate value in a subregister use from a constant materialized in a super reg...
This class keeps track of the SPI_SP_INPUT_ADDR config register, which tells the hardware which inter...
Register getScratchRSrcReg() const
Returns the physical register reserved for use as the resource descriptor for scratch accesses.
SIModeRegisterDefaults getMode() const
static unsigned getSubRegFromChannel(unsigned Channel, unsigned NumRegs=1)
bool insert(const value_type &X)
Insert a new element into the SetVector.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
Represent a constant reference to a string, i.e.
static const unsigned CommuteAnyOperandIndex
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
bool isInlinableLiteralV216(uint32_t Literal, uint8_t OpType)
LLVM_READONLY int32_t getMFMAEarlyClobberOp(uint32_t Opcode)
LLVM_READONLY bool hasNamedOperand(uint64_t Opcode, OpName NamedIdx)
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 int32_t getVOPe32(uint32_t Opcode)
constexpr bool isSISrcOperand(const MCOperandInfo &OpInfo)
Is this an AMDGPU specific source operand?
@ OPERAND_REG_INLINE_C_FP64
@ OPERAND_REG_INLINE_C_BF16
@ OPERAND_REG_INLINE_C_V2BF16
@ OPERAND_REG_IMM_V2INT64
@ OPERAND_REG_IMM_V2INT16
@ OPERAND_REG_INLINE_C_INT64
@ OPERAND_REG_IMM_NOINLINE_V2FP16
@ OPERAND_REG_INLINE_C_V2FP16
@ OPERAND_REG_INLINE_AC_INT32
Operands with an AccVGPR register or inline constant.
@ OPERAND_REG_INLINE_AC_FP32
@ OPERAND_REG_INLINE_C_FP32
@ OPERAND_REG_INLINE_C_INT32
@ OPERAND_REG_INLINE_C_V2INT16
@ OPERAND_REG_INLINE_AC_FP64
LLVM_READONLY int32_t getFlatScratchInstSSfromSV(uint32_t Opcode)
bool supportsScaleOffset(const MCInstrInfo &MII, unsigned Opcode)
constexpr bool isVOP3(const T &...O)
constexpr bool isMAI(const T &...O)
constexpr bool isSWMMAC(const T &...O)
constexpr bool isVOP3P(const T &...O)
constexpr bool isWMMA(const T &...O)
constexpr bool isDOT(const T &...O)
constexpr bool isPacked(const T &...O)
NodeAddr< DefNode * > Def
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
TargetInstrInfo::RegSubRegPair getRegSubRegPair(const MachineOperand &O)
Create RegSubRegPair from a register MachineOperand.
MachineBasicBlock::instr_iterator getBundleStart(MachineBasicBlock::instr_iterator I)
Returns an iterator to the first instruction in the bundle containing I.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool execMayBeModifiedBeforeUse(const MachineRegisterInfo &MRI, Register VReg, const MachineInstr &DefMI, const MachineInstr &UseMI)
Return false if EXEC is not changed between the def of VReg at DefMI and the use at UseMI.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
FunctionPass * createSIFoldOperandsLegacyPass()
char & SIFoldOperandsLegacyID
constexpr uint32_t Hi_32(uint64_t Value)
Return the high 32 bits of a 64 bit value.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
constexpr uint32_t Lo_32(uint64_t Value)
Return the low 32 bits of a 64 bit value.
@ Sub
Subtraction of integers.
DWARFExpression::Operation Op
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
iterator_range< df_iterator< T > > depth_first(const T &G)
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
constexpr uint64_t Make_64(uint32_t High, uint32_t Low)
Make a 64-bit integer from a high / low pair of 32-bit integers.
MCRegisterClass TargetRegisterClass
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
@ PreserveSign
The sign of a flushed-to-zero number is preserved in the sign of 0.
DenormalModeKind Output
Denormal flushing mode for floating point instruction results in the default floating point environme...
DenormalMode FP64FP16Denormals
If this is set, neither input or output denormals are flushed for both f64 and f16/v2f16 instructions...
bool IEEE
Floating point opcodes that support exception flag gathering quiet and propagate signaling NaN inputs...
DenormalMode FP32Denormals
If this is set, neither input or output denormals are flushed for most f32 instructions.