clang 22.0.0git
LiveOrigins.cpp
Go to the documentation of this file.
1//===- LiveOrigins.cpp - Live Origins Analysis -----------------*- 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
10#include "Dataflow.h"
11#include "llvm/Support/ErrorHandling.h"
12
14namespace {
15
16/// The dataflow lattice for origin liveness analysis.
17/// It tracks which origins are live, why they're live (which UseFact),
18/// and the confidence level of that liveness.
19struct Lattice {
20 LivenessMap LiveOrigins;
21
22 Lattice() : LiveOrigins(nullptr) {};
23
24 explicit Lattice(LivenessMap L) : LiveOrigins(L) {}
25
26 bool operator==(const Lattice &Other) const {
27 return LiveOrigins == Other.LiveOrigins;
28 }
29
30 bool operator!=(const Lattice &Other) const { return !(*this == Other); }
31
32 void dump(llvm::raw_ostream &OS, const OriginManager &OM) const {
33 if (LiveOrigins.isEmpty())
34 OS << " <empty>\n";
35 for (const auto &Entry : LiveOrigins) {
36 OriginID OID = Entry.first;
37 const LivenessInfo &Info = Entry.second;
38 OS << " ";
39 OM.dump(OID, OS);
40 OS << " is ";
41 switch (Info.Kind) {
43 OS << "definitely";
44 break;
46 OS << "maybe";
47 break;
49 llvm_unreachable("liveness kind of live origins should not be dead.");
50 }
51 OS << " live at this point\n";
52 }
53 }
54};
55
56/// The analysis that tracks which origins are live, with granular information
57/// about the causing use fact and confidence level. This is a backward
58/// analysis.
59class AnalysisImpl
60 : public DataflowAnalysis<AnalysisImpl, Lattice, Direction::Backward> {
61
62public:
63 AnalysisImpl(const CFG &C, AnalysisDeclContext &AC, FactManager &F,
64 LivenessMap::Factory &SF)
65 : DataflowAnalysis(C, AC, F), FactMgr(F), Factory(SF) {}
66 using DataflowAnalysis<AnalysisImpl, Lattice, Direction::Backward>::transfer;
67
68 StringRef getAnalysisName() const { return "LiveOrigins"; }
69
70 Lattice getInitialState() { return Lattice(Factory.getEmptyMap()); }
71
72 /// Merges two lattices by combining liveness information.
73 /// When the same origin has different confidence levels, we take the lower
74 /// one.
75 Lattice join(Lattice L1, Lattice L2) const {
76 LivenessMap Merged = L1.LiveOrigins;
77 // Take the earliest UseFact to make the join hermetic and commutative.
78 auto CombineUseFact = [](const UseFact &A,
79 const UseFact &B) -> const UseFact * {
80 return A.getUseExpr()->getExprLoc() < B.getUseExpr()->getExprLoc() ? &A
81 : &B;
82 };
83 auto CombineLivenessKind = [](LivenessKind K1,
85 assert(K1 != LivenessKind::Dead && "LivenessKind should not be dead.");
86 assert(K2 != LivenessKind::Dead && "LivenessKind should not be dead.");
87 // Only return "Must" if both paths are "Must", otherwise Maybe.
88 if (K1 == LivenessKind::Must && K2 == LivenessKind::Must)
89 return LivenessKind::Must;
91 };
92 auto CombineLivenessInfo = [&](const LivenessInfo *L1,
93 const LivenessInfo *L2) -> LivenessInfo {
94 assert((L1 || L2) && "unexpectedly merging 2 empty sets");
95 if (!L1)
96 return LivenessInfo(L2->CausingUseFact, LivenessKind::Maybe);
97 if (!L2)
98 return LivenessInfo(L1->CausingUseFact, LivenessKind::Maybe);
99 return LivenessInfo(
100 CombineUseFact(*L1->CausingUseFact, *L2->CausingUseFact),
101 CombineLivenessKind(L1->Kind, L2->Kind));
102 };
103 return Lattice(utils::join(
104 L1.LiveOrigins, L2.LiveOrigins, Factory, CombineLivenessInfo,
105 // A symmetric join is required here. If an origin is live on one
106 // branch but not the other, its confidence must be demoted to `Maybe`.
108 }
109
110 /// A read operation makes the origin live with definite confidence, as it
111 /// dominates this program point. A write operation kills the liveness of
112 /// the origin since it overwrites the value.
113 Lattice transfer(Lattice In, const UseFact &UF) {
114 OriginID OID = UF.getUsedOrigin(FactMgr.getOriginMgr());
115 // Write kills liveness.
116 if (UF.isWritten())
117 return Lattice(Factory.remove(In.LiveOrigins, OID));
118 // Read makes origin live with definite confidence (dominates this point).
119 return Lattice(Factory.add(In.LiveOrigins, OID,
120 LivenessInfo(&UF, LivenessKind::Must)));
121 }
122
123 /// Issuing a new loan to an origin kills its liveness.
124 Lattice transfer(Lattice In, const IssueFact &IF) {
125 return Lattice(Factory.remove(In.LiveOrigins, IF.getOriginID()));
126 }
127
128 /// An OriginFlow kills the liveness of the destination origin if `KillDest`
129 /// is true. Otherwise, it propagates liveness from destination to source.
130 Lattice transfer(Lattice In, const OriginFlowFact &OF) {
131 if (!OF.getKillDest())
132 return In;
133 return Lattice(Factory.remove(In.LiveOrigins, OF.getDestOriginID()));
134 }
135
136 LivenessMap getLiveOriginsAt(ProgramPoint P) const {
137 return getState(P).LiveOrigins;
138 }
139
140 // Dump liveness values on all test points in the program.
141 void dump(llvm::raw_ostream &OS,
142 llvm::StringMap<ProgramPoint> TestPoints) const {
143 llvm::dbgs() << "==========================================\n";
144 llvm::dbgs() << getAnalysisName() << " results:\n";
145 llvm::dbgs() << "==========================================\n";
146 for (const auto &Entry : TestPoints) {
147 OS << "TestPoint: " << Entry.getKey() << "\n";
148 getState(Entry.getValue()).dump(OS, FactMgr.getOriginMgr());
149 }
150 }
151
152private:
153 FactManager &FactMgr;
154 LivenessMap::Factory &Factory;
155};
156} // namespace
157
158// PImpl wrapper implementation
159class LiveOriginsAnalysis::Impl : public AnalysisImpl {
160 using AnalysisImpl::AnalysisImpl;
161};
162
164 FactManager &F,
165 LivenessMap::Factory &SF)
166 : PImpl(std::make_unique<Impl>(C, AC, F, SF)) {
167 PImpl->run();
168}
169
171
173 return PImpl->getLiveOriginsAt(P);
174}
175
176void LiveOriginsAnalysis::dump(llvm::raw_ostream &OS,
177 llvm::StringMap<ProgramPoint> TestPoints) const {
178 PImpl->dump(OS, TestPoints);
179}
180} // namespace clang::lifetimes::internal
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
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.
Definition CFG.h:1222
A generic, policy-based driver for dataflow analyses.
Definition Dataflow.h:57
void dump(llvm::raw_ostream &OS, llvm::StringMap< ProgramPoint > TestPoints) const
LiveOriginsAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, LivenessMap::Factory &SF)
LivenessMap getLiveOriginsAt(ProgramPoint P) const
Returns the set of origins that are live at a specific program point, along with the the details of t...
void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env, Environment::ValueModel &Model)
Evaluates S and updates Env accordingly.
Definition Transfer.cpp:956
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
@ Symmetric
A symmetric join applies the JoinValues operation to keys unique to either map, ensuring that values ...
Definition Utils.h:59
static llvm::ImmutableSet< T > join(llvm::ImmutableSet< T > A, llvm::ImmutableSet< T > B, typename llvm::ImmutableSet< T >::Factory &F)
Computes the union of two ImmutableSets.
Definition Utils.h:39
const Fact * ProgramPoint
A ProgramPoint identifies a location in the CFG by pointing to a specific Fact.
Definition Facts.h:74
utils::ID< struct OriginTag > OriginID
Definition Origins.h:23
llvm::ImmutableMap< OriginID, LivenessInfo > LivenessMap
Definition LiveOrigins.h:74
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
Definition CallGraph.h:204
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
bool operator!=(CanQual< T > x, CanQual< U > y)
@ Other
Other implicit parameter.
Definition Decl.h:1746