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 =
955MachineInstr *SIWholeQuadMode::lowerKillI1(MachineInstr &
MI,
bool IsWQM) {
961 MachineInstr *MaskUpdateMI =
nullptr;
963 const bool IsDemote = IsWQM && (
MI.getOpcode() == AMDGPU::SI_DEMOTE_I1);
964 const MachineOperand &
Op =
MI.getOperand(0);
965 int64_t KillVal =
MI.getOperand(1).getImm();
966 MachineInstr *ComputeKilledMaskMI =
nullptr;
972 if (
Op.getImm() == KillVal) {
979 bool IsLastTerminator = std::next(
MI.getIterator()) ==
MBB.
end();
980 if (!IsLastTerminator) {
1013 MachineInstr *EarlyTermMI =
1018 MachineInstr *NewTerm;
1019 MachineInstr *WQMMaskMI =
nullptr;
1036 }
else if (!IsWQM) {
1056 if (ComputeKilledMaskMI)
1079void SIWholeQuadMode::lowerBlock(MachineBasicBlock &
MBB, BlockInfo &BI) {
1080 if (!BI.NeedsLowering)
1085 SmallVector<MachineInstr *, 4> SplitPoints;
1087 char State = BI.InitialState;
1091 auto MIState = StateTransition.find(&
MI);
1092 if (MIState != StateTransition.end())
1093 State = MIState->second;
1095 MachineInstr *SplitPoint =
nullptr;
1096 switch (
MI.getOpcode()) {
1097 case AMDGPU::SI_DEMOTE_I1:
1098 case AMDGPU::SI_KILL_I1_TERMINATOR:
1099 SplitPoint = lowerKillI1(
MI, State == StateWQM);
1101 case AMDGPU::SI_KILL_F32_COND_IMM_TERMINATOR:
1102 SplitPoint = lowerKillF32(
MI);
1104 case AMDGPU::ENTER_STRICT_WWM:
1105 ActiveLanesReg =
MI.getOperand(0).getReg();
1107 case AMDGPU::EXIT_STRICT_WWM:
1110 case AMDGPU::V_SET_INACTIVE_B32:
1111 if (ActiveLanesReg) {
1112 LiveInterval &LI = LIS->
getInterval(
MI.getOperand(5).getReg());
1114 MI.getOperand(5).setReg(ActiveLanesReg);
1117 assert(State == StateExact || State == StateWQM);
1128 for (MachineInstr *
MI : SplitPoints)
1148 SlotIndex FirstIdx = FirstNonDbg != MBBE
1153 SlotIndex Idx = PreferLast ? LastIdx : FirstIdx;
1154 const LiveRange::Segment *S;
1163 if (
Next < FirstIdx)
1168 assert(EndMI &&
"Segment does not end on valid instruction");
1192 bool IsExecDef =
false;
1193 for (
const MachineOperand &MO :
MBBI->all_defs()) {
1195 MO.getReg() == AMDGPU::EXEC_LO || MO.getReg() == AMDGPU::EXEC;
1209void SIWholeQuadMode::toExact(MachineBasicBlock &
MBB,
1214 bool IsTerminator = Before ==
MBB.
end();
1215 if (!IsTerminator) {
1217 if (FirstTerm !=
MBB.
end()) {
1220 IsTerminator = BeforeIdx > FirstTermIdx;
1243 StateTransition[
MI] = StateExact;
1246void SIWholeQuadMode::toWQM(MachineBasicBlock &
MBB,
1262 StateTransition[
MI] = StateWQM;
1265void SIWholeQuadMode::toStrictMode(MachineBasicBlock &
MBB,
1267 Register SaveOrig,
char StrictStateNeeded) {
1270 assert(StrictStateNeeded == StateStrictWWM ||
1271 StrictStateNeeded == StateStrictWQM);
1275 if (StrictStateNeeded == StateStrictWWM) {
1285 StateTransition[
MI] = StrictStateNeeded;
1288void SIWholeQuadMode::fromStrictMode(MachineBasicBlock &
MBB,
1290 Register SavedOrig,
char NonStrictState,
1291 char CurrentStrictState) {
1295 assert(CurrentStrictState == StateStrictWWM ||
1296 CurrentStrictState == StateStrictWQM);
1300 if (CurrentStrictState == StateStrictWWM) {
1310 StateTransition[
MI] = NonStrictState;
1313void SIWholeQuadMode::processBlock(MachineBasicBlock &
MBB, BlockInfo &BI,
1317 if (!IsEntry && BI.Needs == StateWQM && BI.OutNeeds != StateExact) {
1318 BI.InitialState = StateWQM;
1327 bool WQMFromExec = IsEntry;
1328 char State = (IsEntry || !(BI.InNeeds & StateWQM)) ? StateExact : StateWQM;
1329 char NonStrictState = 0;
1335 if (
II != IE &&
II->getOpcode() == AMDGPU::COPY &&
1336 II->getOperand(1).getReg() == LMC.
ExecReg)
1351 BI.InitialState = State;
1353 for (
unsigned Idx = 0;; ++Idx) {
1355 char Needs = StateExact | StateWQM;
1361 if (FirstStrict == IE)
1365 if (IsEntry && Idx == 0 && (BI.InNeeds & StateWQM))
1371 MachineInstr &
MI = *
II;
1373 if (
MI.isTerminator() ||
TII->mayReadEXEC(*MRI,
MI)) {
1374 auto III = Instructions.find(&
MI);
1375 if (III != Instructions.end()) {
1376 if (III->second.Needs & StateStrictWWM)
1377 Needs = StateStrictWWM;
1378 else if (III->second.Needs & StateStrictWQM)
1379 Needs = StateStrictWQM;
1380 else if (III->second.Needs & StateWQM)
1383 Needs &= ~III->second.Disabled;
1384 OutNeeds = III->second.OutNeeds;
1389 Needs = StateExact | StateWQM | StateStrict;
1393 if (
MI.isBranch() && OutNeeds == StateExact)
1399 if (BI.OutNeeds & StateWQM)
1401 else if (BI.OutNeeds == StateExact)
1404 Needs = StateWQM | StateExact;
1408 if (!(Needs & State)) {
1410 if (State == StateStrictWWM || Needs == StateStrictWWM ||
1411 State == StateStrictWQM || Needs == StateStrictWQM) {
1413 First = FirstStrict;
1420 bool SaveSCC =
false;
1423 case StateStrictWWM:
1424 case StateStrictWQM:
1428 SaveSCC = (Needs & StateStrict) || ((Needs & StateWQM) && WQMFromExec);
1432 SaveSCC = !(Needs & StateWQM);
1438 char StartState = State & StateStrict ? NonStrictState : State;
1440 StartState == StateWQM && (Needs & StateExact) && !(Needs & StateWQM);
1441 bool ExactToWQM = StartState == StateExact && (Needs & StateWQM) &&
1442 !(Needs & StateExact);
1443 bool PreferLast = Needs == StateWQM;
1448 if ((WQMToExact && (OutNeeds & StateWQM)) || ExactToWQM) {
1450 if (
TII->hasUnwantedEffectsWhenEXECEmpty(*
I)) {
1451 PreferLast = WQMToExact;
1457 prepareInsertion(
MBB,
First,
II, PreferLast, SaveSCC);
1459 if (State & StateStrict) {
1460 assert(State == StateStrictWWM || State == StateStrictWQM);
1461 assert(SavedNonStrictReg);
1462 fromStrictMode(
MBB, Before, SavedNonStrictReg, NonStrictState, State);
1465 SavedNonStrictReg = 0;
1466 State = NonStrictState;
1469 if (Needs & StateStrict) {
1470 NonStrictState = State;
1471 assert(Needs == StateStrictWWM || Needs == StateStrictWQM);
1472 assert(!SavedNonStrictReg);
1475 toStrictMode(
MBB, Before, SavedNonStrictReg, Needs);
1479 if (!WQMFromExec && (OutNeeds & StateWQM)) {
1484 toExact(
MBB, Before, SavedWQMReg);
1486 }
else if (ExactToWQM) {
1487 assert(WQMFromExec == (SavedWQMReg == 0));
1489 toWQM(
MBB, Before, SavedWQMReg);
1505 if (Needs != (StateExact | StateWQM | StateStrict)) {
1506 if (Needs != (StateExact | StateWQM))
1517 assert(!SavedNonStrictReg);
1520bool SIWholeQuadMode::lowerLiveMaskQueries() {
1521 for (MachineInstr *
MI : LiveMaskQueries) {
1525 MachineInstr *
Copy =
1530 MI->eraseFromParent();
1532 return !LiveMaskQueries.empty();
1535bool SIWholeQuadMode::lowerCopyInstrs() {
1536 for (MachineInstr *
MI : LowerToMovInstrs) {
1537 assert(
MI->getNumExplicitOperands() == 2);
1542 TRI->getRegClassForOperandReg(*MRI,
MI->getOperand(0));
1543 if (
TRI->isVGPRClass(regClass)) {
1544 const unsigned MovOp =
TII->getMovOpcode(regClass);
1545 MI->setDesc(
TII->get(MovOp));
1549 assert(
any_of(
MI->implicit_operands(), [](
const MachineOperand &MO) {
1550 return MO.isUse() && MO.getReg() == AMDGPU::EXEC;
1556 if (
MI->getOperand(0).isEarlyClobber()) {
1558 MI->getOperand(0).setIsEarlyClobber(
false);
1561 int Index =
MI->findRegisterUseOperandIdx(AMDGPU::EXEC,
nullptr);
1562 while (Index >= 0) {
1563 MI->removeOperand(Index);
1564 Index =
MI->findRegisterUseOperandIdx(AMDGPU::EXEC,
nullptr);
1566 MI->setDesc(
TII->get(AMDGPU::COPY));
1570 for (MachineInstr *
MI : LowerToCopyInstrs) {
1573 if (
MI->getOpcode() == AMDGPU::V_SET_INACTIVE_B32) {
1574 assert(
MI->getNumExplicitOperands() == 6);
1576 LiveInterval *RecomputeLI =
nullptr;
1577 if (
MI->getOperand(4).isReg())
1578 RecomputeLI = &LIS->
getInterval(
MI->getOperand(4).getReg());
1580 MI->removeOperand(5);
1581 MI->removeOperand(4);
1582 MI->removeOperand(3);
1583 MI->removeOperand(1);
1588 assert(
MI->getNumExplicitOperands() == 2);
1591 unsigned CopyOp =
MI->getOperand(1).isReg()
1592 ? (unsigned)AMDGPU::COPY
1593 :
TII->getMovOpcode(
TRI->getRegClassForOperandReg(
1594 *MRI,
MI->getOperand(0)));
1595 MI->setDesc(
TII->get(CopyOp));
1598 return !LowerToCopyInstrs.empty() || !LowerToMovInstrs.empty();
1601bool SIWholeQuadMode::lowerKillInstrs(
bool IsWQM) {
1602 for (MachineInstr *
MI : KillInstrs) {
1603 MachineInstr *SplitPoint =
nullptr;
1604 switch (
MI->getOpcode()) {
1605 case AMDGPU::SI_DEMOTE_I1:
1606 case AMDGPU::SI_KILL_I1_TERMINATOR:
1607 SplitPoint = lowerKillI1(*
MI, IsWQM);
1609 case AMDGPU::SI_KILL_F32_COND_IMM_TERMINATOR:
1610 SplitPoint = lowerKillF32(*
MI);
1616 return !KillInstrs.empty();
1619void SIWholeQuadMode::lowerInitExec(MachineInstr &
MI) {
1622 if (
MI.getOpcode() == AMDGPU::SI_INIT_WHOLE_WAVE) {
1624 "init whole wave not in entry block");
1638 MI.eraseFromParent();
1647 if (
MI.getOpcode() == AMDGPU::SI_INIT_EXEC) {
1651 .
addImm(
MI.getOperand(0).getImm());
1656 MI.eraseFromParent();
1667 Register InputReg =
MI.getOperand(0).getReg();
1668 MachineInstr *FirstMI = &*
MBB->
begin();
1670 MachineInstr *DefInstr = MRI->
getVRegDef(InputReg);
1673 if (DefInstr != FirstMI) {
1692 auto BfeMI =
BuildMI(*
MBB, FirstMI,
DL,
TII->get(AMDGPU::S_BFE_U32), CountReg)
1694 .
addImm((
MI.getOperand(1).getImm() & Mask) | 0x70000)
1699 auto CmpMI =
BuildMI(*
MBB, FirstMI,
DL,
TII->get(AMDGPU::S_CMP_EQ_U32))
1700 .
addReg(CountReg, RegState::Kill)
1706 MI.eraseFromParent();
1711 MI.eraseFromParent();
1726SIWholeQuadMode::lowerInitExecInstrs(MachineBasicBlock &Entry,
bool &
Changed) {
1729 for (MachineInstr *
MI : InitExecInstrs) {
1733 if (
MI->getParent() == &Entry)
1734 InsertPt = std::next(
MI->getIterator());
1745 <<
" ------------- \n");
1748 Instructions.clear();
1750 LiveMaskQueries.clear();
1751 LowerToCopyInstrs.clear();
1752 LowerToMovInstrs.clear();
1754 InitExecInstrs.clear();
1755 SetInactiveInstrs.
clear();
1756 StateTransition.clear();
1767 const bool HasLiveMaskQueries = !LiveMaskQueries.empty();
1768 const bool HasWaveModes = GlobalFlags & ~StateExact;
1769 const bool HasKills = !KillInstrs.empty();
1770 const bool UsesWQM = GlobalFlags & StateWQM;
1771 if (HasKills || UsesWQM || (HasWaveModes && HasLiveMaskQueries)) {
1782 for (MachineInstr *
MI : SetInactiveInstrs) {
1783 if (LowerToCopyInstrs.contains(
MI))
1785 auto &
Info = Instructions[
MI];
1786 if (
Info.MarkedStates & StateStrict) {
1787 Info.Needs |= StateStrictWWM;
1788 Info.Disabled &= ~StateStrictWWM;
1789 Blocks[
MI->getParent()].Needs |= StateStrictWWM;
1792 LowerToCopyInstrs.insert(
MI);
1798 Changed |= lowerLiveMaskQueries();
1801 if (!HasWaveModes) {
1803 Changed |= lowerKillInstrs(
false);
1804 }
else if (GlobalFlags == StateWQM) {
1811 lowerKillInstrs(
true);
1815 if (GlobalFlags & StateWQM)
1816 Blocks[&
Entry].InNeeds |= StateWQM;
1818 for (
auto &BII : Blocks)
1819 processBlock(*BII.first, BII.second, BII.first == &Entry);
1821 for (
auto &BII : Blocks)
1822 lowerBlock(*BII.first, BII.second);
1827 if (LiveMaskReg != LMC.
ExecReg)
1836 if (!KillInstrs.empty() || !InitExecInstrs.empty())
1842bool SIWholeQuadModeLegacy::runOnMachineFunction(
MachineFunction &MF) {
1843 LiveIntervals *LIS = &getAnalysis<LiveIntervalsWrapperPass>().getLIS();
1844 auto *MDTWrapper = getAnalysisIfAvailable<MachineDominatorTreeWrapperPass>();
1845 MachineDominatorTree *MDT = MDTWrapper ? &MDTWrapper->getDomTree() :
nullptr;
1847 getAnalysisIfAvailable<MachinePostDominatorTreeWrapperPass>();
1848 MachinePostDominatorTree *PDT =
1849 PDTWrapper ? &PDTWrapper->getPostDomTree() :
nullptr;
1850 SIWholeQuadMode Impl(MF, LIS, MDT, PDT);
1851 return Impl.run(MF);
1864 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 & setOperandDead(unsigned OpIdx) 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()