@@ -735,6 +735,142 @@ class LifetimeDataflow {
735
735
}
736
736
};
737
737
738
+ // ========================================================================= //
739
+ // Expired Loans Analysis
740
+ // ========================================================================= //
741
+
742
+ // / The lattice for tracking expired loans. It is a set of loan IDs.
743
+ struct ExpiredLattice {
744
+ LoanSet Expired;
745
+
746
+ ExpiredLattice () = default ;
747
+ explicit ExpiredLattice (LoanSet S) : Expired(S) {}
748
+
749
+ bool operator ==(const ExpiredLattice &Other) const {
750
+ return Expired == Other.Expired ;
751
+ }
752
+ bool operator !=(const ExpiredLattice &Other) const {
753
+ return !(*this == Other);
754
+ }
755
+
756
+ // / Computes the union of two lattices.
757
+ ExpiredLattice join (const ExpiredLattice &Other,
758
+ LoanSet::Factory &Factory) const {
759
+ LoanSet JoinedSet = Expired;
760
+ for (LoanID LID : Other.Expired )
761
+ JoinedSet = Factory.add (JoinedSet, LID);
762
+ return ExpiredLattice (JoinedSet);
763
+ }
764
+
765
+ void dump (llvm::raw_ostream &OS) const {
766
+ OS << " ExpiredLattice State:\n " ;
767
+ if (Expired.isEmpty ())
768
+ OS << " <empty>\n " ;
769
+ for (const LoanID &LID : Expired)
770
+ OS << " Loan " << LID << " is expired\n " ;
771
+ }
772
+ };
773
+
774
+ // / Transfer function for the expired loans analysis.
775
+ class ExpiredLoansTransferer {
776
+ FactManager &AllFacts;
777
+ LoanSet::Factory &SetFactory;
778
+
779
+ public:
780
+ explicit ExpiredLoansTransferer (FactManager &F, LoanSet::Factory &SF)
781
+ : AllFacts(F), SetFactory(SF) {}
782
+
783
+ // / Computes the exit state of a block by applying all its facts sequentially
784
+ // / to a given entry state.
785
+ ExpiredLattice transferBlock (const CFGBlock *Block,
786
+ ExpiredLattice EntryState) {
787
+ ExpiredLattice BlockState = EntryState;
788
+ llvm::ArrayRef<const Fact *> Facts = AllFacts.getFacts (Block);
789
+
790
+ for (const Fact *F : Facts) {
791
+ BlockState = transferFact (BlockState, F);
792
+ }
793
+ return BlockState;
794
+ }
795
+
796
+ private:
797
+ ExpiredLattice transferFact (ExpiredLattice In, const Fact *F) {
798
+ if (const auto *EF = F->getAs <ExpireFact>())
799
+ return ExpiredLattice (SetFactory.add (In.Expired , EF->getLoanID ()));
800
+
801
+ if (const auto *IF = F->getAs <IssueFact>())
802
+ return ExpiredLattice (SetFactory.remove (In.Expired , IF->getLoanID ()));
803
+
804
+ return In;
805
+ }
806
+ };
807
+
808
+ // / Dataflow analysis driver for tracking expired loans.
809
+ class ExpiredLoansAnalysis {
810
+ const CFG &Cfg;
811
+ AnalysisDeclContext &AC;
812
+ LoanSet::Factory SetFactory;
813
+ ExpiredLoansTransferer Xfer;
814
+
815
+ llvm::DenseMap<const CFGBlock *, ExpiredLattice> BlockEntryStates;
816
+ llvm::DenseMap<const CFGBlock *, ExpiredLattice> BlockExitStates;
817
+
818
+ public:
819
+ ExpiredLoansAnalysis (const CFG &C, FactManager &FS, AnalysisDeclContext &AC)
820
+ : Cfg(C), AC(AC), Xfer(FS, SetFactory) {}
821
+
822
+ void run () {
823
+ llvm::TimeTraceScope TimeProfile (" Expired Loans Analysis" );
824
+ ForwardDataflowWorklist Worklist (Cfg, AC);
825
+ const CFGBlock *Entry = &Cfg.getEntry ();
826
+ BlockEntryStates[Entry] = ExpiredLattice (SetFactory.getEmptySet ());
827
+ Worklist.enqueueBlock (Entry);
828
+ while (const CFGBlock *B = Worklist.dequeue ()) {
829
+ ExpiredLattice EntryState = getEntryState (B);
830
+ ExpiredLattice ExitState = Xfer.transferBlock (B, EntryState);
831
+ BlockExitStates[B] = ExitState;
832
+
833
+ for (const CFGBlock *Successor : B->succs ()) {
834
+ auto SuccIt = BlockEntryStates.find (Successor);
835
+ ExpiredLattice OldSuccEntryState = (SuccIt != BlockEntryStates.end ())
836
+ ? SuccIt->second
837
+ : ExpiredLattice{};
838
+ ExpiredLattice NewSuccEntryState =
839
+ OldSuccEntryState.join (ExitState, SetFactory);
840
+ if (SuccIt == BlockEntryStates.end () ||
841
+ NewSuccEntryState != OldSuccEntryState) {
842
+ BlockEntryStates[Successor] = NewSuccEntryState;
843
+ Worklist.enqueueBlock (Successor);
844
+ }
845
+ }
846
+ }
847
+ }
848
+
849
+ void dump () const {
850
+ llvm::dbgs () << " ==========================================\n " ;
851
+ llvm::dbgs () << " Expired Loans Results:\n " ;
852
+ llvm::dbgs () << " ==========================================\n " ;
853
+ const CFGBlock &B = Cfg.getExit ();
854
+ getExitState (&B).dump (llvm::dbgs ());
855
+ }
856
+
857
+ ExpiredLattice getEntryState (const CFGBlock *B) const {
858
+ auto It = BlockEntryStates.find (B);
859
+ if (It != BlockEntryStates.end ()) {
860
+ return It->second ;
861
+ }
862
+ return ExpiredLattice (SetFactory.getEmptySet ());
863
+ }
864
+
865
+ ExpiredLattice getExitState (const CFGBlock *B) const {
866
+ auto It = BlockExitStates.find (B);
867
+ if (It != BlockExitStates.end ()) {
868
+ return It->second ;
869
+ }
870
+ return ExpiredLattice (SetFactory.getEmptySet ());
871
+ }
872
+ };
873
+
738
874
// ========================================================================= //
739
875
// TODO: Analysing dataflow results and error reporting.
740
876
// ========================================================================= //
@@ -762,5 +898,9 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg,
762
898
LifetimeDataflow Dataflow (Cfg, FactMgr, AC);
763
899
Dataflow.run ();
764
900
DEBUG_WITH_TYPE (" LifetimeDataflow" , Dataflow.dump ());
901
+
902
+ ExpiredLoansAnalysis ExpiredAnalysis (Cfg, FactMgr, AC);
903
+ ExpiredAnalysis.run ();
904
+ DEBUG_WITH_TYPE (" ExpiredLoans" , ExpiredAnalysis.dump ());
765
905
}
766
906
} // namespace clang
0 commit comments