https://github.com/usx95 updated 
https://github.com/llvm/llvm-project/pull/148967

>From 7502ee577452c5c5d9bb4c9a8b24d6c4825cedd1 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <u...@google.com>
Date: Tue, 15 Jul 2025 21:24:11 +0000
Subject: [PATCH] add-backward-analysis-capability

---
 clang/lib/Analysis/LifetimeSafety.cpp | 108 ++++++++++++++------------
 1 file changed, 59 insertions(+), 49 deletions(-)

diff --git a/clang/lib/Analysis/LifetimeSafety.cpp 
b/clang/lib/Analysis/LifetimeSafety.cpp
index 0e013ec23e776..829da3ceb4c83 100644
--- a/clang/lib/Analysis/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety.cpp
@@ -499,13 +499,16 @@ class FactGenerator : public 
ConstStmtVisitor<FactGenerator> {
 // ========================================================================= //
 //                         Generic Dataflow Analysis
 // ========================================================================= //
-/// A generic, policy-based driver for forward dataflow analyses. It combines
+
+enum class Direction { Forward, Backward };
+
+/// A generic, policy-based driver for dataflow analyses. It combines
 /// the dataflow runner and the transferer logic into a single class hierarchy.
 ///
 /// The derived class is expected to provide:
 /// - A `Lattice` type.
 /// - `StringRef getAnalysisName() const`
-/// - `Lattice getInitialState();` The initial state at the function entry.
+/// - `Lattice getInitialState();` The initial state of the analysis.
 /// - `Lattice join(Lattice, Lattice);` Merges states from multiple CFG paths.
 /// - `Lattice transfer(Lattice, const FactType&);` Defines how a single
 ///   lifetime-relevant `Fact` transforms the lattice state. Only overloads
@@ -514,18 +517,23 @@ class FactGenerator : public 
ConstStmtVisitor<FactGenerator> {
 /// \tparam Derived The CRTP derived class that implements the specific
 /// analysis.
 /// \tparam LatticeType The dataflow lattice used by the analysis.
+/// \tparam Dir The direction of the analysis (Forward or Backward).
 /// TODO: Maybe use the dataflow framework! The framework might need changes
 /// to support the current comparison done at block-entry.
-template <typename Derived, typename LatticeType> class DataflowAnalysis {
+template <typename Derived, typename LatticeType, Direction Dir>
+class DataflowAnalysis {
 public:
   using Lattice = LatticeType;
+  using Base = DataflowAnalysis<Derived, LatticeType, Dir>;
 
 private:
   const CFG &Cfg;
   AnalysisDeclContext &AC;
 
-  llvm::DenseMap<const CFGBlock *, Lattice> BlockEntryStates;
-  llvm::DenseMap<const CFGBlock *, Lattice> BlockExitStates;
+  llvm::DenseMap<const CFGBlock *, Lattice> InStates;
+  llvm::DenseMap<const CFGBlock *, Lattice> OutStates;
+
+  static constexpr bool isForward() { return Dir == Direction::Forward; }
 
 protected:
   FactManager &AllFacts;
@@ -539,75 +547,76 @@ template <typename Derived, typename LatticeType> class 
DataflowAnalysis {
     Derived &D = static_cast<Derived &>(*this);
     llvm::TimeTraceScope Time(D.getAnalysisName());
 
-    ForwardDataflowWorklist Worklist(Cfg, AC);
-    const CFGBlock *Entry = &Cfg.getEntry();
-    BlockEntryStates[Entry] = D.getInitialState();
-    Worklist.enqueueBlock(Entry);
-    llvm::SmallBitVector Visited;
-    Visited.resize(Cfg.getNumBlockIDs() + 1);
-
-    while (const CFGBlock *B = Worklist.dequeue()) {
-      Lattice EntryState = getEntryState(B);
-      Lattice ExitState = transferBlock(B, EntryState);
-      BlockExitStates[B] = ExitState;
-      Visited.set(B->getBlockID());
+    using Worklist =
+        std::conditional_t<Dir == Direction::Forward, ForwardDataflowWorklist,
+                           BackwardDataflowWorklist>;
+    Worklist W(Cfg, AC);
+
+    const CFGBlock *Start = isForward() ? &Cfg.getEntry() : &Cfg.getExit();
+    InStates[Start] = D.getInitialState();
+    W.enqueueBlock(Start);
 
-      for (const CFGBlock *Successor : B->succs()) {
-        Lattice OldSuccEntryState = getEntryState(Successor);
-        Lattice NewSuccEntryState = D.join(OldSuccEntryState, ExitState);
+    llvm::SmallBitVector Visited(Cfg.getNumBlockIDs() + 1);
 
-        // Enqueue the successor if its entry state has changed or if we have
+    while (const CFGBlock *B = W.dequeue()) {
+      Lattice StateIn = getInState(B);
+      Lattice StateOut = transferBlock(B, StateIn);
+      OutStates[B] = StateOut;
+      Visited.set(B->getBlockID());
+      for (const CFGBlock *AdjacentB : isForward() ? B->succs() : B->preds()) {
+        Lattice OldInState = getInState(AdjacentB);
+        Lattice NewInState = D.join(OldInState, StateOut);
+        // Enqueue the adjacent block if its in-state has changed or if we have
         // never visited it.
-        if (!Visited.test(Successor->getBlockID()) ||
-            NewSuccEntryState != OldSuccEntryState) {
-          BlockEntryStates[Successor] = NewSuccEntryState;
-          Worklist.enqueueBlock(Successor);
+        if (!Visited.test(AdjacentB->getBlockID()) ||
+            NewInState != OldInState) {
+          InStates[AdjacentB] = NewInState;
+          W.enqueueBlock(AdjacentB);
         }
       }
     }
   }
 
-  Lattice getEntryState(const CFGBlock *B) const {
-    return BlockEntryStates.lookup(B);
-  }
+  Lattice getInState(const CFGBlock *B) const { return InStates.lookup(B); }
 
-  Lattice getExitState(const CFGBlock *B) const {
-    return BlockExitStates.lookup(B);
-  }
+  Lattice getOutStates(const CFGBlock *B) const { return OutStates.lookup(B); }
 
   void dump() const {
     const Derived *D = static_cast<const Derived *>(this);
     llvm::dbgs() << "==========================================\n";
     llvm::dbgs() << D->getAnalysisName() << " results:\n";
     llvm::dbgs() << "==========================================\n";
-    const CFGBlock &B = Cfg.getExit();
-    getExitState(&B).dump(llvm::dbgs());
+    const CFGBlock &B = isForward() ? Cfg.getExit() : Cfg.getEntry();
+    getOutStates(&B).dump(llvm::dbgs());
   }
 
-private:
-  /// Computes the exit state of a block by applying all its facts sequentially
-  /// to a given entry state.
+  /// Computes the state at one end of a block by applying all its facts
+  /// sequentially to a given state from the other end.
   /// TODO: We might need to store intermediate states per-fact in the block 
for
   /// later analysis.
-  Lattice transferBlock(const CFGBlock *Block, Lattice EntryState) {
-    Lattice BlockState = EntryState;
-    for (const Fact *F : AllFacts.getFacts(Block)) {
-      BlockState = transferFact(BlockState, F);
-    }
-    return BlockState;
+  Lattice transferBlock(const CFGBlock *Block, Lattice State) {
+    auto Facts = AllFacts.getFacts(Block);
+    if constexpr (isForward())
+      for (const Fact *F : Facts)
+        State = transferFact(State, F);
+    else
+      for (const Fact *F : llvm::reverse(Facts))
+        State = transferFact(State, F);
+    return State;
   }
 
   Lattice transferFact(Lattice In, const Fact *F) {
-    Derived *d = static_cast<Derived *>(this);
+    assert(F);
+    Derived *D = static_cast<Derived *>(this);
     switch (F->getKind()) {
     case Fact::Kind::Issue:
-      return d->transfer(In, *F->getAs<IssueFact>());
+      return D->transfer(In, *F->getAs<IssueFact>());
     case Fact::Kind::Expire:
-      return d->transfer(In, *F->getAs<ExpireFact>());
+      return D->transfer(In, *F->getAs<ExpireFact>());
     case Fact::Kind::AssignOrigin:
-      return d->transfer(In, *F->getAs<AssignOriginFact>());
+      return D->transfer(In, *F->getAs<AssignOriginFact>());
     case Fact::Kind::ReturnOfOrigin:
-      return d->transfer(In, *F->getAs<ReturnOfOriginFact>());
+      return D->transfer(In, *F->getAs<ReturnOfOriginFact>());
     }
     llvm_unreachable("Unknown fact kind");
   }
@@ -715,7 +724,8 @@ struct LoanPropagationLattice {
 
 /// The analysis that tracks which loans belong to which origins.
 class LoanPropagationAnalysis
-    : public DataflowAnalysis<LoanPropagationAnalysis, LoanPropagationLattice> 
{
+    : public DataflowAnalysis<LoanPropagationAnalysis, LoanPropagationLattice,
+                              Direction::Forward> {
 
   LifetimeFactory &Factory;
 
@@ -724,7 +734,7 @@ class LoanPropagationAnalysis
                           LifetimeFactory &Factory)
       : DataflowAnalysis(C, AC, F), Factory(Factory) {}
 
-  using DataflowAnalysis<LoanPropagationAnalysis, Lattice>::transfer;
+  using Base::transfer;
 
   StringRef getAnalysisName() const { return "LoanPropagation"; }
 

_______________________________________________
llvm-branch-commits mailing list
llvm-branch-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to