@@ -735,6 +735,142 @@ class LifetimeDataflow {
735735 }
736736};
737737
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+
738874// ========================================================================= //
739875// TODO: Analysing dataflow results and error reporting.
740876// ========================================================================= //
@@ -762,5 +898,9 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg,
762898 LifetimeDataflow Dataflow (Cfg, FactMgr, AC);
763899 Dataflow.run ();
764900 DEBUG_WITH_TYPE (" LifetimeDataflow" , Dataflow.dump ());
901+
902+ ExpiredLoansAnalysis ExpiredAnalysis (Cfg, FactMgr, AC);
903+ ExpiredAnalysis.run ();
904+ DEBUG_WITH_TYPE (" ExpiredLoans" , ExpiredAnalysis.dump ());
765905}
766906} // namespace clang
0 commit comments