44#ifndef LLVM_ADT_GENERICUNIFORMITYIMPL_H
45#define LLVM_ADT_GENERICUNIFORMITYIMPL_H
56#define DEBUG_TYPE "uniformity"
88 using BlockT =
typename ContextT::BlockT;
93 using CycleT =
typename CycleInfoT::CycleT;
108 POIndex[&BB] = m_order.
size();
111 <<
"): " << Context.print(&BB) <<
"\n");
113 ReducibleCycleHeaders.
insert(&BB);
118 return POIndex.
lookup(BB);
122 return ReducibleCycleHeaders.
contains(BB);
129 const ContextT &Context;
139template <
typename>
class DivergencePropagator;
261 using BlockT =
typename ContextT::BlockT;
268 using CycleT =
typename CycleInfoT::CycleT;
318 CachedControlDivDescs;
329 using BlockT =
typename ContextT::BlockT;
333 using UseT =
typename ContextT::UseT;
338 using CycleT =
typename CycleInfoT::CycleT;
342 typename SyncDependenceAnalysisT::DivergenceDescriptor;
382 if (
I.isTerminator()) {
445 void taintAndPushAllDefs(
const BlockT &JoinBlock);
449 void taintAndPushPhiNodes(
const BlockT &JoinBlock);
454 void propagateCycleExitDivergence(
const BlockT &DivExit,
458 void analyzeCycleExitDivergence(
const CycleT &DefCycle);
471 bool isTemporalDivergent(
const BlockT &ObservingBlock,
475template <
typename ImplT>
483 using BlockT =
typename ContextT::BlockT;
489 using CycleT =
typename CycleInfoT::CycleT;
494 typename SyncDependenceAnalysisT::DivergenceDescriptor;
510 std::unique_ptr<DivergenceDescriptorT>
DivDesc;
520 Out <<
"Propagator::BlockLabels {\n";
521 for (
int BlockIdx = (
int)
CyclePOT.size() - 1; BlockIdx >= 0; --BlockIdx) {
524 Out <<
Context.print(
Block) <<
"(" << BlockIdx <<
") : ";
528 Out <<
Context.print(Label) <<
"\n";
540 <<
"\tpushed label: " <<
Context.print(&PushedLabel)
542 <<
"\told label: " <<
Context.print(OldLabel) <<
"\n");
545 if (OldLabel == &PushedLabel)
548 if (OldLabel != &SuccBlock) {
549 auto SuccIdx =
CyclePOT.getIndex(&SuccBlock);
578 DivDesc->CycleDivBlocks.insert(&ExitBlock);
590 DivDesc->JoinDivBlocks.insert(&SuccBlock);
604 const BlockT *FloorLabel =
nullptr;
610 if (DivTermCycle && !DivTermCycle->contains(SuccBlock)) {
614 DivDesc->CycleDivBlocks.insert(SuccBlock);
616 <<
Context.print(SuccBlock) <<
"\n");
618 auto SuccIdx =
CyclePOT.getIndex(SuccBlock);
620 FloorIdx = std::min<int>(FloorIdx, SuccIdx);
625 if (BlockIdx == -1 || BlockIdx < FloorIdx)
631 if (BlockIdx == DivTermIdx) {
638 << BlockIdx <<
"\n");
643 bool CausedJoin =
false;
644 int LoweredFloorIdx = FloorIdx;
664 const auto *BlockCycle =
CI.getCycle(
Block);
670 if (
const auto *BlockCycle = getReducibleParent(
Block)) {
672 BlockCycle->getExitBlocks(BlockCycleExits);
673 for (
auto *BlockCycleExit : BlockCycleExits) {
676 std::min<int>(LoweredFloorIdx,
CyclePOT.getIndex(BlockCycleExit));
680 CausedJoin |=
visitEdge(*SuccBlock, *Label);
682 std::min<int>(LoweredFloorIdx,
CyclePOT.getIndex(SuccBlock));
689 FloorIdx = LoweredFloorIdx;
690 }
else if (FloorLabel != Label) {
693 FloorIdx = LoweredFloorIdx;
714 for (
const auto *Exit : Exits) {
717 DivDesc->CycleDivBlocks.insert(Exit);
728template <
typename ContextT>
732template <
typename ContextT>
735 : CyclePO(Context), DT(DT), CI(CI) {
739template <
typename ContextT>
744 return EmptyDivergenceDesc;
748 auto ItCached = CachedControlDivDescs.find(DivTermBlock);
749 if (ItCached != CachedControlDivDescs.end())
750 return *ItCached->second;
760 for (
const auto *BB :
Blocks) {
761 Out << LS << CI.getSSAContext().
print(BB);
768 dbgs() <<
"\nResult (" << CI.getSSAContext().print(DivTermBlock)
769 <<
"):\n JoinDivBlocks: " << printBlockSet(DivDesc->JoinDivBlocks)
770 <<
" CycleDivBlocks: " << printBlockSet(DivDesc->CycleDivBlocks)
775 CachedControlDivDescs.try_emplace(DivTermBlock, std::move(DivDesc));
776 assert(ItInserted.second);
777 return *ItInserted.first->second;
780template <
typename ContextT>
783 if (isAlwaysUniform(
I))
786 if (
I.isTerminator()) {
787 Marked = DivergentTermBlocks.insert(
I.getParent()).second;
790 << Context.print(
I.getParent()) <<
"\n");
793 Marked = markDefsDivergent(
I);
797 Worklist.push_back(&
I);
800template <
typename ContextT>
803 if (DivergentValues.insert(Val).second) {
804 LLVM_DEBUG(
dbgs() <<
"marked divergent: " << Context.print(Val) <<
"\n");
810template <
typename ContextT>
813 UniformOverrides.insert(&Instr);
829template <
typename ContextT>
831 const CycleT &DefCycle) {
833 DefCycle.getExitBlocks(Exits);
834 for (
auto *Exit : Exits) {
835 for (
auto &Phi : Exit->phis()) {
836 if (usesValueFromCycle(Phi, DefCycle)) {
842 for (
auto *BB : DefCycle.blocks()) {
844 [&](BlockT *Exit) {
return DT.
dominates(BB, Exit); }))
846 for (
auto &
II : *BB) {
847 propagateTemporalDivergence(
II, DefCycle);
852template <
typename ContextT>
853void GenericUniformityAnalysisImpl<ContextT>::propagateCycleExitDivergence(
854 const BlockT &DivExit,
const CycleT &InnerDivCycle) {
855 LLVM_DEBUG(
dbgs() <<
"\tpropCycleExitDiv " << Context.print(&DivExit)
857 auto *DivCycle = &InnerDivCycle;
858 auto *OuterDivCycle = DivCycle;
859 auto *ExitLevelCycle = CI.getCycle(&DivExit);
860 const unsigned CycleExitDepth =
861 ExitLevelCycle ? ExitLevelCycle->getDepth() : 0;
864 while (DivCycle && DivCycle->getDepth() > CycleExitDepth) {
866 << Context.print(DivCycle->getHeader()) <<
"\n");
867 OuterDivCycle = DivCycle;
868 DivCycle = DivCycle->getParentCycle();
871 << Context.print(OuterDivCycle->getHeader()) <<
"\n");
873 if (!DivergentExitCycles.insert(OuterDivCycle).second)
878 for (
const auto *
C : AssumedDivergent) {
879 if (
C->contains(OuterDivCycle))
883 analyzeCycleExitDivergence(*OuterDivCycle);
886template <
typename ContextT>
887void GenericUniformityAnalysisImpl<ContextT>::taintAndPushAllDefs(
889 LLVM_DEBUG(
dbgs() <<
"taintAndPushAllDefs " << Context.print(&BB) <<
"\n");
890 for (
const auto &
I :
instrs(BB)) {
894 if (
I.isTerminator())
902template <
typename ContextT>
903void GenericUniformityAnalysisImpl<ContextT>::taintAndPushPhiNodes(
904 const BlockT &JoinBlock) {
905 LLVM_DEBUG(
dbgs() <<
"taintAndPushPhiNodes in " << Context.print(&JoinBlock)
907 for (
const auto &Phi : JoinBlock.phis()) {
915 if (ContextT::isConstantOrUndefValuePhi(Phi))
924template <
typename CycleT>
928 [Candidate](CycleT *
C) {
return C->contains(Candidate); }))
939template <
typename CycleT,
typename BlockT>
941 const BlockT *DivTermBlock,
942 const BlockT *JoinBlock) {
949 const auto *OriginalCycle =
Cycle;
951 while (Parent && !Parent->contains(DivTermBlock)) {
967 LLVM_DEBUG(
dbgs() <<
"cycle made divergent by external branch\n");
975template <
typename ContextT,
typename CycleT,
typename BlockT,
976 typename DominatorTreeT>
979 const BlockT *JoinBlock,
const DominatorTreeT &DT,
982 <<
" for internal branch " << Context.print(DivTermBlock)
999 <<
" does not dominate join\n");
1003 LLVM_DEBUG(
dbgs() <<
" header " << Context.print(Parent->getHeader())
1004 <<
" does not dominate join\n");
1009 LLVM_DEBUG(
dbgs() <<
" cycle made divergent by internal branch\n");
1013template <
typename ContextT,
typename CycleT,
typename BlockT,
1014 typename DominatorTreeT>
1015static const CycleT *
1017 const BlockT *JoinBlock,
const DominatorTreeT &DT,
1018 ContextT &Context) {
1034template <
typename ContextT>
1035bool GenericUniformityAnalysisImpl<ContextT>::isTemporalDivergent(
1036 const BlockT &ObservingBlock,
const InstructionT &Def)
const {
1037 const BlockT *DefBlock = Def.getParent();
1038 for (
const CycleT *
Cycle = CI.getCycle(DefBlock);
1041 if (DivergentExitCycles.contains(
Cycle)) {
1048template <
typename ContextT>
1051 const auto *DivTermBlock = Term.getParent();
1052 DivergentTermBlocks.insert(DivTermBlock);
1053 LLVM_DEBUG(
dbgs() <<
"analyzeControlDiv " << Context.print(DivTermBlock)
1060 const auto &DivDesc = SDA.getJoinBlocks(DivTermBlock);
1064 for (
const auto *JoinBlock : DivDesc.JoinDivBlocks) {
1065 const auto *
Cycle = CI.getCycle(JoinBlock);
1066 LLVM_DEBUG(
dbgs() <<
"visiting join block " << Context.print(JoinBlock)
1069 Cycle, DivTermBlock, JoinBlock, DT, Context)) {
1074 taintAndPushPhiNodes(*JoinBlock);
1080 return A->getDepth() >
B->getDepth();
1088 for (
auto *
C : DivCycles) {
1092 for (
const BlockT *BB :
C->blocks()) {
1093 taintAndPushAllDefs(*BB);
1097 const auto *BranchCycle = CI.getCycle(DivTermBlock);
1098 assert(DivDesc.CycleDivBlocks.empty() || BranchCycle);
1099 for (
const auto *DivExitBlock : DivDesc.CycleDivBlocks) {
1100 propagateCycleExitDivergence(*DivExitBlock, *BranchCycle);
1104template <
typename ContextT>
1107 auto DivValuesCopy = DivergentValues;
1108 for (
const auto DivVal : DivValuesCopy) {
1109 assert(isDivergent(DivVal) &&
"Worklist invariant violated!");
1115 while (!Worklist.empty()) {
1117 Worklist.pop_back();
1121 if (
I->isTerminator()) {
1122 analyzeControlDivergence(*
I);
1127 assert(isDivergent(*
I) &&
"Worklist invariant violated!");
1132template <
typename ContextT>
1135 return UniformOverrides.contains(&Instr);
1138template <
typename ContextT>
1145template <
typename ContextT>
1147 bool haveDivergentArgs =
false;
1152 if (DivergentValues.empty() && DivergentTermBlocks.empty() &&
1153 DivergentExitCycles.empty()) {
1154 OS <<
"ALL VALUES UNIFORM\n";
1158 for (
const auto &entry : DivergentValues) {
1159 const BlockT *parent = Context.getDefBlock(entry);
1161 if (!haveDivergentArgs) {
1162 OS <<
"DIVERGENT ARGUMENTS:\n";
1163 haveDivergentArgs =
true;
1165 OS <<
" DIVERGENT: " << Context.print(entry) <<
'\n';
1169 if (!AssumedDivergent.empty()) {
1170 OS <<
"CYCLES ASSSUMED DIVERGENT:\n";
1171 for (
const CycleT *cycle : AssumedDivergent) {
1172 OS <<
" " << cycle->print(Context) <<
'\n';
1176 if (!DivergentExitCycles.empty()) {
1177 OS <<
"CYCLES WITH DIVERGENT EXIT:\n";
1178 for (
const CycleT *cycle : DivergentExitCycles) {
1179 OS <<
" " << cycle->print(Context) <<
'\n';
1184 OS <<
"\nBLOCK " << Context.print(&
block) <<
'\n';
1186 OS <<
"DEFINITIONS\n";
1188 Context.appendBlockDefs(defs,
block);
1189 for (
auto value : defs) {
1190 if (isDivergent(
value))
1191 OS <<
" DIVERGENT: ";
1194 OS << Context.print(
value) <<
'\n';
1197 OS <<
"TERMINATORS\n";
1199 Context.appendBlockTerms(terms,
block);
1200 bool divergentTerminators = hasDivergentTerminator(
block);
1201 for (
auto *
T : terms) {
1202 if (divergentTerminators)
1203 OS <<
" DIVERGENT: ";
1206 OS << Context.print(
T) <<
'\n';
1209 OS <<
"END BLOCK\n";
1213template <
typename ContextT>
1215 return DA->hasDivergence();
1218template <
typename ContextT>
1219const typename ContextT::FunctionT &
1221 return DA->getFunction();
1225template <
typename ContextT>
1227 return DA->isDivergent(V);
1230template <
typename ContextT>
1232 return DA->isDivergent(*
I);
1235template <
typename ContextT>
1237 return DA->isDivergentUse(U);
1240template <
typename ContextT>
1242 return DA->hasDivergentTerminator(
B);
1246template <
typename ContextT>
1251template <
typename ContextT>
1256 while (!Stack.empty()) {
1257 auto *NextBB = Stack.back();
1258 if (Finalized.
count(NextBB)) {
1262 LLVM_DEBUG(
dbgs() <<
" visiting " << CI.getSSAContext().print(NextBB)
1264 auto *NestedCycle = CI.getCycle(NextBB);
1267 while (NestedCycle->getParentCycle() !=
Cycle)
1268 NestedCycle = NestedCycle->getParentCycle();
1270 SmallVector<BlockT *, 3> NestedExits;
1271 NestedCycle->getExitBlocks(NestedExits);
1272 bool PushedNodes =
false;
1273 for (
auto *NestedExitBB : NestedExits) {
1275 << CI.getSSAContext().print(NestedExitBB) <<
"\n");
1278 if (Finalized.
count(NestedExitBB))
1281 Stack.push_back(NestedExitBB);
1283 << CI.getSSAContext().print(NestedExitBB) <<
"\n");
1288 computeCyclePO(CI, NestedCycle, Finalized);
1295 bool PushedNodes =
false;
1298 << CI.getSSAContext().print(SuccBB) <<
"\n");
1301 if (Finalized.
count(SuccBB))
1304 Stack.push_back(SuccBB);
1305 LLVM_DEBUG(
dbgs() <<
" pushed succ: " << CI.getSSAContext().print(SuccBB)
1311 << CI.getSSAContext().print(NextBB) <<
"\n");
1313 Finalized.
insert(NextBB);
1314 appendBlock(*NextBB);
1320template <
typename ContextT>
1321void ModifiedPostOrder<ContextT>::computeCyclePO(
1322 const CycleInfoT &CI,
const CycleT *
Cycle,
1323 SmallPtrSetImpl<const BlockT *> &Finalized) {
1325 SmallVector<const BlockT *>
Stack;
1329 << CI.getSSAContext().print(CycleHeader) <<
"\n");
1330 assert(!Finalized.count(CycleHeader));
1331 Finalized.insert(CycleHeader);
1335 << CI.getSSAContext().print(CycleHeader) <<
"\n");
1340 LLVM_DEBUG(
dbgs() <<
" examine succ: " << CI.getSSAContext().print(BB)
1344 if (BB == CycleHeader)
1346 if (!Finalized.count(BB)) {
1347 LLVM_DEBUG(
dbgs() <<
" pushed succ: " << CI.getSSAContext().print(BB)
1349 Stack.push_back(BB);
1354 computeStackPO(Stack, CI,
Cycle, Finalized);
1360template <
typename ContextT>
1364 auto *
F = CI.getFunction();
1366 Stack.push_back(&
F->front());
1367 computeStackPO(Stack, CI,
nullptr, Finalized);
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
Given that RA is a live value
This file defines the DenseSet and SmallDenseSet classes.
DenseMap< Block *, BlockRelaxAux > Blocks
uint64_t IntrinsicInst * II
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallPtrSet class.
This file defines the SparseBitVector class.
unify loop Fixup each natural loop to have a single exit block
ValueT lookup(const_arg_type_t< KeyT > Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Implements a dense probed hash-table based set.
Compute divergence starting with a divergent branch.
typename SyncDependenceAnalysisT::BlockLabelMap BlockLabelMapT
const ModifiedPO & CyclePOT
GenericSyncDependenceAnalysis< ContextT > SyncDependenceAnalysisT
typename ContextT::DominatorTreeT DominatorTreeT
bool computeJoin(const BlockT &SuccBlock, const BlockT &PushedLabel)
const BlockT & DivTermBlock
std::unique_ptr< DivergenceDescriptorT > DivDesc
void printDefs(raw_ostream &Out)
typename ContextT::FunctionT FunctionT
GenericCycleInfo< ContextT > CycleInfoT
const DominatorTreeT & DT
ModifiedPostOrder< ContextT > ModifiedPO
std::unique_ptr< DivergenceDescriptorT > computeJoinPoints()
BlockLabelMapT & BlockLabels
SparseBitVector FreshLabels
bool visitCycleExitEdge(const BlockT &ExitBlock, const BlockT &Label)
typename ContextT::ValueRefT ValueRefT
typename ContextT::BlockT BlockT
typename SyncDependenceAnalysisT::DivergenceDescriptor DivergenceDescriptorT
typename CycleInfoT::CycleT CycleT
DivergencePropagator(const ModifiedPO &CyclePOT, const DominatorTreeT &DT, const CycleInfoT &CI, const BlockT &DivTermBlock)
bool visitEdge(const BlockT &SuccBlock, const BlockT &Label)
bool properlyDominates(const DomTreeNodeBase< NodeT > *A, const DomTreeNodeBase< NodeT > *B) const
properlyDominates - Returns true iff A dominates B and A != B.
bool isReachableFromEntry(const Use &U) const
Provide an overload for a Use.
bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
Cycle information for a function.
A possibly irreducible generalization of a Loop.
BlockT * getHeader() const
bool isReducible() const
Whether the cycle is a natural loop.
void getExitBlocks(SmallVectorImpl< BlockT * > &TmpStorage) const
Return all of the successor blocks of this cycle.
bool contains(const BlockT *Block) const
Return whether Block is contained in the cycle.
const GenericCycle * getParentCycle() const
Locate join blocks for disjoint paths starting at a divergent branch.
GenericSyncDependenceAnalysis(const ContextT &Context, const DominatorTreeT &DT, const CycleInfoT &CI)
ModifiedPostOrder< ContextT > ModifiedPO
typename ContextT::DominatorTreeT DominatorTreeT
GenericCycleInfo< ContextT > CycleInfoT
typename ContextT::FunctionT FunctionT
typename ContextT::InstructionT InstructionT
typename ContextT::BlockT BlockT
typename ContextT::ValueRefT ValueRefT
typename CycleInfoT::CycleT CycleT
const DivergenceDescriptor & getJoinBlocks(const BlockT *DivTermBlock)
Computes divergent join points and cycle exits caused by branch divergence in Term.
Construct a specially modified post-order traversal of cycles.
typename ContextT::FunctionT FunctionT
const BlockT * operator[](size_t idx) const
typename CycleInfoT::CycleT CycleT
bool isReducibleCycleHeader(const BlockT *BB) const
ModifiedPostOrder(const ContextT &C)
unsigned count(BlockT *BB) const
void compute(const CycleInfoT &CI)
Generically compute the modified post order.
GenericCycleInfo< ContextT > CycleInfoT
void appendBlock(const BlockT &BB, bool isReducibleCycleHeader=false)
unsigned getIndex(const BlockT *BB) const
typename std::vector< BlockT * >::const_iterator const_iterator
typename ContextT::DominatorTreeT DominatorTreeT
typename ContextT::BlockT BlockT
Simple wrapper around std::function<void(raw_ostream&)>.
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
This class implements an extremely fast bulk output stream that can only output to a stream.
@ C
The default llvm calling convention, compatible with C.
This is an optimization pass for GlobalISel generic memory operations.
static const CycleT * getIntDivCycle(const CycleT *Cycle, const BlockT *DivTermBlock, const BlockT *JoinBlock, const DominatorTreeT &DT, ContextT &Context)
Return the outermost cycle made divergent by branch inside it.
static const CycleT * getExtDivCycle(const CycleT *Cycle, const BlockT *DivTermBlock, const BlockT *JoinBlock)
Return the outermost cycle made divergent by branch outside it.
auto successors(const MachineBasicBlock *BB)
static bool insertIfNotContained(SmallVector< CycleT * > &Cycles, CycleT *Candidate)
Add Candidate to Cycles if it is not already contained in Cycles.
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
void sort(IteratorTy Start, IteratorTy End)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
auto succ_size(const MachineBasicBlock *BB)
auto instrs(const MachineBasicBlock &BB)
static const CycleT * getOutermostDivergentCycle(const CycleT *Cycle, const BlockT *DivTermBlock, const BlockT *JoinBlock, const DominatorTreeT &DT, ContextT &Context)
Information discovered by the sync dependence analysis for each divergent branch.
ConstBlockSet CycleDivBlocks
ConstBlockSet JoinDivBlocks
BlockLabelMap BlockLabels