@@ -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,21 @@ 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.
517
- // / TODO: Maybe use the dataflow framework! The framework might need changes
518
- // / to support the current comparison done at block-entry.
519
- template < typename Derived, typename LatticeType> class DataflowAnalysis {
520
+ // / \tparam Dir The direction of the analysis (Forward or Backward).
521
+ template < typename Derived, typename LatticeType, Direction Dir>
522
+ class DataflowAnalysis {
520
523
public:
521
524
using Lattice = LatticeType;
525
+ using Base = DataflowAnalysis<Derived, LatticeType, Dir>;
522
526
523
527
private:
524
528
const CFG &Cfg;
525
529
AnalysisDeclContext &AC;
526
530
527
- llvm::DenseMap<const CFGBlock *, Lattice> BlockEntryStates;
528
- llvm::DenseMap<const CFGBlock *, Lattice> BlockExitStates;
531
+ llvm::DenseMap<const CFGBlock *, Lattice> InStates;
532
+ llvm::DenseMap<const CFGBlock *, Lattice> OutStates;
533
+
534
+ static constexpr bool isForward () { return Dir == Direction::Forward; }
529
535
530
536
protected:
531
537
FactManager &AllFacts;
@@ -539,75 +545,76 @@ template <typename Derived, typename LatticeType> class DataflowAnalysis {
539
545
Derived &D = static_cast <Derived &>(*this );
540
546
llvm::TimeTraceScope Time (D.getAnalysisName ());
541
547
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 ());
548
+ using Worklist =
549
+ std::conditional_t <Dir == Direction::Forward, ForwardDataflowWorklist,
550
+ BackwardDataflowWorklist>;
551
+ Worklist W (Cfg, AC);
552
+
553
+ const CFGBlock *Start = isForward () ? &Cfg.getEntry () : &Cfg.getExit ();
554
+ InStates[Start] = D.getInitialState ();
555
+ W.enqueueBlock (Start);
554
556
555
- for (const CFGBlock *Successor : B->succs ()) {
556
- Lattice OldSuccEntryState = getEntryState (Successor);
557
- Lattice NewSuccEntryState = D.join (OldSuccEntryState, ExitState);
557
+ llvm::SmallBitVector Visited (Cfg.getNumBlockIDs () + 1 );
558
558
559
- // Enqueue the successor if its entry state has changed or if we have
559
+ while (const CFGBlock *B = W.dequeue ()) {
560
+ Lattice StateIn = getInState (B);
561
+ Lattice StateOut = transferBlock (B, StateIn);
562
+ OutStates[B] = StateOut;
563
+ Visited.set (B->getBlockID ());
564
+ for (const CFGBlock *AdjacentB : isForward () ? B->succs () : B->preds ()) {
565
+ Lattice OldInState = getInState (AdjacentB);
566
+ Lattice NewInState = D.join (OldInState, StateOut);
567
+ // Enqueue the adjacent block if its in-state has changed or if we have
560
568
// never visited it.
561
- if (!Visited.test (Successor ->getBlockID ()) ||
562
- NewSuccEntryState != OldSuccEntryState ) {
563
- BlockEntryStates[Successor ] = NewSuccEntryState ;
564
- Worklist .enqueueBlock (Successor );
569
+ if (!Visited.test (AdjacentB ->getBlockID ()) ||
570
+ NewInState != OldInState ) {
571
+ InStates[AdjacentB ] = NewInState ;
572
+ W .enqueueBlock (AdjacentB );
565
573
}
566
574
}
567
575
}
568
576
}
569
577
570
- Lattice getEntryState (const CFGBlock *B) const {
571
- return BlockEntryStates.lookup (B);
572
- }
578
+ Lattice getInState (const CFGBlock *B) const { return InStates.lookup (B); }
573
579
574
- Lattice getExitState (const CFGBlock *B) const {
575
- return BlockExitStates.lookup (B);
576
- }
580
+ Lattice getOutStates (const CFGBlock *B) const { return OutStates.lookup (B); }
577
581
578
582
void dump () const {
579
583
const Derived *D = static_cast <const Derived *>(this );
580
584
llvm::dbgs () << " ==========================================\n " ;
581
585
llvm::dbgs () << D->getAnalysisName () << " results:\n " ;
582
586
llvm::dbgs () << " ==========================================\n " ;
583
- const CFGBlock &B = Cfg.getExit ();
584
- getExitState (&B).dump (llvm::dbgs ());
587
+ const CFGBlock &B = isForward () ? Cfg.getExit () : Cfg. getEntry ();
588
+ getOutStates (&B).dump (llvm::dbgs ());
585
589
}
586
590
587
- private:
588
- // / Computes the exit state of a block by applying all its facts sequentially
589
- // / to a given entry state.
591
+ // / Computes the state at one end of a block by applying all its facts
592
+ // / sequentially to a given state from the other end.
590
593
// / TODO: We might need to store intermediate states per-fact in the block for
591
594
// / 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;
595
+ Lattice transferBlock (const CFGBlock *Block, Lattice State) {
596
+ auto Facts = AllFacts.getFacts (Block);
597
+ if constexpr (isForward ())
598
+ for (const Fact *F : Facts)
599
+ State = transferFact (State, F);
600
+ else
601
+ for (const Fact *F : llvm::reverse (Facts))
602
+ State = transferFact (State, F);
603
+ return State;
598
604
}
599
605
600
606
Lattice transferFact (Lattice In, const Fact *F) {
601
- Derived *d = static_cast <Derived *>(this );
607
+ assert (F);
608
+ Derived *D = static_cast <Derived *>(this );
602
609
switch (F->getKind ()) {
603
610
case Fact::Kind::Issue:
604
- return d ->transfer (In, *F->getAs <IssueFact>());
611
+ return D ->transfer (In, *F->getAs <IssueFact>());
605
612
case Fact::Kind::Expire:
606
- return d ->transfer (In, *F->getAs <ExpireFact>());
613
+ return D ->transfer (In, *F->getAs <ExpireFact>());
607
614
case Fact::Kind::AssignOrigin:
608
- return d ->transfer (In, *F->getAs <AssignOriginFact>());
615
+ return D ->transfer (In, *F->getAs <AssignOriginFact>());
609
616
case Fact::Kind::ReturnOfOrigin:
610
- return d ->transfer (In, *F->getAs <ReturnOfOriginFact>());
617
+ return D ->transfer (In, *F->getAs <ReturnOfOriginFact>());
611
618
}
612
619
llvm_unreachable (" Unknown fact kind" );
613
620
}
@@ -715,7 +722,8 @@ struct LoanPropagationLattice {
715
722
716
723
// / The analysis that tracks which loans belong to which origins.
717
724
class LoanPropagationAnalysis
718
- : public DataflowAnalysis<LoanPropagationAnalysis, LoanPropagationLattice> {
725
+ : public DataflowAnalysis<LoanPropagationAnalysis, LoanPropagationLattice,
726
+ Direction::Forward> {
719
727
720
728
LifetimeFactory &Factory;
721
729
@@ -724,7 +732,7 @@ class LoanPropagationAnalysis
724
732
LifetimeFactory &Factory)
725
733
: DataflowAnalysis(C, AC, F), Factory(Factory) {}
726
734
727
- using DataflowAnalysis<LoanPropagationAnalysis, Lattice> ::transfer;
735
+ using Base ::transfer;
728
736
729
737
StringRef getAnalysisName () const { return " LoanPropagation" ; }
730
738
0 commit comments