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