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();
128 if (DefSubReg != AMDGPU::NoSubRegister)
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 {
185 const FoldableDef &OpToFold)
const;
188 unsigned convertToVALUOp(
unsigned Opc,
bool UseVOP3 =
false)
const {
190 case AMDGPU::S_ADD_I32: {
191 if (ST->hasAddNoCarryInsts())
192 return UseVOP3 ? AMDGPU::V_ADD_U32_e64 : AMDGPU::V_ADD_U32_e32;
193 return UseVOP3 ? AMDGPU::V_ADD_CO_U32_e64 : AMDGPU::V_ADD_CO_U32_e32;
195 case AMDGPU::S_OR_B32:
196 return UseVOP3 ? AMDGPU::V_OR_B32_e64 : AMDGPU::V_OR_B32_e32;
197 case AMDGPU::S_AND_B32:
198 return UseVOP3 ? AMDGPU::V_AND_B32_e64 : AMDGPU::V_AND_B32_e32;
199 case AMDGPU::S_MUL_I32:
200 return AMDGPU::V_MUL_LO_U32_e64;
202 return AMDGPU::INSTRUCTION_LIST_END;
206 bool foldCopyToVGPROfScalarAddOfFrameIndex(
Register DstReg,
Register SrcReg,
212 int64_t ImmVal)
const;
216 int64_t ImmVal)
const;
220 const FoldableDef &OpToFold)
const;
229 getRegSeqInit(
SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs,
232 std::pair<int64_t, const TargetRegisterClass *>
249 bool foldInstOperand(
MachineInstr &
MI,
const FoldableDef &OpToFold)
const;
251 bool foldCopyToAGPRRegSequence(
MachineInstr *CopyMI)
const;
258 std::pair<const MachineOperand *, int> isOMod(
const MachineInstr &
MI)
const;
267 SIFoldOperandsImpl() =
default;
281 return SIFoldOperandsImpl().run(MF);
284 StringRef getPassName()
const override {
return "SI Fold Operands"; }
302char SIFoldOperandsLegacy::
ID = 0;
311 TRI.getSubRegisterClass(RC, MO.getSubReg()))
319 case AMDGPU::V_MAC_F32_e64:
320 return AMDGPU::V_MAD_F32_e64;
321 case AMDGPU::V_MAC_F16_e64:
322 return AMDGPU::V_MAD_F16_e64;
323 case AMDGPU::V_FMAC_F32_e64:
324 return AMDGPU::V_FMA_F32_e64;
325 case AMDGPU::V_FMAC_F16_e64:
326 return AMDGPU::V_FMA_F16_gfx9_e64;
327 case AMDGPU::V_FMAC_F16_t16_e64:
328 return AMDGPU::V_FMA_F16_gfx9_t16_e64;
329 case AMDGPU::V_FMAC_F16_fake16_e64:
330 return AMDGPU::V_FMA_F16_gfx9_fake16_e64;
331 case AMDGPU::V_FMAC_LEGACY_F32_e64:
332 return AMDGPU::V_FMA_LEGACY_F32_e64;
333 case AMDGPU::V_FMAC_F64_e64:
334 return AMDGPU::V_FMA_F64_e64;
336 return AMDGPU::INSTRUCTION_LIST_END;
342 const FoldableDef &OpToFold)
const {
343 if (!OpToFold.isFI())
346 const unsigned Opc =
UseMI.getOpcode();
348 case AMDGPU::S_ADD_I32:
349 case AMDGPU::S_ADD_U32:
350 case AMDGPU::V_ADD_U32_e32:
351 case AMDGPU::V_ADD_CO_U32_e32:
355 return UseMI.getOperand(OpNo == 1 ? 2 : 1).isImm() &&
357 case AMDGPU::V_ADD_U32_e64:
358 case AMDGPU::V_ADD_CO_U32_e64:
359 return UseMI.getOperand(OpNo == 2 ? 3 : 2).isImm() &&
366 return OpNo == AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::vaddr);
370 int SIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::saddr);
374 int VIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::vaddr);
375 return OpNo == VIdx && SIdx == -1;
381bool SIFoldOperandsImpl::foldCopyToVGPROfScalarAddOfFrameIndex(
383 if (
TRI->isVGPR(*MRI, DstReg) &&
TRI->isSGPRReg(*MRI, SrcReg) &&
386 if (!Def ||
Def->getNumOperands() != 4)
389 MachineOperand *Src0 = &
Def->getOperand(1);
390 MachineOperand *Src1 = &
Def->getOperand(2);
401 const bool UseVOP3 = !Src0->
isImm() ||
TII->isInlineConstant(*Src0);
402 unsigned NewOp = convertToVALUOp(
Def->getOpcode(), UseVOP3);
403 if (NewOp == AMDGPU::INSTRUCTION_LIST_END ||
404 !
Def->getOperand(3).isDead())
407 MachineBasicBlock *
MBB =
Def->getParent();
409 if (NewOp != AMDGPU::V_ADD_CO_U32_e32) {
410 MachineInstrBuilder
Add =
413 if (
Add->getDesc().getNumDefs() == 2) {
415 Add.addDef(CarryOutReg, RegState::Dead);
419 Add.add(*Src0).add(*Src1).setMIFlags(
Def->getFlags());
423 Def->eraseFromParent();
424 MI.eraseFromParent();
428 assert(NewOp == AMDGPU::V_ADD_CO_U32_e32);
439 Def->eraseFromParent();
440 MI.eraseFromParent();
449 return new SIFoldOperandsLegacy();
452bool SIFoldOperandsImpl::canUseImmWithOpSel(
const MachineInstr *
MI,
454 int64_t ImmVal)
const {
461 int OpNo =
MI->getOperandNo(&Old);
463 unsigned Opcode =
MI->getOpcode();
464 uint8_t OpType =
TII->get(Opcode).operands()[OpNo].OperandType;
486bool SIFoldOperandsImpl::tryFoldImmWithOpSel(MachineInstr *
MI,
unsigned UseOpNo,
487 int64_t ImmVal)
const {
488 MachineOperand &Old =
MI->getOperand(UseOpNo);
489 unsigned Opcode =
MI->getOpcode();
490 int OpNo =
MI->getOperandNo(&Old);
491 uint8_t OpType =
TII->get(Opcode).operands()[OpNo].OperandType;
503 AMDGPU::OpName ModName = AMDGPU::OpName::NUM_OPERAND_NAMES;
504 unsigned SrcIdx = ~0;
505 if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src0)) {
506 ModName = AMDGPU::OpName::src0_modifiers;
508 }
else if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src1)) {
509 ModName = AMDGPU::OpName::src1_modifiers;
511 }
else if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src2)) {
512 ModName = AMDGPU::OpName::src2_modifiers;
515 assert(ModName != AMDGPU::OpName::NUM_OPERAND_NAMES);
516 int ModIdx = AMDGPU::getNamedOperandIdx(Opcode, ModName);
517 MachineOperand &
Mod =
MI->getOperand(ModIdx);
518 unsigned ModVal =
Mod.getImm();
524 uint32_t
Imm = (
static_cast<uint32_t
>(ImmHi) << 16) | ImmLo;
529 auto tryFoldToInline = [&](uint32_t
Imm) ->
bool {
538 uint16_t
Lo =
static_cast<uint16_t
>(
Imm);
539 uint16_t
Hi =
static_cast<uint16_t
>(
Imm >> 16);
545 if (ST->hasBF16InlineConstFromUpperFP32() &&
549 Mod.setImm(NewModVal);
554 if (
static_cast<int16_t
>(
Lo) < 0) {
555 int32_t SExt =
static_cast<int16_t
>(
Lo);
557 Mod.setImm(NewModVal);
572 uint32_t Swapped = (
static_cast<uint32_t
>(
Lo) << 16) |
Hi;
583 if (tryFoldToInline(Imm))
592 bool IsUAdd = Opcode == AMDGPU::V_PK_ADD_U16;
593 bool IsUSub = Opcode == AMDGPU::V_PK_SUB_U16;
594 if (SrcIdx == 1 && (IsUAdd || IsUSub)) {
596 AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::clamp);
597 bool Clamp =
MI->getOperand(ClampIdx).getImm() != 0;
600 uint16_t NegLo = -
static_cast<uint16_t
>(
Imm);
601 uint16_t NegHi = -
static_cast<uint16_t
>(
Imm >> 16);
602 uint32_t NegImm = (
static_cast<uint32_t
>(NegHi) << 16) | NegLo;
604 if (tryFoldToInline(NegImm)) {
606 IsUAdd ? AMDGPU::V_PK_SUB_U16 : AMDGPU::V_PK_ADD_U16;
607 MI->setDesc(
TII->get(NegOpcode));
616bool SIFoldOperandsImpl::updateOperand(FoldCandidate &Fold)
const {
617 MachineInstr *
MI = Fold.UseMI;
618 MachineOperand &Old =
MI->getOperand(Fold.UseOpNo);
621 std::optional<int64_t> ImmVal;
623 ImmVal = Fold.Def.getEffectiveImmVal();
625 if (ImmVal && canUseImmWithOpSel(Fold.UseMI, Fold.UseOpNo, *ImmVal)) {
626 if (tryFoldImmWithOpSel(Fold.UseMI, Fold.UseOpNo, *ImmVal))
632 int OpNo =
MI->getOperandNo(&Old);
633 if (!
TII->isOperandLegal(*
MI, OpNo, &New))
639 if ((Fold.isImm() || Fold.isFI() || Fold.isGlobal()) && Fold.needsShrink()) {
640 MachineBasicBlock *
MBB =
MI->getParent();
647 int Op32 = Fold.ShrinkOpcode;
648 MachineOperand &Dst0 =
MI->getOperand(0);
649 MachineOperand &Dst1 =
MI->getOperand(1);
657 MachineInstr *Inst32 =
TII->buildShrunkInst(*
MI, Op32);
659 if (HaveNonDbgCarryUse) {
662 .
addReg(AMDGPU::VCC, RegState::Kill);
672 for (
unsigned I =
MI->getNumOperands() - 1;
I > 0; --
I)
673 MI->removeOperand(
I);
674 MI->setDesc(
TII->get(AMDGPU::IMPLICIT_DEF));
677 TII->commuteInstruction(*Inst32,
false);
681 assert(!Fold.needsShrink() &&
"not handled");
686 if (NewMFMAOpc == -1)
688 MI->setDesc(
TII->get(NewMFMAOpc));
689 MI->untieRegOperand(0);
690 const MCInstrDesc &MCID =
MI->getDesc();
691 for (
unsigned I = 0;
I <
MI->getNumDefs(); ++
I)
693 MI->getOperand(
I).setIsEarlyClobber(
true);
698 int OpNo =
MI->getOperandNo(&Old);
699 if (!
TII->isOperandLegal(*
MI, OpNo, &New))
706 if (Fold.isGlobal()) {
707 Old.
ChangeToGA(Fold.Def.OpToFold->getGlobal(),
708 Fold.Def.OpToFold->getOffset(),
709 Fold.Def.OpToFold->getTargetFlags());
718 MachineOperand *
New = Fold.Def.OpToFold;
722 TII->getRegClass(
MI->getDesc(), Fold.UseOpNo)) {
724 TRI->getRegClassForReg(*MRI,
New->getReg());
727 if (
New->getSubReg()) {
729 TRI->getMatchingSuperRegClass(NewRC, OpRC,
New->getSubReg());
735 if (
New->getReg().isVirtual() &&
738 <<
TRI->getRegClassName(ConstrainRC) <<
'\n');
745 if (Old.
getSubReg() == AMDGPU::lo16 &&
TRI->isSGPRReg(*MRI,
New->getReg()))
747 if (
New->getReg().isPhysical()) {
755 if (
MI->isBundledWithPred()) {
757 for (MachineOperand &MO : Header.operands()) {
758 if (MO.getReg() == OldReg) {
759 MO.setReg(
New->getReg());
760 MO.setSubReg(
New->getSubReg());
769 FoldCandidate &&Entry) {
771 for (FoldCandidate &Fold : FoldList)
772 if (Fold.UseMI == Entry.UseMI && Fold.UseOpNo == Entry.UseOpNo)
774 LLVM_DEBUG(
dbgs() <<
"Append " << (Entry.Commuted ?
"commuted" :
"normal")
775 <<
" operand " << Entry.UseOpNo <<
"\n " << *Entry.UseMI);
781 const FoldableDef &FoldOp,
782 bool Commuted =
false,
int ShrinkOp = -1) {
784 FoldCandidate(
MI, OpNo, FoldOp, Commuted, ShrinkOp));
792 if (!ST->hasPKF32InstsReplicatingLower32BitsOfScalarInput())
802 const FoldableDef &OpToFold) {
803 assert(OpToFold.isImm() &&
"Expected immediate operand");
804 uint64_t ImmVal = OpToFold.getEffectiveImmVal().value();
810bool SIFoldOperandsImpl::tryAddToFoldList(
811 SmallVectorImpl<FoldCandidate> &FoldList, MachineInstr *
MI,
unsigned OpNo,
812 const FoldableDef &OpToFold)
const {
813 const unsigned Opc =
MI->getOpcode();
815 auto tryToFoldAsFMAAKorMK = [&]() {
816 if (!OpToFold.isImm())
819 const bool TryAK = OpNo == 3;
820 const unsigned NewOpc = TryAK ? AMDGPU::S_FMAAK_F32 : AMDGPU::S_FMAMK_F32;
821 MI->setDesc(
TII->get(NewOpc));
824 bool FoldAsFMAAKorMK =
825 tryAddToFoldList(FoldList,
MI, TryAK ? 3 : 2, OpToFold);
826 if (FoldAsFMAAKorMK) {
828 MI->untieRegOperand(3);
831 MachineOperand &Op1 =
MI->getOperand(1);
832 MachineOperand &Op2 =
MI->getOperand(2);
849 bool IsLegal = OpToFold.isOperandLegal(*
TII, *
MI, OpNo);
850 if (!IsLegal && OpToFold.isImm()) {
851 if (std::optional<int64_t> ImmVal = OpToFold.getEffectiveImmVal())
852 IsLegal = canUseImmWithOpSel(
MI, OpNo, *ImmVal);
858 if (NewOpc != AMDGPU::INSTRUCTION_LIST_END) {
861 MI->setDesc(
TII->get(NewOpc));
866 bool FoldAsMAD = tryAddToFoldList(FoldList,
MI, OpNo, OpToFold);
868 MI->untieRegOperand(OpNo);
872 MI->removeOperand(
MI->getNumExplicitOperands() - 1);
878 if (
Opc == AMDGPU::S_FMAC_F32 && OpNo == 3) {
879 if (tryToFoldAsFMAAKorMK())
884 if (OpToFold.isImm()) {
886 if (
Opc == AMDGPU::S_SETREG_B32)
887 ImmOpc = AMDGPU::S_SETREG_IMM32_B32;
888 else if (
Opc == AMDGPU::S_SETREG_B32_mode)
889 ImmOpc = AMDGPU::S_SETREG_IMM32_B32_mode;
891 MI->setDesc(
TII->get(ImmOpc));
900 bool CanCommute =
TII->findCommutedOpIndices(*
MI, OpNo, CommuteOpNo);
904 MachineOperand &
Op =
MI->getOperand(OpNo);
905 MachineOperand &CommutedOp =
MI->getOperand(CommuteOpNo);
911 if (!
Op.isReg() || !CommutedOp.
isReg())
916 if (
Op.isReg() && CommutedOp.
isReg() &&
917 (
Op.getReg() == CommutedOp.
getReg() &&
921 if (!
TII->commuteInstruction(*
MI,
false, OpNo, CommuteOpNo))
925 if (!OpToFold.isOperandLegal(*
TII, *
MI, CommuteOpNo)) {
926 if ((
Opc != AMDGPU::V_ADD_CO_U32_e64 &&
Opc != AMDGPU::V_SUB_CO_U32_e64 &&
927 Opc != AMDGPU::V_SUBREV_CO_U32_e64) ||
928 (!OpToFold.isImm() && !OpToFold.isFI() && !OpToFold.isGlobal())) {
929 TII->commuteInstruction(*
MI,
false, OpNo, CommuteOpNo);
935 MachineOperand &OtherOp =
MI->getOperand(OpNo);
936 if (!OtherOp.
isReg() ||
943 unsigned MaybeCommutedOpc =
MI->getOpcode();
957 if (
Opc == AMDGPU::S_FMAC_F32 &&
958 (OpNo != 1 || !
MI->getOperand(1).isIdenticalTo(
MI->getOperand(2)))) {
959 if (tryToFoldAsFMAAKorMK())
965 if (OpToFold.isImm() &&
974bool SIFoldOperandsImpl::isUseSafeToFold(
const MachineInstr &
MI,
975 const MachineOperand &UseMO)
const {
977 return !
TII->isSDWA(
MI);
985 SubDef &&
TII.isFoldableCopy(*SubDef);
987 unsigned SrcIdx =
TII.getFoldableCopySrcIdx(*SubDef);
996 if (
SrcOp.getSubReg())
1004 MachineInstr &RegSeq,
1005 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs)
const {
1021 else if (!
TRI->getCommonSubClass(RC, OpRC))
1026 Defs.emplace_back(&SrcOp, SubRegIdx);
1031 if (DefSrc && (DefSrc->
isReg() || DefSrc->
isImm())) {
1032 Defs.emplace_back(DefSrc, SubRegIdx);
1036 Defs.emplace_back(&SrcOp, SubRegIdx);
1046 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs,
1049 if (!Def || !
Def->isRegSequence())
1052 return getRegSeqInit(*Def, Defs);
1055std::pair<int64_t, const TargetRegisterClass *>
1056SIFoldOperandsImpl::isRegSeqSplat(MachineInstr &RegSeq)
const {
1062 bool TryToMatchSplat64 =
false;
1064 std::optional<int64_t>
Imm;
1065 for (
unsigned I = 0,
E = Defs.
size();
I !=
E; ++
I) {
1066 const MachineOperand *
Op = Defs[
I].first;
1070 if (!Def ||
Def->isImplicitDef())
1076 int64_t SubImm =
Op->getImm();
1082 if (Imm != SubImm) {
1083 if (
I == 1 && (
E & 1) == 0) {
1086 TryToMatchSplat64 =
true;
1094 if (!TryToMatchSplat64) {
1096 return {*
Imm, SrcRC};
1103 for (
unsigned I = 0,
E = Defs.
size();
I !=
E;
I += 2) {
1104 const MachineOperand *Op0 = Defs[
I].first;
1105 const MachineOperand *Op1 = Defs[
I + 1].first;
1110 unsigned SubReg0 = Defs[
I].second;
1111 unsigned SubReg1 = Defs[
I + 1].second;
1115 if (
TRI->getChannelFromSubReg(SubReg0) + 1 !=
1116 TRI->getChannelFromSubReg(SubReg1))
1119 if (
TRI->getSubRegIdxSize(SubReg0) != 32)
1124 SplatVal64 = MergedVal;
1125 else if (SplatVal64 != MergedVal)
1132 return {SplatVal64, RC64};
1135bool SIFoldOperandsImpl::tryFoldRegSeqSplat(
1136 MachineInstr *
UseMI,
unsigned UseOpIdx, int64_t SplatVal,
1139 if (UseOpIdx >=
Desc.getNumOperands())
1146 int16_t RCID =
TII->getOpRegClassID(
Desc.operands()[UseOpIdx]);
1155 if (SplatVal != 0 && SplatVal != -1) {
1159 uint8_t OpTy =
Desc.operands()[UseOpIdx].OperandType;
1165 OpRC =
TRI->getSubRegisterClass(OpRC, AMDGPU::sub0);
1172 OpRC =
TRI->getSubRegisterClass(OpRC, AMDGPU::sub0_sub1);
1178 if (!
TRI->getCommonSubClass(OpRC, SplatRC))
1183 if (!
TII->isOperandLegal(*
UseMI, UseOpIdx, &TmpOp))
1189bool SIFoldOperandsImpl::tryToFoldACImm(
1190 const FoldableDef &OpToFold, MachineInstr *
UseMI,
unsigned UseOpIdx,
1191 SmallVectorImpl<FoldCandidate> &FoldList)
const {
1193 if (UseOpIdx >=
Desc.getNumOperands())
1200 if (OpToFold.isImm() && OpToFold.isOperandLegal(*
TII, *
UseMI, UseOpIdx)) {
1211bool SIFoldOperandsImpl::foldOperand(
1212 FoldableDef OpToFold, MachineInstr *
UseMI,
int UseOpIdx,
1213 SmallVectorImpl<FoldCandidate> &FoldList,
1214 SmallVectorImpl<MachineInstr *> &CopiesToReplace)
const {
1218 if (!isUseSafeToFold(*
UseMI, *UseOp))
1222 if (UseOp->
isReg() && OpToFold.isReg()) {
1226 if (UseOp->
getSubReg() != AMDGPU::NoSubRegister &&
1228 !
TRI->isSGPRReg(*MRI, OpToFold.getReg())))
1241 std::tie(SplatVal, SplatRC) = isRegSeqSplat(*
UseMI);
1246 for (
unsigned I = 0;
I != UsesToProcess.size(); ++
I) {
1247 MachineOperand *RSUse = UsesToProcess[
I];
1248 MachineInstr *RSUseMI = RSUse->
getParent();
1258 if (tryFoldRegSeqSplat(RSUseMI, OpNo, SplatVal, SplatRC)) {
1259 FoldableDef SplatDef(SplatVal, SplatRC);
1267 if (RSUse->
getSubReg() != RegSeqDstSubReg)
1273 FoldList, CopiesToReplace);
1279 if (tryToFoldACImm(OpToFold,
UseMI, UseOpIdx, FoldList))
1282 if (frameIndexMayFold(*
UseMI, UseOpIdx, OpToFold)) {
1287 if (
TII->getNamedOperand(*
UseMI, AMDGPU::OpName::srsrc)->getReg() !=
1293 MachineOperand &SOff =
1294 *
TII->getNamedOperand(*
UseMI, AMDGPU::OpName::soffset);
1305 TII->getNamedOperand(*
UseMI, AMDGPU::OpName::cpol)->getImm();
1320 bool FoldingImmLike =
1321 OpToFold.isImm() || OpToFold.isFI() || OpToFold.isGlobal();
1340 for (
unsigned MovOp :
1341 {AMDGPU::S_MOV_B32, AMDGPU::V_MOV_B32_e32, AMDGPU::S_MOV_B64,
1342 AMDGPU::V_MOV_B64_PSEUDO, AMDGPU::V_MOV_B16_t16_e64,
1343 AMDGPU::V_ACCVGPR_WRITE_B32_e64, AMDGPU::AV_MOV_B32_IMM_PSEUDO,
1344 AMDGPU::AV_MOV_B64_IMM_PSEUDO}) {
1345 const MCInstrDesc &MovDesc =
TII->get(MovOp);
1355 const int SrcIdx = MovOp == AMDGPU::V_MOV_B16_t16_e64 ? 2 : 1;
1357 int16_t RegClassID =
TII->getOpRegClassID(MovDesc.
operands()[SrcIdx]);
1358 if (RegClassID != -1) {
1362 MovSrcRC =
TRI->getMatchingSuperRegClass(SrcRC, MovSrcRC, UseSubReg);
1366 if (MovOp == AMDGPU::AV_MOV_B32_IMM_PSEUDO &&
1367 (!OpToFold.isImm() ||
1368 !
TII->isImmOperandLegal(MovDesc, SrcIdx,
1369 *OpToFold.getEffectiveImmVal())))
1382 if (!OpToFold.isImm() ||
1383 !
TII->isImmOperandLegal(MovDesc, 1, *OpToFold.getEffectiveImmVal()))
1389 while (ImpOpI != ImpOpE) {
1396 if (MovOp == AMDGPU::V_MOV_B16_t16_e64) {
1398 MachineOperand NewSrcOp(SrcOp);
1420 LLVM_DEBUG(
dbgs() <<
"Folding " << *OpToFold.OpToFold <<
"\n into "
1425 unsigned SubRegIdx = OpToFold.getSubReg();
1439 static_assert(AMDGPU::sub1_hi16 == 12,
"Subregister layout has changed");
1444 if (SubRegIdx > AMDGPU::sub1) {
1445 LaneBitmask
M =
TRI->getSubRegIndexLaneMask(SubRegIdx);
1446 M |=
M.getLane(
M.getHighestLane() - 1);
1447 SmallVector<unsigned, 4> Indexes;
1448 TRI->getCoveringSubRegIndexes(
TRI->getRegClassForReg(*MRI,
UseReg), M,
1450 assert(Indexes.
size() == 1 &&
"Expected one 32-bit subreg to cover");
1451 SubRegIdx = Indexes[0];
1453 }
else if (
TII->getOpSize(*
UseMI, 1) == 4)
1456 SubRegIdx = AMDGPU::sub0;
1461 OpToFold.OpToFold->setIsKill(
false);
1466 if (foldCopyToAGPRRegSequence(
UseMI))
1471 if (UseOpc == AMDGPU::V_READFIRSTLANE_B32 ||
1472 (UseOpc == AMDGPU::V_READLANE_B32 &&
1474 AMDGPU::getNamedOperandIdx(UseOpc, AMDGPU::OpName::src0))) {
1479 if (FoldingImmLike) {
1482 *OpToFold.DefMI, *
UseMI))
1488 if (OpToFold.isImm()) {
1490 *OpToFold.getEffectiveImmVal());
1491 }
else if (OpToFold.isFI())
1494 assert(OpToFold.isGlobal());
1496 OpToFold.OpToFold->getOffset(),
1497 OpToFold.OpToFold->getTargetFlags());
1503 if (OpToFold.isReg() &&
TRI->isSGPRReg(*MRI, OpToFold.getReg())) {
1506 *OpToFold.DefMI, *
UseMI))
1528 UseDesc.
operands()[UseOpIdx].RegClass == -1)
1536 Changed |= tryAddToFoldList(FoldList,
UseMI, UseOpIdx, OpToFold);
1543 case AMDGPU::S_ADD_I32:
1544 case AMDGPU::S_ADD_U32:
1547 case AMDGPU::S_SUB_I32:
1548 case AMDGPU::S_SUB_U32:
1551 case AMDGPU::V_AND_B32_e64:
1552 case AMDGPU::V_AND_B32_e32:
1553 case AMDGPU::S_AND_B32:
1556 case AMDGPU::V_OR_B32_e64:
1557 case AMDGPU::V_OR_B32_e32:
1558 case AMDGPU::S_OR_B32:
1561 case AMDGPU::V_XOR_B32_e64:
1562 case AMDGPU::V_XOR_B32_e32:
1563 case AMDGPU::S_XOR_B32:
1566 case AMDGPU::S_XNOR_B32:
1569 case AMDGPU::S_NAND_B32:
1572 case AMDGPU::S_NOR_B32:
1575 case AMDGPU::S_ANDN2_B32:
1578 case AMDGPU::S_ORN2_B32:
1581 case AMDGPU::V_LSHL_B32_e64:
1582 case AMDGPU::V_LSHL_B32_e32:
1583 case AMDGPU::S_LSHL_B32:
1585 Result =
LHS << (
RHS & 31);
1587 case AMDGPU::V_LSHLREV_B32_e64:
1588 case AMDGPU::V_LSHLREV_B32_e32:
1589 Result =
RHS << (
LHS & 31);
1591 case AMDGPU::V_LSHR_B32_e64:
1592 case AMDGPU::V_LSHR_B32_e32:
1593 case AMDGPU::S_LSHR_B32:
1594 Result =
LHS >> (
RHS & 31);
1596 case AMDGPU::V_LSHRREV_B32_e64:
1597 case AMDGPU::V_LSHRREV_B32_e32:
1598 Result =
RHS >> (
LHS & 31);
1600 case AMDGPU::V_ASHR_I32_e64:
1601 case AMDGPU::V_ASHR_I32_e32:
1602 case AMDGPU::S_ASHR_I32:
1603 Result =
static_cast<int32_t
>(
LHS) >> (
RHS & 31);
1605 case AMDGPU::V_ASHRREV_I32_e64:
1606 case AMDGPU::V_ASHRREV_I32_e32:
1607 Result =
static_cast<int32_t
>(
RHS) >> (
LHS & 31);
1615 return IsScalar ? AMDGPU::S_MOV_B32 : AMDGPU::V_MOV_B32_e32;
1621bool SIFoldOperandsImpl::tryConstantFoldOp(MachineInstr *
MI)
const {
1622 if (!
MI->allImplicitDefsAreDead())
1625 unsigned Opc =
MI->getOpcode();
1627 int Src0Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src0);
1631 MachineOperand *Src0 = &
MI->getOperand(Src0Idx);
1632 std::optional<int64_t> Src0Imm =
TII->getImmOrMaterializedImm(*Src0);
1634 if ((
Opc == AMDGPU::V_NOT_B32_e64 ||
Opc == AMDGPU::V_NOT_B32_e32 ||
1635 Opc == AMDGPU::S_NOT_B32) &&
1637 MI->getOperand(1).ChangeToImmediate(~*Src0Imm);
1638 TII->mutateAndCleanupImplicit(
1643 int Src1Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src1);
1647 MachineOperand *Src1 = &
MI->getOperand(Src1Idx);
1648 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*Src1);
1650 if (!Src0Imm && !Src1Imm)
1656 if (Src0Imm && Src1Imm) {
1661 bool IsSGPR =
TRI->isSGPRReg(*MRI,
MI->getOperand(0).getReg());
1665 MI->getOperand(Src0Idx).ChangeToImmediate(NewImm);
1666 MI->removeOperand(Src1Idx);
1673 if (
Opc == AMDGPU::S_SUB_I32 ||
Opc == AMDGPU::S_SUB_U32) {
1674 if (Src1Imm &&
static_cast<int32_t
>(*Src1Imm) == 0) {
1676 MI->removeOperand(Src1Idx);
1677 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1683 if (!
MI->isCommutable())
1686 if (Src0Imm && !Src1Imm) {
1692 int32_t Src1Val =
static_cast<int32_t
>(*Src1Imm);
1693 if (
Opc == AMDGPU::S_ADD_I32 ||
Opc == AMDGPU::S_ADD_U32) {
1696 MI->removeOperand(Src1Idx);
1697 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1703 if (
Opc == AMDGPU::V_OR_B32_e64 ||
1704 Opc == AMDGPU::V_OR_B32_e32 ||
1705 Opc == AMDGPU::S_OR_B32) {
1708 MI->removeOperand(Src1Idx);
1709 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1710 }
else if (Src1Val == -1) {
1712 MI->removeOperand(Src0Idx);
1713 TII->mutateAndCleanupImplicit(
1721 if (
Opc == AMDGPU::V_AND_B32_e64 ||
Opc == AMDGPU::V_AND_B32_e32 ||
1722 Opc == AMDGPU::S_AND_B32) {
1725 MI->removeOperand(Src0Idx);
1726 TII->mutateAndCleanupImplicit(
1728 }
else if (Src1Val == -1) {
1730 MI->removeOperand(Src1Idx);
1731 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1738 if (
Opc == AMDGPU::V_XOR_B32_e64 ||
Opc == AMDGPU::V_XOR_B32_e32 ||
1739 Opc == AMDGPU::S_XOR_B32) {
1742 MI->removeOperand(Src1Idx);
1743 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1752bool SIFoldOperandsImpl::tryFoldCndMask(MachineInstr &
MI)
const {
1753 unsigned Opc =
MI.getOpcode();
1754 if (
Opc != AMDGPU::V_CNDMASK_B32_e32 &&
Opc != AMDGPU::V_CNDMASK_B32_e64 &&
1755 Opc != AMDGPU::V_CNDMASK_B64_PSEUDO)
1758 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
1759 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
1761 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*Src1);
1765 std::optional<int64_t> Src0Imm =
TII->getImmOrMaterializedImm(*Src0);
1766 if (!Src0Imm || *Src0Imm != *Src1Imm)
1771 AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src1_modifiers);
1773 AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src0_modifiers);
1774 if ((Src1ModIdx != -1 &&
MI.getOperand(Src1ModIdx).getImm() != 0) ||
1775 (Src0ModIdx != -1 &&
MI.getOperand(Src0ModIdx).getImm() != 0))
1781 int Src2Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
1783 MI.removeOperand(Src2Idx);
1784 MI.removeOperand(AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src1));
1785 if (Src1ModIdx != -1)
1786 MI.removeOperand(Src1ModIdx);
1787 if (Src0ModIdx != -1)
1788 MI.removeOperand(Src0ModIdx);
1789 TII->mutateAndCleanupImplicit(
MI, NewDesc);
1794bool SIFoldOperandsImpl::tryFoldZeroHighBits(MachineInstr &
MI)
const {
1795 if (
MI.getOpcode() != AMDGPU::V_AND_B32_e64 &&
1796 MI.getOpcode() != AMDGPU::V_AND_B32_e32)
1799 std::optional<int64_t> Src0Imm =
1800 TII->getImmOrMaterializedImm(
MI.getOperand(1));
1801 if (!Src0Imm || *Src0Imm != 0xffff || !
MI.getOperand(2).isReg())
1805 MachineInstr *SrcDef = MRI->
getVRegDef(Src1);
1811 if (!
MI.getOperand(2).isKill())
1813 MI.eraseFromParent();
1817bool SIFoldOperandsImpl::foldInstOperand(MachineInstr &
MI,
1818 const FoldableDef &OpToFold)
const {
1822 SmallVector<MachineInstr *, 4> CopiesToReplace;
1824 MachineOperand &Dst =
MI.getOperand(0);
1829 for (
auto *U : UsesToProcess) {
1830 MachineInstr *
UseMI =
U->getParent();
1832 FoldableDef SubOpToFold = OpToFold.getWithSubReg(*
TRI,
U->getSubReg());
1837 if (CopiesToReplace.
empty() && FoldList.
empty())
1841 for (MachineInstr *Copy : CopiesToReplace)
1842 Copy->addImplicitDefUseOperands(*MF);
1844 SetVector<MachineInstr *> ConstantFoldCandidates;
1845 for (FoldCandidate &Fold : FoldList) {
1846 assert(!Fold.isReg() || Fold.Def.OpToFold);
1847 if (Fold.isReg() && Fold.getReg().isVirtual()) {
1849 const MachineInstr *
DefMI = Fold.Def.DefMI;
1857 assert(Fold.Def.OpToFold && Fold.isReg());
1864 <<
static_cast<int>(Fold.UseOpNo) <<
" of "
1868 ConstantFoldCandidates.
insert(Fold.UseMI);
1870 }
else if (Fold.Commuted) {
1872 TII->commuteInstruction(*Fold.UseMI,
false);
1876 for (MachineInstr *
MI : ConstantFoldCandidates) {
1877 if (tryConstantFoldOp(
MI)) {
1887bool SIFoldOperandsImpl::foldCopyToAGPRRegSequence(MachineInstr *CopyMI)
const {
1894 if (!
TRI->isAGPRClass(DefRC))
1906 DenseMap<TargetInstrInfo::RegSubRegPair, Register> VGPRCopies;
1915 unsigned NumFoldable = 0;
1917 for (
unsigned I = 1;
I != NumRegSeqOperands;
I += 2) {
1934 DefRC, &AMDGPU::AGPR_32RegClass, SubRegIdx);
1954 TRI->getMatchingSuperRegClass(DefRC, InputRC, SubRegIdx);
1965 if (NumFoldable == 0)
1968 CopyMI->
setDesc(
TII->get(AMDGPU::REG_SEQUENCE));
1972 for (
auto [Def, DestSubIdx] : NewDefs) {
1973 if (!
Def->isReg()) {
1977 BuildMI(
MBB, CopyMI,
DL,
TII->get(AMDGPU::V_ACCVGPR_WRITE_B32_e64), Tmp)
1982 Def->setIsKill(
false);
1984 Register &VGPRCopy = VGPRCopies[Src];
1987 TRI->getSubRegisterClass(UseRC, DestSubIdx);
2012 B.addImm(DestSubIdx);
2019bool SIFoldOperandsImpl::tryFoldFoldableCopy(
2020 MachineInstr &
MI, MachineOperand *&CurrentKnownM0Val)
const {
2024 if (DstReg == AMDGPU::M0) {
2025 MachineOperand &NewM0Val =
MI.getOperand(1);
2026 if (CurrentKnownM0Val && CurrentKnownM0Val->
isIdenticalTo(NewM0Val)) {
2027 MI.eraseFromParent();
2038 MachineOperand *OpToFoldPtr;
2039 if (
MI.getOpcode() == AMDGPU::V_MOV_B16_t16_e64) {
2041 if (
TII->hasAnyModifiersSet(
MI))
2043 OpToFoldPtr = &
MI.getOperand(2);
2045 OpToFoldPtr = &
MI.getOperand(1);
2046 MachineOperand &OpToFold = *OpToFoldPtr;
2050 if (!FoldingImm && !OpToFold.
isReg())
2055 !
TRI->isConstantPhysReg(OpToFold.
getReg()))
2084 if (
MI.getOpcode() == AMDGPU::COPY && OpToFold.
isReg() &&
2086 if (DstRC == &AMDGPU::SReg_32RegClass &&
2095 if (OpToFold.
isReg() &&
MI.isCopy() && !
MI.getOperand(1).getSubReg()) {
2096 if (foldCopyToAGPRRegSequence(&
MI))
2100 FoldableDef
Def(OpToFold, DstRC);
2101 bool Changed = foldInstOperand(
MI, Def);
2108 auto *InstToErase = &
MI;
2110 auto &SrcOp = InstToErase->getOperand(1);
2112 InstToErase->eraseFromParent();
2114 InstToErase =
nullptr;
2118 if (!InstToErase || !
TII->isFoldableCopy(*InstToErase))
2122 if (InstToErase && InstToErase->isRegSequence() &&
2124 InstToErase->eraseFromParent();
2134 return OpToFold.
isReg() &&
2135 foldCopyToVGPROfScalarAddOfFrameIndex(DstReg, OpToFold.
getReg(),
MI);
2140const MachineOperand *
2141SIFoldOperandsImpl::isClamp(
const MachineInstr &
MI)
const {
2142 unsigned Op =
MI.getOpcode();
2144 case AMDGPU::V_MAX_F32_e64:
2145 case AMDGPU::V_MAX_F16_e64:
2146 case AMDGPU::V_MAX_F16_t16_e64:
2147 case AMDGPU::V_MAX_F16_fake16_e64:
2148 case AMDGPU::V_MAX_F64_e64:
2149 case AMDGPU::V_MAX_NUM_F64_e64:
2150 case AMDGPU::V_PK_MAX_F16:
2151 case AMDGPU::V_MAX_BF16_PSEUDO_e64:
2152 case AMDGPU::V_PK_MAX_NUM_BF16: {
2153 if (
MI.mayRaiseFPException())
2156 if (!
TII->getNamedOperand(
MI, AMDGPU::OpName::clamp)->getImm())
2160 const MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2161 const MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2165 Src0->
getSubReg() != AMDGPU::NoSubRegister)
2169 if (
TII->hasModifiersSet(
MI, AMDGPU::OpName::omod))
2173 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers)->getImm();
2175 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers)->getImm();
2179 unsigned UnsetMods =
2180 (
Op == AMDGPU::V_PK_MAX_F16 ||
Op == AMDGPU::V_PK_MAX_NUM_BF16)
2183 if (Src0Mods != UnsetMods && Src1Mods != UnsetMods)
2193bool SIFoldOperandsImpl::tryFoldClamp(MachineInstr &
MI) {
2194 const MachineOperand *ClampSrc = isClamp(
MI);
2210 if (
Def->mayRaiseFPException())
2213 MachineOperand *DefClamp =
TII->getNamedOperand(*Def, AMDGPU::OpName::clamp);
2217 LLVM_DEBUG(
dbgs() <<
"Folding clamp " << *DefClamp <<
" into " << *Def);
2223 Register MIDstReg =
MI.getOperand(0).getReg();
2224 if (
TRI->isSGPRReg(*MRI, DefReg)) {
2233 MI.eraseFromParent();
2238 if (
TII->convertToThreeAddress(*Def,
nullptr,
nullptr))
2239 Def->eraseFromParent();
2246 case AMDGPU::V_MUL_F64_e64:
2247 case AMDGPU::V_MUL_F64_pseudo_e64: {
2249 case 0x3fe0000000000000:
2251 case 0x4000000000000000:
2253 case 0x4010000000000000:
2259 case AMDGPU::V_MUL_F32_e64: {
2260 switch (
static_cast<uint32_t>(Val)) {
2271 case AMDGPU::V_MUL_F16_e64:
2272 case AMDGPU::V_MUL_F16_t16_e64:
2273 case AMDGPU::V_MUL_F16_fake16_e64: {
2274 switch (
static_cast<uint16_t>(Val)) {
2293std::pair<const MachineOperand *, int>
2294SIFoldOperandsImpl::isOMod(
const MachineInstr &
MI)
const {
2295 unsigned Op =
MI.getOpcode();
2297 case AMDGPU::V_MUL_F64_e64:
2298 case AMDGPU::V_MUL_F64_pseudo_e64:
2299 case AMDGPU::V_MUL_F32_e64:
2300 case AMDGPU::V_MUL_F16_t16_e64:
2301 case AMDGPU::V_MUL_F16_fake16_e64:
2302 case AMDGPU::V_MUL_F16_e64: {
2304 if ((
Op == AMDGPU::V_MUL_F32_e64 &&
2306 ((
Op == AMDGPU::V_MUL_F64_e64 ||
Op == AMDGPU::V_MUL_F64_pseudo_e64 ||
2307 Op == AMDGPU::V_MUL_F16_e64 ||
Op == AMDGPU::V_MUL_F16_t16_e64 ||
2308 Op == AMDGPU::V_MUL_F16_fake16_e64) &&
2311 MI.mayRaiseFPException())
2314 const MachineOperand *RegOp =
nullptr;
2315 const MachineOperand *ImmOp =
nullptr;
2316 const MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2317 const MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2318 if (Src0->
isImm()) {
2321 }
else if (Src1->
isImm()) {
2329 TII->hasModifiersSet(
MI, AMDGPU::OpName::src0_modifiers) ||
2330 TII->hasModifiersSet(
MI, AMDGPU::OpName::src1_modifiers) ||
2331 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod) ||
2332 TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp))
2335 return std::pair(RegOp, OMod);
2337 case AMDGPU::V_ADD_F64_e64:
2338 case AMDGPU::V_ADD_F64_pseudo_e64:
2339 case AMDGPU::V_ADD_F32_e64:
2340 case AMDGPU::V_ADD_F16_e64:
2341 case AMDGPU::V_ADD_F16_t16_e64:
2342 case AMDGPU::V_ADD_F16_fake16_e64: {
2344 if ((
Op == AMDGPU::V_ADD_F32_e64 &&
2346 ((
Op == AMDGPU::V_ADD_F64_e64 ||
Op == AMDGPU::V_ADD_F64_pseudo_e64 ||
2347 Op == AMDGPU::V_ADD_F16_e64 ||
Op == AMDGPU::V_ADD_F16_t16_e64 ||
2348 Op == AMDGPU::V_ADD_F16_fake16_e64) &&
2353 const MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2354 const MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2358 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::src0_modifiers) &&
2359 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::src1_modifiers) &&
2360 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp) &&
2361 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::omod))
2372bool SIFoldOperandsImpl::tryFoldOMod(MachineInstr &
MI) {
2373 const MachineOperand *RegOp;
2375 std::tie(RegOp, OMod) = isOMod(
MI);
2377 RegOp->
getSubReg() != AMDGPU::NoSubRegister ||
2382 MachineOperand *DefOMod =
TII->getNamedOperand(*Def, AMDGPU::OpName::omod);
2386 if (
Def->mayRaiseFPException())
2391 if (
TII->hasModifiersSet(*Def, AMDGPU::OpName::clamp))
2401 MI.eraseFromParent();
2406 if (
TII->convertToThreeAddress(*Def,
nullptr,
nullptr))
2407 Def->eraseFromParent();
2414bool SIFoldOperandsImpl::tryFoldRegSequence(MachineInstr &
MI) {
2416 auto Reg =
MI.getOperand(0).getReg();
2418 if (!ST->hasGFX90AInsts() || !
TRI->isVGPR(*MRI,
Reg) ||
2423 if (!getRegSeqInit(Defs,
Reg))
2426 for (
auto &[
Op, SubIdx] : Defs) {
2429 if (
TRI->isAGPR(*MRI,
Op->getReg()))
2432 const MachineInstr *SubDef = MRI->
getVRegDef(
Op->getReg());
2440 MachineInstr *
UseMI =
Op->getParent();
2449 if (
Op->getSubReg())
2455 if (!OpRC || !
TRI->isVectorSuperClass(OpRC))
2461 TII->get(AMDGPU::REG_SEQUENCE), Dst);
2463 for (
auto &[Def, SubIdx] : Defs) {
2464 Def->setIsKill(
false);
2465 if (
TRI->isAGPR(*MRI,
Def->getReg())) {
2478 RS->eraseFromParent();
2487 MI.eraseFromParent();
2495 Register &OutReg,
unsigned &OutSubReg) {
2505 if (
TRI.isAGPR(MRI, CopySrcReg)) {
2506 OutReg = CopySrcReg;
2515 if (!CopySrcDef || !CopySrcDef->
isCopy())
2522 OtherCopySrc.
getSubReg() != AMDGPU::NoSubRegister ||
2523 !
TRI.isAGPR(MRI, OtherCopySrcReg))
2526 OutReg = OtherCopySrcReg;
2560bool SIFoldOperandsImpl::tryFoldPhiAGPR(MachineInstr &
PHI) {
2564 if (!
TRI->isVGPR(*MRI, PhiOut))
2570 for (
unsigned K = 1;
K <
PHI.getNumExplicitOperands();
K += 2) {
2571 MachineOperand &MO =
PHI.getOperand(K);
2573 if (!Copy || !
Copy->isCopy())
2577 unsigned AGPRRegMask = AMDGPU::NoSubRegister;
2582 if (
const auto *SubRC =
TRI->getSubRegisterClass(CopyInRC, AGPRRegMask))
2593 bool IsAGPR32 = (ARC == &AMDGPU::AGPR_32RegClass);
2597 for (
unsigned K = 1;
K <
PHI.getNumExplicitOperands();
K += 2) {
2598 MachineOperand &MO =
PHI.getOperand(K);
2602 MachineBasicBlock *InsertMBB =
nullptr;
2605 unsigned CopyOpc = AMDGPU::COPY;
2610 if (
Def->isCopy()) {
2612 unsigned AGPRSubReg = AMDGPU::NoSubRegister;
2625 MachineOperand &CopyIn =
Def->getOperand(1);
2628 CopyOpc = AMDGPU::V_ACCVGPR_WRITE_B32_e64;
2631 InsertMBB =
Def->getParent();
2639 MachineInstr *
MI =
BuildMI(*InsertMBB, InsertPt,
PHI.getDebugLoc(),
2640 TII->get(CopyOpc), NewReg)
2650 PHI.getOperand(0).setReg(NewReg);
2656 TII->get(AMDGPU::COPY), PhiOut)
2664bool SIFoldOperandsImpl::tryFoldLoad(MachineInstr &
MI) {
2666 if (!ST->hasGFX90AInsts() ||
MI.getNumExplicitDefs() != 1)
2669 MachineOperand &
Def =
MI.getOperand(0);
2686 while (!
Users.empty()) {
2687 const MachineInstr *
I =
Users.pop_back_val();
2688 if (!
I->isCopy() && !
I->isRegSequence())
2690 Register DstReg =
I->getOperand(0).getReg();
2694 if (
TRI->isAGPR(*MRI, DstReg))
2698 Users.push_back(&U);
2703 if (!
TII->isOperandLegal(
MI, 0, &Def)) {
2708 while (!MoveRegs.
empty()) {
2750bool SIFoldOperandsImpl::tryOptimizeAGPRPhis(MachineBasicBlock &
MBB) {
2753 if (ST->hasGFX90AInsts())
2757 DenseMap<std::pair<Register, unsigned>, std::vector<MachineOperand *>>
2760 for (
auto &
MI :
MBB) {
2764 if (!
TRI->isAGPR(*MRI,
MI.getOperand(0).getReg()))
2767 for (
unsigned K = 1;
K <
MI.getNumOperands();
K += 2) {
2768 MachineOperand &PhiMO =
MI.getOperand(K);
2778 for (
const auto &[Entry, MOs] : RegToMO) {
2779 if (MOs.size() == 1)
2784 MachineBasicBlock *DefMBB =
Def->getParent();
2791 MachineInstr *VGPRCopy =
2793 TII->get(AMDGPU::V_ACCVGPR_READ_B32_e64), TempVGPR)
2799 TII->get(AMDGPU::COPY), TempAGPR)
2803 for (MachineOperand *MO : MOs) {
2815bool SIFoldOperandsImpl::run(MachineFunction &MF) {
2821 MFI = MF.
getInfo<SIMachineFunctionInfo>();
2831 MachineOperand *CurrentKnownM0Val =
nullptr;
2839 if (tryConstantFoldOp(&
MI)) {
2844 if (tryFoldZeroHighBits(
MI)) {
2849 if (
MI.isRegSequence() && tryFoldRegSequence(
MI)) {
2854 if (
MI.isPHI() && tryFoldPhiAGPR(
MI)) {
2859 if (
MI.mayLoad() && tryFoldLoad(
MI)) {
2864 if (
TII->isFoldableCopy(
MI)) {
2865 Changed |= tryFoldFoldableCopy(
MI, CurrentKnownM0Val);
2870 if (CurrentKnownM0Val &&
MI.modifiesRegister(AMDGPU::M0,
TRI))
2871 CurrentKnownM0Val =
nullptr;
2889 bool Changed = SIFoldOperandsImpl().run(MF);
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Provides AMDGPU specific target descriptions.
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)
MachineInstr unsigned OpIdx
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
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)
Represent the analysis usage information of a pass.
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
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.
const MachineBasicBlock * getParent() const
bool readsRegister(Register Reg, const TargetRegisterInfo *TRI) const
Return true if the MachineInstr reads the specified register.
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
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.
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 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.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
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
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)
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_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)
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
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.
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.
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()
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
char & SIFoldOperandsLegacyID
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.