clang 23.0.0git
AnalysisDriver.cpp
Go to the documentation of this file.
1//===- AnalysisDriver.cpp -------------------------------------------------===//
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
14#include "llvm/ADT/STLExtras.h"
15#include "llvm/Support/Error.h"
16#include "llvm/Support/ErrorHandling.h"
17#include <map>
18#include <vector>
19
20using namespace clang;
21using namespace ssaf;
22
23AnalysisDriver::AnalysisDriver(std::unique_ptr<LUSummary> LU)
24 : LU(std::move(LU)) {}
25
27AnalysisDriver::toposort(llvm::ArrayRef<AnalysisName> Roots) {
28 struct Visitor {
29 enum class State { Unvisited, Visiting, Visited };
30
31 std::map<AnalysisName, State> Marks;
32 std::vector<AnalysisName> Path;
33 std::vector<std::unique_ptr<AnalysisBase>> Result;
34
35 explicit Visitor(size_t N) {
36 Path.reserve(N);
37 Result.reserve(N);
38 }
39
40 std::string formatCycle(const AnalysisName &CycleEntry) const {
41 auto CycleBegin = llvm::find(Path, CycleEntry);
42 std::string Cycle;
43 llvm::raw_string_ostream OS(Cycle);
44 llvm::interleave(llvm::make_range(CycleBegin, Path.end()), OS, " -> ");
45 OS << " -> " << CycleEntry;
46 return Cycle;
47 }
48
49 llvm::Error visit(const AnalysisName &Name) {
50 auto [It, _] = Marks.emplace(Name, State::Unvisited);
51
52 switch (It->second) {
53 case State::Visited:
54 return llvm::Error::success();
55
56 case State::Visiting:
57 return ErrorBuilder::create(std::errc::invalid_argument,
58 "cycle detected: {0}", formatCycle(Name))
59 .build();
60
61 case State::Unvisited: {
62 It->second = State::Visiting;
63 Path.push_back(Name);
64
65 llvm::Expected<std::unique_ptr<AnalysisBase>> V =
67 if (!V) {
68 return V.takeError();
69 }
70
71 // Unwrap for convenience to avoid the noise of dereferencing an
72 // Expected on every subsequent access.
73 std::unique_ptr<AnalysisBase> Analysis = std::move(*V);
74
75 for (const auto &Dep : Analysis->dependencyNames()) {
76 if (auto Err = visit(Dep)) {
77 return Err;
78 }
79 }
80
81 // std::map iterators are not invalidated by insertions, so It remains
82 // valid after recursive visit() calls that insert new entries.
83 It->second = State::Visited;
84 Path.pop_back();
85 Result.push_back(std::move(Analysis));
86
87 return llvm::Error::success();
88 }
89 }
90 llvm_unreachable("unhandled State");
91 }
92 };
93
94 Visitor V(Roots.size());
95 for (const auto &Root : Roots) {
96 if (auto Err = V.visit(Root)) {
97 return std::move(Err);
98 }
99 }
100 return std::move(V.Result);
101}
102
103llvm::Error AnalysisDriver::executeSummaryAnalysis(SummaryAnalysisBase &Summary,
104 WPASuite &Suite) const {
105 SummaryName SN = Summary.summaryName();
106 auto DataIt = LU->Data.find(SN);
107 if (DataIt == LU->Data.end()) {
108 return ErrorBuilder::create(std::errc::invalid_argument,
109 "no data for analysis '{0}' in LUSummary",
110 Summary.analysisName())
111 .build();
112 }
113
114 if (auto Err = Summary.initialize()) {
115 return Err;
116 }
117
118 for (auto &[Id, EntitySummary] : DataIt->second) {
119 if (auto Err = Summary.add(Id, *EntitySummary)) {
120 return Err;
121 }
122 }
123
124 if (auto Err = Summary.finalize()) {
125 return Err;
126 }
127
128 return llvm::Error::success();
129}
130
131llvm::Error AnalysisDriver::executeDerivedAnalysis(DerivedAnalysisBase &Derived,
132 WPASuite &Suite) const {
133 std::map<AnalysisName, const AnalysisResult *> DepMap;
134
135 for (const auto &DepName : Derived.dependencyNames()) {
136 auto It = Suite.Data.find(DepName);
137 if (It == Suite.Data.end()) {
138 ErrorBuilder::fatal("missing dependency '{0}' for analysis '{1}': "
139 "dependency graph is not topologically sorted",
140 DepName, Derived.analysisName());
141 }
142 DepMap[DepName] = It->second.get();
143 }
144
145 if (auto Err = Derived.initialize(DepMap)) {
146 return Err;
147 }
148
149 while (true) {
150 auto StepOrErr = Derived.step();
151 if (!StepOrErr) {
152 return StepOrErr.takeError();
153 }
154 if (!*StepOrErr) {
155 break;
156 }
157 }
158
159 if (auto Err = Derived.finalize()) {
160 return Err;
161 }
162
163 return llvm::Error::success();
164}
165
166llvm::Expected<WPASuite> AnalysisDriver::execute(
167 EntityIdTable IdTable,
168 llvm::ArrayRef<std::unique_ptr<AnalysisBase>> Sorted) const {
169 WPASuite Suite;
170 Suite.IdTable = std::move(IdTable);
171
172 for (auto &Analysis : Sorted) {
173 switch (Analysis->TheKind) {
174 case AnalysisBase::Kind::Summary: {
175 SummaryAnalysisBase &SA = static_cast<SummaryAnalysisBase &>(*Analysis);
176 if (auto Err = executeSummaryAnalysis(SA, Suite)) {
177 return std::move(Err);
178 }
179 break;
180 }
181 case AnalysisBase::Kind::Derived: {
182 DerivedAnalysisBase &DA = static_cast<DerivedAnalysisBase &>(*Analysis);
183 if (auto Err = executeDerivedAnalysis(DA, Suite)) {
184 return std::move(Err);
185 }
186 break;
187 }
188 }
189 AnalysisName Name = Analysis->analysisName();
190 Suite.Data.emplace(std::move(Name), std::move(*Analysis).result());
191 }
192
193 return std::move(Suite);
194}
195
197 auto ExpectedSorted = toposort(AnalysisRegistry::names());
198 if (!ExpectedSorted) {
199 return ExpectedSorted.takeError();
200 }
201 return execute(std::move(LU->IdTable), *ExpectedSorted);
202}
203
206 auto ExpectedSorted = toposort(Names);
207 if (!ExpectedSorted) {
208 return ExpectedSorted.takeError();
209 }
210
211 return execute(LU->IdTable, *ExpectedSorted);
212}
#define V(N, I)
virtual AnalysisName analysisName() const =0
Name of this analysis.
virtual const std::vector< AnalysisName > & dependencyNames() const =0
AnalysisNames of all AnalysisResult dependencies.
llvm::Expected< WPASuite > run() const
Type-safe variant of run(names).
AnalysisDriver(std::unique_ptr< LUSummary > LU)
Uniquely identifies a whole-program analysis and the AnalysisResult it produces.
static const std::vector< AnalysisName > & names()
Returns the names of all registered analyses.
static llvm::Expected< std::unique_ptr< AnalysisBase > > instantiate(const AnalysisName &Name)
Instantiates the analysis registered under Name, or returns an error if no such analysis is registere...
Type-erased base for derived analyses.
Manages entity name interning and provides efficient EntityId handles.
static ErrorBuilder create(std::error_code EC, const char *Fmt, Args &&...ArgVals)
Create an ErrorBuilder with an error code and formatted message.
static void fatal(const char *Fmt, Args &&...ArgVals)
Report a fatal error with formatted message and terminate execution.
llvm::Error build() const
Build and return the final error.
Type-erased base for summary analyses.
virtual SummaryName summaryName() const =0
SummaryName of the EntitySummary type this analysis consumes.
Bundles the EntityIdTable (moved from the LUSummary) and the analysis results produced by one Analysi...
Definition WPASuite.h:35
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
Definition TypeBase.h:905