12#ifndef LLVM_EXECUTIONENGINE_ORC_WAITINGONGRAPH_H
13#define LLVM_EXECUTIONENGINE_ORC_WAITINGONGRAPH_H
26class WaitingOnGraphTest;
98 size_t OrigSize = this->
size();
100 assert((!AssertNoOverlap || this->
size() == (OrigSize +
Other.size())) &&
101 "merge of overlapping elements");
102 return this->
size() != OrigSize;
108 size_t OrigSize = this->
size();
111 if (OrigSize == 0 ||
Other.empty())
116 if (OrigSize >
Other.size()) {
117 for (
auto &Elem :
Other)
121 for (
auto &Elem : *
this)
122 if (
Other.count(Elem))
127 return this->
size() < OrigSize;
137 for (
auto &Elem : *
this)
157 bool AssertNoElementsOverlap =
false) {
159 for (
auto &[Container, Elements] :
Other)
160 Changed |= (*this)[Container].merge(Elements, AssertNoElementsOverlap);
168 for (
auto &[Container, Elements] :
Other) {
169 assert(!Elements.empty() &&
"Stale row for Container in Other");
170 auto I = this->
find(Container);
171 if (
I == this->
end())
173 Changed |=
I->second.remove(Elements);
174 if (
I->second.empty())
175 this->
erase(Container);
185 template <
typename Visitor>
bool visit(Visitor &&V) {
191 for (
auto &[Container, Elements] : *
this) {
192 assert(!Elements.empty() &&
"empty row for container");
193 if (V(Container, Elements)) {
195 if (Elements.empty())
201 this->
erase(Container);
210 using ElemToSuperNodeMap =
232 ElemToSuperNodeMap *RegisteredElemToSN =
nullptr;
236 void mapDefsTo(ElemToSuperNodeMap &ElemToSN,
SuperNode *SN,
237 bool AbandonOldMapping =
false) {
239 for (
auto &[Container, Elements] : Defs) {
240 assert(!Elements.empty() &&
"Empty elements for container?");
241 auto &ContainerElemToSN = ElemToSN[Container];
242 for (
auto &Elem : Elements)
243 ContainerElemToSN[Elem] = SN;
245 assert((AbandonOldMapping || !SN->RegisteredElemToSN ||
246 SN->RegisteredElemToSN == &ElemToSN) &&
247 "SN defs split across maps");
248 SN->RegisteredElemToSN = &ElemToSN;
253 void mapDefsToThis(ElemToSuperNodeMap &ElemToSN,
254 bool AbandonOldMapping =
false) {
255 mapDefsTo(ElemToSN,
this, AbandonOldMapping);
260 void unmapDefsFromThis() {
261 assert(RegisteredElemToSN &&
"No registered ElemToSuperNodeMap");
262 for (
auto &[Container, Elements] : Defs) {
263 auto I = RegisteredElemToSN->find(Container);
264 assert(
I != RegisteredElemToSN->end() &&
"Container not in map");
265 auto &ContainerElemToSN =
I->second;
266 for (
auto &Elem : Elements) {
267 assert(ContainerElemToSN[Elem] ==
this &&
"Mapping not present");
268 ContainerElemToSN.erase(Elem);
270 if (ContainerElemToSN.empty())
271 RegisteredElemToSN->erase(
I);
273 RegisteredElemToSN =
nullptr;
281 bool hoistDeps(SuperNodeDepsMap &SuperNodeDeps,
282 ElemToSuperNodeMap &ElemToSN) {
284 auto I = ElemToSN.find(Container);
285 if (
I == ElemToSN.end())
288 auto &ContainerElemToSN =
I->second;
290 auto J = ContainerElemToSN.find(Elem);
291 if (J == ContainerElemToSN.end())
294 auto *DefSN = J->second;
296 SuperNodeDeps[DefSN].insert(
this);
311 template <
typename Vector,
typename Visitor>
312 static void visitWithRemoval(
Vector &Vec, Visitor &&V) {
313 for (
size_t I = 0;
I != Vec.size();) {
315 if (
I != Vec.size() - 1)
325 std::unique_ptr<SuperNode> addOrCreateSuperNode(ContainerElementsMap Defs,
326 ContainerElementsMap Deps) {
327 auto H = getHash(Deps);
328 if (
auto *ExistingSN = findCanonicalSuperNode(
H, Deps)) {
329 ExistingSN->Defs.merge(Defs,
true);
334 std::make_unique<SuperNode>(std::move(Defs), std::move(Deps));
335 CanonicalSNs[
H].push_back(NewSN.get());
336 assert(!SNHashes.count(NewSN.get()));
337 SNHashes[NewSN.get()] =
H;
341 void coalesce(std::vector<std::unique_ptr<SuperNode>> &SNs,
342 ElemToSuperNodeMap &ElemToSN,
343 bool AbandonOldMapping =
false) {
344 visitWithRemoval(SNs, [&](std::unique_ptr<SuperNode> &SN) {
345 assert(!SNHashes.count(SN.get()) &&
346 "Elements of SNs should be new to the coalescer");
347 auto H = getHash(SN->Deps);
348 if (
auto *CanonicalSN = findCanonicalSuperNode(
H, SN->Deps)) {
349 SN->mapDefsTo(ElemToSN, CanonicalSN, AbandonOldMapping);
350 CanonicalSN->Defs.merge(SN->Defs,
true);
353 CanonicalSNs[
H].push_back(SN.get());
354 SNHashes[SN.get()] =
H;
364 CanonicalSNs.clear();
369 void erase(SuperNode *SN) {
374 auto I = SNHashes.find(SN);
375 assert(
I != SNHashes.end() &&
"SN not tracked by coalescer");
381 auto I = CanonicalSNs.find(
H);
382 assert(
I != CanonicalSNs.end() &&
"Hash not in CanonicalSNs");
383 auto &SNs =
I->second;
386 for (; J != SNs.size(); ++J)
390 assert(J < SNs.size() &&
"SN not in CanonicalSNs map");
395 CanonicalSNs.erase(
I);
399 hash_code getHash(
const ContainerElementsMap &M) {
401 SortedContainers.reserve(
M.size());
402 for (
auto &[Container, Elems] : M)
403 SortedContainers.push_back(Container);
406 for (
auto &Container : SortedContainers) {
407 auto &ContainerElems =
M.at(Container);
409 ContainerElems.end());
416 SuperNode *findCanonicalSuperNode(hash_code
H,
417 const ContainerElementsMap &M) {
418 for (
auto *SN : CanonicalSNs[
H])
424 DenseMap<hash_code, SmallVector<SuperNode *>> CanonicalSNs;
425 DenseMap<SuperNode *, hash_code> SNHashes;
438 if (
auto SN = C.addOrCreateSuperNode(std::move(Defs), std::move(Deps)))
439 SNs.push_back(std::move(SN));
443 return std::move(SNs);
448 std::vector<std::unique_ptr<SuperNode>> SNs;
451 class SimplifyResult {
456 const std::vector<std::unique_ptr<SuperNode>> &
superNodes()
const {
462 ElemToSuperNodeMap ElemToSN)
464 std::vector<std::unique_ptr<SuperNode>> SNs;
465 ElemToSuperNodeMap ElemToSN;
478 static SimplifyResult
simplify(std::vector<std::unique_ptr<SuperNode>> SNs,
479 OpRecorder *Rec =
nullptr) {
481 Rec->recordSimplify(SNs);
484 ElemToSuperNodeMap ElemToSN;
486 SN->mapDefsToThis(ElemToSN);
488 SuperNodeDepsMap SuperNodeDeps;
489 hoistDeps(SNs, SuperNodeDeps, ElemToSN);
490 propagateDeps(SuperNodeDeps);
495 return {std::move(SNs), std::move(ElemToSN)};
499 std::vector<std::unique_ptr<SuperNode>>
Ready;
500 std::vector<std::unique_ptr<SuperNode>>
Failed;
510 template <
typename GetExternalStateFn>
511 EmitResult
emit(SimplifyResult SR, GetExternalStateFn &&GetExternalState) {
512 auto NewSNs = std::move(SR.SNs);
513 auto ElemToNewSN = std::move(SR.ElemToSN);
516 auto FailedSNs = processExternalDeps(NewSNs, GetExternalState);
518 SuperNodeDepsMap SuperNodeDeps;
521 std::vector<std::unique_ptr<SuperNode>> ModifiedPendingSNs;
522 visitWithRemoval(PendingSNs, [&](std::unique_ptr<SuperNode> &SN) {
523 if (SN->hoistDeps(SuperNodeDeps, ElemToNewSN)) {
524 ModifiedPendingSNs.push_back(std::move(SN));
531 for (
auto &SN : ModifiedPendingSNs)
532 CoalesceToPendingSNs.erase(SN.get());
534 hoistDeps(NewSNs, SuperNodeDeps, ElemToPendingSN);
535 propagateDeps(SuperNodeDeps);
537 propagateFailures(FailedSNs, SuperNodeDeps);
541 std::vector<std::unique_ptr<SuperNode>> ReadyNodes, FailedNodes;
542 processReadyOrFailed(ModifiedPendingSNs, ReadyNodes, FailedNodes,
543 SuperNodeDeps, FailedSNs,
true);
544 processReadyOrFailed(NewSNs, ReadyNodes, FailedNodes, SuperNodeDeps,
547 CoalesceToPendingSNs.coalesce(ModifiedPendingSNs, ElemToPendingSN);
548 CoalesceToPendingSNs.coalesce(NewSNs, ElemToPendingSN,
552 for (
auto &SN : ModifiedPendingSNs)
553 PendingSNs.push_back(std::move(SN));
556 for (
auto &SN : NewSNs) {
557 SN->mapDefsToThis(ElemToPendingSN,
true);
558 PendingSNs.push_back(std::move(SN));
561 return {std::move(ReadyNodes), std::move(FailedNodes)};
568 std::vector<std::unique_ptr<SuperNode>>
569 fail(
const ContainerElementsMap &
Failed, OpRecorder *Rec =
nullptr) {
573 std::vector<std::unique_ptr<SuperNode>> FailedSNs;
575 visitWithRemoval(PendingSNs, [&](std::unique_ptr<SuperNode> &SN) {
576 for (
auto &[Container, Elements] : SN->Deps) {
577 auto I =
Failed.find(Container);
581 auto &FailedElems =
I->second;
582 for (
auto &Elem : Elements) {
583 if (FailedElems.count(Elem)) {
584 CoalesceToPendingSNs.erase(SN.get());
585 SN->unmapDefsFromThis();
586 FailedSNs.push_back(std::move(SN));
605 for (
auto &PendingSN : PendingSNs) {
606 if (PendingSN->Deps.empty())
607 ErrLog() <<
"Pending SN " << PendingSN.get() <<
" has empty dep set.\n";
609 bool BadElem =
false;
610 for (
auto &[Container, Elems] : PendingSN->Deps) {
611 auto I = ElemToPendingSN.find(Container);
612 if (
I == ElemToPendingSN.end())
615 ErrLog() <<
"Pending SN " << PendingSN.get()
616 <<
" has dependence map entry for " << Container
617 <<
" with empty element set.\n";
618 for (
auto &Elem : Elems) {
619 if (
I->second.count(Elem)) {
620 ErrLog() <<
"Pending SN " << PendingSN.get()
621 <<
" has dependence on emitted element ( " << Container
622 <<
", " << Elem <<
")\n";
632 for (
auto &[Container, Elems] : PendingSN->Defs) {
634 ErrLog() <<
"Pending SN " << PendingSN.get()
635 <<
" has def map entry for " << Container
636 <<
" with empty element set.\n";
637 DefCount += Elems.size();
638 auto I = ElemToPendingSN.find(Container);
639 if (
I == ElemToPendingSN.end())
640 ErrLog() <<
"Pending SN " << PendingSN.get() <<
" has "
641 << Elems.size() <<
" defs in container " << Container
642 <<
" not covered by ElemsToPendingSN.\n";
644 for (
auto &Elem : Elems) {
645 auto J =
I->second.find(Elem);
646 if (J ==
I->second.end())
647 ErrLog() <<
"Pending SN " << PendingSN.get() <<
" has element ("
648 << Container <<
", " << Elem
649 <<
") not covered by ElemsToPendingSN.\n";
650 else if (J->second != PendingSN.get())
651 ErrLog() <<
"ElemToPendingSN value invalid for (" << Container
652 <<
", " << Elem <<
")\n";
658 size_t DefCount2 = 0;
659 for (
auto &[Container, Elems] : ElemToPendingSN)
660 DefCount2 += Elems.size();
662 assert(DefCount2 >= DefCount);
663 if (DefCount2 != DefCount)
664 ErrLog() <<
"ElemToPendingSN contains extra elements.\n";
671 static void hoistDeps(std::vector<std::unique_ptr<SuperNode>> &SNs,
672 SuperNodeDepsMap &SuperNodeDeps,
673 ElemToSuperNodeMap &ElemToSN) {
676 SN->hoistDeps(SuperNodeDeps, ElemToSN);
680 static void propagateDeps(SuperNodeDepsMap &SuperNodeDeps) {
683 if (SuperNodeDeps.empty())
687 Worklist.
reserve(SuperNodeDeps.size());
688 for (
auto &[SN, SNDependants] : SuperNodeDeps)
696 while (!Worklist.
empty()) {
698 auto I = SuperNodeDeps.find(SN);
699 if (
I == SuperNodeDeps.end())
702 for (
auto *DependantSN :
I->second)
703 if (DependantSN->Deps.merge(SN->Deps))
704 ToVisitNext.
insert(DependantSN);
707 if (ToVisitNext.
empty())
714 static void propagateFailures(DenseSet<SuperNode *> &FailedNodes,
715 SuperNodeDepsMap &SuperNodeDeps) {
716 if (FailedNodes.empty())
721 while (!Worklist.
empty()) {
723 auto I = SuperNodeDeps.find(SN);
724 if (
I == SuperNodeDeps.end())
727 for (
auto *DependantSN :
I->second)
728 if (FailedNodes.insert(DependantSN).second)
733 template <
typename GetExternalStateFn>
734 static DenseSet<SuperNode *>
735 processExternalDeps(std::vector<std::unique_ptr<SuperNode>> &SNs,
736 GetExternalStateFn &GetExternalState) {
737 DenseSet<SuperNode *> FailedSNs;
739 SN->Deps.visit([&](
ContainerId &Container, ElementSet &Elements) {
741 switch (GetExternalState(Container, Elem)) {
747 FailedSNs.insert(SN.get());
757 void processReadyOrFailed(std::vector<std::unique_ptr<SuperNode>> &SNs,
758 std::vector<std::unique_ptr<SuperNode>> &
Ready,
759 std::vector<std::unique_ptr<SuperNode>> &
Failed,
760 SuperNodeDepsMap &SuperNodeDeps,
761 const DenseSet<SuperNode *> &FailedSNs,
762 bool UnmapFromElemToSN) {
764 visitWithRemoval(SNs, [&](std::unique_ptr<SuperNode> &SN) {
765 bool SNFailed = FailedSNs.count(SN.get());
766 bool SNReady = SN->Deps.empty();
768 if (SNReady || SNFailed) {
769 if (UnmapFromElemToSN)
770 SN->unmapDefsFromThis();
772 ToList.push_back(std::move(SN));
779 std::vector<std::unique_ptr<SuperNode>> PendingSNs;
780 ElemToSuperNodeMap ElemToPendingSN;
781 Coalescer CoalesceToPendingSNs;
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
ReachingDefInfo InstSet & ToRemove
This file defines the DenseMap class.
This file defines the DenseSet and SmallDenseSet classes.
register Register Coalescer
This file defines the SmallVector class.
Implements a dense probed hash-table based set.
void reserve(size_type N)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
std::pair< iterator, bool > insert(const ValueT &V)
bool remove(const ContainerElementsMap &Other)
Remove all elements in Other from this map.
bool merge(const ContainerElementsMap &Other, bool AssertNoElementsOverlap=false)
Merge the elements of Other into this map.
friend class ContainerElementsMapTest
bool visit(Visitor &&V)
Call V on each (Container, Elements) pair in this map.
friend class ElementSetTest
bool remove_if(Pred &&P)
Remove all elements for which Pred returns true.
bool remove(const ElementSet &Other)
Remove all elements in Other from this set.
bool merge(const ElementSet &Other, bool AssertNoOverlap=false)
Merge the elements of Other into this set.
virtual void recordFail(const ContainerElementsMap &Failed)=0
virtual void recordEnd()=0
virtual ~OpRecorder()=default
virtual void recordSimplify(const std::vector< std::unique_ptr< SuperNode > > &SNs)=0
friend class WaitingOnGraph
const std::vector< std::unique_ptr< SuperNode > > & superNodes() const
friend class WaitingOnGraphTest
Build SuperNodes from (definition-set, dependence-set) pairs.
void add(ContainerElementsMap Defs, ContainerElementsMap Deps)
std::vector< std::unique_ptr< SuperNode > > takeSuperNodes()
const ContainerElementsMap & defs() const
friend class WaitingOnGraph
ContainerElementsMap & deps()
friend class WaitingOnGraphTest
const ContainerElementsMap & deps() const
SuperNode(ContainerElementsMap Defs, ContainerElementsMap Deps)
ContainerElementsMap & defs()
WaitingOnGraph class template.
NonOwningSymbolStringPtr ElementId
std::vector< std::unique_ptr< SuperNode > > fail(const ContainerElementsMap &Failed, OpRecorder *Rec=nullptr)
Identify the given symbols as Failed.
static SimplifyResult simplify(std::vector< std::unique_ptr< SuperNode > > SNs, OpRecorder *Rec=nullptr)
Preprocess a list of SuperNodes to remove all intra-SN dependencies.
EmitResult emit(SimplifyResult SR, GetExternalStateFn &&GetExternalState)
Add the given SuperNodes to the graph, returning any SuperNodes that move to the Ready or Failed stat...
friend class WaitingOnGraphTest
bool validate(raw_ostream &Log)
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.
@ C
The default llvm calling convention, compatible with C.
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
testing::Matcher< const detail::ErrorHolder & > Failed()
void erase(Container &C, ValueType V)
Wrapper function to remove a value from a container:
void sort(IteratorTy Start, IteratorTy End)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
Implement std::hash so that hash_code can be used in STL containers.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
std::vector< std::unique_ptr< SuperNode > > Failed
std::vector< std::unique_ptr< SuperNode > > Ready