@@ -119,6 +119,101 @@ auto GenericCycle<ContextT>::getCyclePredecessor() const -> BlockT * {
119
119
return Out;
120
120
}
121
121
122
+ // / \brief Verify that this is actually a well-formed cycle in the CFG.
123
+ template <typename ContextT> void GenericCycle<ContextT>::verifyCycle() const {
124
+ #ifndef NDEBUG
125
+ assert (!Blocks.empty () && " Cycle cannot be empty." );
126
+ DenseSet<BlockT *> Blocks;
127
+ for (BlockT *BB : blocks ()) {
128
+ assert (Blocks.insert (BB).second ); // duplicates in block list?
129
+ }
130
+ assert (!Entries.empty () && " Cycle must have one or more entries." );
131
+
132
+ DenseSet<BlockT *> Entries;
133
+ for (BlockT *Entry : entries ()) {
134
+ assert (Entries.insert (Entry).second ); // duplicate entry?
135
+ assert (contains (Entry));
136
+ }
137
+
138
+ // Setup for using a depth-first iterator to visit every block in the cycle.
139
+ SmallVector<BlockT *, 8 > ExitBBs;
140
+ getExitBlocks (ExitBBs);
141
+ df_iterator_default_set<BlockT *> VisitSet;
142
+ VisitSet.insert (ExitBBs.begin (), ExitBBs.end ());
143
+
144
+ // Keep track of the BBs visited.
145
+ SmallPtrSet<BlockT *, 8 > VisitedBBs;
146
+
147
+ // Check the individual blocks.
148
+ for (BlockT *BB : depth_first_ext (getHeader (), VisitSet)) {
149
+ assert (llvm::any_of (llvm::children<BlockT *>(BB),
150
+ [&](BlockT *B) { return contains (B); }) &&
151
+ " Cycle block has no in-cycle successors!" );
152
+
153
+ assert (llvm::any_of (llvm::inverse_children<BlockT *>(BB),
154
+ [&](BlockT *B) { return contains (B); }) &&
155
+ " Cycle block has no in-cycle predecessors!" );
156
+
157
+ DenseSet<BlockT *> OutsideCyclePreds;
158
+ for (BlockT *B : llvm::inverse_children<BlockT *>(BB))
159
+ if (!contains (B))
160
+ OutsideCyclePreds.insert (B);
161
+
162
+ if (Entries.contains (BB)) {
163
+ assert (!OutsideCyclePreds.empty () && " Entry is unreachable!" );
164
+ } else if (!OutsideCyclePreds.empty ()) {
165
+ // A non-entry block shouldn't be reachable from outside the cycle,
166
+ // though it is permitted if the predecessor is not itself actually
167
+ // reachable.
168
+ BlockT *EntryBB = &BB->getParent ()->front ();
169
+ for (BlockT *CB : depth_first (EntryBB))
170
+ assert (!OutsideCyclePreds.contains (CB) &&
171
+ " Non-entry block reachable from outside!" );
172
+ }
173
+ assert (BB != &getHeader ()->getParent ()->front () &&
174
+ " Cycle contains function entry block!" );
175
+
176
+ VisitedBBs.insert (BB);
177
+ }
178
+
179
+ if (VisitedBBs.size () != getNumBlocks ()) {
180
+ dbgs () << " The following blocks are unreachable in the cycle: " ;
181
+ for (auto *BB : Blocks) {
182
+ if (!VisitedBBs.count (BB)) {
183
+ dbgs () << *BB << " \n " ;
184
+ }
185
+ }
186
+ assert (false && " Unreachable block in cycle" );
187
+ }
188
+
189
+ verifyCycleNest ();
190
+ #endif
191
+ }
192
+
193
+ // / \brief Verify the parent-child relations of this cycle.
194
+ // /
195
+ // / Note that this does \em not check that cycle is really a cycle in the CFG.
196
+ template <typename ContextT>
197
+ void GenericCycle<ContextT>::verifyCycleNest() const {
198
+ #ifndef NDEBUG
199
+ // Check the subcycles.
200
+ for (GenericCycle *Child : children ()) {
201
+ // Each block in each subcycle should be contained within this cycle.
202
+ for (BlockT *BB : Child->blocks ()) {
203
+ assert (contains (BB) &&
204
+ " Cycle does not contain all the blocks of a subcycle!" );
205
+ }
206
+ assert (Child->Depth == Depth + 1 );
207
+ }
208
+
209
+ // Check the parent cycle pointer.
210
+ if (ParentCycle) {
211
+ assert (is_contained (ParentCycle->children (), this ) &&
212
+ " Cycle is not a subcycle of its parent!" );
213
+ }
214
+ #endif
215
+ }
216
+
122
217
// / \brief Helper class for computing cycle information.
123
218
template <typename ContextT> class GenericCycleInfoCompute {
124
219
using BlockT = typename ContextT::BlockT;
@@ -400,8 +495,7 @@ void GenericCycleInfo<ContextT>::compute(FunctionT &F) {
400
495
LLVM_DEBUG (errs () << " Computing cycles for function: " << F.getName ()
401
496
<< " \n " );
402
497
Compute.run (&F.front ());
403
-
404
- assert (validateTree ());
498
+ verify ();
405
499
}
406
500
407
501
template <typename ContextT>
@@ -414,7 +508,7 @@ void GenericCycleInfo<ContextT>::splitCriticalEdge(BlockT *Pred, BlockT *Succ,
414
508
return ;
415
509
416
510
addBlockToCycle (NewBlock, Cycle);
417
- assert ( validateTree () );
511
+ Cycle-> verifyCycle ( );
418
512
}
419
513
420
514
// / \brief Find the innermost cycle containing a given block.
@@ -468,73 +562,34 @@ unsigned GenericCycleInfo<ContextT>::getCycleDepth(const BlockT *Block) const {
468
562
return Cycle->getDepth ();
469
563
}
470
564
471
- #ifndef NDEBUG
472
- // / \brief Validate the internal consistency of the cycle tree.
565
+ // / \brief Verify the internal consistency of the cycle tree.
473
566
// /
474
567
// / Note that this does \em not check that cycles are really cycles in the CFG,
475
568
// / or that the right set of cycles in the CFG were found.
476
569
template <typename ContextT>
477
- bool GenericCycleInfo<ContextT>::validateTree() const {
478
- DenseSet<BlockT *> Blocks;
479
- DenseSet<BlockT *> Entries;
480
-
481
- auto reportError = [](const char *File, int Line, const char *Cond) {
482
- errs () << File << ' :' << Line
483
- << " : GenericCycleInfo::validateTree: " << Cond << ' \n ' ;
484
- };
485
- #define check (cond ) \
486
- do { \
487
- if (!(cond)) { \
488
- reportError (__FILE__, __LINE__, #cond); \
489
- return false ; \
490
- } \
491
- } while (false )
492
-
493
- for (const auto *TLC : toplevel_cycles ()) {
494
- for (const CycleT *Cycle : depth_first (TLC)) {
495
- if (Cycle->ParentCycle )
496
- check (is_contained (Cycle->ParentCycle ->children (), Cycle));
497
-
498
- for (BlockT *Block : Cycle->Blocks ) {
499
- auto MapIt = BlockMap.find (Block);
500
- check (MapIt != BlockMap.end ());
501
- check (Cycle->contains (MapIt->second ));
502
- check (Blocks.insert (Block).second ); // duplicates in block list?
503
- }
504
- Blocks.clear ();
505
-
506
- check (!Cycle->Entries .empty ());
507
- for (BlockT *Entry : Cycle->Entries ) {
508
- check (Entries.insert (Entry).second ); // duplicate entry?
509
- check (is_contained (Cycle->Blocks , Entry));
510
- }
511
- Entries.clear ();
512
-
513
- unsigned ChildDepth = 0 ;
514
- for (const CycleT *Child : Cycle->children ()) {
515
- check (Child->Depth > Cycle->Depth );
516
- if (!ChildDepth) {
517
- ChildDepth = Child->Depth ;
518
- } else {
519
- check (ChildDepth == Child->Depth );
520
- }
570
+ void GenericCycleInfo<ContextT>::verifyCycleNest(bool VerifyFull) const {
571
+ #ifndef NDEBUG
572
+ for (CycleT *TopCycle : toplevel_cycles ()) {
573
+ for (CycleT *Cycle : depth_first (TopCycle)) {
574
+ if (VerifyFull)
575
+ Cycle->verifyCycle ();
576
+ else
577
+ Cycle->verifyCycleNest ();
578
+ // Check the block map entries for blocks contained in this cycle.
579
+ for (BlockT *BB : Cycle->blocks ()) {
580
+ auto MapIt = BlockMap.find (BB);
581
+ assert (MapIt != BlockMap.end ());
582
+ assert (Cycle->contains (MapIt->second ));
521
583
}
522
584
}
523
585
}
586
+ #endif
587
+ }
524
588
525
- for (const auto &Entry : BlockMap) {
526
- BlockT *Block = Entry.first ;
527
- for (const CycleT *Cycle = Entry.second ; Cycle;
528
- Cycle = Cycle->ParentCycle ) {
529
- check (is_contained (Cycle->Blocks , Block));
530
- }
531
- }
532
-
533
- #undef check
534
-
535
- return true ;
589
+ // / \brief Verify that the entire cycle tree well-formed.
590
+ template <typename ContextT> void GenericCycleInfo<ContextT>::verify() const {
591
+ verifyCycleNest (/* VerifyFull=*/ true );
536
592
}
537
- #endif
538
593
539
594
// / \brief Print the cycle info.
540
595
template <typename ContextT>
0 commit comments