17
17
#include " swift/AST/FileSystem.h"
18
18
#include " swift/Basic/LLVM.h"
19
19
#include " swift/Basic/LLVMInitialize.h"
20
+ #include " swift/Demangling/Demangle.h"
20
21
#include " swift/Serialization/ModuleSummary.h"
21
22
#include " llvm/Support/CommandLine.h"
23
+ #include " llvm/Support/GraphWriter.h"
22
24
#include " llvm/Support/MemoryBuffer.h"
23
25
#include " llvm/Support/YAMLParser.h"
24
26
#include " llvm/Support/YAMLTraits.h"
@@ -30,6 +32,7 @@ enum class ActionType : unsigned {
30
32
None,
31
33
BinaryToYAML,
32
34
YAMLToBinary,
35
+ BinaryToDot,
33
36
};
34
37
35
38
namespace options {
@@ -49,9 +52,11 @@ static llvm::cl::opt<ActionType>
49
52
llvm::cl::cat(Category),
50
53
llvm::cl::values(
51
54
clEnumValN (ActionType::BinaryToYAML, " to-yaml" ,
52
- " Convert new binary .swiftdeps format to YAML" ),
55
+ " Convert new binary .swiftmodule.summary format to YAML" ),
53
56
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" )));
55
60
56
61
} // namespace options
57
62
@@ -154,6 +159,184 @@ void MappingTraits<ModuleSummaryIndex>::mapping(IO &io, ModuleSummaryIndex &V) {
154
159
} // namespace yaml
155
160
} // namespace llvm
156
161
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
+
157
340
int main (int argc, char *argv[]) {
158
341
PROGRAM_START (argc, argv);
159
342
llvm::cl::ParseCommandLineOptions (argc, argv, " Swift Module Summary Test\n " );
@@ -193,7 +376,7 @@ int main(int argc, char *argv[]) {
193
376
}
194
377
break ;
195
378
}
196
- case ActionType::YAMLToBinary:
379
+ case ActionType::YAMLToBinary: {
197
380
ModuleSummaryIndex summary;
198
381
llvm::yaml::Input yamlReader (fileBufOrErr.get ()->getMemBufferRef (),
199
382
nullptr );
@@ -209,5 +392,17 @@ int main(int argc, char *argv[]) {
209
392
}
210
393
break ;
211
394
}
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
+ }
212
407
return 0 ;
213
408
}
0 commit comments