Skip to content

Commit 979cb9c

Browse files
authored
Merge pull request #17925 from gottesmm/pr-ee4013a4ba1a0f471cdc45bf15601a2c55002cdd
[caller-analysis] Change the dumping format to be a yaml format and u…
2 parents 56f322f + 3051cd3 commit 979cb9c

File tree

5 files changed

+598
-163
lines changed

5 files changed

+598
-163
lines changed

include/swift/SILOptimizer/Analysis/CallerAnalysis.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,28 @@ class CallerAnalysis : public SILAnalysis {
119119
/// Notify the analysis about changed witness or vtables.
120120
virtual void invalidateFunctionTables() override { }
121121

122-
const FunctionInfo &getCallerInfo(SILFunction *F) {
122+
const FunctionInfo &getCallerInfo(SILFunction *F) const {
123123
// Recompute every function in the invalidated function list and empty the
124124
// list.
125-
processRecomputeFunctionList();
126-
return FuncInfos[F];
125+
auto *self = const_cast<CallerAnalysis *>(this);
126+
self->processRecomputeFunctionList();
127+
return self->FuncInfos[F];
127128
}
129+
130+
#ifndef NDEBUG
131+
LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED,
132+
"Only for use in the debugger");
133+
#endif
134+
135+
/// Print the state of the caller analysis as a sequence of yaml documents for
136+
/// each callee we are tracking.
137+
void print(llvm::raw_ostream &os) const;
138+
139+
/// Print the state of the caller analysis as a sequence of yaml documents for
140+
/// each callee we are tracking to the passed in file path.
141+
LLVM_ATTRIBUTE_DEPRECATED(void print(const char *filePath)
142+
const LLVM_ATTRIBUTE_USED,
143+
"Only for use in the debugger");
128144
};
129145

130146
/// NOTE: this can be extended to contain the callsites of the function.

lib/SILOptimizer/Analysis/CallerAnalysis.cpp

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,15 @@
1414

1515
#include "swift/SIL/SILModule.h"
1616
#include "swift/SILOptimizer/Utils/Local.h"
17+
#include "llvm/Support/FileSystem.h"
18+
#include "llvm/Support/YAMLTraits.h"
1719

1820
using namespace swift;
1921

22+
//===----------------------------------------------------------------------===//
23+
// Actual Analysis
24+
//===----------------------------------------------------------------------===//
25+
2026
void CallerAnalysis::processFunctionCallSites(SILFunction *F) {
2127
// Scan the whole module and search Apply sites.
2228
for (auto &BB : *F) {
@@ -53,8 +59,8 @@ void CallerAnalysis::processFunctionCallSites(SILFunction *F) {
5359
}
5460
continue;
5561
}
56-
}
57-
}
62+
}
63+
}
5864
}
5965

6066
void CallerAnalysis::invalidateExistingCalleeRelation(SILFunction *F) {
@@ -66,9 +72,107 @@ void CallerAnalysis::invalidateExistingCalleeRelation(SILFunction *F) {
6672
}
6773
}
6874

75+
//===----------------------------------------------------------------------===//
76+
// CallerAnalysis YAML Dumper
77+
//===----------------------------------------------------------------------===//
78+
79+
namespace {
80+
81+
using llvm::yaml::IO;
82+
using llvm::yaml::MappingTraits;
83+
using llvm::yaml::Output;
84+
using llvm::yaml::ScalarEnumerationTraits;
85+
using llvm::yaml::SequenceTraits;
86+
87+
/// A special struct that marshals call graph state into a form that is easy for
88+
/// llvm's yaml i/o to dump. Its structure is meant to correspond to how the
89+
/// data should be shown by the printer, so naturally it is slightly redundant.
90+
struct YAMLCallGraphNode {
91+
StringRef calleeName;
92+
bool hasCaller;
93+
unsigned minPartialAppliedArgs;
94+
std::vector<StringRef> partialAppliers;
95+
std::vector<StringRef> fullAppliers;
96+
97+
YAMLCallGraphNode() = delete;
98+
~YAMLCallGraphNode() = default;
99+
100+
// This is a data structure that can not be copied or moved.
101+
YAMLCallGraphNode(const YAMLCallGraphNode &) = delete;
102+
YAMLCallGraphNode(YAMLCallGraphNode &&) = delete;
103+
YAMLCallGraphNode &operator=(const YAMLCallGraphNode &) = delete;
104+
YAMLCallGraphNode &operator=(YAMLCallGraphNode &&) = delete;
105+
106+
YAMLCallGraphNode(StringRef calleeName, bool hasCaller,
107+
unsigned minPartialAppliedArgs,
108+
std::vector<StringRef> &&partialAppliers,
109+
std::vector<StringRef> &&fullAppliers)
110+
: calleeName(calleeName), hasCaller(hasCaller),
111+
minPartialAppliedArgs(minPartialAppliedArgs),
112+
partialAppliers(std::move(partialAppliers)),
113+
fullAppliers(std::move(fullAppliers)) {}
114+
};
115+
116+
} // end anonymous namespace
117+
118+
namespace llvm {
119+
namespace yaml {
120+
121+
template <> struct MappingTraits<YAMLCallGraphNode> {
122+
static void mapping(IO &io, YAMLCallGraphNode &func) {
123+
io.mapRequired("calleeName", func.calleeName);
124+
io.mapRequired("hasCaller", func.hasCaller);
125+
io.mapRequired("minPartialAppliedArgs", func.minPartialAppliedArgs);
126+
io.mapRequired("partialAppliers", func.partialAppliers);
127+
io.mapRequired("fullAppliers", func.fullAppliers);
128+
}
129+
};
130+
131+
} // namespace yaml
132+
} // namespace llvm
133+
134+
void CallerAnalysis::dump() const { print(llvm::errs()); }
135+
136+
void CallerAnalysis::print(const char *filePath) const {
137+
using namespace llvm::sys;
138+
std::error_code error;
139+
llvm::raw_fd_ostream fileOutputStream(filePath, error, fs::F_Text);
140+
if (error) {
141+
llvm::errs() << "Failed to open path \"" << filePath << "\" for writing.!";
142+
llvm_unreachable("default error handler");
143+
}
144+
print(fileOutputStream);
145+
}
146+
147+
void CallerAnalysis::print(llvm::raw_ostream &os) const {
148+
llvm::yaml::Output yout(os);
149+
150+
// NOTE: We purposely do not iterate over our internal state here to ensure
151+
// that we dump for all functions and that we dump the state we have stored
152+
// with the functions in module order.
153+
for (auto &f : Mod) {
154+
const auto &fi = getCallerInfo(&f);
155+
156+
std::vector<StringRef> fullAppliers;
157+
for (auto *caller : fi.Callers) {
158+
fullAppliers.push_back(caller->getName());
159+
}
160+
std::vector<StringRef> partialAppliers;
161+
for (auto iter : fi.PartialAppliers) {
162+
partialAppliers.push_back(iter.first->getName());
163+
}
164+
165+
YAMLCallGraphNode node(f.getName(), fi.hasCaller(),
166+
fi.getMinPartialAppliedArgs(),
167+
std::move(partialAppliers), std::move(fullAppliers));
168+
yout << node;
169+
}
170+
}
171+
69172
//===----------------------------------------------------------------------===//
70173
// Main Entry Point
71174
//===----------------------------------------------------------------------===//
175+
72176
SILAnalysis *swift::createCallerAnalysis(SILModule *M) {
73177
return new CallerAnalysis(M);
74178
}

lib/SILOptimizer/UtilityPasses/CallerAnalysisPrinter.cpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@
1414
//
1515
//===----------------------------------------------------------------------===//
1616

17-
#include "swift/SILOptimizer/Analysis/CallerAnalysis.h"
1817
#include "swift/SIL/SILFunction.h"
1918
#include "swift/SIL/SILModule.h"
19+
#include "swift/SILOptimizer/Analysis/CallerAnalysis.h"
2020
#include "swift/SILOptimizer/PassManager/Transforms.h"
21+
#include "llvm/Support/YAMLTraits.h"
2122
#include "llvm/Support/raw_ostream.h"
2223

2324
using namespace swift;
@@ -26,19 +27,15 @@ using namespace swift;
2627

2728
namespace {
2829

30+
/// A pass that dumps the caller analysis state in yaml form. Intended to allow
31+
/// for visualizing of the caller analysis via external data visualization and
32+
/// analysis programs.
2933
class CallerAnalysisPrinterPass : public SILModuleTransform {
3034
/// The entry point to the transformation.
3135
void run() override {
3236
auto *CA = getAnalysis<CallerAnalysis>();
33-
for (auto &F : *getModule()) {
34-
const CallerAnalysis::FunctionInfo &FI = CA->getCallerInfo(&F);
35-
const char *hasCaller = FI.hasCaller() ? "true" : "false";
36-
llvm::outs() << "Function " << F.getName() << " has caller: "
37-
<< hasCaller << ", partial applied args = "
38-
<< FI.getMinPartialAppliedArgs() << "\n";
39-
}
37+
CA->print(llvm::outs());
4038
}
41-
4239
};
4340

4441
} // end anonymous namespace

0 commit comments

Comments
 (0)