LLVM: lib/Analysis/BlockFrequencyInfoImpl.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
18#include "llvm/Config/llvm-config.h"
27#include
28#include
29#include
30#include
31#include
32#include
33#include
34#include
35#include
36#include
37
38using namespace llvm;
40
41#define DEBUG_TYPE "block-freq"
42
43namespace llvm {
45 "check-bfi-unknown-block-queries",
47 cl::desc("Check if block frequency is queried for an unknown block "
48 "for debugging missed BFI updates"));
49
51 "use-iterative-bfi-inference", cl::Hidden,
52 cl::desc("Apply an iterative post-processing to infer correct BFI counts"));
53
56 cl::desc("Iterative inference: maximum number of update iterations "
57 "per block"));
58
61 cl::desc("Iterative inference: delta convergence precision; smaller values "
62 "typically lead to better results at the cost of worsen runtime"));
63}
64
69}
70
71#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
73#endif
74
77 if (N < 10)
78 return '0' + N;
79 return 'a' + N - 10;
80}
81
83 for (int Digits = 0; Digits < 16; ++Digits)
84 OS << getHexDigit(Mass >> (60 - Digits * 4) & 0xf);
85 return OS;
86}
87
88namespace {
89
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116struct DitheringDistributer {
119
120 DitheringDistributer(Distribution &Dist, const BlockMass &Mass);
121
123};
124
125}
126
127DitheringDistributer::DitheringDistributer(Distribution &Dist,
129 Dist.normalize();
130 RemWeight = Dist.Total;
131 RemMass = Mass;
132}
133
135 assert(Weight && "invalid weight");
136 assert(Weight <= RemWeight);
138
139
140 RemWeight -= Weight;
141 RemMass -= Mass;
142 return Mass;
143}
144
145void Distribution::add(const BlockNode &Node, uint64_t Amount,
146 Weight::DistType Type) {
147 assert(Amount && "invalid weight of 0");
149
150
151 bool IsOverflow = NewTotal < Total;
152 assert(!(DidOverflow && IsOverflow) && "unexpected repeated overflow");
153 DidOverflow |= IsOverflow;
154
155
156 Total = NewTotal;
157
158
159 Weights.push_back(Weight(Type, Node, Amount));
160}
161
163 assert(OtherW.TargetNode.isValid());
164 if (!W.Amount) {
165 W = OtherW;
166 return;
167 }
168 assert(W.Type == OtherW.Type);
169 assert(W.TargetNode == OtherW.TargetNode);
170 assert(OtherW.Amount && "Expected non-zero weight");
171 if (W.Amount > W.Amount + OtherW.Amount)
172
174 else
175 W.Amount += OtherW.Amount;
176}
177
179
180 llvm::sort(Weights, [](const Weight &L, const Weight &R) {
181 return L.TargetNode < R.TargetNode;
182 });
183
184
185 WeightList::iterator O = Weights.begin();
186 for (WeightList::const_iterator I = O, L = O, E = Weights.end(); I != E;
187 ++O, (I = L)) {
188 *O = *I;
189
190
191 for (++L; L != E && I->TargetNode == L->TargetNode; ++L)
193 }
194
195
196 Weights.erase(O, Weights.end());
197}
198
200
202
203 HashTable Combined(NextPowerOf2(2 * Weights.size()));
204 for (const Weight &W : Weights)
206
207
208 if (Weights.size() == Combined.size())
209 return;
210
211
212 Weights.clear();
213 Weights.reserve(Combined.size());
214 for (const auto &I : Combined)
215 Weights.push_back(I.second);
216}
217
219
220 if (Weights.size() > 128) {
222 return;
223 }
224
226}
227
231 if (!Shift)
232 return N;
233 return (N >> Shift) + (UINT64_C(1) & N >> (Shift - 1));
234}
235
236void Distribution::normalize() {
237
238 if (Weights.empty())
239 return;
240
241
242 if (Weights.size() > 1)
244
245
246 if (Weights.size() == 1) {
248 Weights.front().Amount = 1;
249 return;
250 }
251
252
253
254
255
256 int Shift = 0;
257 if (DidOverflow)
258 Shift = 33;
259 else if (Total > UINT32_MAX)
261
262
263 if (!Shift) {
264
265
266 assert(Total == std::accumulate(Weights.begin(), Weights.end(), UINT64_C(0),
268 return Sum + W.Amount;
269 }) &&
270 "Expected total to be correct");
271 return;
272 }
273
274
275
277
278
279 for (Weight &W : Weights) {
280
281
282 assert(W.TargetNode.isValid());
283 W.Amount = std::max(UINT64_C(1), shiftRightAndRound(W.Amount, Shift));
284 assert(W.Amount <= UINT32_MAX);
285
286
287 Total += W.Amount;
288 }
290}
291
293
294
295 std::vector().swap(Freqs);
296 IsIrrLoopHeader.clear();
297 std::vector().swap(Working);
299}
300
301
302
303
305 std::vector SavedFreqs(std::move(BFI.Freqs));
306 SparseBitVector<> SavedIsIrrLoopHeader(std::move(BFI.IsIrrLoopHeader));
307 BFI.clear();
308 BFI.Freqs = std::move(SavedFreqs);
309 BFI.IsIrrLoopHeader = std::move(SavedIsIrrLoopHeader);
310}
311
319
320 auto isLoopHeader = [&OuterLoop](const BlockNode &Node) {
321 return OuterLoop && OuterLoop->isHeader(Node);
322 };
323
324 BlockNode Resolved = Working[Succ.Index].getResolvedNode();
325
326#ifndef NDEBUG
327 auto debugSuccessor = [&](const char *Type) {
328 dbgs() << " =>"
329 << " [" << Type << "] weight = " << Weight;
330 if (!isLoopHeader(Resolved))
332 if (Resolved != Succ)
334 dbgs() << "\n";
335 };
336 (void)debugSuccessor;
337#endif
338
339 if (isLoopHeader(Resolved)) {
340 LLVM_DEBUG(debugSuccessor("backedge"));
342 return true;
343 }
344
345 if (Working[Resolved.Index].getContainingLoop() != OuterLoop) {
346 LLVM_DEBUG(debugSuccessor(" exit "));
348 return true;
349 }
350
351 if (Resolved < Pred) {
352 if (!isLoopHeader(Pred)) {
353
355 "unhandled irreducible control flow");
356
357
358 LLVM_DEBUG(debugSuccessor("abort!!!"));
359 return false;
360 }
361
362
363
364
365 assert(OuterLoop && OuterLoop->isIrreducible() && !isLoopHeader(Resolved) &&
366 "unhandled irreducible control flow");
367 }
368
369 LLVM_DEBUG(debugSuccessor(" local "));
371 return true;
372}
373
376
377 for (const auto &I : Loop.Exits)
378 if (!addToDist(Dist, OuterLoop, Loop.getHeader(), I.first,
379 I.second.getMass()))
380
381 return false;
382
383 return true;
384}
385
386
388
389 LLVM_DEBUG(dbgs() << "compute-loop-scale: " << getLoopName(Loop) << "\n");
390
391
392
393
394
395
396
397
398
399
400 const Scaled64 InfiniteLoopScale(1, 12);
401
402
403
405 for (auto &Mass : Loop.BackedgeMass)
406 TotalBackedgeMass += Mass;
408
409
410
411
414
415 LLVM_DEBUG(dbgs() << " - exit-mass = " << ExitMass << " ("
417 << ")\n"
418 << " - scale = " << Loop.Scale << "\n");
419}
420
421
423 LLVM_DEBUG(dbgs() << "packaging-loop: " << getLoopName(Loop) << "\n");
424
425
427 if (auto *Loop = Working[M.Index].getPackagedLoop())
428 Loop->Exits.clear();
430 }
431 Loop.IsPackaged = true;
432}
433
434#ifndef NDEBUG
436 const DitheringDistributer &D, const BlockNode &T,
438 dbgs() << " => assign " << M << " (" << D.RemMass << ")";
440 dbgs() << " [" << Desc << "]";
441 if (T.isValid())
442 dbgs() << " to " << BFI.getBlockName(T);
443 dbgs() << "\n";
444}
445#endif
446
452
453
454 DitheringDistributer D(Dist, Mass);
455
457
458 BlockMass Taken = D.takeMass(W.Amount);
459 if (W.Type == Weight::Local) {
460 Working[W.TargetNode.Index].getMass() += Taken;
462 continue;
463 }
464
465
466 assert(OuterLoop && "backedge or exit outside of loop");
467
468
469 if (W.Type == Weight::Backedge) {
472 continue;
473 }
474
475
476 assert(W.Type == Weight::Exit);
477 OuterLoop->Exits.push_back(std::make_pair(W.TargetNode, Taken));
479 }
480}
481
483 const Scaled64 &Min, const Scaled64 &Max) {
484
485
486
487
488
489
490
491 const unsigned MaxBits = sizeof(Scaled64::DigitsType) * CHAR_BIT;
492
493
494
495 const unsigned Slack = 10;
496 Scaled64 ScalingFactor = Scaled64(1, MaxBits - Slack) / Max;
497
498
499 LLVM_DEBUG(dbgs() << "float-to-int: min = " << Min << ", max = " << Max
500 << ", factor = " << ScalingFactor << "\n");
501 (void)Min;
502 for (size_t Index = 0; Index < BFI.Freqs.size(); ++Index) {
503 Scaled64 Scaled = BFI.Freqs[Index].Scaled * ScalingFactor;
504 BFI.Freqs[Index].Integer = std::max(UINT64_C(1), Scaled.toInt<uint64_t>());
505 LLVM_DEBUG(dbgs() << " - " << BFI.getBlockName(Index) << ": float = "
506 << BFI.Freqs[Index].Scaled << ", scaled = " << Scaled
507 << ", int = " << BFI.Freqs[Index].Integer << "\n");
508 }
509}
510
511
512
513
514
516 LLVM_DEBUG(dbgs() << "unwrap-loop-package: " << BFI.getLoopName(Loop)
517 << ": mass = " << Loop.Mass << ", scale = " << Loop.Scale
518 << "\n");
519 Loop.Scale *= Loop.Mass.toScaled();
520 Loop.IsPackaged = false;
522
523
524
525
526 for (const BlockNode &N : Loop.Nodes) {
527 const auto &Working = BFI.Working[N.Index];
528 Scaled64 &F = Working.isAPackage() ? Working.getPackagedLoop()->Scale
529 : BFI.Freqs[N.Index].Scaled;
530 Scaled64 New = Loop.Scale * F;
531 LLVM_DEBUG(dbgs() << " - " << BFI.getBlockName(N) << ": " << F << " => "
532 << New << "\n");
533 F = New;
534 }
535}
536
538
539 for (size_t Index = 0; Index < Working.size(); ++Index)
540 Freqs[Index].Scaled = Working[Index].Mass.toScaled();
541
544}
545
547
548
549 auto Min = Scaled64::getLargest();
550 auto Max = Scaled64::getZero();
551 for (size_t Index = 0; Index < Working.size(); ++Index) {
552
553 Min = std::min(Min, Freqs[Index].Scaled);
554 Max = std::max(Max, Freqs[Index].Scaled);
555 }
556
557
559
560
562
563
565}
566
569 if (!Node.isValid()) {
570#ifndef NDEBUG
574 OS << "*** Detected BFI query for unknown block " << getBlockName(Node);
576 }
577#endif
579 }
581}
582
583std::optional<uint64_t>
586 bool AllowSynthetic) const {
587 return getProfileCountFromFreq(F, getBlockFreq(Node), AllowSynthetic);
588}
589
592 auto EntryCount = F.getEntryCount(AllowSynthetic);
593 if (!EntryCount)
594 return std::nullopt;
595
596 APInt BlockCount(128, EntryCount->getCount());
598 APInt EntryFreq(128, getEntryFreq().getFrequency());
599 BlockCount *= BlockFreq;
600
601
602 BlockCount = (BlockCount + EntryFreq.lshr(1)).udiv(EntryFreq);
604}
605
606bool
608 if (!Node.isValid())
609 return false;
610 return IsIrrLoopHeader.test(Node.Index);
611}
612
613Scaled64
615 if (!Node.isValid())
616 return Scaled64::getZero();
617 return Freqs[Node.Index].Scaled;
618}
619
622 assert(Node.isValid() && "Expected valid node");
623 assert(Node.Index < Freqs.size() && "Expected legal index");
624 Freqs[Node.Index].Integer = Freq.getFrequency();
625}
626
627std::string
629 return {};
630}
631
632std::string
635}
636
640 for (auto N : OuterLoop.Nodes)
643}
644
648 if (.Working[Index].isPackaged())
651}
652
656}
657
660 if (OuterLoop && OuterLoop->isHeader(Succ))
661 return;
663 if (L == Lookup.end())
664 return;
665 IrrNode &SuccIrr = *L->second;
666 Irr.Edges.push_back(&SuccIrr);
667 SuccIrr.Edges.push_front(&Irr);
669}
670
671namespace llvm {
672
677
681};
682
683}
684
685
686
687
688
692 const std::vector<const IrreducibleGraph::IrrNode *> &SCC,
693 LoopData::NodeList &Headers, LoopData::NodeList &Others) {
694
696
697
698 for (const auto *I : SCC)
699 InSCC[I] = false;
700
701 for (auto I = InSCC.begin(), E = InSCC.end(); I != E; ++I) {
702 auto &Irr = *I->first;
703 for (const auto *P : make_range(Irr.pred_begin(), Irr.pred_end())) {
705 continue;
706
707
708 I->second = true;
709 Headers.push_back(Irr.Node);
710 LLVM_DEBUG(dbgs() << " => entry = " << BFI.getBlockName(Irr.Node)
711 << "\n");
712 break;
713 }
714 }
715 assert(Headers.size() >= 2 &&
716 "Expected irreducible CFG; -loop-info is likely invalid");
717 if (Headers.size() == InSCC.size()) {
718
720 return;
721 }
722
723
724 for (const auto &I : InSCC) {
725
726 if (I.second)
727 continue;
728
729 auto &Irr = *I.first;
730 for (const auto *P : make_range(Irr.pred_begin(), Irr.pred_end())) {
731
732 if (P->Node < Irr.Node)
733 continue;
734
735
736
738 continue;
739
740
741 Headers.push_back(Irr.Node);
742 LLVM_DEBUG(dbgs() << " => extra = " << BFI.getBlockName(Irr.Node)
743 << "\n");
744 break;
745 }
746 if (Headers.back() == Irr.Node)
747
748 continue;
749
750
751 Others.push_back(Irr.Node);
752 LLVM_DEBUG(dbgs() << " => other = " << BFI.getBlockName(Irr.Node) << "\n");
753 }
756}
757
760 LoopData *OuterLoop, std::list::iterator Insert,
761 const std::vector<const IrreducibleGraph::IrrNode *> &SCC) {
762
764
765 LoopData::NodeList Headers;
766 LoopData::NodeList Others;
768
769 auto Loop = BFI.Loops.emplace(Insert, OuterLoop, Headers.begin(),
770 Headers.end(), Others.begin(), Others.end());
771
772
773 for (const auto &N : Loop->Nodes)
774 if (BFI.Working[N.Index].isLoopHeader())
775 BFI.Working[N.Index].Loop->Parent = &*Loop;
776 else
777 BFI.Working[N.Index].Loop = &*Loop;
778}
779
783 std::list::iterator Insert) {
784 assert((OuterLoop == nullptr) == (Insert == Loops.begin()));
785 auto Prev = OuterLoop ? std::prev(Insert) : Loops.end();
786
788 if (I->size() < 2)
789 continue;
790
791
793 }
794
795 if (OuterLoop)
796 return make_range(std::next(Prev), Insert);
798}
799
800void
805 auto O = OuterLoop.Nodes.begin() + 1;
806 for (auto I = O, E = OuterLoop.Nodes.end(); I != E; ++I)
807 if (!Working[I->Index].isPackaged())
808 *O++ = *I;
810}
811
813 assert(Loop.isIrreducible() && "this only makes sense on irreducible loops");
814
815
816
817
818
819
820
823
826 auto &HeaderNode = Loop.Nodes[H];
827 auto &BackedgeMass = Loop.BackedgeMass[Loop.getHeaderIndex(HeaderNode)];
828 LLVM_DEBUG(dbgs() << " - Add back edge mass for node "
829 << getBlockName(HeaderNode) << ": " << BackedgeMass
830 << "\n");
831 if (BackedgeMass.getMass() > 0)
832 Dist.addLocal(HeaderNode, BackedgeMass.getMass());
833 else
834 LLVM_DEBUG(dbgs() << " Nothing added. Back edge mass is zero\n");
835 }
836
837 DitheringDistributer D(Dist, LoopMass);
838
839 LLVM_DEBUG(dbgs() << " Distribute loop mass " << LoopMass
840 << " to headers using above weights\n");
842 BlockMass Taken = D.takeMass(W.Amount);
843 assert(W.Type == Weight::Local && "all weights should be local");
844 Working[W.TargetNode.Index].getMass() = Taken;
846 }
847}
848
851 DitheringDistributer D(Dist, LoopMass);
853 BlockMass Taken = D.takeMass(W.Amount);
854 assert(W.Type == Weight::Local && "all weights should be local");
855 Working[W.TargetNode.Index].getMass() = Taken;
857 }
858}
This file implements a class to represent arbitrary precision integral constant values and operations...
static void combineWeightsBySorting(WeightList &Weights)
static void cleanup(BlockFrequencyInfoImplBase &BFI)
Clear all memory not needed downstream.
static void combineWeightsByHashing(WeightList &Weights)
static void unwrapLoop(BlockFrequencyInfoImplBase &BFI, LoopData &Loop)
Unwrap a loop package.
static void combineWeight(Weight &W, const Weight &OtherW)
static void debugAssign(const BlockFrequencyInfoImplBase &BFI, const DitheringDistributer &D, const BlockNode &T, const BlockMass &M, const char *Desc)
static void combineWeights(WeightList &Weights)
static char getHexDigit(int N)
static void findIrreducibleHeaders(const BlockFrequencyInfoImplBase &BFI, const IrreducibleGraph &G, const std::vector< const IrreducibleGraph::IrrNode * > &SCC, LoopData::NodeList &Headers, LoopData::NodeList &Others)
Find extra irreducible headers.
static void convertFloatingToInteger(BlockFrequencyInfoImplBase &BFI, const Scaled64 &Min, const Scaled64 &Max)
static void createIrreducibleLoop(BlockFrequencyInfoImplBase &BFI, const IrreducibleGraph &G, LoopData *OuterLoop, std::list< LoopData >::iterator Insert, const std::vector< const IrreducibleGraph::IrrNode * > &SCC)
static uint64_t shiftRightAndRound(uint64_t N, int Shift)
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
This file defines the DenseMap class.
This builds on the llvm/ADT/GraphTraits.h file to find the strongly connected components (SCCs) of a ...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallString class.
Class for arbitrary precision integers.
uint64_t getLimitedValue(uint64_t Limit=UINT64_MAX) const
If this value is smaller than the specified limit, return it, otherwise return the limit value.
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
Base class for BlockFrequencyInfoImpl.
std::vector< WorkingData > Working
Loop data: see initializeLoops().
bool addLoopSuccessorsToDist(const LoopData *OuterLoop, LoopData &Loop, Distribution &Dist)
Add all edges out of a packaged loop to the distribution.
ScaledNumber< uint64_t > Scaled64
std::string getLoopName(const LoopData &Loop) const
bool isIrrLoopHeader(const BlockNode &Node)
void computeLoopScale(LoopData &Loop)
Compute the loop scale for a loop.
void packageLoop(LoopData &Loop)
Package up a loop.
virtual std::string getBlockName(const BlockNode &Node) const
void finalizeMetrics()
Finalize frequency metrics.
void setBlockFreq(const BlockNode &Node, BlockFrequency Freq)
void updateLoopWithIrreducible(LoopData &OuterLoop)
Update a loop after packaging irreducible SCCs inside of it.
void clear()
Clear all memory.
std::optional< uint64_t > getBlockProfileCount(const Function &F, const BlockNode &Node, bool AllowSynthetic=false) const
BlockFrequency getBlockFreq(const BlockNode &Node) const
void distributeIrrLoopHeaderMass(Distribution &Dist)
iterator_range< std::list< LoopData >::iterator > analyzeIrreducible(const bfi_detail::IrreducibleGraph &G, LoopData *OuterLoop, std::list< LoopData >::iterator Insert)
Analyze irreducible SCCs.
bool addToDist(Distribution &Dist, const LoopData *OuterLoop, const BlockNode &Pred, const BlockNode &Succ, uint64_t Weight)
Add an edge to the distribution.
void unwrapLoops()
Unwrap loops.
std::optional< uint64_t > getProfileCountFromFreq(const Function &F, BlockFrequency Freq, bool AllowSynthetic=false) const
Scaled64 getFloatingBlockFreq(const BlockNode &Node) const
void distributeMass(const BlockNode &Source, LoopData *OuterLoop, Distribution &Dist)
Distribute mass according to a distribution.
void adjustLoopHeaderMass(LoopData &Loop)
Adjust the mass of all headers in an irreducible loop.
uint64_t getFrequency() const
Returns the frequency as a fixpoint number scaled by the entry frequency.
ValueT lookup(const_arg_type_t< KeyT > Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
BlockT * getHeader() const
Represents a single loop in the control flow graph.
Simple representation of a scaled number.
ScaledNumber inverse() const
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
iterator erase(const_iterator CI)
void push_back(const T &Elt)
The instances of the Type class are immutable: once they are created, they are never changed.
raw_ostream & print(raw_ostream &OS) const
static BlockMass getEmpty()
static BlockMass getFull()
ScaledNumber< uint64_t > toScaled() const
Convert to scaled number.
A range adaptor for a pair of iterators.
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an SmallVector or SmallString.
std::string getBlockName(const BlockT *BB)
Get the name of a MachineBasicBlock.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
scc_iterator< T > scc_begin(const T &G)
Construct the begin iterator for a deduced graph type T.
llvm:🆑:opt< unsigned > IterativeBFIMaxIterationsPerBlock
int countl_zero(T Val)
Count number of 0's from the most significant bit to the least stopping at the first 1.
void sort(IteratorTy Start, IteratorTy End)
llvm:🆑:opt< bool > UseIterativeBFIInference
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
llvm:🆑:opt< bool > CheckBFIUnknownBlockQueries
llvm:🆑:opt< double > IterativeBFIPrecision
constexpr uint64_t NextPowerOf2(uint64_t A)
Returns the next power of two (in 64-bits) that is strictly greater than A.
Representative of a block.
Distribution of unscaled probability weight.
void addBackedge(const BlockNode &Node, uint64_t Amount)
SmallVector< Weight, 4 > WeightList
WeightList Weights
Individual successor weights.
void addExit(const BlockNode &Node, uint64_t Amount)
void addLocal(const BlockNode &Node, uint64_t Amount)
Stats about a block itself.
bool isHeader(const BlockNode &Node) const
ExitMap Exits
Successor edges (and weights).
bool isIrreducible() const
BlockNode getHeader() const
NodeList Nodes
Header and the members of the loop.
HeaderMassList BackedgeMass
Mass returned to each loop header.
HeaderMassList::difference_type getHeaderIndex(const BlockNode &B)
Unscaled probability weight.
Description of the encoding of one expression Op.
static ChildIteratorType child_begin(NodeRef N)
static ChildIteratorType child_end(NodeRef N)
GraphT::IrrNode::iterator ChildIteratorType
static NodeRef getEntryNode(const GraphT &G)
std::deque< const IrrNode * > Edges
Graph of irreducible control flow.
void addNodesInFunction()
void addEdge(IrrNode &Irr, const BlockNode &Succ, const BFIBase::LoopData *OuterLoop)
std::vector< IrrNode > Nodes
SmallDenseMap< uint32_t, IrrNode *, 4 > Lookup
void addNode(const BlockNode &Node)
void addNodesInLoop(const BFIBase::LoopData &OuterLoop)