44#ifndef LLVM_ADT_GENERICUNIFORMITYIMPL_H
45#define LLVM_ADT_GENERICUNIFORMITYIMPL_H
57#define DEBUG_TYPE "uniformity"
92 using BlockT =
typename ContextT::BlockT;
101 bool empty()
const {
return Order.empty(); }
102 size_t size()
const {
return Order.size(); }
109 return Num < POIndex.size() && POIndex[Num] != InvalidIndex;
115 POIndex[Num] = Order.size();
116 Order.push_back(&BB);
118 <<
"): " << Context.print(&BB) <<
"\n");
119 if (IsReducibleCycleHeader)
120 ReducibleCycleHeaders.insert(&BB);
125 assert(Num < POIndex.size() && POIndex[Num] != InvalidIndex);
130 return ReducibleCycleHeaders.contains(BB);
139 const ContextT &Context;
149template <
typename>
class DivergencePropagator;
271 using BlockT =
typename ContextT::BlockT;
316 CachedControlDivDescs;
327 using BlockT =
typename ContextT::BlockT;
331 using UseT =
typename ContextT::UseT;
339 typename SyncDependenceAnalysisT::DivergenceDescriptor;
342 std::tuple<ConstValueRefT, InstructionT *, CycleRef>;
381 assert(
I.isTerminator() &&
"Expected a terminator instruction!");
396 if (ContextT::isAlwaysUniform(V))
473 void taintAndPushAllDefs(
const BlockT &JoinBlock);
477 void taintAndPushPhiNodes(
const BlockT &JoinBlock);
482 void propagateCycleExitDivergence(
const BlockT &DivExit,
CycleRef DivCycle);
485 void analyzeCycleExitDivergence(
CycleRef DefCycle);
497 bool isTemporalDivergent(
const BlockT &ObservingBlock,
501template <
typename ImplT>
509 using BlockT =
typename ContextT::BlockT;
519 typename SyncDependenceAnalysisT::DivergenceDescriptor;
534 std::unique_ptr<DivergenceDescriptorT>
DivDesc;
558 Out <<
"Propagator::BlockLabels {\n";
559 for (
int BlockIdx = (
int)
CyclePOT.size() - 1; BlockIdx >= 0; --BlockIdx) {
562 Out <<
Context.print(
Block) <<
"(" << BlockIdx <<
") : ";
566 Out <<
Context.print(Label) <<
"\n";
575 const auto *OldLabel =
label(&SuccBlock);
578 <<
"\tpushed label: " <<
Context.print(&PushedLabel)
580 <<
"\told label: " <<
Context.print(OldLabel) <<
"\n");
583 if (OldLabel == &PushedLabel)
586 if (OldLabel != &SuccBlock) {
587 auto SuccIdx =
CyclePOT.getIndex(&SuccBlock);
597 label(&SuccBlock) = &PushedLabel;
604 label(&SuccBlock) = &SuccBlock;
616 DivDesc->CycleDivBlocks.insert(&ExitBlock);
628 DivDesc->JoinDivBlocks.insert(&SuccBlock);
649 if (
CI.isReducible(
C))
652 if (
CI.isReducible(
P))
663 if (DivTermCycle && !
CI.contains(DivTermCycle, SuccBlock)) {
667 DivDesc->CycleDivBlocks.insert(SuccBlock);
669 <<
Context.print(SuccBlock) <<
"\n");
688 (!IrreducibleAncestor || !
CI.contains(IrreducibleAncestor,
Block)))
694 if (BlockIdx == DivTermIdx) {
700 << BlockIdx <<
"\n");
725 CI.getExitBlocks(BlockCycle, BlockCycleExits);
727 for (
auto *BlockCycleExit : BlockCycleExits) {
745 if (
CI.isReducible(
C)) {
751 CI.getExitBlocks(
C, Exits);
752 auto *Header =
CI.getHeader(
C);
753 auto *HeaderLabel =
label(Header);
754 for (
const auto *Exit : Exits) {
755 if (
label(Exit) != HeaderLabel) {
757 DivDesc->CycleDivBlocks.insert(Exit);
768template <
typename ContextT>
771 : CyclePO(Context), DT(DT), CI(CI) {
775template <
typename ContextT>
780 return EmptyDivergenceDesc;
784 auto ItCached = CachedControlDivDescs.find(DivTermBlock);
785 if (ItCached != CachedControlDivDescs.end())
786 return *ItCached->second;
796 for (
const auto *BB : Blocks) {
797 Out << LS << CI.getSSAContext().print(BB);
804 dbgs() <<
"\nResult (" << CI.getSSAContext().print(DivTermBlock)
805 <<
"):\n JoinDivBlocks: " << PrintBlockSet(DivDesc->JoinDivBlocks)
806 <<
" CycleDivBlocks: " << PrintBlockSet(DivDesc->CycleDivBlocks)
811 CachedControlDivDescs.try_emplace(DivTermBlock, std::move(DivDesc));
812 assert(ItInserted.second);
813 return *ItInserted.first->second;
816template <
typename ContextT>
829 if (
I.isTerminator()) {
833 <<
Context.print(
I.getParent()) <<
"\n");
843template <
typename ContextT>
853template <
typename ContextT>
856 UniformOverrides.insert(&Instr);
859template <
typename ContextT>
878template <
typename ContextT>
879void GenericUniformityAnalysisImpl<ContextT>::analyzeCycleExitDivergence(
882 CI.getExitBlocks(DefCycle, Exits);
883 for (
auto *Exit : Exits) {
884 for (
auto &Phi : Exit->phis()) {
885 if (usesValueFromCycle(Phi, DefCycle)) {
891 for (
auto *BB : CI.getBlocks(DefCycle)) {
893 [&](BlockT *Exit) {
return DT.dominates(BB, Exit); }))
895 for (
auto &
II : *BB) {
896 propagateTemporalDivergence(
II, DefCycle);
901template <
typename ContextT>
902void GenericUniformityAnalysisImpl<ContextT>::propagateCycleExitDivergence(
903 const BlockT &DivExit,
CycleRef InnerDivCycle) {
908 CycleRef ExitLevelCycle = CI.getCycle(&DivExit);
909 const unsigned CycleExitDepth =
910 ExitLevelCycle ? CI.getDepth(ExitLevelCycle) : 0;
913 while (DivCycle && CI.getDepth(DivCycle) > CycleExitDepth) {
915 <<
Context.print(CI.getHeader(DivCycle)) <<
"\n");
916 OuterDivCycle = DivCycle;
917 DivCycle = CI.getParentCycle(DivCycle);
920 <<
Context.print(CI.getHeader(OuterDivCycle)) <<
"\n");
922 if (!DivergentExitCycles.insert(OuterDivCycle))
927 for (
auto C : AssumedDivergent) {
928 if (CI.contains(
C, OuterDivCycle))
932 analyzeCycleExitDivergence(OuterDivCycle);
935template <
typename ContextT>
936void GenericUniformityAnalysisImpl<ContextT>::taintAndPushAllDefs(
939 for (
const auto &
I :
instrs(BB)) {
943 if (
I.isTerminator())
951template <
typename ContextT>
952void GenericUniformityAnalysisImpl<ContextT>::taintAndPushPhiNodes(
953 const BlockT &JoinBlock) {
956 for (
const auto &Phi : JoinBlock.phis()) {
964 if (ContextT::isConstantOrUndefValuePhi(Phi))
973template <
typename CycleInfoT>
977 [&](
CycleRef C) {
return CI.contains(
C, Candidate); }))
979 Cycles.push_back(Candidate);
988template <
typename CycleInfoT,
typename BlockT>
990 const BlockT *DivTermBlock,
const BlockT *JoinBlock) {
992 assert(CI.contains(Cycle, JoinBlock));
994 if (CI.contains(Cycle, DivTermBlock))
998 CycleRef Parent = CI.getParentCycle(Cycle);
999 while (Parent && !CI.contains(Parent, DivTermBlock)) {
1001 Parent = CI.getParentCycle(Cycle);
1007 (void)OriginalCycle;
1008 assert(Cycle == OriginalCycle || !CI.isReducible(Cycle));
1010 if (CI.isReducible(Cycle)) {
1011 assert(CI.getHeader(Cycle) == JoinBlock);
1015 LLVM_DEBUG(
dbgs() <<
"cycle made divergent by external branch\n");
1023template <
typename ContextT,
typename CycleInfoT,
typename BlockT,
1024 typename DominatorTreeT>
1026 const BlockT *DivTermBlock,
const BlockT *JoinBlock,
1027 const DominatorTreeT &DT, ContextT &Context) {
1029 <<
" for internal branch " << Context.print(DivTermBlock)
1031 if (DT.properlyDominates(DivTermBlock, JoinBlock))
1035 assert(Cycle && CI.contains(Cycle, JoinBlock));
1036 while (Cycle && !CI.contains(Cycle, DivTermBlock)) {
1037 Cycle = CI.getParentCycle(Cycle);
1039 if (!Cycle || CI.isReducible(Cycle))
1042 if (DT.properlyDominates(CI.getHeader(Cycle), JoinBlock))
1045 LLVM_DEBUG(
dbgs() <<
" header " << Context.print(CI.getHeader(Cycle))
1046 <<
" does not dominate join\n");
1048 CycleRef Parent = CI.getParentCycle(Cycle);
1049 while (Parent && !DT.properlyDominates(CI.getHeader(Parent), JoinBlock)) {
1050 LLVM_DEBUG(
dbgs() <<
" header " << Context.print(CI.getHeader(Parent))
1051 <<
" does not dominate join\n");
1053 Parent = CI.getParentCycle(Parent);
1056 LLVM_DEBUG(
dbgs() <<
" cycle made divergent by internal branch\n");
1060template <
typename ContextT,
typename CycleInfoT,
typename BlockT,
1061 typename DominatorTreeT>
1064 const BlockT *DivTermBlock,
const BlockT *JoinBlock,
1065 const DominatorTreeT &DT, ContextT &Context) {
1082template <
typename ContextT>
1083bool GenericUniformityAnalysisImpl<ContextT>::isTemporalDivergent(
1084 const BlockT &ObservingBlock,
const InstructionT &Def)
const {
1085 const BlockT *DefBlock = Def.getParent();
1086 for (
auto C = CI.getCycle(DefBlock);
C && !CI.contains(
C, &ObservingBlock);
1087 C = CI.getParentCycle(
C)) {
1088 if (DivergentExitCycles.contains(
C)) {
1095template <
typename ContextT>
1098 const auto *DivTermBlock = Term.getParent();
1104 if (!DT.isReachableFromEntry(DivTermBlock))
1107 const auto &DivDesc = SDA.getJoinBlocks(DivTermBlock);
1111 for (
const auto *JoinBlock : DivDesc.JoinDivBlocks) {
1116 CI,
C, DivTermBlock, JoinBlock, DT,
Context)) {
1121 taintAndPushPhiNodes(*JoinBlock);
1127 return CI.getDepth(
A) >
CI.getDepth(
B);
1135 for (
auto C : DivCycles) {
1139 for (
const BlockT *BB :
CI.getBlocks(
C)) {
1140 taintAndPushAllDefs(*BB);
1144 CycleRef BranchCycle =
CI.getCycle(DivTermBlock);
1145 assert(DivDesc.CycleDivBlocks.empty() || BranchCycle);
1146 for (
const auto *DivExitBlock : DivDesc.CycleDivBlocks) {
1147 propagateCycleExitDivergence(*DivExitBlock, BranchCycle);
1151template <
typename ContextT>
1163 if (
I->isTerminator()) {
1174template <
typename ContextT>
1180template <
typename ContextT>
1183 return UniformOverrides.contains(&Instr);
1186template <
typename ContextT>
1192template <
typename ContextT>
1196 DA.reset(
new ImplT{DT, CI,
TTI});
1199template <
typename ContextT>
1204 constexpr bool IsMIR = std::is_same<InstructionT, MachineInstr>::value;
1205 std::string NewLine = IsMIR ?
"" :
"\n";
1207 bool FoundDivergence =
false;
1211 if (!AssumedDivergent.empty()) {
1212 FoundDivergence =
true;
1213 OS <<
"CYCLES ASSUMED DIVERGENT:\n";
1214 for (
auto C : AssumedDivergent) {
1215 OS <<
" " <<
CI.print(
C) <<
'\n';
1219 if (!DivergentExitCycles.empty()) {
1220 FoundDivergence =
true;
1221 OS <<
"CYCLES WITH DIVERGENT EXIT:\n";
1222 for (
auto C : DivergentExitCycles) {
1223 OS <<
" " <<
CI.print(
C) <<
'\n';
1228 FoundDivergence =
true;
1229 OS <<
"\nTEMPORAL DIVERGENCE LIST:\n";
1232 OS <<
"Value :" <<
Context.print(Val) << NewLine
1233 <<
"Used by :" <<
Context.print(UseInst) << NewLine
1234 <<
"Outside cycle :" <<
CI.print(
C) <<
"\n\n";
1241 OS <<
"DEFINITIONS\n";
1244 for (
auto Value : Defs) {
1246 FoundDivergence =
true;
1247 OS <<
" DIVERGENT: ";
1254 OS <<
"TERMINATORS\n";
1258 if (DivergentTerminators)
1259 FoundDivergence =
true;
1260 for (
auto *
T : Terms) {
1261 if (DivergentTerminators)
1262 OS <<
" DIVERGENT: ";
1268 OS <<
"END BLOCK\n";
1271 if (!FoundDivergence)
1272 OS <<
"ALL VALUES UNIFORM\n";
1275template <
typename ContextT>
1279 return make_range(DA->TemporalDivergenceList.begin(),
1280 DA->TemporalDivergenceList.end());
1283template <
typename ContextT>
1284const typename ContextT::FunctionT &
1286 return DA->getFunction();
1289template <
typename ContextT>
1292 return DA->getCycleInfo();
1298template <
typename ContextT>
1300 return DA && DA->isDivergent(V);
1303template <
typename ContextT>
1306 assert(
I->isTerminator() &&
"Expected a terminator instruction!");
1307 return DA && DA->isDivergentTerminator(*
I);
1310template <
typename ContextT>
1312 return DA && DA->isDivergentUse(U);
1315template <
typename ContextT>
1317 return DA && DA->hasDivergentTerminator(
B);
1321template <
typename ContextT>
1324 Out <<
" Uniformity analysis not computed (no branch divergence).\n";
1330template <
typename ContextT>
1331void llvm::ModifiedPostOrder<ContextT>::computeStackPO(
1335 while (!Stack.empty()) {
1336 auto *NextBB = Stack.back();
1337 if (Finalized.
count(NextBB)) {
1341 LLVM_DEBUG(
dbgs() <<
" visiting " << CI.getSSAContext().print(NextBB)
1343 CycleRef NestedCycle = CI.getCycle(NextBB);
1344 if (
C != NestedCycle &&
1345 (!
C || (NestedCycle && CI.contains(
C, NestedCycle)))) {
1347 while (CI.getParentCycle(NestedCycle) !=
C)
1348 NestedCycle = CI.getParentCycle(NestedCycle);
1351 CI.getExitBlocks(NestedCycle, NestedExits);
1352 bool PushedNodes =
false;
1353 for (
auto *NestedExitBB : NestedExits) {
1355 << CI.getSSAContext().print(NestedExitBB) <<
"\n");
1356 if (
C && !CI.contains(
C, NestedExitBB))
1358 if (Finalized.
count(NestedExitBB))
1361 Stack.push_back(NestedExitBB);
1363 << CI.getSSAContext().print(NestedExitBB) <<
"\n");
1368 computeCyclePO(CI, NestedCycle, Finalized);
1375 bool PushedNodes =
false;
1378 << CI.getSSAContext().print(SuccBB) <<
"\n");
1379 if (
C && !CI.contains(
C, SuccBB))
1381 if (Finalized.
count(SuccBB))
1384 Stack.push_back(SuccBB);
1385 LLVM_DEBUG(
dbgs() <<
" pushed succ: " << CI.getSSAContext().print(SuccBB)
1391 << CI.getSSAContext().print(NextBB) <<
"\n");
1393 Finalized.
insert(NextBB);
1394 appendBlock(*NextBB);
1400template <
typename ContextT>
1401void ModifiedPostOrder<ContextT>::computeCyclePO(
1406 auto *CycleHeader = CI.getHeader(
C);
1409 << CI.getSSAContext().print(CycleHeader) <<
"\n");
1410 assert(!Finalized.count(CycleHeader));
1411 Finalized.insert(CycleHeader);
1415 << CI.getSSAContext().print(CycleHeader) <<
"\n");
1416 appendBlock(*CycleHeader, CI.isReducible(
C));
1420 LLVM_DEBUG(
dbgs() <<
" examine succ: " << CI.getSSAContext().print(BB)
1422 if (!CI.contains(
C, BB))
1424 if (BB == CycleHeader)
1426 if (!Finalized.count(BB)) {
1427 LLVM_DEBUG(
dbgs() <<
" pushed succ: " << CI.getSSAContext().print(BB)
1429 Stack.push_back(BB);
1434 computeStackPO(Stack, CI,
C, Finalized);
1440template <
typename ContextT>
1444 auto *
F = CI.getFunction();
1447 Stack.push_back(&
F->front());
1448 computeStackPO(Stack, CI,
CycleRef(), Finalized);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines the DenseSet and SmallDenseSet classes.
uint64_t IntrinsicInst * II
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file defines the SparseBitVector class.
static const unsigned InvalidIndex
static Function * getFunction(FunctionType *Ty, const Twine &Name, Module *M)
Opaque handle to a cycle within a GenericCycleInfo that wraps the cycle's preorder index.
Implements a dense probed hash-table based set.
Compute divergence starting with a divergent branch.
const ModifiedPO & CyclePOT
GenericSyncDependenceAnalysis< ContextT > SyncDependenceAnalysisT
const BlockT *& label(const BlockT *BB)
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
SmallVector< const BlockT * > BlockLabels
const DominatorTreeT & DT
ModifiedPostOrder< ContextT > ModifiedPO
std::unique_ptr< DivergenceDescriptorT > computeJoinPoints()
SparseBitVector FreshLabels
bool visitCycleExitEdge(const BlockT &ExitBlock, const BlockT &Label)
typename ContextT::ValueRefT ValueRefT
typename ContextT::BlockT BlockT
DivergencePropagator(const ModifiedPO &CyclePOT, const DominatorTreeT &DT, const CycleInfoT &CI, const BlockT &DivTermBlock)
bool visitEdge(const BlockT &SuccBlock, const BlockT &Label)
typename SyncDependenceAnalysisT::DivergenceDescriptor DivergenceDescriptorT
Cycle information for a function.
Locate join blocks for disjoint paths starting at a divergent branch.
GenericSyncDependenceAnalysis(const ContextT &Context, const DominatorTreeT &DT, const CycleInfoT &CI)
ModifiedPostOrder< ContextT > ModifiedPO
DivergencePropagator< ContextT > DivergencePropagatorT
SmallPtrSet< const BlockT *, 4 > ConstBlockSet
typename ContextT::DominatorTreeT DominatorTreeT
GenericCycleInfo< ContextT > CycleInfoT
typename ContextT::FunctionT FunctionT
typename ContextT::InstructionT InstructionT
typename ContextT::BlockT BlockT
typename ContextT::ValueRefT ValueRefT
const DivergenceDescriptor & getJoinBlocks(const BlockT *DivTermBlock)
Computes divergent join points and cycle exits caused by branch divergence in Term.
A helper class to return the specified delimiter string after the first invocation of operator String...
Construct a specially modified post-order traversal of cycles.
typename ContextT::FunctionT FunctionT
bool isReducibleCycleHeader(const BlockT *BB) const
void appendBlock(const BlockT &BB, bool IsReducibleCycleHeader=false)
const BlockT * operator[](size_t Idx) const
ModifiedPostOrder(const ContextT &C)
unsigned count(BlockT *BB) const
void compute(const CycleInfoT &CI)
Generically compute the modified post order.
GenericCycleInfo< ContextT > CycleInfoT
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.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
A SetVector that performs no allocations if smaller than a certain size.
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.
LLVM Value Representation.
A range adaptor for a pair of iterators.
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.
bool insertIfNotContained(const CycleInfoT &CI, SmallVector< CycleRef > &Cycles, CycleRef Candidate)
Add Candidate to Cycles if it is not already contained in Cycles.
CycleRef getExtDivCycle(const CycleInfoT &CI, CycleRef Cycle, const BlockT *DivTermBlock, const BlockT *JoinBlock)
Return the outermost cycle made divergent by branch outside it.
auto successors(const MachineBasicBlock *BB)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
CycleRef getOutermostDivergentCycle(const CycleInfoT &CI, CycleRef Cycle, const BlockT *DivTermBlock, const BlockT *JoinBlock, const DominatorTreeT &DT, ContextT &Context)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
auto succ_size(const MachineBasicBlock *BB)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
auto instrs(const MachineBasicBlock &BB)
CycleRef getIntDivCycle(const CycleInfoT &CI, CycleRef Cycle, const BlockT *DivTermBlock, const BlockT *JoinBlock, const DominatorTreeT &DT, ContextT &Context)
Return the outermost cycle made divergent by branch inside it.
Information discovered by the sync dependence analysis for each divergent branch.
ConstBlockSet CycleDivBlocks
ConstBlockSet JoinDivBlocks