55// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66//
77// ===----------------------------------------------------------------------===//
8- #include " clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h"
9- #include " Dataflow.h"
8+ #include < cassert>
109#include < memory>
1110
11+ #include " Dataflow.h"
12+ #include " clang/Analysis/Analyses/LifetimeSafety/Facts.h"
13+ #include " clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h"
14+ #include " clang/Analysis/Analyses/LifetimeSafety/Loans.h"
15+ #include " clang/Analysis/Analyses/LifetimeSafety/Origins.h"
16+ #include " clang/Analysis/Analyses/LifetimeSafety/Utils.h"
17+ #include " clang/Analysis/AnalysisDeclContext.h"
18+ #include " clang/Analysis/CFG.h"
19+ #include " clang/Basic/LLVM.h"
20+ #include " llvm/ADT/BitVector.h"
21+ #include " llvm/ADT/SmallVector.h"
22+ #include " llvm/Support/TimeProfiler.h"
23+ #include " llvm/Support/raw_ostream.h"
24+
1225namespace clang ::lifetimes::internal {
26+
27+ // Prepass to find persistent origins. An origin is persistent if it is
28+ // referenced in more than one basic block.
29+ static llvm::BitVector computePersistentOrigins (const FactManager &FactMgr,
30+ const CFG &C) {
31+ llvm::TimeTraceScope (" ComputePersistentOrigins" );
32+ unsigned NumOrigins = FactMgr.getOriginMgr ().getNumOrigins ();
33+ llvm::BitVector PersistentOrigins (NumOrigins);
34+
35+ llvm::SmallVector<const CFGBlock *> OriginToFirstSeenBlock (NumOrigins,
36+ nullptr );
37+ for (const CFGBlock *B : C) {
38+ for (const Fact *F : FactMgr.getFacts (B)) {
39+ auto CheckOrigin = [&](OriginID OID) {
40+ if (PersistentOrigins.test (OID.Value ))
41+ return ;
42+ auto &FirstSeenBlock = OriginToFirstSeenBlock[OID.Value ];
43+ if (FirstSeenBlock == nullptr )
44+ FirstSeenBlock = B;
45+ if (FirstSeenBlock != B) {
46+ // We saw this origin in more than one block.
47+ PersistentOrigins.set (OID.Value );
48+ }
49+ };
50+
51+ switch (F->getKind ()) {
52+ case Fact::Kind::Issue:
53+ CheckOrigin (F->getAs <IssueFact>()->getOriginID ());
54+ break ;
55+ case Fact::Kind::OriginFlow: {
56+ const auto *OF = F->getAs <OriginFlowFact>();
57+ CheckOrigin (OF->getDestOriginID ());
58+ CheckOrigin (OF->getSrcOriginID ());
59+ break ;
60+ }
61+ case Fact::Kind::ReturnOfOrigin:
62+ CheckOrigin (F->getAs <ReturnOfOriginFact>()->getReturnedOriginID ());
63+ break ;
64+ case Fact::Kind::Use:
65+ CheckOrigin (F->getAs <UseFact>()->getUsedOrigin ());
66+ break ;
67+ case Fact::Kind::Expire:
68+ case Fact::Kind::TestPoint:
69+ break ;
70+ }
71+ }
72+ }
73+ return PersistentOrigins;
74+ }
75+
1376namespace {
77+
1478// / Represents the dataflow lattice for loan propagation.
1579// /
1680// / This lattice tracks which loans each origin may hold at a given program
1781// / point.The lattice has a finite height: An origin's loan set is bounded by
1882// / the total number of loans in the function.
19- // / TODO(opt): To reduce the lattice size, propagate origins of declarations,
20- // / not expressions, because expressions are not visible across blocks.
2183struct Lattice {
2284 // / The map from an origin to the set of loans it contains.
23- OriginLoanMap Origins = OriginLoanMap(nullptr );
24-
25- explicit Lattice (const OriginLoanMap &S) : Origins(S) {}
85+ // / Origins that appear in multiple blocks. Participates in join operations.
86+ OriginLoanMap PersistentOrigins = OriginLoanMap(nullptr );
87+ // / Origins confined to a single block. Discarded at block boundaries.
88+ OriginLoanMap BlockLocalOrigins = OriginLoanMap(nullptr );
89+
90+ explicit Lattice (const OriginLoanMap &Persistent,
91+ const OriginLoanMap &BlockLocal)
92+ : PersistentOrigins(Persistent), BlockLocalOrigins(BlockLocal) {}
2693 Lattice () = default ;
2794
2895 bool operator ==(const Lattice &Other) const {
29- return Origins == Other.Origins ;
96+ return PersistentOrigins == Other.PersistentOrigins &&
97+ BlockLocalOrigins == Other.BlockLocalOrigins ;
3098 }
3199 bool operator !=(const Lattice &Other) const { return !(*this == Other); }
32100
33101 void dump (llvm::raw_ostream &OS) const {
34102 OS << " LoanPropagationLattice State:\n " ;
35- if (Origins.isEmpty ())
103+ OS << " Persistent Origins:\n " ;
104+ if (PersistentOrigins.isEmpty ())
36105 OS << " <empty>\n " ;
37- for (const auto &Entry : Origins) {
106+ for (const auto &Entry : PersistentOrigins) {
107+ if (Entry.second .isEmpty ())
108+ OS << " Origin " << Entry.first << " contains no loans\n " ;
109+ for (const LoanID &LID : Entry.second )
110+ OS << " Origin " << Entry.first << " contains Loan " << LID << " \n " ;
111+ }
112+ OS << " Block-Local Origins:\n " ;
113+ if (BlockLocalOrigins.isEmpty ())
114+ OS << " <empty>\n " ;
115+ for (const auto &Entry : BlockLocalOrigins) {
38116 if (Entry.second .isEmpty ())
39117 OS << " Origin " << Entry.first << " contains no loans\n " ;
40118 for (const LoanID &LID : Entry.second )
@@ -50,7 +128,8 @@ class AnalysisImpl
50128 OriginLoanMap::Factory &OriginLoanMapFactory,
51129 LoanSet::Factory &LoanSetFactory)
52130 : DataflowAnalysis(C, AC, F), OriginLoanMapFactory(OriginLoanMapFactory),
53- LoanSetFactory (LoanSetFactory) {}
131+ LoanSetFactory (LoanSetFactory),
132+ PersistentOrigins(computePersistentOrigins(F, C)) {}
54133
55134 using Base::transfer;
56135
@@ -59,10 +138,10 @@ class AnalysisImpl
59138 Lattice getInitialState () { return Lattice{}; }
60139
61140 // / 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 .
141+ // / Only persistent origins are joined; block-local origins are discarded .
63142 Lattice join (Lattice A, Lattice B) {
64143 OriginLoanMap JoinedOrigins = utils::join (
65- A.Origins , B.Origins , OriginLoanMapFactory,
144+ A.PersistentOrigins , B.PersistentOrigins , OriginLoanMapFactory,
66145 [&](const LoanSet *S1, const LoanSet *S2) {
67146 assert ((S1 || S2) && " unexpectedly merging 2 empty sets" );
68147 if (!S1)
@@ -74,16 +153,15 @@ class AnalysisImpl
74153 // Asymmetric join is a performance win. For origins present only on one
75154 // branch, the loan set can be carried over as-is.
76155 utils::JoinKind::Asymmetric);
77- return Lattice (JoinedOrigins);
156+ return Lattice (JoinedOrigins, OriginLoanMapFactory. getEmptyMap () );
78157 }
79158
80159 // / A new loan is issued to the origin. Old loans are erased.
81160 Lattice transfer (Lattice In, const IssueFact &F) {
82161 OriginID OID = F.getOriginID ();
83162 LoanID LID = F.getLoanID ();
84- return Lattice (OriginLoanMapFactory.add (
85- In.Origins , OID,
86- LoanSetFactory.add (LoanSetFactory.getEmptySet (), LID)));
163+ LoanSet NewLoans = LoanSetFactory.add (LoanSetFactory.getEmptySet (), LID);
164+ return setLoans (In, OID, NewLoans);
87165 }
88166
89167 // / A flow from source to destination. If `KillDest` is true, this replaces
@@ -98,22 +176,41 @@ class AnalysisImpl
98176 LoanSet SrcLoans = getLoans (In, SrcOID);
99177 LoanSet MergedLoans = utils::join (DestLoans, SrcLoans, LoanSetFactory);
100178
101- return Lattice (OriginLoanMapFactory. add (In. Origins , DestOID, MergedLoans) );
179+ return setLoans (In , DestOID, MergedLoans);
102180 }
103181
104182 LoanSet getLoans (OriginID OID, ProgramPoint P) const {
105183 return getLoans (getState (P), OID);
106184 }
107185
108186private:
187+ // / Returns true if the origin is persistent (referenced in multiple blocks).
188+ bool isPersistent (OriginID OID) const {
189+ return PersistentOrigins.test (OID.Value );
190+ }
191+
192+ Lattice setLoans (Lattice L, OriginID OID, LoanSet Loans) {
193+ if (isPersistent (OID))
194+ return Lattice (OriginLoanMapFactory.add (L.PersistentOrigins , OID, Loans),
195+ L.BlockLocalOrigins );
196+ return Lattice (L.PersistentOrigins ,
197+ OriginLoanMapFactory.add (L.BlockLocalOrigins , OID, Loans));
198+ }
199+
109200 LoanSet getLoans (Lattice L, OriginID OID) const {
110- if (auto *Loans = L.Origins .lookup (OID))
201+ const OriginLoanMap *Map =
202+ isPersistent (OID) ? &L.PersistentOrigins : &L.BlockLocalOrigins ;
203+ if (auto *Loans = Map->lookup (OID))
111204 return *Loans;
112205 return LoanSetFactory.getEmptySet ();
113206 }
114207
115208 OriginLoanMap::Factory &OriginLoanMapFactory;
116209 LoanSet::Factory &LoanSetFactory;
210+ // / Boolean vector indexed by origin ID. If true, the origin appears in
211+ // / multiple basic blocks and must participate in join operations. If false,
212+ // / the origin is block-local and can be discarded at block boundaries.
213+ llvm::BitVector PersistentOrigins;
117214};
118215} // namespace
119216
0 commit comments