LLVM 22.0.0git
WaitingOnGraph.h
Go to the documentation of this file.
1//===------ WaitingOnGraph.h - ORC symbol dependence graph ------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Defines WaitingOnGraph and related utilities.
10//
11//===----------------------------------------------------------------------===//
12#ifndef LLVM_EXECUTIONENGINE_ORC_WAITINGONGRAPH_H
13#define LLVM_EXECUTIONENGINE_ORC_WAITINGONGRAPH_H
14
15#include "llvm/ADT/DenseMap.h"
16#include "llvm/ADT/DenseSet.h"
17#include "llvm/ADT/STLExtras.h"
20
21#include <algorithm>
22#include <vector>
23
24namespace llvm::orc::detail {
25
26class WaitingOnGraphTest;
27
28/// WaitingOnGraph class template.
29///
30/// This type is intended to provide efficient dependence tracking for Symbols
31/// in an ORC program.
32///
33/// WaitingOnGraph models a directed graph with four partitions:
34/// 1. Not-yet-emitted nodes: Nodes identified as waited-on in an emit
35/// operation.
36/// 2. Emitted nodes: Nodes emitted and waiting on some non-empty set of
37/// other nodes.
38/// 3. Ready nodes: Nodes emitted and not waiting on any other nodes
39/// (either because they weren't waiting on any nodes when they were
40/// emitted, or because all transitively waited-on nodes have since
41/// been emitted).
42/// 4. Failed nodes: Nodes that have been marked as failed-to-emit, and
43/// nodes that were found to transitively wait-on some failed node.
44///
45/// Nodes are added to the graph by *emit* and *fail* operations.
46///
47/// The *emit* operation takes a bipartite *local dependence graph* as an
48/// argument and returns...
49/// a. the set of nodes (both existing and newly added from the local
50/// dependence graph) whose waiting-on set is the empty set, and...
51/// b. the set of newly added nodes that are found to depend on failed
52/// nodes.
53///
54/// The *fail* operation takes a set of failed nodes and returns the set of
55/// Emitted nodes that were waiting on the failed nodes.
56///
57/// The concrete representation adopts several approaches for efficiency:
58///
59/// 1. Only *Emitted* and *Not-yet-emitted* nodes are represented explicitly.
60/// *Ready* and *Failed* nodes are represented by the values returned by the
61/// GetExternalStateFn argument to *emit*.
62///
63/// 2. Labels are (*Container*, *Element*) pairs that are intended to represent
64/// ORC symbols (ORC uses types Container = JITDylib,
65/// Element = NonOwningSymbolStringPtr). The internal representation of the
66/// graph is optimized on the assumption that there are many more Elements
67/// (symbol names) than Containers (JITDylibs) used to construct the labels.
68/// (Consider for example the common case where most JIT'd code is placed in
69/// a single "main" JITDylib).
70///
71/// 3. The data structure stores *SuperNodes* which have multiple labels. This
72/// reduces the number of nodes and edges in the graph in the common case
73/// where many JIT symbols have the same set of dependencies. SuperNodes are
74/// coalesced when their dependence sets become equal.
75///
76/// 4. The *simplify* method can be applied to an initial *local dependence
77/// graph* (as a list of SuperNodes) to eliminate any internal dependence
78/// relationships that would have to be propagated internally by *emit*.
79/// Access to the WaitingOnGraph is assumed to be guarded by a mutex (ORC
80/// will access it from multiple threads) so this allows some pre-processing
81/// to be performed outside the mutex.
82template <typename ContainerIdT, typename ElementIdT> class WaitingOnGraph {
83 friend class WaitingOnGraphTest;
84
85public:
86 using ContainerId = ContainerIdT;
87 using ElementId = ElementIdT;
90
91 class SuperNode {
92 friend class WaitingOnGraph;
93 friend class WaitingOnGraphTest;
94
95 public:
97 : Defs(std::move(Defs)), Deps(std::move(Deps)) {}
98 ContainerElementsMap &defs() { return Defs; }
99 const ContainerElementsMap &defs() const { return Defs; }
100 ContainerElementsMap &deps() { return Deps; }
101 const ContainerElementsMap &deps() const { return Deps; }
102
103 private:
106 };
107
108private:
109 using ElemToSuperNodeMap =
111
112 using SuperNodeDepsMap = DenseMap<SuperNode *, DenseSet<SuperNode *>>;
113
114 class Coalescer {
115 public:
116 std::unique_ptr<SuperNode> addOrCreateSuperNode(ContainerElementsMap Defs,
118 auto H = getHash(Deps);
119 if (auto *ExistingSN = findCanonicalSuperNode(H, Deps)) {
120 for (auto &[Container, Elems] : Defs) {
121 auto &DstCElems = ExistingSN->Defs[Container];
122 [[maybe_unused]] size_t ExpectedSize =
123 DstCElems.size() + Elems.size();
124 DstCElems.insert(Elems.begin(), Elems.end());
125 assert(DstCElems.size() == ExpectedSize);
126 }
127 return nullptr;
128 }
129
130 auto NewSN =
131 std::make_unique<SuperNode>(std::move(Defs), std::move(Deps));
132 CanonicalSNs[H].push_back(NewSN.get());
133 return NewSN;
134 }
135
136 void coalesce(std::vector<std::unique_ptr<SuperNode>> &SNs,
137 ElemToSuperNodeMap &ElemToSN) {
138 for (size_t I = 0; I != SNs.size();) {
139 auto &SN = SNs[I];
140 auto H = getHash(SN->Deps);
141 if (auto *CanonicalSN = findCanonicalSuperNode(H, SN->Deps)) {
142 for (auto &[Container, Elems] : SN->Defs) {
143 CanonicalSN->Defs[Container].insert(Elems.begin(), Elems.end());
144 auto &ContainerElemToSN = ElemToSN[Container];
145 for (auto &Elem : Elems)
146 ContainerElemToSN[Elem] = CanonicalSN;
147 }
148 std::swap(SN, SNs.back());
149 SNs.pop_back();
150 } else {
151 CanonicalSNs[H].push_back(SN.get());
152 ++I;
153 }
154 }
155 }
156
157 template <typename Pred> void remove(Pred &&Remove) {
158 for (auto &[Hash, SNs] : CanonicalSNs) {
159 bool Found = false;
160 for (size_t I = 0; I != SNs.size(); ++I) {
161 if (Remove(SNs[I])) {
162 std::swap(SNs[I], SNs.back());
163 SNs.pop_back();
164 Found = true;
165 break;
166 }
167 }
168 if (Found) {
169 if (SNs.empty())
170 CanonicalSNs.erase(Hash);
171 break;
172 }
173 }
174 }
175
176 private:
177 hash_code getHash(const ContainerElementsMap &M) {
178 SmallVector<ContainerId> SortedContainers;
179 SortedContainers.reserve(M.size());
180 for (auto &[Container, Elems] : M)
181 SortedContainers.push_back(Container);
182 llvm::sort(SortedContainers);
183 hash_code Hash(0);
184 for (auto &Container : SortedContainers) {
185 auto &ContainerElems = M.at(Container);
186 SmallVector<ElementId> SortedElems(ContainerElems.begin(),
187 ContainerElems.end());
188 llvm::sort(SortedElems);
189 Hash = hash_combine(
190 Hash, Container,
191 hash_combine_range(SortedElems.begin(), SortedElems.end()));
192 }
193 return Hash;
194 }
195
196 SuperNode *findCanonicalSuperNode(hash_code H,
197 const ContainerElementsMap &M) {
198 for (auto *SN : CanonicalSNs[H])
199 if (SN->Deps == M)
200 return SN;
201 return nullptr;
202 }
203
204 DenseMap<hash_code, SmallVector<SuperNode *>> CanonicalSNs;
205 };
206
207public:
208 /// Build SuperNodes from (definition-set, dependence-set) pairs.
209 ///
210 /// Coalesces definition-sets with identical dependence-sets.
212 public:
214 if (Defs.empty())
215 return;
216 // Remove any self-reference.
218 for (auto &[Container, Elems] : Defs) {
219 assert(!Elems.empty() && "Defs for container must not be empty");
220 auto I = Deps.find(Container);
221 if (I == Deps.end())
222 continue;
223 auto &DepsForContainer = I->second;
224 for (auto &Elem : Elems)
225 DepsForContainer.erase(Elem);
226 if (DepsForContainer.empty())
227 ToRemove.push_back(Container);
228 }
229 for (auto &Container : ToRemove)
230 Deps.erase(Container);
231 if (auto SN = C.addOrCreateSuperNode(std::move(Defs), std::move(Deps)))
232 SNs.push_back(std::move(SN));
233 }
234 std::vector<std::unique_ptr<SuperNode>> takeSuperNodes() {
235 return std::move(SNs);
236 }
237
238 private:
239 Coalescer C;
240 std::vector<std::unique_ptr<SuperNode>> SNs;
241 };
242
243 class SimplifyResult {
244 friend class WaitingOnGraph;
245 friend class WaitingOnGraphTest;
246
247 public:
248 const std::vector<std::unique_ptr<SuperNode>> &superNodes() const {
249 return SNs;
250 }
251
252 private:
253 SimplifyResult(std::vector<std::unique_ptr<SuperNode>> SNs,
254 ElemToSuperNodeMap ElemToSN)
255 : SNs(std::move(SNs)), ElemToSN(std::move(ElemToSN)) {}
256 std::vector<std::unique_ptr<SuperNode>> SNs;
257 ElemToSuperNodeMap ElemToSN;
258 };
259
260 /// Preprocess a list of SuperNodes to remove all intra-SN dependencies.
261 static SimplifyResult simplify(std::vector<std::unique_ptr<SuperNode>> SNs) {
262 // Build ElemToSN map.
263 ElemToSuperNodeMap ElemToSN;
264 for (auto &SN : SNs) {
265 for (auto &[Container, Elements] : SN->Defs) {
266 auto &ContainerElemToSN = ElemToSN[Container];
267 for (auto &E : Elements)
268 ContainerElemToSN[E] = SN.get();
269 }
270 }
271
272 SuperNodeDepsMap SuperNodeDeps;
273 hoistDeps(SuperNodeDeps, SNs, ElemToSN);
274 propagateSuperNodeDeps(SuperNodeDeps);
275 sinkDeps(SNs, SuperNodeDeps);
276
277 // Pre-coalesce nodes.
278 Coalescer().coalesce(SNs, ElemToSN);
279
280 return {std::move(SNs), std::move(ElemToSN)};
281 }
282
283 struct EmitResult {
284 std::vector<std::unique_ptr<SuperNode>> Ready;
285 std::vector<std::unique_ptr<SuperNode>> Failed;
286 };
287
288 enum class ExternalState { None, Ready, Failed };
289
290 /// Add the given SuperNodes to the graph, returning any SuperNodes that
291 /// move to the Ready or Failed states as a result.
292 /// The GetExternalState function is used to represent SuperNodes that have
293 /// already become Ready or Failed (since such nodes are not explicitly
294 /// represented in the graph).
295 template <typename GetExternalStateFn>
296 EmitResult emit(SimplifyResult SR, GetExternalStateFn &&GetExternalState) {
297 auto NewSNs = std::move(SR.SNs);
298 auto ElemToNewSN = std::move(SR.ElemToSN);
299
300 // First process any dependencies on nodes with external state.
301 auto FailedSNs = processExternalDeps(NewSNs, GetExternalState);
302
303 // Collect the PendingSNs whose dep sets are about to be modified.
304 std::vector<std::unique_ptr<SuperNode>> ModifiedPendingSNs;
305 for (size_t I = 0; I != PendingSNs.size();) {
306 auto &SN = PendingSNs[I];
307 bool Remove = false;
308 for (auto &[Container, Elems] : SN->Deps) {
309 auto I = ElemToNewSN.find(Container);
310 if (I == ElemToNewSN.end())
311 continue;
312 for (auto Elem : Elems) {
313 if (I->second.contains(Elem)) {
314 Remove = true;
315 break;
316 }
317 }
318 if (Remove)
319 break;
320 }
321 if (Remove) {
322 ModifiedPendingSNs.push_back(std::move(SN));
323 std::swap(SN, PendingSNs.back());
324 PendingSNs.pop_back();
325 } else
326 ++I;
327 }
328
329 // Remove cycles from the graphs.
330 SuperNodeDepsMap SuperNodeDeps;
331 hoistDeps(SuperNodeDeps, ModifiedPendingSNs, ElemToNewSN);
332
333 CoalesceToPendingSNs.remove(
334 [&](SuperNode *SN) { return SuperNodeDeps.count(SN); });
335
336 hoistDeps(SuperNodeDeps, NewSNs, ElemToPendingSN);
337 propagateSuperNodeDeps(SuperNodeDeps);
338 sinkDeps(NewSNs, SuperNodeDeps);
339 sinkDeps(ModifiedPendingSNs, SuperNodeDeps);
340
341 // Process supernodes. Pending first, since we'll update PendingSNs when we
342 // incorporate NewSNs.
343 std::vector<std::unique_ptr<SuperNode>> ReadyNodes, FailedNodes;
344 processReadyOrFailed(ModifiedPendingSNs, ReadyNodes, FailedNodes,
345 SuperNodeDeps, ElemToPendingSN, FailedSNs);
346 processReadyOrFailed(NewSNs, ReadyNodes, FailedNodes, SuperNodeDeps,
347 ElemToNewSN, FailedSNs);
348
349 CoalesceToPendingSNs.coalesce(ModifiedPendingSNs, ElemToPendingSN);
350 CoalesceToPendingSNs.coalesce(NewSNs, ElemToPendingSN);
351
352 // Integrate remaining ModifiedPendingSNs and NewSNs into PendingSNs.
353 for (auto &SN : ModifiedPendingSNs)
354 PendingSNs.push_back(std::move(SN));
355
356 // Update ElemToPendingSN for the remaining elements.
357 for (auto &SN : NewSNs) {
358 for (auto &[Container, Elems] : SN->Defs) {
359 auto &Row = ElemToPendingSN[Container];
360 for (auto &Elem : Elems)
361 Row[Elem] = SN.get();
362 }
363 PendingSNs.push_back(std::move(SN));
364 }
365
366 return {std::move(ReadyNodes), std::move(FailedNodes)};
367 }
368
369 /// Identify the given symbols as Failed.
370 /// The elements of the Failed map will not be included in the returned
371 /// result, so clients should take whatever actions are needed to mark
372 /// this as failed in their external representation.
373 std::vector<std::unique_ptr<SuperNode>>
375 std::vector<std::unique_ptr<SuperNode>> FailedSNs;
376
377 for (size_t I = 0; I != PendingSNs.size();) {
378 auto &PendingSN = PendingSNs[I];
379 bool FailPendingSN = false;
380 for (auto &[Container, Elems] : PendingSN->Deps) {
381 if (FailPendingSN)
382 break;
383 auto I = Failed.find(Container);
384 if (I == Failed.end())
385 continue;
386 for (auto &Elem : Elems) {
387 if (I->second.count(Elem)) {
388 FailPendingSN = true;
389 break;
390 }
391 }
392 }
393 if (FailPendingSN) {
394 FailedSNs.push_back(std::move(PendingSN));
395 PendingSN = std::move(PendingSNs.back());
396 PendingSNs.pop_back();
397 } else
398 ++I;
399 }
400
401 for (auto &SN : FailedSNs) {
402 CoalesceToPendingSNs.remove(
403 [&](SuperNode *SNC) { return SNC == SN.get(); });
404 for (auto &[Container, Elems] : SN->Defs) {
405 assert(ElemToPendingSN.count(Container));
406 auto &CElems = ElemToPendingSN[Container];
407 for (auto &Elem : Elems)
408 CElems.erase(Elem);
409 if (CElems.empty())
410 ElemToPendingSN.erase(Container);
411 }
412 }
413
414 return FailedSNs;
415 }
416
418 bool AllGood = true;
419 auto ErrLog = [&]() -> raw_ostream & {
420 AllGood = false;
421 return Log;
422 };
423
424 size_t DefCount = 0;
425 for (auto &PendingSN : PendingSNs) {
426 if (PendingSN->Deps.empty())
427 ErrLog() << "Pending SN " << PendingSN.get() << " has empty dep set.\n";
428 else {
429 bool BadElem = false;
430 for (auto &[Container, Elems] : PendingSN->Deps) {
431 auto I = ElemToPendingSN.find(Container);
432 if (I == ElemToPendingSN.end())
433 continue;
434 if (Elems.empty())
435 ErrLog() << "Pending SN " << PendingSN.get()
436 << " has dependence map entry for " << Container
437 << " with empty element set.\n";
438 for (auto &Elem : Elems) {
439 if (I->second.count(Elem)) {
440 ErrLog() << "Pending SN " << PendingSN.get()
441 << " has dependence on emitted element ( " << Container
442 << ", " << Elem << ")\n";
443 BadElem = true;
444 break;
445 }
446 }
447 if (BadElem)
448 break;
449 }
450 }
451
452 for (auto &[Container, Elems] : PendingSN->Defs) {
453 if (Elems.empty())
454 ErrLog() << "Pending SN " << PendingSN.get()
455 << " has def map entry for " << Container
456 << " with empty element set.\n";
457 DefCount += Elems.size();
458 auto I = ElemToPendingSN.find(Container);
459 if (I == ElemToPendingSN.end())
460 ErrLog() << "Pending SN " << PendingSN.get() << " has "
461 << Elems.size() << " defs in container " << Container
462 << " not covered by ElemsToPendingSN.\n";
463 else {
464 for (auto &Elem : Elems) {
465 auto J = I->second.find(Elem);
466 if (J == I->second.end())
467 ErrLog() << "Pending SN " << PendingSN.get() << " has element ("
468 << Container << ", " << Elem
469 << ") not covered by ElemsToPendingSN.\n";
470 else if (J->second != PendingSN.get())
471 ErrLog() << "ElemToPendingSN value invalid for (" << Container
472 << ", " << Elem << ")\n";
473 }
474 }
475 }
476 }
477
478 size_t DefCount2 = 0;
479 for (auto &[Container, Elems] : ElemToPendingSN)
480 DefCount2 += Elems.size();
481
482 assert(DefCount2 >= DefCount);
483 if (DefCount2 != DefCount)
484 ErrLog() << "ElemToPendingSN contains extra elements.\n";
485
486 return AllGood;
487 }
488
489private:
490 // Replace individual dependencies with supernode dependencies.
491 //
492 // For all dependencies in SNs, if the corresponding node is defined in
493 // ElemToSN then remove the individual dependency and add the record the
494 // dependency on the corresponding supernode in SuperNodeDeps.
495 static void hoistDeps(SuperNodeDepsMap &SuperNodeDeps,
496 std::vector<std::unique_ptr<SuperNode>> &SNs,
497 ElemToSuperNodeMap &ElemToSN) {
498 for (auto &SN : SNs) {
499 auto &SNDeps = SuperNodeDeps[SN.get()];
500 for (auto &[DefContainer, DefElems] : ElemToSN) {
501 auto I = SN->Deps.find(DefContainer);
502 if (I == SN->Deps.end())
503 continue;
504 for (auto &[DefElem, DefSN] : DefElems)
505 if (I->second.erase(DefElem))
506 SNDeps.insert(DefSN);
507 if (I->second.empty())
508 SN->Deps.erase(I);
509 }
510 }
511 }
512
513 // Compute transitive closure of deps for each node.
514 static void propagateSuperNodeDeps(SuperNodeDepsMap &SuperNodeDeps) {
515 for (auto &[SN, Deps] : SuperNodeDeps) {
516 DenseSet<SuperNode *> Reachable({SN});
517 SmallVector<SuperNode *> Worklist(Deps.begin(), Deps.end());
518
519 while (!Worklist.empty()) {
520 auto *DepSN = Worklist.pop_back_val();
521 if (!Reachable.insert(DepSN).second)
522 continue;
523 auto I = SuperNodeDeps.find(DepSN);
524 if (I == SuperNodeDeps.end())
525 continue;
526 for (auto *DepSNDep : I->second)
527 Worklist.push_back(DepSNDep);
528 }
529
530 Deps = std::move(Reachable);
531 }
532 }
533
534 // Sink SuperNode dependencies back to dependencies on individual nodes.
535 static void sinkDeps(std::vector<std::unique_ptr<SuperNode>> &SNs,
536 SuperNodeDepsMap &SuperNodeDeps) {
537 for (auto &SN : SNs) {
538 auto I = SuperNodeDeps.find(SN.get());
539 if (I == SuperNodeDeps.end())
540 continue;
541
542 for (auto *DepSN : I->second)
543 for (auto &[Container, Elems] : DepSN->Deps)
544 SN->Deps[Container].insert(Elems.begin(), Elems.end());
545 }
546 }
547
548 template <typename GetExternalStateFn>
549 static std::vector<SuperNode *>
550 processExternalDeps(std::vector<std::unique_ptr<SuperNode>> &SNs,
551 GetExternalStateFn &GetExternalState) {
552 std::vector<SuperNode *> FailedSNs;
553 for (auto &SN : SNs) {
554 bool SNHasError = false;
555 SmallVector<ContainerId> ContainersToRemove;
556 for (auto &[Container, Elems] : SN->Deps) {
557 SmallVector<ElementId> ElemToRemove;
558 for (auto &Elem : Elems) {
559 switch (GetExternalState(Container, Elem)) {
561 break;
563 ElemToRemove.push_back(Elem);
564 break;
566 ElemToRemove.push_back(Elem);
567 SNHasError = true;
568 break;
569 }
570 }
571 for (auto &Elem : ElemToRemove)
572 Elems.erase(Elem);
573 if (Elems.empty())
574 ContainersToRemove.push_back(Container);
575 }
576 for (auto &Container : ContainersToRemove)
577 SN->Deps.erase(Container);
578 if (SNHasError)
579 FailedSNs.push_back(SN.get());
580 }
581
582 return FailedSNs;
583 }
584
585 void processReadyOrFailed(std::vector<std::unique_ptr<SuperNode>> &SNs,
586 std::vector<std::unique_ptr<SuperNode>> &Ready,
587 std::vector<std::unique_ptr<SuperNode>> &Failed,
588 SuperNodeDepsMap &SuperNodeDeps,
589 ElemToSuperNodeMap &ElemToSNs,
590 std::vector<SuperNode *> FailedSNs) {
591 for (size_t I = 0; I != SNs.size();) {
592 auto &SN = SNs[I];
593
594 bool SNFailed = false;
595 assert(SuperNodeDeps.count(SN.get()));
596 auto &SNSuperNodeDeps = SuperNodeDeps[SN.get()];
597 for (auto *FailedSN : FailedSNs) {
598 if (FailedSN == SN.get() || SNSuperNodeDeps.count(FailedSN)) {
599 SNFailed = true;
600 break;
601 }
602 }
603
604 bool SNReady = SN->Deps.empty();
605
606 if (SNReady || SNFailed) {
607 auto &NodeList = SNFailed ? Failed : Ready;
608 NodeList.push_back(std::move(SN));
609 std::swap(SN, SNs.back());
610 SNs.pop_back();
611 } else
612 ++I;
613 }
614 }
615
616 std::vector<std::unique_ptr<SuperNode>> PendingSNs;
617 ElemToSuperNodeMap ElemToPendingSN;
618 Coalescer CoalesceToPendingSNs;
619};
620
621} // namespace llvm::orc::detail
622
623#endif // LLVM_EXECUTIONENGINE_ORC_WAITINGONGRAPH_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
ReachingDefInfo InstSet & ToRemove
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file defines the DenseMap class.
This file defines the DenseSet and SmallDenseSet classes.
#define I(x, y, z)
Definition MD5.cpp:58
#define H(x, y, z)
Definition MD5.cpp:57
register Register Coalescer
This file contains some templates that are useful if you are working with the STL at all.
This file defines the SmallVector class.
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:167
bool erase(const KeyT &Val)
Definition DenseMap.h:311
bool empty() const
Definition DenseMap.h:109
iterator end()
Definition DenseMap.h:81
Implements a dense probed hash-table based set.
Definition DenseSet.h:279
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
const std::vector< std::unique_ptr< SuperNode > > & superNodes() const
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
const ContainerElementsMap & deps() const
SuperNode(ContainerElementsMap Defs, ContainerElementsMap Deps)
WaitingOnGraph class template.
std::vector< std::unique_ptr< SuperNode > > fail(const ContainerElementsMap &Failed)
Identify the given symbols as Failed.
EmitResult emit(SimplifyResult SR, GetExternalStateFn &&GetExternalState)
Add the given SuperNodes to the graph, returning any SuperNodes that move to the Ready or Failed stat...
static SimplifyResult simplify(std::vector< std::unique_ptr< SuperNode > > SNs)
Preprocess a list of SuperNodes to remove all intra-SN dependencies.
bool validate(raw_ostream &Log)
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
SmallVector< Node, 4 > NodeList
Definition RDFGraph.h:550
testing::Matcher< const detail::ErrorHolder & > Failed()
Definition Error.h:198
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1622
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.
Definition STLExtras.h:1867
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition Hashing.h:592
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
Definition Hashing.h:466
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:867
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:869
std::vector< std::unique_ptr< SuperNode > > Failed
std::vector< std::unique_ptr< SuperNode > > Ready