26#define DEBUG_TYPE "si-fold-operands"
47 unsigned DefSubReg = AMDGPU::NoSubRegister;
52 FoldableDef() =
delete;
54 unsigned DefSubReg = AMDGPU::NoSubRegister)
55 : DefRC(DefRC), DefSubReg(DefSubReg), Kind(FoldOp.
getType()) {
58 ImmToFold = FoldOp.
getImm();
59 }
else if (FoldOp.
isFI()) {
60 FrameIndexToFold = FoldOp.
getIndex();
70 unsigned DefSubReg = AMDGPU::NoSubRegister)
71 : ImmToFold(FoldImm), DefRC(DefRC), DefSubReg(DefSubReg),
76 FoldableDef Copy(*
this);
77 Copy.DefSubReg =
TRI.composeSubRegIndices(DefSubReg, SubReg);
85 return OpToFold->getReg();
88 unsigned getSubReg()
const {
90 return OpToFold->getSubReg();
101 return FrameIndexToFold;
109 std::optional<int64_t> getEffectiveImmVal()
const {
117 unsigned OpIdx)
const {
120 std::optional<int64_t> ImmToFold = getEffectiveImmVal();
130 if (DefSubReg != AMDGPU::NoSubRegister)
138 if (DefSubReg != AMDGPU::NoSubRegister)
140 return TII.isOperandLegal(
MI,
OpIdx, OpToFold);
147struct FoldCandidate {
155 bool Commuted =
false,
int ShrinkOp = -1)
156 :
UseMI(
MI), Def(Def), ShrinkOpcode(ShrinkOp), UseOpNo(OpNo),
157 Commuted(Commuted) {}
159 bool isFI()
const {
return Def.isFI(); }
163 return Def.FrameIndexToFold;
166 bool isImm()
const {
return Def.isImm(); }
168 bool isReg()
const {
return Def.isReg(); }
172 bool isGlobal()
const {
return Def.isGlobal(); }
174 bool needsShrink()
const {
return ShrinkOpcode != -1; }
177class SIFoldOperandsImpl {
188 const FoldableDef &OpToFold)
const;
191 unsigned convertToVALUOp(
unsigned Opc,
bool UseVOP3 =
false)
const {
193 case AMDGPU::S_ADD_I32: {
194 if (ST->hasAddNoCarryInsts())
195 return UseVOP3 ? AMDGPU::V_ADD_U32_e64 : AMDGPU::V_ADD_U32_e32;
196 return UseVOP3 ? AMDGPU::V_ADD_CO_U32_e64 : AMDGPU::V_ADD_CO_U32_e32;
198 case AMDGPU::S_OR_B32:
199 return UseVOP3 ? AMDGPU::V_OR_B32_e64 : AMDGPU::V_OR_B32_e32;
200 case AMDGPU::S_AND_B32:
201 return UseVOP3 ? AMDGPU::V_AND_B32_e64 : AMDGPU::V_AND_B32_e32;
202 case AMDGPU::S_MUL_I32:
203 return AMDGPU::V_MUL_LO_U32_e64;
205 return AMDGPU::INSTRUCTION_LIST_END;
209 bool foldCopyToVGPROfScalarAddOfFrameIndex(
Register DstReg,
Register SrcReg,
215 int64_t ImmVal)
const;
219 int64_t ImmVal)
const;
223 const FoldableDef &OpToFold)
const;
226 bool isTemporallyDivergentUse(
const FoldableDef &OpToFold,
234 getRegSeqInit(
SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs,
237 std::pair<int64_t, const TargetRegisterClass *>
254 bool foldInstOperand(
MachineInstr &
MI,
const FoldableDef &OpToFold)
const;
256 bool foldCopyToAGPRRegSequence(
MachineInstr *CopyMI)
const;
263 std::pair<const MachineOperand *, int> isOMod(
const MachineInstr &
MI)
const;
272 SIFoldOperandsImpl() =
default;
287 &getAnalysis<MachineLoopInfoWrapperPass>().getLI();
288 return SIFoldOperandsImpl().run(MF, MLI);
291 StringRef getPassName()
const override {
return "SI Fold Operands"; }
313char SIFoldOperandsLegacy::ID = 0;
322 TRI.getSubRegisterClass(RC, MO.getSubReg()))
330 case AMDGPU::V_MAC_F32_e64:
331 return AMDGPU::V_MAD_F32_e64;
332 case AMDGPU::V_MAC_F16_e64:
333 return AMDGPU::V_MAD_F16_e64;
334 case AMDGPU::V_FMAC_F32_e64:
335 return AMDGPU::V_FMA_F32_e64;
336 case AMDGPU::V_FMAC_F16_e64:
337 return AMDGPU::V_FMA_F16_gfx9_e64;
338 case AMDGPU::V_FMAC_F16_t16_e64:
339 return AMDGPU::V_FMA_F16_gfx9_t16_e64;
340 case AMDGPU::V_FMAC_F16_fake16_e64:
341 return AMDGPU::V_FMA_F16_gfx9_fake16_e64;
342 case AMDGPU::V_FMAC_LEGACY_F32_e64:
343 return AMDGPU::V_FMA_LEGACY_F32_e64;
344 case AMDGPU::V_FMAC_F64_e64:
345 return AMDGPU::V_FMA_F64_e64;
347 return AMDGPU::INSTRUCTION_LIST_END;
353 const FoldableDef &OpToFold)
const {
354 if (!OpToFold.isFI())
357 const unsigned Opc =
UseMI.getOpcode();
359 case AMDGPU::S_ADD_I32:
360 case AMDGPU::S_ADD_U32:
361 case AMDGPU::V_ADD_U32_e32:
362 case AMDGPU::V_ADD_CO_U32_e32:
366 return UseMI.getOperand(OpNo == 1 ? 2 : 1).isImm() &&
368 case AMDGPU::V_ADD_U32_e64:
369 case AMDGPU::V_ADD_CO_U32_e64:
370 return UseMI.getOperand(OpNo == 2 ? 3 : 2).isImm() &&
377 return OpNo == AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::vaddr);
381 int SIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::saddr);
385 int VIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::vaddr);
386 return OpNo == VIdx && SIdx == -1;
392bool SIFoldOperandsImpl::foldCopyToVGPROfScalarAddOfFrameIndex(
394 if (
TRI->isVGPR(*MRI, DstReg) &&
TRI->isSGPRReg(*MRI, SrcReg) &&
397 if (!Def ||
Def->getNumOperands() != 4)
400 MachineOperand *Src0 = &
Def->getOperand(1);
401 MachineOperand *Src1 = &
Def->getOperand(2);
412 const bool UseVOP3 = !Src0->
isImm() ||
TII->isInlineConstant(*Src0);
413 unsigned NewOp = convertToVALUOp(
Def->getOpcode(), UseVOP3);
414 if (NewOp == AMDGPU::INSTRUCTION_LIST_END ||
415 !
Def->getOperand(3).isDead())
418 MachineBasicBlock *
MBB =
Def->getParent();
420 if (NewOp != AMDGPU::V_ADD_CO_U32_e32) {
421 MachineInstrBuilder
Add =
424 if (
Add->getDesc().getNumDefs() == 2) {
426 Add.addDef(CarryOutReg, RegState::Dead);
430 Add.add(*Src0).add(*Src1).setMIFlags(
Def->getFlags());
434 Def->eraseFromParent();
435 MI.eraseFromParent();
439 assert(NewOp == AMDGPU::V_ADD_CO_U32_e32);
450 Def->eraseFromParent();
451 MI.eraseFromParent();
460 return new SIFoldOperandsLegacy();
463bool SIFoldOperandsImpl::canUseImmWithOpSel(
const MachineInstr *
MI,
465 int64_t ImmVal)
const {
472 int OpNo =
MI->getOperandNo(&Old);
474 unsigned Opcode =
MI->getOpcode();
475 uint8_t OpType =
TII->get(Opcode).operands()[OpNo].OperandType;
497bool SIFoldOperandsImpl::tryFoldImmWithOpSel(MachineInstr *
MI,
unsigned UseOpNo,
498 int64_t ImmVal)
const {
499 MachineOperand &Old =
MI->getOperand(UseOpNo);
500 unsigned Opcode =
MI->getOpcode();
501 int OpNo =
MI->getOperandNo(&Old);
502 uint8_t OpType =
TII->get(Opcode).operands()[OpNo].OperandType;
514 AMDGPU::OpName ModName = AMDGPU::OpName::NUM_OPERAND_NAMES;
515 unsigned SrcIdx = ~0;
516 if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src0)) {
517 ModName = AMDGPU::OpName::src0_modifiers;
519 }
else if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src1)) {
520 ModName = AMDGPU::OpName::src1_modifiers;
522 }
else if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src2)) {
523 ModName = AMDGPU::OpName::src2_modifiers;
526 assert(ModName != AMDGPU::OpName::NUM_OPERAND_NAMES);
527 int ModIdx = AMDGPU::getNamedOperandIdx(Opcode, ModName);
528 MachineOperand &
Mod =
MI->getOperand(ModIdx);
529 unsigned ModVal =
Mod.getImm();
535 uint32_t
Imm = (
static_cast<uint32_t
>(ImmHi) << 16) | ImmLo;
540 auto tryFoldToInline = [&](uint32_t
Imm) ->
bool {
549 uint16_t
Lo =
static_cast<uint16_t
>(
Imm);
550 uint16_t
Hi =
static_cast<uint16_t
>(
Imm >> 16);
556 if (ST->hasBF16InlineConstFromUpperFP32() &&
560 Mod.setImm(NewModVal);
565 if (
static_cast<int16_t
>(
Lo) < 0) {
566 int32_t SExt =
static_cast<int16_t
>(
Lo);
568 Mod.setImm(NewModVal);
583 uint32_t Swapped = (
static_cast<uint32_t
>(
Lo) << 16) |
Hi;
594 if (tryFoldToInline(Imm))
603 bool IsUAdd = Opcode == AMDGPU::V_PK_ADD_U16;
604 bool IsUSub = Opcode == AMDGPU::V_PK_SUB_U16;
605 if (SrcIdx == 1 && (IsUAdd || IsUSub)) {
607 AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::clamp);
608 bool Clamp =
MI->getOperand(ClampIdx).getImm() != 0;
611 uint16_t NegLo = -
static_cast<uint16_t
>(
Imm);
612 uint16_t NegHi = -
static_cast<uint16_t
>(
Imm >> 16);
613 uint32_t NegImm = (
static_cast<uint32_t
>(NegHi) << 16) | NegLo;
615 if (tryFoldToInline(NegImm)) {
617 IsUAdd ? AMDGPU::V_PK_SUB_U16 : AMDGPU::V_PK_ADD_U16;
618 MI->setDesc(
TII->get(NegOpcode));
627bool SIFoldOperandsImpl::updateOperand(FoldCandidate &Fold)
const {
628 MachineInstr *
MI = Fold.UseMI;
629 MachineOperand &Old =
MI->getOperand(Fold.UseOpNo);
632 std::optional<int64_t> ImmVal;
634 ImmVal = Fold.Def.getEffectiveImmVal();
636 if (ImmVal && canUseImmWithOpSel(Fold.UseMI, Fold.UseOpNo, *ImmVal)) {
637 if (tryFoldImmWithOpSel(Fold.UseMI, Fold.UseOpNo, *ImmVal))
643 int OpNo =
MI->getOperandNo(&Old);
644 if (!
TII->isOperandLegal(*
MI, OpNo, &New))
650 if ((Fold.isImm() || Fold.isFI() || Fold.isGlobal()) && Fold.needsShrink()) {
651 MachineBasicBlock *
MBB =
MI->getParent();
658 int Op32 = Fold.ShrinkOpcode;
659 MachineOperand &Dst0 =
MI->getOperand(0);
660 MachineOperand &Dst1 =
MI->getOperand(1);
668 MachineInstr *Inst32 =
TII->buildShrunkInst(*
MI, Op32);
670 if (HaveNonDbgCarryUse) {
673 .
addReg(AMDGPU::VCC, RegState::Kill);
683 for (
unsigned I =
MI->getNumOperands() - 1;
I > 0; --
I)
684 MI->removeOperand(
I);
685 MI->setDesc(
TII->get(AMDGPU::IMPLICIT_DEF));
688 TII->commuteInstruction(*Inst32,
false);
692 assert(!Fold.needsShrink() &&
"not handled");
697 if (NewMFMAOpc == -1)
699 MI->setDesc(
TII->get(NewMFMAOpc));
700 MI->untieRegOperand(0);
701 const MCInstrDesc &MCID =
MI->getDesc();
702 for (
unsigned I = 0;
I <
MI->getNumDefs(); ++
I)
704 MI->getOperand(
I).setIsEarlyClobber(
true);
709 int OpNo =
MI->getOperandNo(&Old);
710 if (!
TII->isOperandLegal(*
MI, OpNo, &New))
717 if (Fold.isGlobal()) {
718 Old.
ChangeToGA(Fold.Def.OpToFold->getGlobal(),
719 Fold.Def.OpToFold->getOffset(),
720 Fold.Def.OpToFold->getTargetFlags());
729 MachineOperand *
New = Fold.Def.OpToFold;
733 TII->getRegClass(
MI->getDesc(), Fold.UseOpNo)) {
735 TRI->getRegClassForReg(*MRI,
New->getReg());
738 if (
New->getSubReg()) {
740 TRI->getMatchingSuperRegClass(NewRC, OpRC,
New->getSubReg());
746 if (
New->getReg().isVirtual() &&
749 <<
TRI->getRegClassName(ConstrainRC) <<
'\n');
756 if (Old.
getSubReg() == AMDGPU::lo16 &&
TRI->isSGPRReg(*MRI,
New->getReg()))
758 if (
New->getReg().isPhysical()) {
766 if (
MI->isBundledWithPred()) {
768 for (MachineOperand &MO : Header.operands()) {
769 if (MO.getReg() == OldReg) {
770 MO.setReg(
New->getReg());
771 MO.setSubReg(
New->getSubReg());
780 FoldCandidate &&Entry) {
782 for (FoldCandidate &Fold : FoldList)
783 if (Fold.UseMI == Entry.UseMI && Fold.UseOpNo == Entry.UseOpNo)
785 LLVM_DEBUG(
dbgs() <<
"Append " << (Entry.Commuted ?
"commuted" :
"normal")
786 <<
" operand " << Entry.UseOpNo <<
"\n " << *Entry.UseMI);
792 const FoldableDef &FoldOp,
793 bool Commuted =
false,
int ShrinkOp = -1) {
795 FoldCandidate(
MI, OpNo, FoldOp, Commuted, ShrinkOp));
803 if (!ST->hasPKF32InstsReplicatingLower32BitsOfScalarInput())
813 const FoldableDef &OpToFold) {
814 assert(OpToFold.isImm() &&
"Expected immediate operand");
815 uint64_t ImmVal = OpToFold.getEffectiveImmVal().value();
821bool SIFoldOperandsImpl::tryAddToFoldList(
822 SmallVectorImpl<FoldCandidate> &FoldList, MachineInstr *
MI,
unsigned OpNo,
823 const FoldableDef &OpToFold)
const {
824 const unsigned Opc =
MI->getOpcode();
826 auto tryToFoldAsFMAAKorMK = [&]() {
827 if (!OpToFold.isImm())
830 const bool TryAK = OpNo == 3;
831 const unsigned NewOpc = TryAK ? AMDGPU::S_FMAAK_F32 : AMDGPU::S_FMAMK_F32;
832 MI->setDesc(
TII->get(NewOpc));
835 bool FoldAsFMAAKorMK =
836 tryAddToFoldList(FoldList,
MI, TryAK ? 3 : 2, OpToFold);
837 if (FoldAsFMAAKorMK) {
839 MI->untieRegOperand(3);
842 MachineOperand &Op1 =
MI->getOperand(1);
843 MachineOperand &Op2 =
MI->getOperand(2);
860 bool IsLegal = OpToFold.isOperandLegal(*
TII, *
MI, OpNo);
861 if (!IsLegal && OpToFold.isImm()) {
862 if (std::optional<int64_t> ImmVal = OpToFold.getEffectiveImmVal())
863 IsLegal = canUseImmWithOpSel(
MI, OpNo, *ImmVal);
869 if (NewOpc != AMDGPU::INSTRUCTION_LIST_END) {
872 MI->setDesc(
TII->get(NewOpc));
877 bool FoldAsMAD = tryAddToFoldList(FoldList,
MI, OpNo, OpToFold);
879 MI->untieRegOperand(OpNo);
883 MI->removeOperand(
MI->getNumExplicitOperands() - 1);
889 if (
Opc == AMDGPU::S_FMAC_F32 && OpNo == 3) {
890 if (tryToFoldAsFMAAKorMK())
895 if (OpToFold.isImm()) {
897 if (
Opc == AMDGPU::S_SETREG_B32)
898 ImmOpc = AMDGPU::S_SETREG_IMM32_B32;
899 else if (
Opc == AMDGPU::S_SETREG_B32_mode)
900 ImmOpc = AMDGPU::S_SETREG_IMM32_B32_mode;
902 MI->setDesc(
TII->get(ImmOpc));
911 bool CanCommute =
TII->findCommutedOpIndices(*
MI, OpNo, CommuteOpNo);
915 MachineOperand &
Op =
MI->getOperand(OpNo);
916 MachineOperand &CommutedOp =
MI->getOperand(CommuteOpNo);
922 if (!
Op.isReg() || !CommutedOp.
isReg())
927 if (
Op.isReg() && CommutedOp.
isReg() &&
928 (
Op.getReg() == CommutedOp.
getReg() &&
932 if (!
TII->commuteInstruction(*
MI,
false, OpNo, CommuteOpNo))
936 if (!OpToFold.isOperandLegal(*
TII, *
MI, CommuteOpNo)) {
937 if ((
Opc != AMDGPU::V_ADD_CO_U32_e64 &&
Opc != AMDGPU::V_SUB_CO_U32_e64 &&
938 Opc != AMDGPU::V_SUBREV_CO_U32_e64) ||
939 (!OpToFold.isImm() && !OpToFold.isFI() && !OpToFold.isGlobal())) {
940 TII->commuteInstruction(*
MI,
false, OpNo, CommuteOpNo);
946 MachineOperand &OtherOp =
MI->getOperand(OpNo);
947 if (!OtherOp.
isReg() ||
954 unsigned MaybeCommutedOpc =
MI->getOpcode();
968 if (
Opc == AMDGPU::S_FMAC_F32 &&
969 (OpNo != 1 || !
MI->getOperand(1).isIdenticalTo(
MI->getOperand(2)))) {
970 if (tryToFoldAsFMAAKorMK())
976 if (OpToFold.isImm() &&
985bool SIFoldOperandsImpl::isUseSafeToFold(
const MachineInstr &
MI,
986 const MachineOperand &UseMO)
const {
988 return !
TII->isSDWA(
MI);
995 if (
MI.modifiesRegister(
TRI.getExec(), &
TRI))
1003bool SIFoldOperandsImpl::isTemporallyDivergentUse(
1004 const FoldableDef &OpToFold,
const MachineInstr &
UseMI)
const {
1005 if (!OpToFold.isReg())
1007 const MachineInstr *
DefMI = OpToFold.DefMI;
1010 !
TRI->isSGPRReg(*MRI, OpToFold.getReg()))
1022 SubDef &&
TII.isFoldableCopy(*SubDef);
1024 unsigned SrcIdx =
TII.getFoldableCopySrcIdx(*SubDef);
1033 if (
SrcOp.getSubReg())
1041 MachineInstr &RegSeq,
1042 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs)
const {
1058 else if (!
TRI->getCommonSubClass(RC, OpRC))
1063 Defs.emplace_back(&SrcOp, SubRegIdx);
1068 if (DefSrc && (DefSrc->
isReg() || DefSrc->
isImm())) {
1069 Defs.emplace_back(DefSrc, SubRegIdx);
1073 Defs.emplace_back(&SrcOp, SubRegIdx);
1083 SmallVectorImpl<std::pair<MachineOperand *, unsigned>> &Defs,
1086 if (!Def || !
Def->isRegSequence())
1089 return getRegSeqInit(*Def, Defs);
1092std::pair<int64_t, const TargetRegisterClass *>
1093SIFoldOperandsImpl::isRegSeqSplat(MachineInstr &RegSeq)
const {
1099 bool TryToMatchSplat64 =
false;
1101 std::optional<int64_t>
Imm;
1102 for (
unsigned I = 0,
E = Defs.
size();
I !=
E; ++
I) {
1103 const MachineOperand *
Op = Defs[
I].first;
1107 if (!Def ||
Def->isImplicitDef())
1113 int64_t SubImm =
Op->getImm();
1119 if (Imm != SubImm) {
1120 if (
I == 1 && (
E & 1) == 0) {
1123 TryToMatchSplat64 =
true;
1131 if (!TryToMatchSplat64) {
1133 return {*
Imm, SrcRC};
1140 for (
unsigned I = 0,
E = Defs.
size();
I !=
E;
I += 2) {
1141 const MachineOperand *Op0 = Defs[
I].first;
1142 const MachineOperand *Op1 = Defs[
I + 1].first;
1147 unsigned SubReg0 = Defs[
I].second;
1148 unsigned SubReg1 = Defs[
I + 1].second;
1152 if (
TRI->getChannelFromSubReg(SubReg0) + 1 !=
1153 TRI->getChannelFromSubReg(SubReg1))
1156 if (
TRI->getSubRegIdxSize(SubReg0) != 32)
1161 SplatVal64 = MergedVal;
1162 else if (SplatVal64 != MergedVal)
1169 return {SplatVal64, RC64};
1172bool SIFoldOperandsImpl::tryFoldRegSeqSplat(
1173 MachineInstr *
UseMI,
unsigned UseOpIdx, int64_t SplatVal,
1176 if (UseOpIdx >=
Desc.getNumOperands())
1183 int16_t RCID =
TII->getOpRegClassID(
Desc.operands()[UseOpIdx]);
1192 if (SplatVal != 0 && SplatVal != -1) {
1196 uint8_t OpTy =
Desc.operands()[UseOpIdx].OperandType;
1203 OpRC =
TRI->getSubRegisterClass(OpRC, AMDGPU::sub0);
1210 OpRC =
TRI->getSubRegisterClass(OpRC, AMDGPU::sub0_sub1);
1216 if (!
TRI->getCommonSubClass(OpRC, SplatRC))
1221 if (!
TII->isOperandLegal(*
UseMI, UseOpIdx, &TmpOp))
1227bool SIFoldOperandsImpl::tryToFoldACImm(
1228 const FoldableDef &OpToFold, MachineInstr *
UseMI,
unsigned UseOpIdx,
1229 SmallVectorImpl<FoldCandidate> &FoldList)
const {
1231 if (UseOpIdx >=
Desc.getNumOperands())
1238 if (OpToFold.isImm() && OpToFold.isOperandLegal(*
TII, *
UseMI, UseOpIdx)) {
1249bool SIFoldOperandsImpl::foldOperand(
1250 FoldableDef OpToFold, MachineInstr *
UseMI,
int UseOpIdx,
1251 SmallVectorImpl<FoldCandidate> &FoldList,
1252 SmallVectorImpl<MachineInstr *> &CopiesToReplace)
const {
1256 if (!isUseSafeToFold(*
UseMI, *UseOp))
1259 if (isTemporallyDivergentUse(OpToFold, *
UseMI))
1263 if (UseOp->
isReg() && OpToFold.isReg()) {
1267 if (UseOp->
getSubReg() != AMDGPU::NoSubRegister &&
1269 !
TRI->isSGPRReg(*MRI, OpToFold.getReg())))
1282 std::tie(SplatVal, SplatRC) = isRegSeqSplat(*
UseMI);
1287 for (
unsigned I = 0;
I != UsesToProcess.size(); ++
I) {
1288 MachineOperand *RSUse = UsesToProcess[
I];
1289 MachineInstr *RSUseMI = RSUse->
getParent();
1299 if (tryFoldRegSeqSplat(RSUseMI, OpNo, SplatVal, SplatRC)) {
1300 FoldableDef SplatDef(SplatVal, SplatRC);
1308 if (RSUse->
getSubReg() != RegSeqDstSubReg)
1314 FoldList, CopiesToReplace);
1320 if (tryToFoldACImm(OpToFold,
UseMI, UseOpIdx, FoldList))
1323 if (frameIndexMayFold(*
UseMI, UseOpIdx, OpToFold)) {
1328 if (
TII->getNamedOperand(*
UseMI, AMDGPU::OpName::srsrc)->getReg() !=
1334 MachineOperand &SOff =
1335 *
TII->getNamedOperand(*
UseMI, AMDGPU::OpName::soffset);
1346 TII->getNamedOperand(*
UseMI, AMDGPU::OpName::cpol)->getImm();
1361 bool FoldingImmLike =
1362 OpToFold.isImm() || OpToFold.isFI() || OpToFold.isGlobal();
1381 for (
unsigned MovOp :
1382 {AMDGPU::S_MOV_B32, AMDGPU::V_MOV_B32_e32, AMDGPU::S_MOV_B64,
1383 AMDGPU::V_MOV_B64_PSEUDO, AMDGPU::V_MOV_B16_t16_e64,
1384 AMDGPU::V_ACCVGPR_WRITE_B32_e64, AMDGPU::AV_MOV_B32_IMM_PSEUDO,
1385 AMDGPU::AV_MOV_B64_IMM_PSEUDO}) {
1386 const MCInstrDesc &MovDesc =
TII->get(MovOp);
1396 const int SrcIdx = MovOp == AMDGPU::V_MOV_B16_t16_e64 ? 2 : 1;
1398 int16_t RegClassID =
TII->getOpRegClassID(MovDesc.
operands()[SrcIdx]);
1399 if (RegClassID != -1) {
1403 MovSrcRC =
TRI->getMatchingSuperRegClass(SrcRC, MovSrcRC, UseSubReg);
1407 if (MovOp == AMDGPU::AV_MOV_B32_IMM_PSEUDO &&
1408 (!OpToFold.isImm() ||
1409 !
TII->isImmOperandLegal(MovDesc, SrcIdx,
1410 *OpToFold.getEffectiveImmVal())))
1423 if (!OpToFold.isImm() ||
1424 !
TII->isImmOperandLegal(MovDesc, 1, *OpToFold.getEffectiveImmVal()))
1430 while (ImpOpI != ImpOpE) {
1437 if (MovOp == AMDGPU::V_MOV_B16_t16_e64) {
1439 MachineOperand NewSrcOp(SrcOp);
1461 LLVM_DEBUG(
dbgs() <<
"Folding " << *OpToFold.OpToFold <<
"\n into "
1466 unsigned SubRegIdx = OpToFold.getSubReg();
1480 static_assert(AMDGPU::sub1_hi16 == 12,
"Subregister layout has changed");
1485 if (SubRegIdx > AMDGPU::sub1) {
1486 LaneBitmask
M =
TRI->getSubRegIndexLaneMask(SubRegIdx);
1487 M |=
M.getLane(
M.getHighestLane() - 1);
1488 SmallVector<unsigned, 4> Indexes;
1489 TRI->getCoveringSubRegIndexes(
TRI->getRegClassForReg(*MRI,
UseReg), M,
1491 assert(Indexes.
size() == 1 &&
"Expected one 32-bit subreg to cover");
1492 SubRegIdx = Indexes[0];
1494 }
else if (
TII->getOpSize(*
UseMI, 1) == 4)
1497 SubRegIdx = AMDGPU::sub0;
1502 OpToFold.OpToFold->setIsKill(
false);
1507 if (foldCopyToAGPRRegSequence(
UseMI))
1512 if (UseOpc == AMDGPU::V_READFIRSTLANE_B32 ||
1513 (UseOpc == AMDGPU::V_READLANE_B32 &&
1515 AMDGPU::getNamedOperandIdx(UseOpc, AMDGPU::OpName::src0))) {
1520 if (FoldingImmLike) {
1523 *OpToFold.DefMI, *
UseMI))
1529 if (OpToFold.isImm()) {
1531 *OpToFold.getEffectiveImmVal());
1532 }
else if (OpToFold.isFI())
1535 assert(OpToFold.isGlobal());
1537 OpToFold.OpToFold->getOffset(),
1538 OpToFold.OpToFold->getTargetFlags());
1544 if (OpToFold.isReg() &&
TRI->isSGPRReg(*MRI, OpToFold.getReg())) {
1547 *OpToFold.DefMI, *
UseMI))
1569 UseDesc.
operands()[UseOpIdx].RegClass == -1)
1577 Changed |= tryAddToFoldList(FoldList,
UseMI, UseOpIdx, OpToFold);
1584 case AMDGPU::S_ADD_I32:
1585 case AMDGPU::S_ADD_U32:
1588 case AMDGPU::S_SUB_I32:
1589 case AMDGPU::S_SUB_U32:
1592 case AMDGPU::V_AND_B32_e64:
1593 case AMDGPU::V_AND_B32_e32:
1594 case AMDGPU::S_AND_B32:
1597 case AMDGPU::V_OR_B32_e64:
1598 case AMDGPU::V_OR_B32_e32:
1599 case AMDGPU::S_OR_B32:
1602 case AMDGPU::V_XOR_B32_e64:
1603 case AMDGPU::V_XOR_B32_e32:
1604 case AMDGPU::S_XOR_B32:
1607 case AMDGPU::S_XNOR_B32:
1610 case AMDGPU::S_NAND_B32:
1613 case AMDGPU::S_NOR_B32:
1616 case AMDGPU::S_ANDN2_B32:
1619 case AMDGPU::S_ORN2_B32:
1622 case AMDGPU::V_LSHL_B32_e64:
1623 case AMDGPU::V_LSHL_B32_e32:
1624 case AMDGPU::S_LSHL_B32:
1626 Result =
LHS << (
RHS & 31);
1628 case AMDGPU::V_LSHLREV_B32_e64:
1629 case AMDGPU::V_LSHLREV_B32_e32:
1630 Result =
RHS << (
LHS & 31);
1632 case AMDGPU::V_LSHR_B32_e64:
1633 case AMDGPU::V_LSHR_B32_e32:
1634 case AMDGPU::S_LSHR_B32:
1635 Result =
LHS >> (
RHS & 31);
1637 case AMDGPU::V_LSHRREV_B32_e64:
1638 case AMDGPU::V_LSHRREV_B32_e32:
1639 Result =
RHS >> (
LHS & 31);
1641 case AMDGPU::V_ASHR_I32_e64:
1642 case AMDGPU::V_ASHR_I32_e32:
1643 case AMDGPU::S_ASHR_I32:
1644 Result =
static_cast<int32_t
>(
LHS) >> (
RHS & 31);
1646 case AMDGPU::V_ASHRREV_I32_e64:
1647 case AMDGPU::V_ASHRREV_I32_e32:
1648 Result =
static_cast<int32_t
>(
RHS) >> (
LHS & 31);
1656 return IsScalar ? AMDGPU::S_MOV_B32 : AMDGPU::V_MOV_B32_e32;
1662bool SIFoldOperandsImpl::tryConstantFoldOp(MachineInstr *
MI)
const {
1663 if (!
MI->allImplicitDefsAreDead())
1666 unsigned Opc =
MI->getOpcode();
1668 int Src0Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src0);
1672 MachineOperand *Src0 = &
MI->getOperand(Src0Idx);
1673 std::optional<int64_t> Src0Imm =
TII->getImmOrMaterializedImm(*Src0);
1675 if ((
Opc == AMDGPU::V_NOT_B32_e64 ||
Opc == AMDGPU::V_NOT_B32_e32 ||
1676 Opc == AMDGPU::S_NOT_B32) &&
1678 MI->getOperand(1).ChangeToImmediate(~*Src0Imm);
1679 TII->mutateAndCleanupImplicit(
1684 int Src1Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src1);
1688 MachineOperand *Src1 = &
MI->getOperand(Src1Idx);
1689 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*Src1);
1691 if (!Src0Imm && !Src1Imm)
1697 if (Src0Imm && Src1Imm) {
1702 bool IsSGPR =
TRI->isSGPRReg(*MRI,
MI->getOperand(0).getReg());
1706 MI->getOperand(Src0Idx).ChangeToImmediate(NewImm);
1707 MI->removeOperand(Src1Idx);
1714 if (
Opc == AMDGPU::S_SUB_I32 ||
Opc == AMDGPU::S_SUB_U32) {
1715 if (Src1Imm &&
static_cast<int32_t
>(*Src1Imm) == 0) {
1717 MI->removeOperand(Src1Idx);
1718 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1724 if (!
MI->isCommutable())
1727 if (Src0Imm && !Src1Imm) {
1733 int32_t Src1Val =
static_cast<int32_t
>(*Src1Imm);
1734 if (
Opc == AMDGPU::S_ADD_I32 ||
Opc == AMDGPU::S_ADD_U32) {
1737 MI->removeOperand(Src1Idx);
1738 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1744 if (
Opc == AMDGPU::V_OR_B32_e64 ||
1745 Opc == AMDGPU::V_OR_B32_e32 ||
1746 Opc == AMDGPU::S_OR_B32) {
1749 MI->removeOperand(Src1Idx);
1750 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1751 }
else if (Src1Val == -1) {
1753 MI->removeOperand(Src0Idx);
1754 TII->mutateAndCleanupImplicit(
1762 if (
Opc == AMDGPU::V_AND_B32_e64 ||
Opc == AMDGPU::V_AND_B32_e32 ||
1763 Opc == AMDGPU::S_AND_B32) {
1766 MI->removeOperand(Src0Idx);
1767 TII->mutateAndCleanupImplicit(
1769 }
else if (Src1Val == -1) {
1771 MI->removeOperand(Src1Idx);
1772 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1779 if (
Opc == AMDGPU::V_XOR_B32_e64 ||
Opc == AMDGPU::V_XOR_B32_e32 ||
1780 Opc == AMDGPU::S_XOR_B32) {
1783 MI->removeOperand(Src1Idx);
1784 TII->mutateAndCleanupImplicit(*
MI,
TII->get(AMDGPU::COPY));
1793bool SIFoldOperandsImpl::tryFoldCndMask(MachineInstr &
MI)
const {
1794 unsigned Opc =
MI.getOpcode();
1795 if (
Opc != AMDGPU::V_CNDMASK_B32_e32 &&
Opc != AMDGPU::V_CNDMASK_B32_e64 &&
1796 Opc != AMDGPU::V_CNDMASK_B64_PSEUDO)
1799 MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
1800 MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
1802 std::optional<int64_t> Src1Imm =
TII->getImmOrMaterializedImm(*Src1);
1806 std::optional<int64_t> Src0Imm =
TII->getImmOrMaterializedImm(*Src0);
1807 if (!Src0Imm || *Src0Imm != *Src1Imm)
1812 AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src1_modifiers);
1814 AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src0_modifiers);
1815 if ((Src1ModIdx != -1 &&
MI.getOperand(Src1ModIdx).getImm() != 0) ||
1816 (Src0ModIdx != -1 &&
MI.getOperand(Src0ModIdx).getImm() != 0))
1822 int Src2Idx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
1824 MI.removeOperand(Src2Idx);
1825 MI.removeOperand(AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src1));
1826 if (Src1ModIdx != -1)
1827 MI.removeOperand(Src1ModIdx);
1828 if (Src0ModIdx != -1)
1829 MI.removeOperand(Src0ModIdx);
1830 TII->mutateAndCleanupImplicit(
MI, NewDesc);
1835bool SIFoldOperandsImpl::tryFoldZeroHighBits(MachineInstr &
MI)
const {
1836 if (
MI.getOpcode() != AMDGPU::V_AND_B32_e64 &&
1837 MI.getOpcode() != AMDGPU::V_AND_B32_e32)
1840 std::optional<int64_t> Src0Imm =
1841 TII->getImmOrMaterializedImm(
MI.getOperand(1));
1842 if (!Src0Imm || *Src0Imm != 0xffff || !
MI.getOperand(2).isReg())
1846 MachineInstr *SrcDef = MRI->
getVRegDef(Src1);
1852 if (!
MI.getOperand(2).isKill())
1854 MI.eraseFromParent();
1858bool SIFoldOperandsImpl::foldInstOperand(MachineInstr &
MI,
1859 const FoldableDef &OpToFold)
const {
1863 SmallVector<MachineInstr *, 4> CopiesToReplace;
1865 MachineOperand &Dst =
MI.getOperand(0);
1870 for (
auto *U : UsesToProcess) {
1871 MachineInstr *
UseMI =
U->getParent();
1873 FoldableDef SubOpToFold = OpToFold.getWithSubReg(*
TRI,
U->getSubReg());
1878 if (CopiesToReplace.
empty() && FoldList.
empty())
1882 for (MachineInstr *Copy : CopiesToReplace)
1883 Copy->addImplicitDefUseOperands(*MF);
1885 SetVector<MachineInstr *> ConstantFoldCandidates;
1886 for (FoldCandidate &Fold : FoldList) {
1887 assert(!Fold.isReg() || Fold.Def.OpToFold);
1888 if (Fold.isReg() && Fold.getReg().isVirtual()) {
1890 const MachineInstr *
DefMI = Fold.Def.DefMI;
1898 assert(Fold.Def.OpToFold && Fold.isReg());
1905 <<
static_cast<int>(Fold.UseOpNo) <<
" of "
1909 ConstantFoldCandidates.
insert(Fold.UseMI);
1911 }
else if (Fold.Commuted) {
1913 TII->commuteInstruction(*Fold.UseMI,
false);
1917 for (MachineInstr *
MI : ConstantFoldCandidates) {
1918 if (tryConstantFoldOp(
MI)) {
1928bool SIFoldOperandsImpl::foldCopyToAGPRRegSequence(MachineInstr *CopyMI)
const {
1935 if (!
TRI->isAGPRClass(DefRC))
1947 DenseMap<TargetInstrInfo::RegSubRegPair, Register> VGPRCopies;
1956 unsigned NumFoldable = 0;
1958 for (
unsigned I = 1;
I != NumRegSeqOperands;
I += 2) {
1975 DefRC, &AMDGPU::AGPR_32RegClass, SubRegIdx);
1995 TRI->getMatchingSuperRegClass(DefRC, InputRC, SubRegIdx);
2006 if (NumFoldable == 0)
2009 CopyMI->
setDesc(
TII->get(AMDGPU::REG_SEQUENCE));
2013 for (
auto [Def, DestSubIdx] : NewDefs) {
2014 if (!
Def->isReg()) {
2018 BuildMI(
MBB, CopyMI,
DL,
TII->get(AMDGPU::V_ACCVGPR_WRITE_B32_e64), Tmp)
2023 Def->setIsKill(
false);
2025 Register &VGPRCopy = VGPRCopies[Src];
2028 TRI->getSubRegisterClass(UseRC, DestSubIdx);
2053 B.addImm(DestSubIdx);
2060bool SIFoldOperandsImpl::tryFoldFoldableCopy(
2061 MachineInstr &
MI, MachineOperand *&CurrentKnownM0Val)
const {
2065 if (DstReg == AMDGPU::M0) {
2066 MachineOperand &NewM0Val =
MI.getOperand(1);
2067 if (CurrentKnownM0Val && CurrentKnownM0Val->
isIdenticalTo(NewM0Val)) {
2068 MI.eraseFromParent();
2079 MachineOperand *OpToFoldPtr;
2080 if (
MI.getOpcode() == AMDGPU::V_MOV_B16_t16_e64) {
2082 if (
TII->hasAnyModifiersSet(
MI))
2084 OpToFoldPtr = &
MI.getOperand(2);
2086 OpToFoldPtr = &
MI.getOperand(1);
2087 MachineOperand &OpToFold = *OpToFoldPtr;
2091 if (!FoldingImm && !OpToFold.
isReg())
2096 !
TRI->isConstantPhysReg(OpToFold.
getReg()))
2125 if (
MI.getOpcode() == AMDGPU::COPY && OpToFold.
isReg() &&
2127 if (DstRC == &AMDGPU::SReg_32RegClass &&
2136 if (OpToFold.
isReg() &&
MI.isCopy() && !
MI.getOperand(1).getSubReg()) {
2137 if (foldCopyToAGPRRegSequence(&
MI))
2141 FoldableDef
Def(OpToFold, DstRC);
2142 bool Changed = foldInstOperand(
MI, Def);
2149 auto *InstToErase = &
MI;
2151 auto &SrcOp = InstToErase->getOperand(1);
2153 InstToErase->eraseFromParent();
2155 InstToErase =
nullptr;
2159 if (!InstToErase || !
TII->isFoldableCopy(*InstToErase))
2163 if (InstToErase && InstToErase->isRegSequence() &&
2165 InstToErase->eraseFromParent();
2175 return OpToFold.
isReg() &&
2176 foldCopyToVGPROfScalarAddOfFrameIndex(DstReg, OpToFold.
getReg(),
MI);
2181const MachineOperand *
2182SIFoldOperandsImpl::isClamp(
const MachineInstr &
MI)
const {
2183 unsigned Op =
MI.getOpcode();
2185 case AMDGPU::V_MAX_F32_e64:
2186 case AMDGPU::V_MAX_F16_e64:
2187 case AMDGPU::V_MAX_F16_t16_e64:
2188 case AMDGPU::V_MAX_F16_fake16_e64:
2189 case AMDGPU::V_MAX_F64_e64:
2190 case AMDGPU::V_MAX_NUM_F64_e64:
2191 case AMDGPU::V_PK_MAX_F16:
2192 case AMDGPU::V_MAX_BF16_PSEUDO_e64:
2193 case AMDGPU::V_PK_MAX_NUM_BF16: {
2194 if (
MI.mayRaiseFPException())
2197 if (!
TII->getNamedOperand(
MI, AMDGPU::OpName::clamp)->getImm())
2201 const MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2202 const MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2206 Src0->
getSubReg() != AMDGPU::NoSubRegister)
2210 if (
TII->hasModifiersSet(
MI, AMDGPU::OpName::omod))
2214 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0_modifiers)->getImm();
2216 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1_modifiers)->getImm();
2220 unsigned UnsetMods =
2221 (
Op == AMDGPU::V_PK_MAX_F16 ||
Op == AMDGPU::V_PK_MAX_NUM_BF16)
2224 if (Src0Mods != UnsetMods && Src1Mods != UnsetMods)
2234bool SIFoldOperandsImpl::tryFoldClamp(MachineInstr &
MI) {
2235 const MachineOperand *ClampSrc = isClamp(
MI);
2251 if (
Def->mayRaiseFPException())
2254 MachineOperand *DefClamp =
TII->getNamedOperand(*Def, AMDGPU::OpName::clamp);
2258 LLVM_DEBUG(
dbgs() <<
"Folding clamp " << *DefClamp <<
" into " << *Def);
2264 Register MIDstReg =
MI.getOperand(0).getReg();
2265 if (
TRI->isSGPRReg(*MRI, DefReg)) {
2274 MI.eraseFromParent();
2279 if (
TII->convertToThreeAddress(*Def,
nullptr,
nullptr))
2280 Def->eraseFromParent();
2287 case AMDGPU::V_MUL_F64_e64:
2288 case AMDGPU::V_MUL_F64_pseudo_e64: {
2290 case 0x3fe0000000000000:
2292 case 0x4000000000000000:
2294 case 0x4010000000000000:
2300 case AMDGPU::V_MUL_F32_e64: {
2301 switch (
static_cast<uint32_t>(Val)) {
2312 case AMDGPU::V_MUL_F16_e64:
2313 case AMDGPU::V_MUL_F16_t16_e64:
2314 case AMDGPU::V_MUL_F16_fake16_e64: {
2315 switch (
static_cast<uint16_t>(Val)) {
2334std::pair<const MachineOperand *, int>
2335SIFoldOperandsImpl::isOMod(
const MachineInstr &
MI)
const {
2336 unsigned Op =
MI.getOpcode();
2338 case AMDGPU::V_MUL_F64_e64:
2339 case AMDGPU::V_MUL_F64_pseudo_e64:
2340 case AMDGPU::V_MUL_F32_e64:
2341 case AMDGPU::V_MUL_F16_t16_e64:
2342 case AMDGPU::V_MUL_F16_fake16_e64:
2343 case AMDGPU::V_MUL_F16_e64: {
2345 if ((
Op == AMDGPU::V_MUL_F32_e64 &&
2347 ((
Op == AMDGPU::V_MUL_F64_e64 ||
Op == AMDGPU::V_MUL_F64_pseudo_e64 ||
2348 Op == AMDGPU::V_MUL_F16_e64 ||
Op == AMDGPU::V_MUL_F16_t16_e64 ||
2349 Op == AMDGPU::V_MUL_F16_fake16_e64) &&
2352 MI.mayRaiseFPException())
2355 const MachineOperand *RegOp =
nullptr;
2356 const MachineOperand *ImmOp =
nullptr;
2357 const MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2358 const MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2359 if (Src0->
isImm()) {
2362 }
else if (Src1->
isImm()) {
2370 TII->hasModifiersSet(
MI, AMDGPU::OpName::src0_modifiers) ||
2371 TII->hasModifiersSet(
MI, AMDGPU::OpName::src1_modifiers) ||
2372 TII->hasModifiersSet(
MI, AMDGPU::OpName::omod) ||
2373 TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp))
2376 return std::pair(RegOp, OMod);
2378 case AMDGPU::V_ADD_F64_e64:
2379 case AMDGPU::V_ADD_F64_pseudo_e64:
2380 case AMDGPU::V_ADD_F32_e64:
2381 case AMDGPU::V_ADD_F16_e64:
2382 case AMDGPU::V_ADD_F16_t16_e64:
2383 case AMDGPU::V_ADD_F16_fake16_e64: {
2385 if ((
Op == AMDGPU::V_ADD_F32_e64 &&
2387 ((
Op == AMDGPU::V_ADD_F64_e64 ||
Op == AMDGPU::V_ADD_F64_pseudo_e64 ||
2388 Op == AMDGPU::V_ADD_F16_e64 ||
Op == AMDGPU::V_ADD_F16_t16_e64 ||
2389 Op == AMDGPU::V_ADD_F16_fake16_e64) &&
2394 const MachineOperand *Src0 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src0);
2395 const MachineOperand *Src1 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src1);
2399 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::src0_modifiers) &&
2400 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::src1_modifiers) &&
2401 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::clamp) &&
2402 !
TII->hasModifiersSet(
MI, AMDGPU::OpName::omod))
2413bool SIFoldOperandsImpl::tryFoldOMod(MachineInstr &
MI) {
2414 const MachineOperand *RegOp;
2416 std::tie(RegOp, OMod) = isOMod(
MI);
2418 RegOp->
getSubReg() != AMDGPU::NoSubRegister ||
2423 MachineOperand *DefOMod =
TII->getNamedOperand(*Def, AMDGPU::OpName::omod);
2427 if (
Def->mayRaiseFPException())
2432 if (
TII->hasModifiersSet(*Def, AMDGPU::OpName::clamp))
2442 MI.eraseFromParent();
2447 if (
TII->convertToThreeAddress(*Def,
nullptr,
nullptr))
2448 Def->eraseFromParent();
2455bool SIFoldOperandsImpl::tryFoldRegSequence(MachineInstr &
MI) {
2457 auto Reg =
MI.getOperand(0).getReg();
2459 if (!ST->hasGFX90AInsts() || !
TRI->isVGPR(*MRI,
Reg) ||
2464 if (!getRegSeqInit(Defs,
Reg))
2467 for (
auto &[
Op, SubIdx] : Defs) {
2470 if (
TRI->isAGPR(*MRI,
Op->getReg()))
2473 const MachineInstr *SubDef = MRI->
getVRegDef(
Op->getReg());
2481 MachineInstr *
UseMI =
Op->getParent();
2490 if (
Op->getSubReg())
2496 if (!OpRC || !
TRI->isVectorSuperClass(OpRC))
2502 TII->get(AMDGPU::REG_SEQUENCE), Dst);
2504 for (
auto &[Def, SubIdx] : Defs) {
2505 Def->setIsKill(
false);
2506 if (
TRI->isAGPR(*MRI,
Def->getReg())) {
2519 RS->eraseFromParent();
2528 MI.eraseFromParent();
2536 Register &OutReg,
unsigned &OutSubReg) {
2546 if (
TRI.isAGPR(MRI, CopySrcReg)) {
2547 OutReg = CopySrcReg;
2556 if (!CopySrcDef || !CopySrcDef->
isCopy())
2563 OtherCopySrc.
getSubReg() != AMDGPU::NoSubRegister ||
2564 !
TRI.isAGPR(MRI, OtherCopySrcReg))
2567 OutReg = OtherCopySrcReg;
2601bool SIFoldOperandsImpl::tryFoldPhiAGPR(MachineInstr &
PHI) {
2605 if (!
TRI->isVGPR(*MRI, PhiOut))
2611 for (
unsigned K = 1;
K <
PHI.getNumExplicitOperands();
K += 2) {
2612 MachineOperand &MO =
PHI.getOperand(K);
2614 if (!Copy || !
Copy->isCopy())
2618 unsigned AGPRRegMask = AMDGPU::NoSubRegister;
2623 if (
const auto *SubRC =
TRI->getSubRegisterClass(CopyInRC, AGPRRegMask))
2634 bool IsAGPR32 = (ARC == &AMDGPU::AGPR_32RegClass);
2638 for (
unsigned K = 1;
K <
PHI.getNumExplicitOperands();
K += 2) {
2639 MachineOperand &MO =
PHI.getOperand(K);
2643 MachineBasicBlock *InsertMBB =
nullptr;
2646 unsigned CopyOpc = AMDGPU::COPY;
2651 if (
Def->isCopy()) {
2653 unsigned AGPRSubReg = AMDGPU::NoSubRegister;
2666 MachineOperand &CopyIn =
Def->getOperand(1);
2669 CopyOpc = AMDGPU::V_ACCVGPR_WRITE_B32_e64;
2672 InsertMBB =
Def->getParent();
2680 MachineInstr *
MI =
BuildMI(*InsertMBB, InsertPt,
PHI.getDebugLoc(),
2681 TII->get(CopyOpc), NewReg)
2691 PHI.getOperand(0).setReg(NewReg);
2697 TII->get(AMDGPU::COPY), PhiOut)
2705bool SIFoldOperandsImpl::tryFoldLoad(MachineInstr &
MI) {
2707 if (!ST->hasGFX90AInsts() ||
MI.getNumExplicitDefs() != 1)
2710 MachineOperand &
Def =
MI.getOperand(0);
2727 while (!
Users.empty()) {
2728 const MachineInstr *
I =
Users.pop_back_val();
2729 if (!
I->isCopy() && !
I->isRegSequence())
2731 Register DstReg =
I->getOperand(0).getReg();
2735 if (
TRI->isAGPR(*MRI, DstReg))
2739 Users.push_back(&U);
2744 if (!
TII->isOperandLegal(
MI, 0, &Def)) {
2749 while (!MoveRegs.
empty()) {
2791bool SIFoldOperandsImpl::tryOptimizeAGPRPhis(MachineBasicBlock &
MBB) {
2794 if (ST->hasGFX90AInsts())
2798 DenseMap<std::pair<Register, unsigned>, std::vector<MachineOperand *>>
2801 for (
auto &
MI :
MBB) {
2805 if (!
TRI->isAGPR(*MRI,
MI.getOperand(0).getReg()))
2808 for (
unsigned K = 1;
K <
MI.getNumOperands();
K += 2) {
2809 MachineOperand &PhiMO =
MI.getOperand(K);
2819 for (
const auto &[Entry, MOs] : RegToMO) {
2820 if (MOs.size() == 1)
2825 MachineBasicBlock *DefMBB =
Def->getParent();
2832 MachineInstr *VGPRCopy =
2834 TII->get(AMDGPU::V_ACCVGPR_READ_B32_e64), TempVGPR)
2840 TII->get(AMDGPU::COPY), TempAGPR)
2844 for (MachineOperand *MO : MOs) {
2856bool SIFoldOperandsImpl::run(MachineFunction &MF,
const MachineLoopInfo *MLI) {
2862 MFI = MF.
getInfo<SIMachineFunctionInfo>();
2873 MachineOperand *CurrentKnownM0Val =
nullptr;
2881 if (tryConstantFoldOp(&
MI)) {
2886 if (tryFoldZeroHighBits(
MI)) {
2891 if (
MI.isRegSequence() && tryFoldRegSequence(
MI)) {
2896 if (
MI.isPHI() && tryFoldPhiAGPR(
MI)) {
2901 if (
MI.mayLoad() && tryFoldLoad(
MI)) {
2906 if (
TII->isFoldableCopy(
MI)) {
2907 Changed |= tryFoldFoldableCopy(
MI, CurrentKnownM0Val);
2912 if (CurrentKnownM0Val &&
MI.modifiesRegister(AMDGPU::M0,
TRI))
2913 CurrentKnownM0Val =
nullptr;
2933 bool Changed = SIFoldOperandsImpl().run(MF, MLI);
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_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.
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
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.
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.
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)
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()
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.