clang 24.0.0git
Dataflow.h
Go to the documentation of this file.
1//===- Dataflow.h - Generic Dataflow Analysis Framework --------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines a generic, policy-based driver for dataflow analyses.
10// It provides a flexible framework that combines the dataflow runner and
11// transfer functions, allowing derived classes to implement specific analyses
12// by defining their lattice, join, and transfer functions.
13//
14//===----------------------------------------------------------------------===//
15#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_DATAFLOW_H
16#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_DATAFLOW_H
17
20#include "clang/Analysis/CFG.h"
22#include "llvm/Support/Debug.h"
23#include "llvm/Support/ErrorHandling.h"
24#include "llvm/Support/TimeProfiler.h"
25#include <optional>
26
28
29enum class Direction { Forward, Backward };
30
31/// A `ProgramPoint` identifies a location in the CFG by pointing to a specific
32/// `Fact`. identified by a lifetime-related event (`Fact`).
33///
34/// A `ProgramPoint` has "after" semantics: it represents the location
35/// immediately after its corresponding `Fact`.
36using ProgramPoint = const Fact *;
37
38/// A generic, policy-based driver for dataflow analyses. It combines
39/// the dataflow runner and the transferer logic into a single class hierarchy.
40///
41/// The derived class is expected to provide:
42/// - A `Lattice` type.
43/// - `StringRef getAnalysisName() const`
44/// - `Lattice getInitialState();` The initial state of the analysis.
45/// - `Lattice join(Lattice, Lattice);` Merges states from multiple CFG paths.
46/// - `Lattice transfer(Lattice, const FactType&);` Defines how a single
47/// lifetime-relevant `Fact` transforms the lattice state. Only overloads
48/// for facts relevant to the analysis need to be implemented.
49///
50/// It may additionally override `Lattice transferAtBlockExit(Lattice);` to
51/// drop state that is not visible outside the block it was computed in.
52///
53/// \tparam Derived The CRTP derived class that implements the specific
54/// analysis.
55/// \tparam LatticeType The dataflow lattice used by the analysis.
56/// \tparam Dir The direction of the analysis (Forward or Backward).
57/// TODO: Maybe use the dataflow framework! The framework might need changes
58/// to support the current comparison done at block-entry.
59template <typename Derived, typename LatticeType, Direction Dir>
61public:
62 using Lattice = LatticeType;
64
65private:
66 const CFG &Cfg;
68
69 /// The dataflow state before a basic block is processed.
70 llvm::DenseMap<const CFGBlock *, Lattice> InStates;
71 /// The dataflow state after a basic block is processed.
72 llvm::DenseMap<const CFGBlock *, Lattice> OutStates;
73 /// Dataflow state at each program point, indexed by Fact ID.
74 /// In a forward analysis, this is the state after the Fact at that point has
75 /// been applied, while in a backward analysis, it is the state before.
76 llvm::SmallVector<Lattice> PointToState;
77
78 static constexpr bool isForward() { return Dir == Direction::Forward; }
79
80protected:
82
83 explicit DataflowAnalysis(const CFG &Cfg, AnalysisDeclContext &AC,
85 : Cfg(Cfg), AC(AC), FactMgr(FactMgr) {}
86
87public:
88 void run() {
89 Derived &D = static_cast<Derived &>(*this);
90 llvm::TimeTraceScope Time(D.getAnalysisName());
91
92 PointToState.resize(FactMgr.getNumFacts());
93
94 using Worklist =
95 std::conditional_t<Dir == Direction::Forward, ForwardDataflowWorklist,
97 Worklist W(Cfg, AC);
98
99 const CFGBlock *Start = isForward() ? &Cfg.getEntry() : &Cfg.getExit();
100 InStates[Start] = D.getInitialState();
101 W.enqueueBlock(Start);
102
103 while (const CFGBlock *B = W.dequeue()) {
104 Lattice StateIn = *getInState(B);
105 Lattice StateOut = transferBlock(B, StateIn);
106 OutStates[B] = StateOut;
107 for (const CFGBlock *AdjacentB : isForward() ? B->succs() : B->preds()) {
108 if (!AdjacentB)
109 continue;
110 std::optional<Lattice> OldInState = getInState(AdjacentB);
111 Lattice NewInState =
112 !OldInState ? StateOut : D.join(*OldInState, StateOut);
113 // Enqueue the adjacent block if its in-state has changed or if we have
114 // never seen it.
115 if (!OldInState || NewInState != *OldInState) {
116 InStates[AdjacentB] = NewInState;
117 W.enqueueBlock(AdjacentB);
118 }
119 }
120 }
121 }
122
123protected:
125 return PointToState[P->getID().Value];
126 }
127
128 std::optional<Lattice> getInState(const CFGBlock *B) const {
129 auto It = InStates.find(B);
130 if (It == InStates.end())
131 return std::nullopt;
132 return It->second;
133 }
134
135 Lattice getOutState(const CFGBlock *B) const { return OutStates.lookup(B); }
136
137 void dump() const {
138 const Derived *D = static_cast<const Derived *>(this);
139 llvm::dbgs() << "==========================================\n";
140 llvm::dbgs() << D->getAnalysisName() << " results:\n";
141 llvm::dbgs() << "==========================================\n";
142 const CFGBlock &B = isForward() ? Cfg.getExit() : Cfg.getEntry();
143 getOutState(&B).dump(llvm::dbgs());
144 }
145
146private:
147 /// Computes the state at one end of a block by applying all its facts
148 /// sequentially to a given state from the other end.
149 Lattice transferBlock(const CFGBlock *Block, Lattice State) {
150 auto Facts = FactMgr.getFacts(Block);
151 if constexpr (isForward()) {
152 for (const Fact *F : Facts) {
153 State = transferFact(State, F);
154 PointToState[F->getID().Value] = State;
155 }
156 } else {
157 for (const Fact *F : llvm::reverse(Facts)) {
158 // In backward analysis, capture the state before applying the fact.
159 PointToState[F->getID().Value] = State;
160 State = transferFact(State, F);
161 }
162 }
163 return static_cast<Derived *>(this)->transferAtBlockExit(State);
164 }
165
166 Lattice transferFact(Lattice In, const Fact *F) {
167 assert(F);
168 Derived *D = static_cast<Derived *>(this);
169 switch (F->getKind()) {
171 return D->transfer(In, *F->getAs<IssueFact>());
173 return D->transfer(In, *F->getAs<ExpireFact>());
175 return D->transfer(In, *F->getAs<OriginFlowFact>());
177 return D->transfer(In, *F->getAs<MovedOriginFact>());
179 return D->transfer(In, *F->getAs<OriginEscapesFact>());
180 case Fact::Kind::Use:
181 return D->transfer(In, *F->getAs<UseFact>());
183 return D->transfer(In, *F->getAs<TestPointFact>());
185 return D->transfer(In, *F->getAs<InvalidateOriginFact>());
187 return D->transfer(In, *F->getAs<KillOriginFact>());
188 }
189 llvm_unreachable("Unknown fact kind");
190 }
191
192public:
194
195 Lattice transfer(Lattice In, const IssueFact &) { return In; }
196 Lattice transfer(Lattice In, const ExpireFact &) { return In; }
197 Lattice transfer(Lattice In, const OriginFlowFact &) { return In; }
198 Lattice transfer(Lattice In, const MovedOriginFact &) { return In; }
199 Lattice transfer(Lattice In, const OriginEscapesFact &) { return In; }
200 Lattice transfer(Lattice In, const UseFact &) { return In; }
201 Lattice transfer(Lattice In, const TestPointFact &) { return In; }
202 Lattice transfer(Lattice In, const InvalidateOriginFact &) { return In; }
203 Lattice transfer(Lattice In, const KillOriginFact &) { return In; }
204};
205} // namespace clang::lifetimes::internal
206#endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_DATAFLOW_H
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
AnalysisDeclContext contains the context data for the function, method or block under analysis.
Represents a single basic block in a source-level CFG.
Definition CFG.h:652
succ_range succs()
Definition CFG.h:1047
void dump() const
Definition CFG.cpp:6400
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
Definition CFG.h:1271
Lattice transfer(Lattice In, const InvalidateOriginFact &)
Definition Dataflow.h:202
DataflowAnalysis(const CFG &Cfg, AnalysisDeclContext &AC, FactManager &FactMgr)
Definition Dataflow.h:83
Lattice transfer(Lattice In, const KillOriginFact &)
Definition Dataflow.h:203
std::optional< Lattice > getInState(const CFGBlock *B) const
Definition Dataflow.h:128
Lattice transfer(Lattice In, const OriginFlowFact &)
Definition Dataflow.h:197
Lattice transfer(Lattice In, const MovedOriginFact &)
Definition Dataflow.h:198
Lattice transfer(Lattice In, const TestPointFact &)
Definition Dataflow.h:201
Lattice getOutState(const CFGBlock *B) const
Definition Dataflow.h:135
Lattice transfer(Lattice In, const UseFact &)
Definition Dataflow.h:200
Lattice transfer(Lattice In, const IssueFact &)
Definition Dataflow.h:195
Lattice transfer(Lattice In, const OriginEscapesFact &)
Definition Dataflow.h:199
Lattice transfer(Lattice In, const ExpireFact &)
Definition Dataflow.h:196
DataflowAnalysis< Derived, Lattice, Dir > Base
Definition Dataflow.h:63
Lattice getState(ProgramPoint P) const
Definition Dataflow.h:124
When an AccessPath expires (e.g., a variable goes out of scope), all loans that are associated with t...
Definition Facts.h:118
llvm::ArrayRef< const Fact * > getFacts(const CFGBlock *B) const
Definition Facts.h:354
An abstract base class for a single, atomic lifetime-relevant event.
Definition Facts.h:40
@ InvalidateOrigin
An origin is invalidated (e.g. vector resized, delete called).
Definition Facts.h:63
@ TestPoint
A marker for a specific point in the code, for testing.
Definition Facts.h:59
@ Expire
A loan expires as its underlying storage is freed (e.g., variable goes out of scope).
Definition Facts.h:48
@ Issue
A new loan is issued from a borrow expression (e.g., &x).
Definition Facts.h:45
@ OriginFlow
An origin is propagated from a source to a destination (e.g., p = q).
Definition Facts.h:53
@ MovedOrigin
An origin that is moved (e.g., passed to an rvalue reference parameter).
Definition Facts.h:57
@ Use
An origin is used (eg. appears as l-value expression like DeclRefExpr).
Definition Facts.h:55
@ OriginEscapes
An origin that escapes the function scope (e.g., via return).
Definition Facts.h:61
@ KillOrigin
All loans of an origin are cleared.
Definition Facts.h:65
Represents that an origin's storage has been invalidated by a container operation (e....
Definition Facts.h:273
All loans are cleared from an origin (e.g., assigning a callable without tracked origins to std::func...
Definition Facts.h:332
Top-level origin of the expression which was found to be moved, e.g, when being used as an argument t...
Definition Facts.h:294
Represents that an origin escapes the current scope through various means.
Definition Facts.h:168
A dummy-fact used to mark a specific point in the code for testing.
Definition Facts.h:315
const Fact * ProgramPoint
A ProgramPoint identifies a location in the CFG by pointing to a specific Fact.
Definition Facts.h:98
A worklist implementation for backward dataflow analysis.
A worklist implementation for forward dataflow analysis.