@@ -499,13 +499,16 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
499
499
// ========================================================================= //
500
500
// Generic Dataflow Analysis
501
501
// ========================================================================= //
502
- // / A generic, policy-based driver for forward dataflow analyses. It combines
502
+
503
+ enum class Direction { Forward, Backward };
504
+
505
+ // / A generic, policy-based driver for dataflow analyses. It combines
503
506
// / the dataflow runner and the transferer logic into a single class hierarchy.
504
507
// /
505
508
// / The derived class is expected to provide:
506
509
// / - A `Lattice` type.
507
510
// / - `StringRef getAnalysisName() const`
508
- // / - `Lattice getInitialState();` The initial state at the function entry .
511
+ // / - `Lattice getInitialState();` The initial state of the analysis .
509
512
// / - `Lattice join(Lattice, Lattice);` Merges states from multiple CFG paths.
510
513
// / - `Lattice transfer(Lattice, const FactType&);` Defines how a single
511
514
// / lifetime-relevant `Fact` transforms the lattice state. Only overloads
@@ -514,18 +517,23 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
514
517
// / \tparam Derived The CRTP derived class that implements the specific
515
518
// / analysis.
516
519
// / \tparam LatticeType The dataflow lattice used by the analysis.
520
+ // / \tparam Dir The direction of the analysis (Forward or Backward).
517
521
// / TODO: Maybe use the dataflow framework! The framework might need changes
518
522
// / to support the current comparison done at block-entry.
519
- template <typename Derived, typename LatticeType> class DataflowAnalysis {
523
+ template <typename Derived, typename LatticeType, Direction Dir>
524
+ class DataflowAnalysis {
520
525
public:
521
526
using Lattice = LatticeType;
527
+ using Base = DataflowAnalysis<Derived, LatticeType, Dir>;
522
528
523
529
private:
524
530
const CFG &Cfg;
525
531
AnalysisDeclContext &AC;
526
532
527
- llvm::DenseMap<const CFGBlock *, Lattice> BlockEntryStates;
528
- llvm::DenseMap<const CFGBlock *, Lattice> BlockExitStates;
533
+ llvm::DenseMap<const CFGBlock *, Lattice> InStates;
534
+ llvm::DenseMap<const CFGBlock *, Lattice> OutStates;
535
+
536
+ static constexpr bool isForward () { return Dir == Direction::Forward; }
529
537
530
538
protected:
531
539
FactManager &AllFacts;
@@ -539,75 +547,76 @@ template <typename Derived, typename LatticeType> class DataflowAnalysis {
539
547
Derived &D = static_cast <Derived &>(*this );
540
548
llvm::TimeTraceScope Time (D.getAnalysisName ());
541
549
542
- ForwardDataflowWorklist Worklist (Cfg, AC);
543
- const CFGBlock *Entry = &Cfg.getEntry ();
544
- BlockEntryStates[Entry] = D.getInitialState ();
545
- Worklist.enqueueBlock (Entry);
546
- llvm::SmallBitVector Visited;
547
- Visited.resize (Cfg.getNumBlockIDs () + 1 );
548
-
549
- while (const CFGBlock *B = Worklist.dequeue ()) {
550
- Lattice EntryState = getEntryState (B);
551
- Lattice ExitState = transferBlock (B, EntryState);
552
- BlockExitStates[B] = ExitState;
553
- Visited.set (B->getBlockID ());
550
+ using Worklist =
551
+ std::conditional_t <Dir == Direction::Forward, ForwardDataflowWorklist,
552
+ BackwardDataflowWorklist>;
553
+ Worklist W (Cfg, AC);
554
+
555
+ const CFGBlock *Start = isForward () ? &Cfg.getEntry () : &Cfg.getExit ();
556
+ InStates[Start] = D.getInitialState ();
557
+ W.enqueueBlock (Start);
554
558
555
- for (const CFGBlock *Successor : B->succs ()) {
556
- Lattice OldSuccEntryState = getEntryState (Successor);
557
- Lattice NewSuccEntryState = D.join (OldSuccEntryState, ExitState);
559
+ llvm::SmallBitVector Visited (Cfg.getNumBlockIDs () + 1 );
558
560
559
- // Enqueue the successor if its entry state has changed or if we have
561
+ while (const CFGBlock *B = W.dequeue ()) {
562
+ Lattice StateIn = getInState (B);
563
+ Lattice StateOut = transferBlock (B, StateIn);
564
+ OutStates[B] = StateOut;
565
+ Visited.set (B->getBlockID ());
566
+ for (const CFGBlock *AdjacentB : isForward () ? B->succs () : B->preds ()) {
567
+ Lattice OldInState = getInState (AdjacentB);
568
+ Lattice NewInState = D.join (OldInState, StateOut);
569
+ // Enqueue the adjacent block if its in-state has changed or if we have
560
570
// never visited it.
561
- if (!Visited.test (Successor ->getBlockID ()) ||
562
- NewSuccEntryState != OldSuccEntryState ) {
563
- BlockEntryStates[Successor ] = NewSuccEntryState ;
564
- Worklist .enqueueBlock (Successor );
571
+ if (!Visited.test (AdjacentB ->getBlockID ()) ||
572
+ NewInState != OldInState ) {
573
+ InStates[AdjacentB ] = NewInState ;
574
+ W .enqueueBlock (AdjacentB );
565
575
}
566
576
}
567
577
}
568
578
}
569
579
570
- Lattice getEntryState (const CFGBlock *B) const {
571
- return BlockEntryStates.lookup (B);
572
- }
580
+ Lattice getInState (const CFGBlock *B) const { return InStates.lookup (B); }
573
581
574
- Lattice getExitState (const CFGBlock *B) const {
575
- return BlockExitStates.lookup (B);
576
- }
582
+ Lattice getOutStates (const CFGBlock *B) const { return OutStates.lookup (B); }
577
583
578
584
void dump () const {
579
585
const Derived *D = static_cast <const Derived *>(this );
580
586
llvm::dbgs () << " ==========================================\n " ;
581
587
llvm::dbgs () << D->getAnalysisName () << " results:\n " ;
582
588
llvm::dbgs () << " ==========================================\n " ;
583
- const CFGBlock &B = Cfg.getExit ();
584
- getExitState (&B).dump (llvm::dbgs ());
589
+ const CFGBlock &B = isForward () ? Cfg.getExit () : Cfg. getEntry ();
590
+ getOutStates (&B).dump (llvm::dbgs ());
585
591
}
586
592
587
- private:
588
- // / Computes the exit state of a block by applying all its facts sequentially
589
- // / to a given entry state.
593
+ // / Computes the state at one end of a block by applying all its facts
594
+ // / sequentially to a given state from the other end.
590
595
// / TODO: We might need to store intermediate states per-fact in the block for
591
596
// / later analysis.
592
- Lattice transferBlock (const CFGBlock *Block, Lattice EntryState) {
593
- Lattice BlockState = EntryState;
594
- for (const Fact *F : AllFacts.getFacts (Block)) {
595
- BlockState = transferFact (BlockState, F);
596
- }
597
- return BlockState;
597
+ Lattice transferBlock (const CFGBlock *Block, Lattice State) {
598
+ auto Facts = AllFacts.getFacts (Block);
599
+ if constexpr (isForward ())
600
+ for (const Fact *F : Facts)
601
+ State = transferFact (State, F);
602
+ else
603
+ for (const Fact *F : llvm::reverse (Facts))
604
+ State = transferFact (State, F);
605
+ return State;
598
606
}
599
607
600
608
Lattice transferFact (Lattice In, const Fact *F) {
601
- Derived *d = static_cast <Derived *>(this );
609
+ assert (F);
610
+ Derived *D = static_cast <Derived *>(this );
602
611
switch (F->getKind ()) {
603
612
case Fact::Kind::Issue:
604
- return d ->transfer (In, *F->getAs <IssueFact>());
613
+ return D ->transfer (In, *F->getAs <IssueFact>());
605
614
case Fact::Kind::Expire:
606
- return d ->transfer (In, *F->getAs <ExpireFact>());
615
+ return D ->transfer (In, *F->getAs <ExpireFact>());
607
616
case Fact::Kind::AssignOrigin:
608
- return d ->transfer (In, *F->getAs <AssignOriginFact>());
617
+ return D ->transfer (In, *F->getAs <AssignOriginFact>());
609
618
case Fact::Kind::ReturnOfOrigin:
610
- return d ->transfer (In, *F->getAs <ReturnOfOriginFact>());
619
+ return D ->transfer (In, *F->getAs <ReturnOfOriginFact>());
611
620
}
612
621
llvm_unreachable (" Unknown fact kind" );
613
622
}
@@ -715,7 +724,8 @@ struct LoanPropagationLattice {
715
724
716
725
// / The analysis that tracks which loans belong to which origins.
717
726
class LoanPropagationAnalysis
718
- : public DataflowAnalysis<LoanPropagationAnalysis, LoanPropagationLattice> {
727
+ : public DataflowAnalysis<LoanPropagationAnalysis, LoanPropagationLattice,
728
+ Direction::Forward> {
719
729
720
730
LifetimeFactory &Factory;
721
731
@@ -724,7 +734,7 @@ class LoanPropagationAnalysis
724
734
LifetimeFactory &Factory)
725
735
: DataflowAnalysis(C, AC, F), Factory(Factory) {}
726
736
727
- using DataflowAnalysis<LoanPropagationAnalysis, Lattice> ::transfer;
737
+ using Base ::transfer;
728
738
729
739
StringRef getAnalysisName () const { return " LoanPropagation" ; }
730
740
0 commit comments