Skip to content

Commit 09d81ce

Browse files
[Prototype] Implement dot export feature
1 parent bcb98b9 commit 09d81ce

File tree

2 files changed

+199
-3
lines changed

2 files changed

+199
-3
lines changed

include/swift/Serialization/ModuleSummary.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ class ModuleSummaryIndex {
259259
FunctionSummaryMapTy::const_iterator functions_end() const {
260260
return FunctionSummaryMap.end();
261261
}
262+
size_t functions_size() const { return FunctionSummaryMap.size(); }
262263
};
263264

264265
/// Compute a \c ModuleSummaryIndex from the given SILModule.

tools/swift-module-summary-test/swift-module-summary-test.cpp

Lines changed: 198 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
#include "swift/AST/FileSystem.h"
1818
#include "swift/Basic/LLVM.h"
1919
#include "swift/Basic/LLVMInitialize.h"
20+
#include "swift/Demangling/Demangle.h"
2021
#include "swift/Serialization/ModuleSummary.h"
2122
#include "llvm/Support/CommandLine.h"
23+
#include "llvm/Support/GraphWriter.h"
2224
#include "llvm/Support/MemoryBuffer.h"
2325
#include "llvm/Support/YAMLParser.h"
2426
#include "llvm/Support/YAMLTraits.h"
@@ -30,6 +32,7 @@ enum class ActionType : unsigned {
3032
None,
3133
BinaryToYAML,
3234
YAMLToBinary,
35+
BinaryToDot,
3336
};
3437

3538
namespace options {
@@ -49,9 +52,11 @@ static llvm::cl::opt<ActionType>
4952
llvm::cl::cat(Category),
5053
llvm::cl::values(
5154
clEnumValN(ActionType::BinaryToYAML, "to-yaml",
52-
"Convert new binary .swiftdeps format to YAML"),
55+
"Convert new binary .swiftmodule.summary format to YAML"),
5356
clEnumValN(ActionType::YAMLToBinary, "from-yaml",
54-
"Convert YAML to new binary .swiftdeps format")));
57+
"Convert YAML to new binary .swiftmodule.summary format"),
58+
clEnumValN(ActionType::BinaryToDot, "binary-to-dot",
59+
"Convert new binary .swiftmodule.summary format to Dot")));
5560

5661
} // namespace options
5762

@@ -154,6 +159,184 @@ void MappingTraits<ModuleSummaryIndex>::mapping(IO &io, ModuleSummaryIndex &V) {
154159
} // namespace yaml
155160
} // namespace llvm
156161

162+
VFuncSlot createVFuncSlot(FunctionSummary::Call call) {
163+
VFuncSlot::KindTy slotKind;
164+
switch (call.getKind()) {
165+
case FunctionSummary::Call::Witness: {
166+
slotKind = VFuncSlot::Witness;
167+
break;
168+
}
169+
case FunctionSummary::Call::VTable: {
170+
slotKind = VFuncSlot::VTable;
171+
break;
172+
}
173+
case FunctionSummary::Call::Direct: {
174+
llvm_unreachable("Can't get slot for static call");
175+
}
176+
case FunctionSummary::Call::kindCount: {
177+
llvm_unreachable("impossible");
178+
}
179+
}
180+
return VFuncSlot(slotKind, call.getCallee());
181+
}
182+
183+
struct CallGraph {
184+
struct Node;
185+
186+
struct Edge {
187+
FunctionSummary::Call Call;
188+
GUID Target;
189+
Node *Child;
190+
};
191+
192+
struct Node {
193+
FunctionSummary *FS;
194+
SmallVector<Edge, 8> Children;
195+
};
196+
197+
struct child_iterator
198+
: public std::iterator<std::random_access_iterator_tag, Node *,
199+
ptrdiff_t> {
200+
SmallVectorImpl<Edge>::iterator baseIter;
201+
202+
child_iterator(SmallVectorImpl<Edge>::iterator baseIter) :
203+
baseIter(baseIter)
204+
{ }
205+
206+
child_iterator &operator++() { baseIter++; return *this; }
207+
child_iterator operator++(int) {
208+
auto tmp = *this;
209+
++baseIter;
210+
return tmp;
211+
}
212+
Node *operator*() const { return baseIter->Child; }
213+
bool operator==(const child_iterator &RHS) const {
214+
return baseIter == RHS.baseIter;
215+
}
216+
bool operator!=(const child_iterator &RHS) const {
217+
return baseIter != RHS.baseIter;
218+
}
219+
difference_type operator-(const child_iterator &RHS) const {
220+
return baseIter - RHS.baseIter;
221+
}
222+
};
223+
224+
std::vector<Node> Nodes;
225+
using iterator = std::vector<Node>::iterator;
226+
CallGraph(ModuleSummaryIndex *);
227+
};
228+
229+
CallGraph::CallGraph(ModuleSummaryIndex *Summary) {
230+
Nodes.resize(Summary->functions_size());
231+
llvm::DenseMap<GUID, Node *> NodeMap;
232+
int idx = 0;
233+
for (auto FI = Summary->functions_begin(), FE = Summary->functions_end();
234+
FI != FE; ++FI) {
235+
Node &node = Nodes[idx++];
236+
node.FS = FI->second.get();
237+
NodeMap[FI->first] = &node;
238+
}
239+
240+
for (Node &node : Nodes) {
241+
for (FunctionSummary::Call call : node.FS->calls()) {
242+
switch (call.getKind()) {
243+
case FunctionSummary::Call::Witness:
244+
case FunctionSummary::Call::VTable: {
245+
VFuncSlot slot = createVFuncSlot(call);
246+
for (auto Impl : Summary->getImplementations(slot)) {
247+
Node *CalleeNode = NodeMap[Impl.Guid];
248+
node.Children.push_back({ call, Impl.Guid, CalleeNode });
249+
}
250+
break;
251+
}
252+
case FunctionSummary::Call::Direct: {
253+
Node *CalleeNode = NodeMap[call.getCallee()];
254+
node.Children.push_back({ call, call.getCallee(), CalleeNode });
255+
break;
256+
}
257+
case FunctionSummary::Call::kindCount:
258+
llvm_unreachable("impossible");
259+
}
260+
}
261+
}
262+
}
263+
264+
265+
namespace llvm {
266+
267+
template <> struct GraphTraits<CallGraph::Node *> {
268+
typedef CallGraph::child_iterator ChildIteratorType;
269+
typedef CallGraph::Node *NodeRef;
270+
271+
static NodeRef getEntryNode(NodeRef N) { return N; }
272+
static inline ChildIteratorType child_begin(NodeRef N) {
273+
return N->Children.begin();
274+
}
275+
static inline ChildIteratorType child_end(NodeRef N) {
276+
return N->Children.end();
277+
}
278+
};
279+
280+
template <> struct GraphTraits<CallGraph *>
281+
: public GraphTraits<CallGraph::Node *> {
282+
typedef CallGraph *GraphType;
283+
typedef CallGraph::Node *NodeRef;
284+
285+
static NodeRef getEntryNode(GraphType F) { return nullptr; }
286+
287+
typedef pointer_iterator<CallGraph::iterator> nodes_iterator;
288+
static nodes_iterator nodes_begin(GraphType CG) {
289+
return nodes_iterator(CG->Nodes.begin());
290+
}
291+
static nodes_iterator nodes_end(GraphType CG) {
292+
return nodes_iterator(CG->Nodes.end());
293+
}
294+
static unsigned size(GraphType CG) { return CG->Nodes.size(); }
295+
};
296+
297+
/// This is everything the llvm::GraphWriter needs to write the call graph in
298+
/// a dot file.
299+
template <>
300+
struct DOTGraphTraits<CallGraph *> : public DefaultDOTGraphTraits {
301+
302+
DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
303+
304+
std::string getNodeLabel(const CallGraph::Node *Node,
305+
const CallGraph *Graph) {
306+
Demangle::Context DCtx;
307+
return DCtx.demangleSymbolAsString(Node->FS->getName());
308+
}
309+
310+
static std::string getEdgeSourceLabel(const CallGraph::Node *Node,
311+
CallGraph::child_iterator I) {
312+
std::string Label;
313+
raw_string_ostream O(Label);
314+
FunctionSummary::Call call = I.baseIter->Call;
315+
Demangle::Context DCtx;
316+
O << DCtx.demangleSymbolAsString(call.getName());
317+
O << " (";
318+
switch (call.getKind()) {
319+
case FunctionSummary::Call::Witness: {
320+
O << "W";
321+
break;
322+
}
323+
case FunctionSummary::Call::VTable: {
324+
O << "V";
325+
break;
326+
}
327+
case FunctionSummary::Call::Direct: {
328+
O << "D";
329+
break;
330+
}
331+
case FunctionSummary::Call::kindCount:
332+
llvm_unreachable("impossible");
333+
}
334+
O << ")";
335+
return Label;
336+
}
337+
};
338+
} // namespace llvm
339+
157340
int main(int argc, char *argv[]) {
158341
PROGRAM_START(argc, argv);
159342
llvm::cl::ParseCommandLineOptions(argc, argv, "Swift Module Summary Test\n");
@@ -193,7 +376,7 @@ int main(int argc, char *argv[]) {
193376
}
194377
break;
195378
}
196-
case ActionType::YAMLToBinary:
379+
case ActionType::YAMLToBinary: {
197380
ModuleSummaryIndex summary;
198381
llvm::yaml::Input yamlReader(fileBufOrErr.get()->getMemBufferRef(),
199382
nullptr);
@@ -209,5 +392,17 @@ int main(int argc, char *argv[]) {
209392
}
210393
break;
211394
}
395+
case ActionType::BinaryToDot: {
396+
modulesummary::ModuleSummaryIndex summary;
397+
modulesummary::loadModuleSummaryIndex(fileBufOrErr.get()->getMemBufferRef(),
398+
summary);
399+
CallGraph CG(&summary);
400+
withOutputFile(diags, options::OutputFilename, [&](raw_ostream &out) {
401+
llvm::WriteGraph(out, &CG);
402+
return false;
403+
});
404+
break;
405+
}
406+
}
212407
return 0;
213408
}

0 commit comments

Comments
 (0)