77// ===----------------------------------------------------------------------===//
88#include " clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h"
99#include " Dataflow.h"
10+ #include " llvm/Support/TimeProfiler.h"
1011#include < memory>
1112
1213namespace clang ::lifetimes::internal {
14+
15+ // Pre-pass to find persistent origins. An origin is persistent if it is
16+ // referenced in more than one basic block.
17+ static llvm::DenseSet<OriginID> computePersistentOrigins (FactManager &FactMgr,
18+ const CFG &C) {
19+ llvm::TimeTraceScope (" ComputePersistentOrigins" );
20+ llvm::DenseSet<OriginID> PersistentOrigins;
21+
22+ llvm::DenseMap<OriginID, const CFGBlock *> OriginToBlock;
23+ for (const CFGBlock *B : C) {
24+ for (const Fact *F : FactMgr.getFacts (B)) {
25+ auto CheckOrigin = [&](OriginID OID) {
26+ if (PersistentOrigins.count (OID))
27+ return ;
28+ auto It = OriginToBlock.find (OID);
29+ if (It == OriginToBlock.end ()) {
30+ OriginToBlock[OID] = B;
31+ } else if (It->second != B) {
32+ // We saw this origin in more than one block.
33+ PersistentOrigins.insert (OID);
34+ }
35+ };
36+
37+ switch (F->getKind ()) {
38+ case Fact::Kind::Issue:
39+ CheckOrigin (F->getAs <IssueFact>()->getOriginID ());
40+ break ;
41+ case Fact::Kind::OriginFlow: {
42+ const auto *OF = F->getAs <OriginFlowFact>();
43+ CheckOrigin (OF->getDestOriginID ());
44+ CheckOrigin (OF->getSrcOriginID ());
45+ break ;
46+ }
47+ case Fact::Kind::ReturnOfOrigin:
48+ CheckOrigin (F->getAs <ReturnOfOriginFact>()->getReturnedOriginID ());
49+ break ;
50+ case Fact::Kind::Use:
51+ CheckOrigin (F->getAs <UseFact>()->getUsedOrigin (FactMgr.getOriginMgr ()));
52+ break ;
53+ case Fact::Kind::Expire:
54+ case Fact::Kind::TestPoint:
55+ break ;
56+ }
57+ }
58+ }
59+ return PersistentOrigins;
60+ }
61+
1362namespace {
63+
1464// / Represents the dataflow lattice for loan propagation.
1565// /
1666// / This lattice tracks which loans each origin may hold at a given program
@@ -20,21 +70,35 @@ namespace {
2070// / not expressions, because expressions are not visible across blocks.
2171struct Lattice {
2272 // / The map from an origin to the set of loans it contains.
23- OriginLoanMap Origins = OriginLoanMap(nullptr );
73+ OriginLoanMap PersistentOrigins = OriginLoanMap(nullptr );
74+ OriginLoanMap BlockLocalOrigins = OriginLoanMap(nullptr );
2475
25- explicit Lattice (const OriginLoanMap &S) : Origins(S) {}
76+ explicit Lattice (const OriginLoanMap &Persistent,
77+ const OriginLoanMap &BlockLocal)
78+ : PersistentOrigins(Persistent), BlockLocalOrigins(BlockLocal) {}
2679 Lattice () = default ;
2780
2881 bool operator ==(const Lattice &Other) const {
29- return Origins == Other.Origins ;
82+ return PersistentOrigins == Other.PersistentOrigins &&
83+ BlockLocalOrigins == Other.BlockLocalOrigins ;
3084 }
3185 bool operator !=(const Lattice &Other) const { return !(*this == Other); }
3286
3387 void dump (llvm::raw_ostream &OS) const {
3488 OS << " LoanPropagationLattice State:\n " ;
35- if (Origins.isEmpty ())
89+ OS << " Persistent Origins:\n " ;
90+ if (PersistentOrigins.isEmpty ())
3691 OS << " <empty>\n " ;
37- for (const auto &Entry : Origins) {
92+ for (const auto &Entry : PersistentOrigins) {
93+ if (Entry.second .isEmpty ())
94+ OS << " Origin " << Entry.first << " contains no loans\n " ;
95+ for (const LoanID &LID : Entry.second )
96+ OS << " Origin " << Entry.first << " contains Loan " << LID << " \n " ;
97+ }
98+ OS << " Block-Local Origins:\n " ;
99+ if (BlockLocalOrigins.isEmpty ())
100+ OS << " <empty>\n " ;
101+ for (const auto &Entry : BlockLocalOrigins) {
38102 if (Entry.second .isEmpty ())
39103 OS << " Origin " << Entry.first << " contains no loans\n " ;
40104 for (const LoanID &LID : Entry.second )
@@ -50,7 +114,8 @@ class AnalysisImpl
50114 OriginLoanMap::Factory &OriginLoanMapFactory,
51115 LoanSet::Factory &LoanSetFactory)
52116 : DataflowAnalysis(C, AC, F), OriginLoanMapFactory(OriginLoanMapFactory),
53- LoanSetFactory (LoanSetFactory) {}
117+ LoanSetFactory (LoanSetFactory),
118+ PersistentOrigins(computePersistentOrigins(F, C)) {}
54119
55120 using Base::transfer;
56121
@@ -59,10 +124,9 @@ class AnalysisImpl
59124 Lattice getInitialState () { return Lattice{}; }
60125
61126 // / Merges two lattices by taking the union of loans for each origin.
62- // TODO(opt): Keep the state small by removing origins which become dead.
63127 Lattice join (Lattice A, Lattice B) {
64128 OriginLoanMap JoinedOrigins = utils::join (
65- A.Origins , B.Origins , OriginLoanMapFactory,
129+ A.PersistentOrigins , B.PersistentOrigins , OriginLoanMapFactory,
66130 [&](const LoanSet *S1, const LoanSet *S2) {
67131 assert ((S1 || S2) && " unexpectedly merging 2 empty sets" );
68132 if (!S1)
@@ -74,16 +138,15 @@ class AnalysisImpl
74138 // Asymmetric join is a performance win. For origins present only on one
75139 // branch, the loan set can be carried over as-is.
76140 utils::JoinKind::Asymmetric);
77- return Lattice (JoinedOrigins);
141+ return Lattice (JoinedOrigins, OriginLoanMapFactory. getEmptyMap () );
78142 }
79143
80144 // / A new loan is issued to the origin. Old loans are erased.
81145 Lattice transfer (Lattice In, const IssueFact &F) {
82146 OriginID OID = F.getOriginID ();
83147 LoanID LID = F.getLoanID ();
84- return Lattice (OriginLoanMapFactory.add (
85- In.Origins , OID,
86- LoanSetFactory.add (LoanSetFactory.getEmptySet (), LID)));
148+ LoanSet NewLoans = LoanSetFactory.add (LoanSetFactory.getEmptySet (), LID);
149+ return setLoans (In, OID, NewLoans);
87150 }
88151
89152 // / A flow from source to destination. If `KillDest` is true, this replaces
@@ -98,22 +161,38 @@ class AnalysisImpl
98161 LoanSet SrcLoans = getLoans (In, SrcOID);
99162 LoanSet MergedLoans = utils::join (DestLoans, SrcLoans, LoanSetFactory);
100163
101- return Lattice (OriginLoanMapFactory. add (In. Origins , DestOID, MergedLoans) );
164+ return setLoans (In , DestOID, MergedLoans);
102165 }
103166
104167 LoanSet getLoans (OriginID OID, ProgramPoint P) const {
105168 return getLoans (getState (P), OID);
106169 }
107170
108171private:
172+ bool isPersistent (OriginID OID) const {
173+ return PersistentOrigins.contains (OID);
174+ }
175+
176+ Lattice setLoans (Lattice L, OriginID OID, LoanSet Loans) {
177+ if (isPersistent (OID)) {
178+ return Lattice (OriginLoanMapFactory.add (L.PersistentOrigins , OID, Loans),
179+ L.BlockLocalOrigins );
180+ }
181+ return Lattice (L.PersistentOrigins ,
182+ OriginLoanMapFactory.add (L.BlockLocalOrigins , OID, Loans));
183+ }
184+
109185 LoanSet getLoans (Lattice L, OriginID OID) const {
110- if (auto *Loans = L.Origins .lookup (OID))
186+ const OriginLoanMap *Map =
187+ isPersistent (OID) ? &L.PersistentOrigins : &L.BlockLocalOrigins ;
188+ if (auto *Loans = Map->lookup (OID))
111189 return *Loans;
112190 return LoanSetFactory.getEmptySet ();
113191 }
114192
115193 OriginLoanMap::Factory &OriginLoanMapFactory;
116194 LoanSet::Factory &LoanSetFactory;
195+ llvm::DenseSet<OriginID> PersistentOrigins;
117196};
118197} // namespace
119198
0 commit comments