@@ -502,6 +502,12 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
502502
503503enum class Direction { Forward, Backward };
504504
505+ // / A program point is a pair of a CFGBlock and a Fact within that block.
506+ // /
507+ // / This is used to represent the state of the program *after* the Fact is
508+ // / executed.
509+ using ProgramPoint = std::pair<const CFGBlock *, const Fact *>;
510+
505511// / A generic, policy-based driver for dataflow analyses. It combines
506512// / the dataflow runner and the transferer logic into a single class hierarchy.
507513// /
@@ -530,8 +536,14 @@ class DataflowAnalysis {
530536 const CFG &Cfg;
531537 AnalysisDeclContext &AC;
532538
539+ // / The dataflow state before a basic block is processed.
533540 llvm::DenseMap<const CFGBlock *, Lattice> InStates;
541+ // / The dataflow state after a basic block is processed.
534542 llvm::DenseMap<const CFGBlock *, Lattice> OutStates;
543+ // / The dataflow state at a Program Point.
544+ // / In a forward analysis, this is the state after the Fact at that point has
545+ // / been applied, while in a backward analysis, it is the state before.
546+ llvm::DenseMap<ProgramPoint, Lattice> PerPointStates;
535547
536548 static constexpr bool isForward () { return Dir == Direction::Forward; }
537549
@@ -577,6 +589,8 @@ class DataflowAnalysis {
577589 }
578590 }
579591
592+ Lattice getState (ProgramPoint P) const { return PerPointStates.lookup (P); }
593+
580594 Lattice getInState (const CFGBlock *B) const { return InStates.lookup (B); }
581595
582596 Lattice getOutState (const CFGBlock *B) const { return OutStates.lookup (B); }
@@ -590,18 +604,23 @@ class DataflowAnalysis {
590604 getOutState (&B).dump (llvm::dbgs ());
591605 }
592606
607+ private:
593608 // / Computes the state at one end of a block by applying all its facts
594609 // / sequentially to a given state from the other end.
595- // / TODO: We might need to store intermediate states per-fact in the block for
596- // / later analysis.
597610 Lattice transferBlock (const CFGBlock *Block, Lattice State) {
598611 auto Facts = AllFacts.getFacts (Block);
599- if constexpr (isForward ())
600- for (const Fact *F : Facts)
612+ if constexpr (isForward ()) {
613+ for (const Fact *F : Facts) {
601614 State = transferFact (State, F);
602- else
603- for (const Fact *F : llvm::reverse (Facts))
615+ PerPointStates[{Block, F}] = State;
616+ }
617+ } else {
618+ for (const Fact *F : llvm::reverse (Facts)) {
619+ // In backward analysis, capture the state before applying the fact.
620+ PerPointStates[{Block, F}] = State;
604621 State = transferFact (State, F);
622+ }
623+ }
605624 return State;
606625 }
607626
@@ -769,6 +788,10 @@ class LoanPropagationAnalysis
769788 Factory.OriginMapFactory .add (In.Origins , DestOID, SrcLoans));
770789 }
771790
791+ LoanSet getLoans (OriginID OID, ProgramPoint P) {
792+ return getLoans (getState (P), OID);
793+ }
794+
772795private:
773796 LoanSet getLoans (Lattice L, OriginID OID) {
774797 if (auto *Loans = L.Origins .lookup (OID))
@@ -779,7 +802,6 @@ class LoanPropagationAnalysis
779802
780803// ========================================================================= //
781804// TODO:
782- // - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)`
783805// - Modify loan expiry analysis to answer `bool isExpired(Loan L, Point P)`
784806// - Modify origin liveness analysis to answer `bool isLive(Origin O, Point P)`
785807// - Using the above three to perform the final error reporting.
0 commit comments