22#include "llvm/ADT/BitVector.h"
23#include "llvm/ADT/ImmutableList.h"
24#include "llvm/ADT/SmallSet.h"
25#include "llvm/ADT/SmallVector.h"
26#include "llvm/Support/raw_ostream.h"
46 : PersistentOrigins(Persistent), BlockLocalOrigins(BlockLocal) {}
50 return PersistentOrigins ==
Other.PersistentOrigins &&
51 BlockLocalOrigins ==
Other.BlockLocalOrigins;
55 void dump(llvm::raw_ostream &OS)
const {
56 OS <<
"LoanPropagationLattice State:\n";
57 OS <<
" Persistent Origins:\n";
58 if (PersistentOrigins.isEmpty())
60 for (
const auto &Entry : PersistentOrigins) {
61 if (Entry.second.isEmpty())
62 OS <<
" Origin " << Entry.first <<
" contains no loans\n";
63 for (
const LoanID &LID : Entry.second)
64 OS <<
" Origin " << Entry.first <<
" contains Loan " << LID <<
"\n";
66 OS <<
" Block-Local Origins:\n";
67 if (BlockLocalOrigins.isEmpty())
69 for (
const auto &Entry : BlockLocalOrigins) {
70 if (Entry.second.isEmpty())
71 OS <<
" Origin " << Entry.first <<
" contains no loans\n";
72 for (
const LoanID &LID : Entry.second)
73 OS <<
" Origin " << Entry.first <<
" contains Loan " << LID <<
"\n";
81 AnalysisImpl(
const CFG &
C, AnalysisDeclContext &AC, FactManager &F,
82 OriginLoanMap::Factory &OriginLoanMapFactory,
83 LoanSet::Factory &LoanSetFactory)
84 : DataflowAnalysis(
C, AC, F), OriginLoanMapFactory(OriginLoanMapFactory),
85 LoanSetFactory(LoanSetFactory),
86 PersistentOrigins(F.getPersistentOrigins()) {}
90 StringRef getAnalysisName()
const {
return "LoanPropagation"; }
92 Lattice getInitialState() {
return Lattice{}; }
95 Lattice
join(Lattice A, Lattice B) {
96 assert(A.BlockLocalOrigins.isEmpty() && B.BlockLocalOrigins.isEmpty() &&
97 "block-local origins must not reach a block boundary");
99 A.PersistentOrigins, B.PersistentOrigins, OriginLoanMapFactory,
101 assert((S1 || S2) &&
"unexpectedly merging 2 empty sets");
106 return utils::join(*S1, *S2, LoanSetFactory);
111 return Lattice(JoinedOrigins, OriginLoanMapFactory.getEmptyMap());
118 Lattice transferAtBlockExit(Lattice L) {
119 return Lattice(L.PersistentOrigins, OriginLoanMapFactory.getEmptyMap());
123 Lattice
transfer(Lattice In,
const IssueFact &F) {
125 LoanID LID = F.getLoanID();
126 LoanSet NewLoans = LoanSetFactory.add(LoanSetFactory.getEmptySet(), LID);
127 return setLoans(In, OID, NewLoans);
133 Lattice
transfer(Lattice In,
const OriginFlowFact &F) {
134 OriginID DestOID = F.getDestOriginID();
135 OriginID SrcOID = F.getSrcOriginID();
138 F.getKillDest() ? LoanSetFactory.getEmptySet() : getLoans(In, DestOID);
139 LoanSet SrcLoans = getLoans(In, SrcOID);
142 return setLoans(In, DestOID, MergedLoans);
145 Lattice
transfer(Lattice In,
const KillOriginFact &F) {
146 return setLoans(In, F.getKilledOrigin(), LoanSetFactory.getEmptySet());
149 Lattice
transfer(Lattice In,
const ExpireFact &F) {
150 if (
auto OID = F.getOriginID())
151 return setLoans(In, *OID, LoanSetFactory.getEmptySet());
156 return getLoans(getState(P), OID);
159 llvm::SmallVector<OriginID> buildOriginFlowChain(
ProgramPoint StartPoint,
162 const CFG *Cfg)
const {
163 assert(getLoans(StartOID, StartPoint).
contains(TargetLoan) &&
164 "TargetLoan must be present in the StartOID at the StartPoint");
167 const CFGBlock *EndBlock =
nullptr;
168 size_t BlockID = FactMgr.getBlockID(StartPoint);
169 for (
const CFGBlock *
Block : *Cfg)
170 if (
Block->getBlockID() == BlockID) {
178 using SearchState = std::pair<const CFGBlock *, OriginID>;
180 SearchState CurrState;
181 llvm::ImmutableList<OriginID> OriginFlowChain;
184 llvm::SmallVector<DFSNode> PendingStates;
185 llvm::SmallSet<SearchState, 16> VistedStates;
186 llvm::ImmutableList<OriginID>::Factory OriginFlowChainFactory;
187 PendingStates.push_back(
188 {{EndBlock, StartOID}, OriginFlowChainFactory.getEmptyList()});
191 while (!PendingStates.empty()) {
192 DFSNode CurrNode = PendingStates.pop_back_val();
193 auto [CurrBlock, CurrOID] = CurrNode.CurrState;
196 const auto [BuildResult,
Complete] =
197 buildOriginFlowChain(CurrBlock, CurrOID, TargetLoan);
198 if (!BuildResult.empty()) {
200 CurrNode.OriginFlowChain =
201 OriginFlowChainFactory.add(OID, CurrNode.OriginFlowChain);
202 CurrOID = BuildResult.back();
207 llvm::SmallVector<OriginID>
Result(CurrNode.OriginFlowChain.begin(),
208 CurrNode.OriginFlowChain.end());
215 for (
const CFGBlock *PredBlock : CurrBlock->preds()) {
216 SearchState NextState = {PredBlock, CurrOID};
217 if (getLoans(getOutState(PredBlock), CurrOID).
contains(TargetLoan) &&
218 VistedStates.insert(NextState).second)
219 PendingStates.push_back({NextState, CurrNode.OriginFlowChain});
223 llvm_unreachable(
"Could not reconstruct origin flow. Search finished "
224 "without reaching IssueFact");
227 llvm::SmallVector<OriginID> buildOriginFlowChain(
const UseFact *UF,
229 const CFG *Cfg)
const {
230 for (
const OriginList *Cur = UF->getUsedOrigins(); Cur;
231 Cur = Cur->peelOuterOrigin())
232 if (getLoans(Cur->getOuterOriginID(), UF).contains(TargetLoan))
233 return dropLoadsInUse(
234 buildOriginFlowChain(UF, Cur->getOuterOriginID(), TargetLoan, Cfg));
243 llvm::SmallVector<OriginID>
244 dropLoadsInUse(llvm::SmallVector<OriginID> Chain)
const {
245 const OriginManager &OM = FactMgr.getOriginMgr();
246 auto FirstDecl = llvm::find_if(
247 Chain, [&](
OriginID OID) {
return !OM.getOrigin(OID).getExpr(); });
248 Chain.erase(std::remove_if(Chain.begin(), FirstDecl,
250 return isa<ImplicitCastExpr>(
251 OM.getOrigin(OID).getExpr());
258 bool isPersistent(
OriginID OID)
const {
259 return PersistentOrigins.test(OID.Value);
263 if (isPersistent(OID))
264 return Lattice(OriginLoanMapFactory.add(L.PersistentOrigins, OID, Loans),
265 L.BlockLocalOrigins);
266 return Lattice(L.PersistentOrigins,
267 OriginLoanMapFactory.add(L.BlockLocalOrigins, OID, Loans));
272 isPersistent(OID) ? &L.PersistentOrigins : &L.BlockLocalOrigins;
273 if (
auto *Loans = Map->lookup(OID))
275 return LoanSetFactory.getEmptySet();
286 std::pair<llvm::SmallVector<OriginID>,
bool>
287 buildOriginFlowChain(
const CFGBlock *
Block,
const OriginID StartOID,
288 const LoanID TargetLoan)
const {
290 llvm::SmallVector<OriginID> OriginFlowChain;
292 for (
const Fact *F : llvm::reverse(FactMgr.getFacts(
Block))) {
293 if (
const auto *IF = F->getAs<IssueFact>())
294 if (IF->getLoanID() == TargetLoan && IF->getOriginID() == CurrOID)
295 return {OriginFlowChain,
true};
297 const auto *OFF = F->getAs<OriginFlowFact>();
298 if (!OFF || OFF->getDestOriginID() != CurrOID)
301 const OriginID SrcOriginID = OFF->getSrcOriginID();
302 if (!getLoans(SrcOriginID, OFF).
contains(TargetLoan))
305 OriginFlowChain.push_back(SrcOriginID);
306 CurrOID = SrcOriginID;
309 return {OriginFlowChain,
false};
312 OriginLoanMap::Factory &OriginLoanMapFactory;
313 LoanSet::Factory &LoanSetFactory;
316 const llvm::BitVector &PersistentOrigins;
321 using AnalysisImpl::AnalysisImpl;
326 OriginLoanMap::Factory &OriginLoanMapFactory,
327 LoanSet::Factory &LoanSetFactory)
328 : PImpl(
std::make_unique<
Impl>(
C, AC, F, OriginLoanMapFactory,
336 return PImpl->getLoans(OID, P);
341 const CFG *Cfg)
const {
342 return PImpl->buildOriginFlowChain(StartPoint, StartOID, TargetLoan, Cfg);
347 return PImpl->buildOriginFlowChain(UF, TargetLoan, Cfg);
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
static bool contains(const std::set< tok::TokenKind > &Terminators, const Token &Tok)
AnalysisDeclContext contains the context data for the function, method or block under analysis.
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
A generic, policy-based driver for dataflow analyses.
llvm::SmallVector< OriginID > buildOriginFlowChain(ProgramPoint StartPoint, const OriginID StartOID, const LoanID TargetLoan, const CFG *Cfg) const
Builds the chain of origins through which a loan has propagated.
LoanSet getLoans(OriginID OID, ProgramPoint P) const
~LoanPropagationAnalysis()
LoanPropagationAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, OriginLoanMap::Factory &OriginLoanMapFactory, LoanSet::Factory &LoanSetFactory)
BlockID
The various types of blocks that can occur within a API notes file.
void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env, Environment::ValueModel &Model)
Evaluates S and updates Env accordingly.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
@ Asymmetric
An asymmetric join preserves keys unique to the first map as-is, while applying the JoinValues operat...
SetTy< T > join(SetTy< T > A, SetTy< T > B, typename SetTy< T >::Factory &F)
Computes the union of two ImmutableSets.
const Fact * ProgramPoint
A ProgramPoint identifies a location in the CFG by pointing to a specific Fact.
utils::ID< struct LoanTag > LoanID
utils::ID< struct OriginTag > OriginID
utils::SetTy< LoanID > LoanSet
utils::MapTy< OriginID, LoanSet > OriginLoanMap
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
@ Result
The result type of a method or function.
bool operator!=(CanQual< T > x, CanQual< U > y)
@ Other
Other implicit parameter.