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