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
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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.
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