12#ifndef LLVM_EXECUTIONENGINE_ORC_WAITINGONGRAPH_H
13#define LLVM_EXECUTIONENGINE_ORC_WAITINGONGRAPH_H
27class WaitingOnGraphTest;
99 size_t OrigSize = this->
size();
101 assert((!AssertNoOverlap || this->
size() == (OrigSize +
Other.size())) &&
102 "merge of overlapping elements");
103 return this->
size() != OrigSize;
109 size_t OrigSize = this->
size();
112 if (OrigSize == 0 ||
Other.empty())
117 if (OrigSize >
Other.size()) {
118 for (
auto &Elem :
Other)
122 for (
auto &Elem : *
this)
123 if (
Other.count(Elem))
128 return this->
size() < OrigSize;
138 for (
auto &Elem : *
this)
158 bool AssertNoElementsOverlap =
false) {
160 for (
auto &[Container, Elements] :
Other)
161 Changed |= (*this)[Container].merge(Elements, AssertNoElementsOverlap);
169 for (
auto &[Container, Elements] :
Other) {
170 assert(!Elements.empty() &&
"Stale row for Container in Other");
171 auto I = this->
find(Container);
172 if (
I == this->
end())
174 Changed |=
I->second.remove(Elements);
175 if (
I->second.empty())
176 this->
erase(Container);
186 template <
typename Visitor>
bool visit(Visitor &&V) {
192 for (
auto &[Container, Elements] : *
this) {
193 assert(!Elements.empty() &&
"empty row for container");
194 if (V(Container, Elements)) {
196 if (Elements.empty())
202 this->
erase(Container);
211 using ElemToSuperNodeMap =
233 ElemToSuperNodeMap *RegisteredElemToSN =
nullptr;
237 void mapDefsTo(ElemToSuperNodeMap &ElemToSN,
SuperNode *SN,
238 bool AbandonOldMapping =
false) {
240 for (
auto &[Container, Elements] : Defs) {
241 assert(!Elements.empty() &&
"Empty elements for container?");
242 auto &ContainerElemToSN = ElemToSN[Container];
243 for (
auto &Elem : Elements)
244 ContainerElemToSN[Elem] = SN;
246 assert((AbandonOldMapping || !SN->RegisteredElemToSN ||
247 SN->RegisteredElemToSN == &ElemToSN) &&
248 "SN defs split across maps");
249 SN->RegisteredElemToSN = &ElemToSN;
254 void mapDefsToThis(ElemToSuperNodeMap &ElemToSN,
255 bool AbandonOldMapping =
false) {
256 mapDefsTo(ElemToSN,
this, AbandonOldMapping);
261 void unmapDefsFromThis() {
262 assert(RegisteredElemToSN &&
"No registered ElemToSuperNodeMap");
263 for (
auto &[Container, Elements] : Defs) {
264 auto I = RegisteredElemToSN->find(Container);
265 assert(
I != RegisteredElemToSN->end() &&
"Container not in map");
266 auto &ContainerElemToSN =
I->second;
267 for (
auto &Elem : Elements) {
268 assert(ContainerElemToSN[Elem] ==
this &&
"Mapping not present");
269 ContainerElemToSN.erase(Elem);
271 if (ContainerElemToSN.empty())
272 RegisteredElemToSN->erase(
I);
274 RegisteredElemToSN =
nullptr;
282 bool hoistDeps(SuperNodeDepsMap &SuperNodeDeps,
283 ElemToSuperNodeMap &ElemToSN) {
285 auto I = ElemToSN.find(Container);
286 if (
I == ElemToSN.end())
289 auto &ContainerElemToSN =
I->second;
291 auto J = ContainerElemToSN.find(Elem);
292 if (J == ContainerElemToSN.end())
295 auto *DefSN = J->second;
297 SuperNodeDeps[DefSN].insert(
this);
312 template <
typename Vector,
typename Visitor>
313 static void visitWithRemoval(
Vector &Vec, Visitor &&V) {
314 for (
size_t I = 0;
I != Vec.size();) {
316 if (
I != Vec.size() - 1)
326 std::unique_ptr<SuperNode> addOrCreateSuperNode(ContainerElementsMap Defs,
327 ContainerElementsMap Deps) {
328 auto H = getHash(Deps);
329 if (
auto *ExistingSN = findCanonicalSuperNode(
H, Deps)) {
330 ExistingSN->Defs.merge(Defs,
true);
335 std::make_unique<SuperNode>(std::move(Defs), std::move(Deps));
336 CanonicalSNs[
H].push_back(NewSN.get());
337 assert(!SNHashes.count(NewSN.get()));
338 SNHashes[NewSN.get()] =
H;
342 void coalesce(std::vector<std::unique_ptr<SuperNode>> &SNs,
343 ElemToSuperNodeMap &ElemToSN,
344 bool AbandonOldMapping =
false) {
345 visitWithRemoval(SNs, [&](std::unique_ptr<SuperNode> &SN) {
346 assert(!SNHashes.count(SN.get()) &&
347 "Elements of SNs should be new to the coalescer");
348 auto H = getHash(SN->Deps);
349 if (
auto *CanonicalSN = findCanonicalSuperNode(
H, SN->Deps)) {
350 SN->mapDefsTo(ElemToSN, CanonicalSN, AbandonOldMapping);
351 CanonicalSN->Defs.merge(SN->Defs,
true);
354 CanonicalSNs[
H].push_back(SN.get());
355 SNHashes[SN.get()] =
H;
365 CanonicalSNs.clear();
370 void erase(SuperNode *SN) {
375 auto I = SNHashes.find(SN);
376 assert(
I != SNHashes.end() &&
"SN not tracked by coalescer");
382 auto I = CanonicalSNs.find(
H);
383 assert(
I != CanonicalSNs.end() &&
"Hash not in CanonicalSNs");
384 auto &SNs =
I->second;
387 for (; J != SNs.size(); ++J)
391 assert(J < SNs.size() &&
"SN not in CanonicalSNs map");
396 CanonicalSNs.erase(
I);
400 hash_code getHash(
const ContainerElementsMap &M) {
402 SortedContainers.reserve(
M.size());
403 for (
auto &[Container, Elems] : M)
404 SortedContainers.push_back(Container);
407 for (
auto &Container : SortedContainers) {
408 auto &ContainerElems =
M.at(Container);
410 ContainerElems.end());
417 SuperNode *findCanonicalSuperNode(hash_code
H,
418 const ContainerElementsMap &M) {
419 for (
auto *SN : CanonicalSNs[
H])
425 DenseMap<hash_code, SmallVector<SuperNode *>> CanonicalSNs;
426 DenseMap<SuperNode *, hash_code> SNHashes;
439 if (
auto SN = C.addOrCreateSuperNode(std::move(Defs), std::move(Deps)))
440 SNs.push_back(std::move(SN));
444 return std::move(SNs);
449 std::vector<std::unique_ptr<SuperNode>> SNs;
452 class SimplifyResult {
457 const std::vector<std::unique_ptr<SuperNode>> &
superNodes()
const {
463 ElemToSuperNodeMap ElemToSN)
465 std::vector<std::unique_ptr<SuperNode>> SNs;
466 ElemToSuperNodeMap ElemToSN;
479 static SimplifyResult
simplify(std::vector<std::unique_ptr<SuperNode>> SNs,
480 OpRecorder *Rec =
nullptr) {
482 Rec->recordSimplify(SNs);
485 ElemToSuperNodeMap ElemToSN;
487 SN->mapDefsToThis(ElemToSN);
489 SuperNodeDepsMap SuperNodeDeps;
490 hoistDeps(SNs, SuperNodeDeps, ElemToSN);
491 propagateDeps(SuperNodeDeps);
496 return {std::move(SNs), std::move(ElemToSN)};
500 std::vector<std::unique_ptr<SuperNode>>
Ready;
501 std::vector<std::unique_ptr<SuperNode>>
Failed;
511 template <
typename GetExternalStateFn>
512 EmitResult
emit(SimplifyResult SR, GetExternalStateFn &&GetExternalState) {
513 auto NewSNs = std::move(SR.SNs);
514 auto ElemToNewSN = std::move(SR.ElemToSN);
517 auto FailedSNs = processExternalDeps(NewSNs, GetExternalState);
519 SuperNodeDepsMap SuperNodeDeps;
522 std::vector<std::unique_ptr<SuperNode>> ModifiedPendingSNs;
523 visitWithRemoval(PendingSNs, [&](std::unique_ptr<SuperNode> &SN) {
524 if (SN->hoistDeps(SuperNodeDeps, ElemToNewSN)) {
525 ModifiedPendingSNs.push_back(std::move(SN));
532 for (
auto &SN : ModifiedPendingSNs)
533 CoalesceToPendingSNs.erase(SN.get());
535 hoistDeps(NewSNs, SuperNodeDeps, ElemToPendingSN);
536 propagateDeps(SuperNodeDeps);
538 propagateFailures(FailedSNs, SuperNodeDeps);
542 std::vector<std::unique_ptr<SuperNode>> ReadyNodes, FailedNodes;
543 processReadyOrFailed(ModifiedPendingSNs, ReadyNodes, FailedNodes,
544 SuperNodeDeps, FailedSNs,
true);
545 processReadyOrFailed(NewSNs, ReadyNodes, FailedNodes, SuperNodeDeps,
548 CoalesceToPendingSNs.coalesce(ModifiedPendingSNs, ElemToPendingSN);
549 CoalesceToPendingSNs.coalesce(NewSNs, ElemToPendingSN,
553 for (
auto &SN : ModifiedPendingSNs)
554 PendingSNs.push_back(std::move(SN));
557 for (
auto &SN : NewSNs) {
558 SN->mapDefsToThis(ElemToPendingSN,
true);
559 PendingSNs.push_back(std::move(SN));
562 return {std::move(ReadyNodes), std::move(FailedNodes)};
569 std::vector<std::unique_ptr<SuperNode>>
570 fail(
const ContainerElementsMap &
Failed, OpRecorder *Rec =
nullptr) {
574 std::vector<std::unique_ptr<SuperNode>> FailedSNs;
576 visitWithRemoval(PendingSNs, [&](std::unique_ptr<SuperNode> &SN) {
577 for (
auto &[Container, Elements] : SN->Deps) {
578 auto I =
Failed.find(Container);
582 auto &FailedElems =
I->second;
583 for (
auto &Elem : Elements) {
584 if (FailedElems.count(Elem)) {
585 CoalesceToPendingSNs.erase(SN.get());
586 SN->unmapDefsFromThis();
587 FailedSNs.push_back(std::move(SN));
606 for (
auto &PendingSN : PendingSNs) {
607 if (PendingSN->Deps.empty())
608 ErrLog() <<
"Pending SN " << PendingSN.get() <<
" has empty dep set.\n";
610 bool BadElem =
false;
611 for (
auto &[Container, Elems] : PendingSN->Deps) {
612 auto I = ElemToPendingSN.find(Container);
613 if (
I == ElemToPendingSN.end())
616 ErrLog() <<
"Pending SN " << PendingSN.get()
617 <<
" has dependence map entry for " << Container
618 <<
" with empty element set.\n";
619 for (
auto &Elem : Elems) {
620 if (
I->second.count(Elem)) {
621 ErrLog() <<
"Pending SN " << PendingSN.get()
622 <<
" has dependence on emitted element ( " << Container
623 <<
", " << Elem <<
")\n";
633 for (
auto &[Container, Elems] : PendingSN->Defs) {
635 ErrLog() <<
"Pending SN " << PendingSN.get()
636 <<
" has def map entry for " << Container
637 <<
" with empty element set.\n";
638 DefCount += Elems.size();
639 auto I = ElemToPendingSN.find(Container);
640 if (
I == ElemToPendingSN.end())
641 ErrLog() <<
"Pending SN " << PendingSN.get() <<
" has "
642 << Elems.size() <<
" defs in container " << Container
643 <<
" not covered by ElemsToPendingSN.\n";
645 for (
auto &Elem : Elems) {
646 auto J =
I->second.find(Elem);
647 if (J ==
I->second.end())
648 ErrLog() <<
"Pending SN " << PendingSN.get() <<
" has element ("
649 << Container <<
", " << Elem
650 <<
") not covered by ElemsToPendingSN.\n";
651 else if (J->second != PendingSN.get())
652 ErrLog() <<
"ElemToPendingSN value invalid for (" << Container
653 <<
", " << Elem <<
")\n";
659 size_t DefCount2 = 0;
660 for (
auto &[Container, Elems] : ElemToPendingSN)
661 DefCount2 += Elems.size();
663 assert(DefCount2 >= DefCount);
664 if (DefCount2 != DefCount)
665 ErrLog() <<
"ElemToPendingSN contains extra elements.\n";
672 static void hoistDeps(std::vector<std::unique_ptr<SuperNode>> &SNs,
673 SuperNodeDepsMap &SuperNodeDeps,
674 ElemToSuperNodeMap &ElemToSN) {
677 SN->hoistDeps(SuperNodeDeps, ElemToSN);
681 static void propagateDeps(SuperNodeDepsMap &SuperNodeDeps) {
684 if (SuperNodeDeps.empty())
688 Worklist.
reserve(SuperNodeDeps.size());
689 for (
auto &[SN, SNDependants] : SuperNodeDeps)
697 while (!Worklist.
empty()) {
699 auto I = SuperNodeDeps.find(SN);
700 if (
I == SuperNodeDeps.end())
703 for (
auto *DependantSN :
I->second)
704 if (DependantSN->Deps.merge(SN->Deps))
705 ToVisitNext.
insert(DependantSN);
708 if (ToVisitNext.
empty())
715 static void propagateFailures(DenseSet<SuperNode *> &FailedNodes,
716 SuperNodeDepsMap &SuperNodeDeps) {
717 if (FailedNodes.empty())
722 while (!Worklist.
empty()) {
724 auto I = SuperNodeDeps.find(SN);
725 if (
I == SuperNodeDeps.end())
728 for (
auto *DependantSN :
I->second)
729 if (FailedNodes.insert(DependantSN).second)
734 template <
typename GetExternalStateFn>
735 static DenseSet<SuperNode *>
736 processExternalDeps(std::vector<std::unique_ptr<SuperNode>> &SNs,
737 GetExternalStateFn &GetExternalState) {
738 DenseSet<SuperNode *> FailedSNs;
740 SN->Deps.visit([&](
ContainerId &Container, ElementSet &Elements) {
742 switch (GetExternalState(Container, Elem)) {
748 FailedSNs.insert(SN.get());
758 void processReadyOrFailed(std::vector<std::unique_ptr<SuperNode>> &SNs,
759 std::vector<std::unique_ptr<SuperNode>> &
Ready,
760 std::vector<std::unique_ptr<SuperNode>> &
Failed,
761 SuperNodeDepsMap &SuperNodeDeps,
762 const DenseSet<SuperNode *> &FailedSNs,
763 bool UnmapFromElemToSN) {
765 visitWithRemoval(SNs, [&](std::unique_ptr<SuperNode> &SN) {
766 bool SNFailed = FailedSNs.count(SN.get());
767 bool SNReady = SN->Deps.empty();
769 if (SNReady || SNFailed) {
770 if (UnmapFromElemToSN)
771 SN->unmapDefsFromThis();
773 ToList.push_back(std::move(SN));
780 std::vector<std::unique_ptr<SuperNode>> PendingSNs;
781 ElemToSuperNodeMap ElemToPendingSN;
782 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