@@ -499,13 +499,16 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
499499// ========================================================================= //
500500// Generic Dataflow Analysis
501501// ========================================================================= //
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
503506// / the dataflow runner and the transferer logic into a single class hierarchy.
504507// /
505508// / The derived class is expected to provide:
506509// / - A `Lattice` type.
507510// / - `StringRef getAnalysisName() const`
508- // / - `Lattice getInitialState();` The initial state at the function entry .
511+ // / - `Lattice getInitialState();` The initial state of the analysis .
509512// / - `Lattice join(Lattice, Lattice);` Merges states from multiple CFG paths.
510513// / - `Lattice transfer(Lattice, const FactType&);` Defines how a single
511514// / lifetime-relevant `Fact` transforms the lattice state. Only overloads
@@ -514,18 +517,23 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
514517// / \tparam Derived The CRTP derived class that implements the specific
515518// / analysis.
516519// / \tparam LatticeType The dataflow lattice used by the analysis.
520+ // / \tparam Dir The direction of the analysis (Forward or Backward).
517521// / TODO: Maybe use the dataflow framework! The framework might need changes
518522// / 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 {
520525public:
521526 using Lattice = LatticeType;
527+ using Base = DataflowAnalysis<Derived, LatticeType, Dir>;
522528
523529private:
524530 const CFG &Cfg;
525531 AnalysisDeclContext &AC;
526532
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; }
529537
530538protected:
531539 FactManager &AllFacts;
@@ -539,75 +547,76 @@ template <typename Derived, typename LatticeType> class DataflowAnalysis {
539547 Derived &D = static_cast <Derived &>(*this );
540548 llvm::TimeTraceScope Time (D.getAnalysisName ());
541549
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);
554558
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 );
558560
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
560570 // 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 );
565575 }
566576 }
567577 }
568578 }
569579
570- Lattice getEntryState (const CFGBlock *B) const {
571- return BlockEntryStates.lookup (B);
572- }
580+ Lattice getInState (const CFGBlock *B) const { return InStates.lookup (B); }
573581
574- Lattice getExitState (const CFGBlock *B) const {
575- return BlockExitStates.lookup (B);
576- }
582+ Lattice getOutState (const CFGBlock *B) const { return OutStates.lookup (B); }
577583
578584 void dump () const {
579585 const Derived *D = static_cast <const Derived *>(this );
580586 llvm::dbgs () << " ==========================================\n " ;
581587 llvm::dbgs () << D->getAnalysisName () << " results:\n " ;
582588 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+ getOutState (&B).dump (llvm::dbgs ());
585591 }
586592
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.
590595 // / TODO: We might need to store intermediate states per-fact in the block for
591596 // / 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;
598606 }
599607
600608 Lattice transferFact (Lattice In, const Fact *F) {
601- Derived *d = static_cast <Derived *>(this );
609+ assert (F);
610+ Derived *D = static_cast <Derived *>(this );
602611 switch (F->getKind ()) {
603612 case Fact::Kind::Issue:
604- return d ->transfer (In, *F->getAs <IssueFact>());
613+ return D ->transfer (In, *F->getAs <IssueFact>());
605614 case Fact::Kind::Expire:
606- return d ->transfer (In, *F->getAs <ExpireFact>());
615+ return D ->transfer (In, *F->getAs <ExpireFact>());
607616 case Fact::Kind::AssignOrigin:
608- return d ->transfer (In, *F->getAs <AssignOriginFact>());
617+ return D ->transfer (In, *F->getAs <AssignOriginFact>());
609618 case Fact::Kind::ReturnOfOrigin:
610- return d ->transfer (In, *F->getAs <ReturnOfOriginFact>());
619+ return D ->transfer (In, *F->getAs <ReturnOfOriginFact>());
611620 }
612621 llvm_unreachable (" Unknown fact kind" );
613622 }
@@ -715,7 +724,8 @@ struct LoanPropagationLattice {
715724
716725// / The analysis that tracks which loans belong to which origins.
717726class LoanPropagationAnalysis
718- : public DataflowAnalysis<LoanPropagationAnalysis, LoanPropagationLattice> {
727+ : public DataflowAnalysis<LoanPropagationAnalysis, LoanPropagationLattice,
728+ Direction::Forward> {
719729
720730 LifetimeFactory &Factory;
721731
@@ -724,7 +734,7 @@ class LoanPropagationAnalysis
724734 LifetimeFactory &Factory)
725735 : DataflowAnalysis(C, AC, F), Factory(Factory) {}
726736
727- using DataflowAnalysis<LoanPropagationAnalysis, Lattice> ::transfer;
737+ using Base ::transfer;
728738
729739 StringRef getAnalysisName () const { return " LoanPropagation" ; }
730740
0 commit comments