1 /* Copyright © International Business Machines Corp., 2006
4 * Author: Josh Triplett <josh@freedesktop.org>
5 * Dan Sheridan <djs@adelard.com>
7 * Licensed under the Open Software License version 1.1
22 #include "expression.h"
23 #include "linearize.h"
26 /* Draw the subgraph for a given entrypoint. Includes details of loads
27 * and stores for globals, and marks return bbs */
28 static void graph_ep(struct entrypoint
*ep
)
30 struct basic_block
*bb
;
31 struct instruction
*insn
;
33 const char *fname
, *sname
;
35 fname
= show_ident(ep
->name
->ident
);
36 sname
= stream_name(ep
->entry
->bb
->pos
.stream
);
38 printf("subgraph cluster%p {\n"
40 " label=<<TABLE BORDER=\"0\" CELLBORDER=\"0\">\n"
41 " <TR><TD>%s</TD></TR>\n"
42 " <TR><TD><FONT POINT-SIZE=\"21\">%s()</FONT></TD></TR>\n"
47 ep
, sname
, fname
, sname
, fname
, ep
->entry
->bb
);
49 FOR_EACH_PTR(ep
->bbs
, bb
) {
50 struct basic_block
*child
;
52 const char * s
= ", ls=\"[";
55 printf(" bb%p [shape=ellipse,label=%d,line=%d,col=%d",
56 bb
, bb
->pos
.line
, bb
->pos
.line
, bb
->pos
.pos
);
59 /* List loads and stores */
60 FOR_EACH_PTR(bb
->insns
, insn
) {
61 switch(insn
->opcode
) {
63 if (insn
->symbol
->type
== PSEUDO_SYM
) {
64 printf("%s store(%s)", s
, show_ident(insn
->symbol
->sym
->ident
));
70 if (insn
->symbol
->type
== PSEUDO_SYM
) {
71 printf("%s load(%s)", s
, show_ident(insn
->symbol
->sym
->ident
));
81 } END_FOR_EACH_PTR(insn
);
88 /* Edges between bbs; lower weight for upward edges */
89 FOR_EACH_PTR(bb
->children
, child
) {
90 printf(" bb%p -> bb%p [op=br, %s];\n", bb
, child
,
91 (bb
->pos
.line
> child
->pos
.line
) ? "weight=5" : "weight=10");
92 } END_FOR_EACH_PTR(child
);
93 } END_FOR_EACH_PTR(bb
);
99 /* Insert edges for intra- or inter-file calls, depending on the value
100 * of internal. Bold edges are used for calls with destinations;
101 * dashed for calls to external functions */
102 static void graph_calls(struct entrypoint
*ep
, int internal
)
104 struct basic_block
*bb
;
105 struct instruction
*insn
;
107 const char *fname
, *sname
;
109 fname
= show_ident(ep
->name
->ident
);
110 sname
= stream_name(ep
->entry
->bb
->pos
.stream
);
112 FOR_EACH_PTR(ep
->bbs
, bb
) {
115 if (!bb
->parents
&& !bb
->children
&& !bb
->insns
&& verbose
< 2)
118 FOR_EACH_PTR(bb
->insns
, insn
) {
119 if (insn
->opcode
== OP_CALL
&&
120 internal
== !(insn
->func
->sym
->ctype
.modifiers
& MOD_EXTERN
)) {
122 /* Find the symbol for the callee's definition */
124 if (insn
->func
->type
== PSEUDO_SYM
) {
125 for (sym
= insn
->func
->sym
->ident
->symbols
;
126 sym
; sym
= sym
->next_id
) {
127 if (sym
->namespace & NS_SYMBOL
&& sym
->ep
)
132 printf("bb%p -> bb%p"
133 "[label=%d,line=%d,col=%d,op=call,style=bold,weight=30];\n",
134 bb
, sym
->ep
->entry
->bb
,
135 insn
->pos
.line
, insn
->pos
.line
, insn
->pos
.pos
);
137 printf("bb%p -> \"%s\" "
138 "[label=%d,line=%d,col=%d,op=extern,style=dashed];\n",
139 bb
, show_pseudo(insn
->func
),
140 insn
->pos
.line
, insn
->pos
.line
, insn
->pos
.pos
);
143 } END_FOR_EACH_PTR(insn
);
144 } END_FOR_EACH_PTR(bb
);
147 int main(int argc
, char **argv
)
149 struct string_list
*filelist
= NULL
;
153 struct symbol_list
*fsyms
, *all_syms
=NULL
;
155 printf("digraph call_graph {\n");
156 fsyms
= sparse_initialize(argc
, argv
, &filelist
);
157 concat_symbol_list(fsyms
, &all_syms
);
159 /* Linearize all symbols, graph internal basic block
160 * structures and intra-file calls */
161 FOR_EACH_PTR_NOTAG(filelist
, file
) {
163 fsyms
= sparse(file
);
164 concat_symbol_list(fsyms
, &all_syms
);
166 FOR_EACH_PTR(fsyms
, sym
) {
168 linearize_symbol(sym
);
169 } END_FOR_EACH_PTR(sym
);
171 FOR_EACH_PTR(fsyms
, sym
) {
174 graph_calls(sym
->ep
, 1);
176 } END_FOR_EACH_PTR_NOTAG(sym
);
178 } END_FOR_EACH_PTR_NOTAG(file
);
180 /* Graph inter-file calls */
181 FOR_EACH_PTR(all_syms
, sym
) {
183 graph_calls(sym
->ep
, 0);
184 } END_FOR_EACH_PTR_NOTAG(sym
);