87#define DEBUG_TYPE "si-wqm"
96 StateStrict = StateStrictWWM | StateStrictWQM,
103 explicit PrintState(
int State) : State(State) {}
109 static const std::pair<char, const char *> Mapping[] = {
110 std::pair(StateWQM,
"WQM"), std::pair(StateStrictWWM,
"StrictWWM"),
111 std::pair(StateStrictWQM,
"StrictWQM"), std::pair(StateExact,
"Exact")};
112 char State = PS.State;
113 for (
auto M : Mapping) {
114 if (State & M.first) {
131 char MarkedStates = 0;
138 char InitialState = 0;
139 bool NeedsLowering =
false;
151class SIWholeQuadMode {
188 std::vector<WorkItem> &Worklist);
191 std::vector<WorkItem> &Worklist);
193 std::vector<WorkItem> &Worklist);
195 std::vector<WorkItem> &Worklist);
196 char scanInstructions(
MachineFunction &MF, std::vector<WorkItem> &Worklist,
198 void propagateInstruction(
MachineInstr &
MI, std::vector<WorkItem> &Worklist);
213 Register SaveOrig,
char StrictStateNeeded);
216 char NonStrictState,
char CurrentStrictState);
225 bool lowerLiveMaskQueries();
226 bool lowerCopyInstrs();
227 bool lowerKillInstrs(
bool IsWQM);
241 StringRef getPassName()
const override {
return "SI Whole Quad Mode"; }
258char SIWholeQuadModeLegacy::ID = 0;
271 return new SIWholeQuadModeLegacy;
276 for (
const auto &BII : Blocks) {
279 <<
" InNeeds = " << PrintState(BII.second.InNeeds)
280 <<
", Needs = " << PrintState(BII.second.Needs)
281 <<
", OutNeeds = " << PrintState(BII.second.OutNeeds) <<
"\n\n";
284 auto III = Instructions.find(&
MI);
285 if (III != Instructions.end()) {
286 dbgs() <<
" " <<
MI <<
" Needs = " << PrintState(III->second.Needs)
287 <<
", OutNeeds = " << PrintState(III->second.OutNeeds) <<
'\n';
294void SIWholeQuadMode::markInstruction(MachineInstr &
MI,
char Flag,
295 std::vector<WorkItem> &Worklist) {
296 InstrInfo &
II = Instructions[&
MI];
298 assert(!(Flag & StateExact) && Flag != 0);
307 Flag &= ~II.Disabled;
311 if ((
II.Needs & Flag) == Flag)
316 Worklist.emplace_back(&
MI);
320void SIWholeQuadMode::markDefs(
const MachineInstr &
UseMI,
LiveRange &LR,
321 VirtRegOrUnit VRegOrUnit,
unsigned SubReg,
322 char Flag, std::vector<WorkItem> &Worklist) {
332 const LaneBitmask UseLanes =
333 SubReg ?
TRI->getSubRegIndexLaneMask(SubReg)
344 LaneBitmask DefinedLanes;
346 PhiEntry(
const VNInfo *Phi,
unsigned PredIdx, LaneBitmask DefinedLanes)
347 :
Phi(
Phi), PredIdx(PredIdx), DefinedLanes(DefinedLanes) {}
349 using VisitKey = std::pair<const VNInfo *, LaneBitmask>;
351 SmallSet<VisitKey, 4> Visited;
352 LaneBitmask DefinedLanes;
353 unsigned NextPredIdx = 0;
355 const VNInfo *NextValue =
nullptr;
356 const VisitKey
Key(
Value, DefinedLanes);
363 if (
Value->isPHIDef()) {
366 assert(
MBB &&
"Phi-def has no defining MBB");
369 unsigned Idx = NextPredIdx;
372 for (; PI != PE && !NextValue; ++PI, ++Idx) {
374 if (!Visited.
count(VisitKey(VN, DefinedLanes)))
384 assert(
MI &&
"Def has no defining instruction");
389 for (
const MachineOperand &
Op :
MI->all_defs()) {
394 LaneBitmask OpLanes =
396 :
TRI->getSubRegIndexLaneMask(
Op.getSubReg());
397 LaneBitmask Overlap = (UseLanes & OpLanes);
400 HasDef |= Overlap.
any();
403 DefinedLanes |= OpLanes;
407 if ((DefinedLanes & UseLanes) != UseLanes) {
410 if (
const VNInfo *VN = LRQ.
valueIn()) {
411 if (!Visited.
count(VisitKey(VN, DefinedLanes)))
418 markInstruction(*
MI, Flag, Worklist);
421 markInstruction(*
MI, Flag, Worklist);
425 if (!NextValue && !PhiStack.
empty()) {
428 NextValue =
Entry.Phi;
429 NextPredIdx =
Entry.PredIdx;
430 DefinedLanes =
Entry.DefinedLanes;
438void SIWholeQuadMode::markOperand(
const MachineInstr &
MI,
439 const MachineOperand &
Op,
char Flag,
440 std::vector<WorkItem> &Worklist) {
447 case AMDGPU::EXEC_LO:
457 markDefs(
MI, LR, VirtRegOrUnit(
Reg),
Op.getSubReg(), Flag, Worklist);
466 markDefs(
MI, LR, VirtRegOrUnit(Unit), AMDGPU::NoSubRegister, Flag,
473void SIWholeQuadMode::markInstructionUses(
const MachineInstr &
MI,
char Flag,
474 std::vector<WorkItem> &Worklist) {
475 LLVM_DEBUG(
dbgs() <<
"markInstructionUses " << PrintState(Flag) <<
": "
478 for (
const MachineOperand &Use :
MI.all_uses())
479 markOperand(
MI, Use, Flag, Worklist);
484char SIWholeQuadMode::scanInstructions(
487 char GlobalFlags = 0;
489 SmallVector<MachineInstr *, 4> SoftWQMInstrs;
490 bool HasImplicitDerivatives =
497 ReversePostOrderTraversal<MachineFunction *> RPOT(&MF);
498 for (MachineBasicBlock *
MBB : RPOT) {
499 BlockInfo &BBI = Blocks[
MBB];
501 for (MachineInstr &
MI : *
MBB) {
502 InstrInfo &III = Instructions[&
MI];
503 unsigned Opcode =
MI.getOpcode();
506 if (
TII->isWQM(Opcode)) {
511 if (ST->hasExtendedImageInsts() && HasImplicitDerivatives) {
515 markInstructionUses(
MI, StateWQM, Worklist);
516 GlobalFlags |= StateWQM;
518 }
else if (Opcode == AMDGPU::WQM) {
522 LowerToCopyInstrs.insert(&
MI);
523 }
else if (Opcode == AMDGPU::SOFT_WQM) {
524 LowerToCopyInstrs.insert(&
MI);
526 }
else if (Opcode == AMDGPU::STRICT_WWM) {
530 markInstructionUses(
MI, StateStrictWWM, Worklist);
531 GlobalFlags |= StateStrictWWM;
533 }
else if (Opcode == AMDGPU::STRICT_WQM ||
534 TII->isDualSourceBlendEXP(
MI)) {
538 markInstructionUses(
MI, StateStrictWQM, Worklist);
539 GlobalFlags |= StateStrictWQM;
541 if (Opcode == AMDGPU::STRICT_WQM) {
547 BBI.Needs |= StateExact;
548 if (!(BBI.InNeeds & StateExact)) {
549 BBI.InNeeds |= StateExact;
550 Worklist.emplace_back(
MBB);
552 GlobalFlags |= StateExact;
553 III.Disabled = StateWQM | StateStrict;
555 }
else if (Opcode == AMDGPU::LDS_PARAM_LOAD ||
556 Opcode == AMDGPU::DS_PARAM_LOAD ||
557 Opcode == AMDGPU::LDS_DIRECT_LOAD ||
558 Opcode == AMDGPU::DS_DIRECT_LOAD) {
561 III.Needs |= StateStrictWQM;
562 GlobalFlags |= StateStrictWQM;
563 }
else if (Opcode == AMDGPU::V_SET_INACTIVE_B32) {
565 III.Disabled = StateStrict;
566 MachineOperand &Inactive =
MI.getOperand(4);
567 if (Inactive.
isReg()) {
568 if (Inactive.
isUndef() &&
MI.getOperand(3).getImm() == 0)
569 LowerToCopyInstrs.insert(&
MI);
571 markOperand(
MI, Inactive, StateStrictWWM, Worklist);
574 BBI.NeedsLowering =
true;
575 }
else if (
TII->isDisableWQM(
MI)) {
576 BBI.Needs |= StateExact;
577 if (!(BBI.InNeeds & StateExact)) {
578 BBI.InNeeds |= StateExact;
579 Worklist.emplace_back(
MBB);
581 GlobalFlags |= StateExact;
582 III.Disabled = StateWQM | StateStrict;
583 }
else if (Opcode == AMDGPU::SI_PS_LIVE ||
584 Opcode == AMDGPU::SI_LIVE_MASK) {
586 }
else if (Opcode == AMDGPU::SI_KILL_I1_TERMINATOR ||
587 Opcode == AMDGPU::SI_KILL_F32_COND_IMM_TERMINATOR ||
588 Opcode == AMDGPU::SI_DEMOTE_I1) {
590 BBI.NeedsLowering =
true;
591 }
else if (Opcode == AMDGPU::SI_INIT_EXEC ||
592 Opcode == AMDGPU::SI_INIT_EXEC_FROM_INPUT ||
593 Opcode == AMDGPU::SI_INIT_WHOLE_WAVE) {
595 }
else if (WQMOutputs) {
600 for (
const MachineOperand &MO :
MI.defs()) {
603 TRI->hasVectorRegisters(
TRI->getPhysRegBaseClass(
Reg))) {
610 if (
TII->hasUnwantedEffectsWhenEXECEmpty(
MI)) {
611 for (
auto &
Op :
MI.uses()) {
614 if (!
TRI->isVectorRegister(*MRI,
Op.getReg()))
623 markInstruction(
MI, Flags, Worklist);
624 GlobalFlags |=
Flags;
633 if (GlobalFlags & StateWQM) {
634 for (MachineInstr *
MI : SetInactiveInstrs)
635 markInstruction(*
MI, StateWQM, Worklist);
636 for (MachineInstr *
MI : SoftWQMInstrs)
637 markInstruction(*
MI, StateWQM, Worklist);
643void SIWholeQuadMode::propagateInstruction(MachineInstr &
MI,
644 std::vector<WorkItem>& Worklist) {
646 InstrInfo
II = Instructions[&
MI];
647 BlockInfo &BI = Blocks[
MBB];
651 if ((
II.OutNeeds & StateWQM) && !(
II.Disabled & StateWQM) &&
652 (
MI.isTerminator() || (
TII->usesVM_CNT(
MI) &&
MI.mayStore()))) {
653 Instructions[&
MI].Needs = StateWQM;
658 if (
II.Needs & StateWQM) {
659 BI.Needs |= StateWQM;
660 if (!(BI.InNeeds & StateWQM)) {
661 BI.InNeeds |= StateWQM;
662 Worklist.emplace_back(
MBB);
667 if (MachineInstr *PrevMI =
MI.getPrevNode()) {
668 char InNeeds = (
II.Needs & ~StateStrict) |
II.OutNeeds;
669 if (!PrevMI->isPHI()) {
670 InstrInfo &PrevII = Instructions[PrevMI];
671 if ((PrevII.OutNeeds | InNeeds) != PrevII.OutNeeds) {
672 PrevII.OutNeeds |= InNeeds;
673 Worklist.emplace_back(PrevMI);
682 markInstructionUses(
MI,
II.Needs, Worklist);
686 if (
II.Needs & StateStrictWWM)
687 BI.Needs |= StateStrictWWM;
688 if (
II.Needs & StateStrictWQM)
689 BI.Needs |= StateStrictWQM;
692void SIWholeQuadMode::propagateBlock(MachineBasicBlock &
MBB,
693 std::vector<WorkItem>& Worklist) {
694 BlockInfo BI = Blocks[&
MBB];
699 InstrInfo &LastII = Instructions[LastMI];
700 if ((LastII.OutNeeds | BI.OutNeeds) != LastII.OutNeeds) {
701 LastII.OutNeeds |= BI.OutNeeds;
702 Worklist.emplace_back(LastMI);
708 BlockInfo &PredBI = Blocks[Pred];
709 if ((PredBI.OutNeeds | BI.InNeeds) == PredBI.OutNeeds)
712 PredBI.OutNeeds |= BI.InNeeds;
713 PredBI.InNeeds |= BI.InNeeds;
714 Worklist.emplace_back(Pred);
719 BlockInfo &SuccBI = Blocks[Succ];
720 if ((SuccBI.InNeeds | BI.OutNeeds) == SuccBI.InNeeds)
723 SuccBI.InNeeds |= BI.OutNeeds;
724 Worklist.emplace_back(Succ);
729 std::vector<WorkItem> Worklist;
731 char GlobalFlags = scanInstructions(MF, Worklist, ExeczSideEffectInstrs);
733 while (!Worklist.empty()) {
734 WorkItem WI = Worklist.back();
738 propagateInstruction(*WI.MI, Worklist);
740 propagateBlock(*WI.MBB, Worklist);
742 if (Worklist.empty()) {
748 for (
auto *
MI : ExeczSideEffectInstrs) {
749 InstrInfo
II = Instructions[
MI];
750 if (
II.OutNeeds & StateWQM)
751 markInstructionUses(*
MI, StateWQM, Worklist);
755 ExeczSideEffectInstrs.clear();
763SIWholeQuadMode::saveSCC(MachineBasicBlock &
MBB,
770 MachineInstr *Restore =
781void SIWholeQuadMode::splitBlock(MachineInstr *TermMI) {
782 MachineBasicBlock *BB = TermMI->
getParent();
786 MachineBasicBlock *SplitBB =
787 BB->
splitAt(*TermMI,
true, LIS);
791 unsigned NewOpcode = 0;
793 case AMDGPU::S_AND_B32:
794 NewOpcode = AMDGPU::S_AND_B32_term;
796 case AMDGPU::S_AND_B64:
797 NewOpcode = AMDGPU::S_AND_B64_term;
799 case AMDGPU::S_MOV_B32:
800 NewOpcode = AMDGPU::S_MOV_B32_term;
802 case AMDGPU::S_MOV_B64:
803 NewOpcode = AMDGPU::S_MOV_B64_term;
805 case AMDGPU::S_ANDN2_B32:
806 NewOpcode = AMDGPU::S_ANDN2_B32_term;
808 case AMDGPU::S_ANDN2_B64:
809 NewOpcode = AMDGPU::S_ANDN2_B64_term;
823 for (MachineBasicBlock *Succ : SplitBB->
successors()) {
824 DTUpdates.
push_back({DomTreeT::Insert, SplitBB, Succ});
825 DTUpdates.
push_back({DomTreeT::Delete, BB, Succ});
827 DTUpdates.
push_back({DomTreeT::Insert, BB, SplitBB});
835MachineInstr *SIWholeQuadMode::lowerKillF32(MachineInstr &
MI) {
850 switch (
MI.getOperand(2).getImm()) {
852 Opcode = AMDGPU::V_CMP_LG_F32_e64;
855 Opcode = AMDGPU::V_CMP_GE_F32_e64;
858 Opcode = AMDGPU::V_CMP_GT_F32_e64;
861 Opcode = AMDGPU::V_CMP_LE_F32_e64;
864 Opcode = AMDGPU::V_CMP_LT_F32_e64;
867 Opcode = AMDGPU::V_CMP_EQ_F32_e64;
870 Opcode = AMDGPU::V_CMP_O_F32_e64;
873 Opcode = AMDGPU::V_CMP_U_F32_e64;
877 Opcode = AMDGPU::V_CMP_NEQ_F32_e64;
881 Opcode = AMDGPU::V_CMP_NLT_F32_e64;
885 Opcode = AMDGPU::V_CMP_NLE_F32_e64;
889 Opcode = AMDGPU::V_CMP_NGT_F32_e64;
893 Opcode = AMDGPU::V_CMP_NGE_F32_e64;
897 Opcode = AMDGPU::V_CMP_NLG_F32_e64;
906 MachineInstr *VcmpMI;
907 const MachineOperand &Op0 =
MI.getOperand(0);
908 const MachineOperand &Op1 =
MI.getOperand(1);
924 MachineInstr *MaskUpdateMI =
931 MachineInstr *EarlyTermMI =
934 MachineInstr *ExecMaskMI =
952MachineInstr *SIWholeQuadMode::lowerKillI1(MachineInstr &
MI,
bool IsWQM) {
958 MachineInstr *MaskUpdateMI =
nullptr;
960 const bool IsDemote = IsWQM && (
MI.getOpcode() == AMDGPU::SI_DEMOTE_I1);
961 const MachineOperand &
Op =
MI.getOperand(0);
962 int64_t KillVal =
MI.getOperand(1).getImm();
963 MachineInstr *ComputeKilledMaskMI =
nullptr;
969 if (
Op.getImm() == KillVal) {
976 bool IsLastTerminator = std::next(
MI.getIterator()) ==
MBB.
end();
977 if (!IsLastTerminator) {
1009 MachineInstr *EarlyTermMI =
1014 MachineInstr *NewTerm;
1015 MachineInstr *WQMMaskMI =
nullptr;
1030 }
else if (!IsWQM) {
1048 if (ComputeKilledMaskMI)
1071void SIWholeQuadMode::lowerBlock(MachineBasicBlock &
MBB, BlockInfo &BI) {
1072 if (!BI.NeedsLowering)
1077 SmallVector<MachineInstr *, 4> SplitPoints;
1079 char State = BI.InitialState;
1083 auto MIState = StateTransition.find(&
MI);
1084 if (MIState != StateTransition.end())
1085 State = MIState->second;
1087 MachineInstr *SplitPoint =
nullptr;
1088 switch (
MI.getOpcode()) {
1089 case AMDGPU::SI_DEMOTE_I1:
1090 case AMDGPU::SI_KILL_I1_TERMINATOR:
1091 SplitPoint = lowerKillI1(
MI, State == StateWQM);
1093 case AMDGPU::SI_KILL_F32_COND_IMM_TERMINATOR:
1094 SplitPoint = lowerKillF32(
MI);
1096 case AMDGPU::ENTER_STRICT_WWM:
1097 ActiveLanesReg =
MI.getOperand(0).getReg();
1099 case AMDGPU::EXIT_STRICT_WWM:
1102 case AMDGPU::V_SET_INACTIVE_B32:
1103 if (ActiveLanesReg) {
1104 LiveInterval &LI = LIS->
getInterval(
MI.getOperand(5).getReg());
1106 MI.getOperand(5).setReg(ActiveLanesReg);
1109 assert(State == StateExact || State == StateWQM);
1120 for (MachineInstr *
MI : SplitPoints)
1140 SlotIndex FirstIdx = FirstNonDbg != MBBE
1145 SlotIndex Idx = PreferLast ? LastIdx : FirstIdx;
1146 const LiveRange::Segment *S;
1155 if (
Next < FirstIdx)
1160 assert(EndMI &&
"Segment does not end on valid instruction");
1184 bool IsExecDef =
false;
1185 for (
const MachineOperand &MO :
MBBI->all_defs()) {
1187 MO.getReg() == AMDGPU::EXEC_LO || MO.getReg() == AMDGPU::EXEC;
1201void SIWholeQuadMode::toExact(MachineBasicBlock &
MBB,
1206 bool IsTerminator = Before ==
MBB.
end();
1207 if (!IsTerminator) {
1209 if (FirstTerm !=
MBB.
end()) {
1212 IsTerminator = BeforeIdx > FirstTermIdx;
1233 StateTransition[
MI] = StateExact;
1236void SIWholeQuadMode::toWQM(MachineBasicBlock &
MBB,
1251 StateTransition[
MI] = StateWQM;
1254void SIWholeQuadMode::toStrictMode(MachineBasicBlock &
MBB,
1256 Register SaveOrig,
char StrictStateNeeded) {
1259 assert(StrictStateNeeded == StateStrictWWM ||
1260 StrictStateNeeded == StateStrictWQM);
1264 if (StrictStateNeeded == StateStrictWWM) {
1272 StateTransition[
MI] = StrictStateNeeded;
1275void SIWholeQuadMode::fromStrictMode(MachineBasicBlock &
MBB,
1277 Register SavedOrig,
char NonStrictState,
1278 char CurrentStrictState) {
1282 assert(CurrentStrictState == StateStrictWWM ||
1283 CurrentStrictState == StateStrictWQM);
1287 if (CurrentStrictState == StateStrictWWM) {
1297 StateTransition[
MI] = NonStrictState;
1300void SIWholeQuadMode::processBlock(MachineBasicBlock &
MBB, BlockInfo &BI,
1304 if (!IsEntry && BI.Needs == StateWQM && BI.OutNeeds != StateExact) {
1305 BI.InitialState = StateWQM;
1314 bool WQMFromExec = IsEntry;
1315 char State = (IsEntry || !(BI.InNeeds & StateWQM)) ? StateExact : StateWQM;
1316 char NonStrictState = 0;
1322 if (
II != IE &&
II->getOpcode() == AMDGPU::COPY &&
1323 II->getOperand(1).getReg() == LMC.
ExecReg)
1338 BI.InitialState = State;
1340 for (
unsigned Idx = 0;; ++Idx) {
1342 char Needs = StateExact | StateWQM;
1348 if (FirstStrict == IE)
1352 if (IsEntry && Idx == 0 && (BI.InNeeds & StateWQM))
1358 MachineInstr &
MI = *
II;
1360 if (
MI.isTerminator() ||
TII->mayReadEXEC(*MRI,
MI)) {
1361 auto III = Instructions.find(&
MI);
1362 if (III != Instructions.end()) {
1363 if (III->second.Needs & StateStrictWWM)
1364 Needs = StateStrictWWM;
1365 else if (III->second.Needs & StateStrictWQM)
1366 Needs = StateStrictWQM;
1367 else if (III->second.Needs & StateWQM)
1370 Needs &= ~III->second.Disabled;
1371 OutNeeds = III->second.OutNeeds;
1376 Needs = StateExact | StateWQM | StateStrict;
1380 if (
MI.isBranch() && OutNeeds == StateExact)
1386 if (BI.OutNeeds & StateWQM)
1388 else if (BI.OutNeeds == StateExact)
1391 Needs = StateWQM | StateExact;
1395 if (!(Needs & State)) {
1397 if (State == StateStrictWWM || Needs == StateStrictWWM ||
1398 State == StateStrictWQM || Needs == StateStrictWQM) {
1400 First = FirstStrict;
1407 bool SaveSCC =
false;
1410 case StateStrictWWM:
1411 case StateStrictWQM:
1415 SaveSCC = (Needs & StateStrict) || ((Needs & StateWQM) && WQMFromExec);
1419 SaveSCC = !(Needs & StateWQM);
1425 char StartState = State & StateStrict ? NonStrictState : State;
1427 StartState == StateWQM && (Needs & StateExact) && !(Needs & StateWQM);
1428 bool ExactToWQM = StartState == StateExact && (Needs & StateWQM) &&
1429 !(Needs & StateExact);
1430 bool PreferLast = Needs == StateWQM;
1435 if ((WQMToExact && (OutNeeds & StateWQM)) || ExactToWQM) {
1437 if (
TII->hasUnwantedEffectsWhenEXECEmpty(*
I)) {
1438 PreferLast = WQMToExact;
1444 prepareInsertion(
MBB,
First,
II, PreferLast, SaveSCC);
1446 if (State & StateStrict) {
1447 assert(State == StateStrictWWM || State == StateStrictWQM);
1448 assert(SavedNonStrictReg);
1449 fromStrictMode(
MBB, Before, SavedNonStrictReg, NonStrictState, State);
1452 SavedNonStrictReg = 0;
1453 State = NonStrictState;
1456 if (Needs & StateStrict) {
1457 NonStrictState = State;
1458 assert(Needs == StateStrictWWM || Needs == StateStrictWQM);
1459 assert(!SavedNonStrictReg);
1462 toStrictMode(
MBB, Before, SavedNonStrictReg, Needs);
1466 if (!WQMFromExec && (OutNeeds & StateWQM)) {
1471 toExact(
MBB, Before, SavedWQMReg);
1473 }
else if (ExactToWQM) {
1474 assert(WQMFromExec == (SavedWQMReg == 0));
1476 toWQM(
MBB, Before, SavedWQMReg);
1492 if (Needs != (StateExact | StateWQM | StateStrict)) {
1493 if (Needs != (StateExact | StateWQM))
1504 assert(!SavedNonStrictReg);
1507bool SIWholeQuadMode::lowerLiveMaskQueries() {
1508 for (MachineInstr *
MI : LiveMaskQueries) {
1512 MachineInstr *
Copy =
1517 MI->eraseFromParent();
1519 return !LiveMaskQueries.empty();
1522bool SIWholeQuadMode::lowerCopyInstrs() {
1523 for (MachineInstr *
MI : LowerToMovInstrs) {
1524 assert(
MI->getNumExplicitOperands() == 2);
1529 TRI->getRegClassForOperandReg(*MRI,
MI->getOperand(0));
1530 if (
TRI->isVGPRClass(regClass)) {
1531 const unsigned MovOp =
TII->getMovOpcode(regClass);
1532 MI->setDesc(
TII->get(MovOp));
1536 assert(
any_of(
MI->implicit_operands(), [](
const MachineOperand &MO) {
1537 return MO.isUse() && MO.getReg() == AMDGPU::EXEC;
1543 if (
MI->getOperand(0).isEarlyClobber()) {
1545 MI->getOperand(0).setIsEarlyClobber(
false);
1548 int Index =
MI->findRegisterUseOperandIdx(AMDGPU::EXEC,
nullptr);
1549 while (Index >= 0) {
1550 MI->removeOperand(Index);
1551 Index =
MI->findRegisterUseOperandIdx(AMDGPU::EXEC,
nullptr);
1553 MI->setDesc(
TII->get(AMDGPU::COPY));
1557 for (MachineInstr *
MI : LowerToCopyInstrs) {
1560 if (
MI->getOpcode() == AMDGPU::V_SET_INACTIVE_B32) {
1561 assert(
MI->getNumExplicitOperands() == 6);
1563 LiveInterval *RecomputeLI =
nullptr;
1564 if (
MI->getOperand(4).isReg())
1565 RecomputeLI = &LIS->
getInterval(
MI->getOperand(4).getReg());
1567 MI->removeOperand(5);
1568 MI->removeOperand(4);
1569 MI->removeOperand(3);
1570 MI->removeOperand(1);
1575 assert(
MI->getNumExplicitOperands() == 2);
1578 unsigned CopyOp =
MI->getOperand(1).isReg()
1579 ? (unsigned)AMDGPU::COPY
1580 :
TII->getMovOpcode(
TRI->getRegClassForOperandReg(
1581 *MRI,
MI->getOperand(0)));
1582 MI->setDesc(
TII->get(CopyOp));
1585 return !LowerToCopyInstrs.empty() || !LowerToMovInstrs.empty();
1588bool SIWholeQuadMode::lowerKillInstrs(
bool IsWQM) {
1589 for (MachineInstr *
MI : KillInstrs) {
1590 MachineInstr *SplitPoint =
nullptr;
1591 switch (
MI->getOpcode()) {
1592 case AMDGPU::SI_DEMOTE_I1:
1593 case AMDGPU::SI_KILL_I1_TERMINATOR:
1594 SplitPoint = lowerKillI1(*
MI, IsWQM);
1596 case AMDGPU::SI_KILL_F32_COND_IMM_TERMINATOR:
1597 SplitPoint = lowerKillF32(*
MI);
1603 return !KillInstrs.empty();
1606void SIWholeQuadMode::lowerInitExec(MachineInstr &
MI) {
1609 if (
MI.getOpcode() == AMDGPU::SI_INIT_WHOLE_WAVE) {
1611 "init whole wave not in entry block");
1624 MI.eraseFromParent();
1633 if (
MI.getOpcode() == AMDGPU::SI_INIT_EXEC) {
1637 .
addImm(
MI.getOperand(0).getImm());
1642 MI.eraseFromParent();
1653 Register InputReg =
MI.getOperand(0).getReg();
1654 MachineInstr *FirstMI = &*
MBB->
begin();
1656 MachineInstr *DefInstr = MRI->
getVRegDef(InputReg);
1659 if (DefInstr != FirstMI) {
1678 auto BfeMI =
BuildMI(*
MBB, FirstMI,
DL,
TII->get(AMDGPU::S_BFE_U32), CountReg)
1680 .
addImm((
MI.getOperand(1).getImm() & Mask) | 0x70000);
1684 auto CmpMI =
BuildMI(*
MBB, FirstMI,
DL,
TII->get(AMDGPU::S_CMP_EQ_U32))
1685 .
addReg(CountReg, RegState::Kill)
1691 MI.eraseFromParent();
1696 MI.eraseFromParent();
1711SIWholeQuadMode::lowerInitExecInstrs(MachineBasicBlock &Entry,
bool &
Changed) {
1714 for (MachineInstr *
MI : InitExecInstrs) {
1718 if (
MI->getParent() == &Entry)
1719 InsertPt = std::next(
MI->getIterator());
1730 <<
" ------------- \n");
1733 Instructions.clear();
1735 LiveMaskQueries.clear();
1736 LowerToCopyInstrs.clear();
1737 LowerToMovInstrs.clear();
1739 InitExecInstrs.clear();
1740 SetInactiveInstrs.
clear();
1741 StateTransition.clear();
1752 const bool HasLiveMaskQueries = !LiveMaskQueries.empty();
1753 const bool HasWaveModes = GlobalFlags & ~StateExact;
1754 const bool HasKills = !KillInstrs.empty();
1755 const bool UsesWQM = GlobalFlags & StateWQM;
1756 if (HasKills || UsesWQM || (HasWaveModes && HasLiveMaskQueries)) {
1767 for (MachineInstr *
MI : SetInactiveInstrs) {
1768 if (LowerToCopyInstrs.contains(
MI))
1770 auto &
Info = Instructions[
MI];
1771 if (
Info.MarkedStates & StateStrict) {
1772 Info.Needs |= StateStrictWWM;
1773 Info.Disabled &= ~StateStrictWWM;
1774 Blocks[
MI->getParent()].Needs |= StateStrictWWM;
1777 LowerToCopyInstrs.insert(
MI);
1783 Changed |= lowerLiveMaskQueries();
1786 if (!HasWaveModes) {
1788 Changed |= lowerKillInstrs(
false);
1789 }
else if (GlobalFlags == StateWQM) {
1795 lowerKillInstrs(
true);
1799 if (GlobalFlags & StateWQM)
1800 Blocks[&
Entry].InNeeds |= StateWQM;
1802 for (
auto &BII : Blocks)
1803 processBlock(*BII.first, BII.second, BII.first == &Entry);
1805 for (
auto &BII : Blocks)
1806 lowerBlock(*BII.first, BII.second);
1811 if (LiveMaskReg != LMC.
ExecReg)
1820 if (!KillInstrs.empty() || !InitExecInstrs.empty())
1826bool SIWholeQuadModeLegacy::runOnMachineFunction(
MachineFunction &MF) {
1827 LiveIntervals *LIS = &getAnalysis<LiveIntervalsWrapperPass>().getLIS();
1828 auto *MDTWrapper = getAnalysisIfAvailable<MachineDominatorTreeWrapperPass>();
1829 MachineDominatorTree *MDT = MDTWrapper ? &MDTWrapper->getDomTree() :
nullptr;
1831 getAnalysisIfAvailable<MachinePostDominatorTreeWrapperPass>();
1832 MachinePostDominatorTree *PDT =
1833 PDTWrapper ? &PDTWrapper->getPostDomTree() :
nullptr;
1834 SIWholeQuadMode Impl(MF, LIS, MDT, PDT);
1835 return Impl.run(MF);
1848 SIWholeQuadMode Impl(MF, LIS, MDT, PDT);
MachineInstrBuilder & UseMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static void analyzeFunction(Function &Fn, const DataLayout &Layout, FunctionVarLocsBuilder *FnVarLocs)
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
AMD GCN specific subclass of TargetSubtarget.
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
Promote Memory to Register
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
static void splitBlock(MachineBasicBlock &MBB, MachineInstr &MI, MachineDominatorTree *MDT, MachineLoopInfo *MLI)
SI Optimize VGPR LiveRange
unsigned getWavefrontSize() const
const unsigned AndSaveExecTermOpc
const unsigned AndTermOpc
static const LaneMaskConstants & get(const GCNSubtarget &ST)
const unsigned OrSaveExecOpc
const unsigned AndSaveExecOpc
PassT::Result * getCachedResult(IRUnitT &IR) const
Get the cached result of an analysis pass for a given IR unit.
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.
void applyUpdates(ArrayRef< UpdateType > Updates)
Inform the dominator tree about a sequence of CFG edge insertions and deletions and perform a batch u...
FunctionPass class - This class is used to implement most global optimizations.
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
void removeAllRegUnitsForPhysReg(MCRegister Reg)
Remove associated live ranges for the register units associated with Reg.
MachineInstr * getInstructionFromIndex(SlotIndex index) const
Returns the instruction associated with the given index.
SlotIndex InsertMachineInstrInMaps(MachineInstr &MI)
LLVM_ABI void handleMove(MachineInstr &MI, bool UpdateFlags=false)
Call this method to notify LiveIntervals that instruction MI has been moved within a basic block.
SlotIndex getInstructionIndex(const MachineInstr &Instr) const
Returns the base index of the given instruction.
void RemoveMachineInstrFromMaps(MachineInstr &MI)
SlotIndex getMBBEndIdx(const MachineBasicBlock *mbb) const
Return the last index in the given basic block.
LiveInterval & getInterval(Register Reg)
void removeInterval(Register Reg)
Interval removal.
LiveRange & getRegUnit(MCRegUnit Unit)
Return the live range for register unit Unit.
LLVM_ABI bool shrinkToUses(LiveInterval *li, SmallVectorImpl< MachineInstr * > *dead=nullptr)
After removing some uses of a register, shrink its live range to just the remaining uses.
MachineBasicBlock * getMBBFromIndex(SlotIndex index) const
LiveInterval & createAndComputeVirtRegInterval(Register Reg)
SlotIndex ReplaceMachineInstrInMaps(MachineInstr &MI, MachineInstr &NewMI)
VNInfo * valueIn() const
Return the value that is live-in to the instruction.
This class represents the liveness of a register, stack slot, etc.
const Segment * getSegmentContaining(SlotIndex Idx) const
Return the segment that contains the specified index, or null if there is none.
LiveQueryResult Query(SlotIndex Idx) const
Query Liveness at Idx.
VNInfo * getVNInfoBefore(SlotIndex Idx) const
getVNInfoBefore - Return the VNInfo that is live up to but not necessarily including Idx,...
static MCRegister from(unsigned Val)
Check the provided unsigned value is a valid MCRegister.
An RAII based helper class to modify MachineFunctionProperties when running pass.
LLVM_ABI instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
succ_iterator succ_begin()
MachineInstr * remove(MachineInstr *I)
Remove the unbundled instruction from the instruction list without deleting it.
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
unsigned succ_size() const
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
LLVM_ABI DebugLoc findDebugLoc(instr_iterator MBBI)
Find the next valid DebugLoc starting at MBBI, skipping any debug instructions.
pred_iterator pred_begin()
LLVM_ABI MachineBasicBlock * splitAt(MachineInstr &SplitInst, bool UpdateLiveIns=true, LiveIntervals *LIS=nullptr)
Split a basic block into 2 pieces at SplitPoint.
instr_iterator instr_end()
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
iterator_range< succ_iterator > successors()
reverse_iterator rbegin()
iterator_range< pred_iterator > predecessors()
MachineInstrBundleIterator< MachineInstr > iterator
Analysis pass which computes a MachineDominatorTree.
Analysis pass which computes a MachineDominatorTree.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
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.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
void dump() const
dump - Print the current MachineFunction to cerr, useful for debugger use.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineBasicBlock & front() const
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
LLVM_ABI MachineInstr * removeFromParent()
Unlink 'this' from the containing basic block, and return it without deleting it.
const MachineBasicBlock * getParent() const
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
Register getReg() const
getReg - Returns the register number.
MachinePostDominatorTree - an analysis pass wrapper for DominatorTree used to compute the post-domina...
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
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 LaneBitmask getMaxLaneMaskForVReg(Register Reg) const
Returns a mask covering all bits that can appear in lane masks of subregisters of the virtual registe...
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.
This class implements a map that also provides access to all stored values in a deterministic order.
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.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
Wrapper class representing virtual and physical registers.
MCRegister asMCReg() const
Utility to check-convert this value to a MCRegister.
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)
SlotIndex getBaseIndex() const
Returns the base index for associated with this index.
A SetVector that performs no allocations if smaller than a certain size.
size_type count(const T &V) const
count - Return 1 if the element is in the set, 0 otherwise.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Wrapper class representing a virtual register or register unit.
constexpr bool isVirtualReg() const
constexpr Register asVirtualReg() const
self_iterator getIterator()
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char WavefrontSize[]
Key for Kernel::CodeProps::Metadata::mWavefrontSize.
LLVM_READONLY int32_t getVOPe32(uint32_t Opcode)
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
Flag
These should be considered private to the implementation of the MCInstrDesc class.
NodeAddr< PhiNode * > Phi
This is an optimization pass for GlobalISel generic memory operations.
IterT next_nodbg(IterT It, IterT End, bool SkipPseudoOp=true)
Increment It, then continue incrementing it while it points to a debug instruction.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
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
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
IterT skipDebugInstructionsForward(IterT It, IterT End, bool SkipPseudoOp=true)
Increment It until it points to a non-debug instruction or to End and return the resulting iterator.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
DominatorTreeBase< T, false > DomTreeBase
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...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
FunctionPass * createSIWholeQuadModeLegacyPass()
DWARFExpression::Operation Op
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
@ Disabled
Don't do any conversion of .debug_str_offsets tables.
LLVM_ABI Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.
MCRegisterClass TargetRegisterClass
WorkItem(const BasicBlock *BB, int St)
static constexpr LaneBitmask getAll()
constexpr bool any() const
static constexpr LaneBitmask getNone()