2 * graph.c: Helper routines to graph various internal states of the code generator
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2003 Ximian, Inc.
10 #include <mono/metadata/debug-helpers.h>
15 convert_name (const char *str
)
17 int i
, j
, len
= strlen (str
);
18 char *res
= g_malloc (len
* 2);
21 for (i
= 0; i
< len
; i
++) {
39 dtree_emit_one_loop_level (MonoCompile
*cfg
, FILE *fp
, MonoBasicBlock
*h
)
46 fprintf (fp
, "subgraph cluster_%d {\n", h
->block_num
);
47 fprintf (fp
, "label=\"loop_%d\"\n", h
->block_num
);
50 for (i
= 1; i
< cfg
->num_bblocks
; ++i
) {
51 bb
= cfg
->bblocks
[i
];
53 if (!h
|| (g_list_find (h
->loop_blocks
, bb
) && bb
!= h
)) {
54 if (bb
->nesting
== level
) {
55 fprintf (fp
, "BB%d -> BB%d;\n", bb
->idom
->block_num
, bb
->block_num
);
58 if (bb
->nesting
== (level
+ 1) && bb
->loop_blocks
) {
59 fprintf (fp
, "BB%d -> BB%d;\n", bb
->idom
->block_num
, bb
->block_num
);
60 dtree_emit_one_loop_level (cfg
, fp
, bb
);
71 cfg_emit_one_loop_level (MonoCompile
*cfg
, FILE *fp
, MonoBasicBlock
*h
)
78 fprintf (fp
, "subgraph cluster_%d {\n", h
->block_num
);
79 fprintf (fp
, "label=\"loop_%d\"\n", h
->block_num
);
82 for (bb
= cfg
->bb_entry
->next_bb
; bb
; bb
= bb
->next_bb
) {
83 if (bb
->region
!= -1) {
84 switch (bb
->region
& (MONO_REGION_FINALLY
|MONO_REGION_CATCH
|MONO_REGION_FAULT
|MONO_REGION_FILTER
)) {
85 case MONO_REGION_CATCH
:
86 fprintf (fp
, "BB%d [color=blue];\n", bb
->block_num
);;
88 case MONO_REGION_FINALLY
:
89 fprintf (fp
, "BB%d [color=green];\n", bb
->block_num
);;
91 case MONO_REGION_FAULT
:
92 case MONO_REGION_FILTER
:
93 fprintf (fp
, "BB%d [color=yellow];\n", bb
->block_num
);;
100 if (!h
|| (g_list_find (h
->loop_blocks
, bb
) && bb
!= h
)) {
102 if (bb
->nesting
== level
) {
103 for (j
= 0; j
< bb
->in_count
; j
++)
104 fprintf (fp
, "BB%d -> BB%d;\n", bb
->in_bb
[j
]->block_num
, bb
->block_num
);
107 if (bb
->nesting
== (level
+ 1) && bb
->loop_blocks
) {
108 for (j
= 0; j
< bb
->in_count
; j
++)
109 fprintf (fp
, "BB%d -> BB%d;\n", bb
->in_bb
[j
]->block_num
, bb
->block_num
);
110 cfg_emit_one_loop_level (cfg
, fp
, bb
);
121 mono_draw_dtree (MonoCompile
*cfg
, FILE *fp
)
123 g_assert ((cfg
->comp_done
& MONO_COMP_IDOM
));
125 fprintf (fp
, "digraph %s {\n", convert_name (cfg
->method
->name
));
126 fprintf (fp
, "node [fontsize=12.0]\nedge [len=1,color=red]\n");
127 fprintf (fp
, "label=\"Dominator tree for %s\";\n", mono_method_full_name (cfg
->method
, TRUE
));
129 fprintf (fp
, "BB0 [shape=doublecircle];\n");
130 fprintf (fp
, "BB1 [color=red];\n");
132 dtree_emit_one_loop_level (cfg
, fp
, NULL
);
138 mono_draw_cfg (MonoCompile
*cfg
, FILE *fp
)
140 fprintf (fp
, "digraph %s {\n", convert_name (cfg
->method
->name
));
141 fprintf (fp
, "node [fontsize=12.0]\nedge [len=1,color=red]\n");
142 fprintf (fp
, "label=\"CFG for %s\";\n", mono_method_full_name (cfg
->method
, TRUE
));
144 fprintf (fp
, "BB0 [shape=doublecircle];\n");
145 fprintf (fp
, "BB1 [color=red];\n");
147 cfg_emit_one_loop_level (cfg
, fp
, NULL
);
153 mono_print_label (FILE *fp
, MonoInst
*tree
) {
159 arity
= mono_burg_arity
[tree
->opcode
];
161 fprintf (fp
, "\\ %s%s", arity
? "(": "", mono_inst_name (tree
->opcode
));
163 switch (tree
->opcode
) {
165 fprintf (fp
, "[%ld]", (long)tree
->inst_c0
);
168 fprintf (fp
, "[%lld]", (long long)tree
->inst_l
);
171 fprintf (fp
, "[%f]", *(double*)tree
->inst_p0
);
174 fprintf (fp
, "[%f]", *(float*)tree
->inst_p0
);
178 fprintf (fp
, "[%d]", (int)tree
->inst_c0
);
181 fprintf (fp
, "[0x%x(%s)]", (int)tree
->inst_offset
, mono_arch_regname (tree
->inst_basereg
));
184 fprintf (fp
, "[%s]", mono_arch_regname (tree
->dreg
));
187 fprintf (fp
, "[%s]", tree
->inst_newa_class
->name
);
188 mono_print_label (fp
, tree
->inst_newa_len
);
199 case OP_VOIDCALLVIRT
: {
200 MonoCallInst
*call
= (MonoCallInst
*)tree
;
202 if (mono_method_signature (call
->method
)->hasthis
&& tree
->inst_left
) {
203 mono_print_label (fp
, tree
->inst_left
);
205 fprintf (fp
, "[%s]", call
->method
->name
);
211 fprintf (fp
, "[%d\\ (", (int)tree
->inst_c0
);
212 for (i
= 0; i
< tree
->inst_phi_args
[0]; i
++) {
214 fprintf (fp
, ",\\ ");
215 fprintf (fp
, "%d", tree
->inst_phi_args
[i
+ 1]);
227 fprintf (fp
, "[B%d]", tree
->inst_target_bb
->block_num
);
237 case OP_VOIDCALL_REG
:
238 mono_print_label (fp
, tree
->inst_left
);
250 fprintf (fp
, "[B%dB%d]", tree
->inst_true_bb
->block_num
, tree
->inst_false_bb
->block_num
);
251 mono_print_label (fp
, tree
->inst_left
);
255 mono_print_label (fp
, tree
->inst_left
);
257 mono_print_label (fp
, tree
->inst_right
);
267 mono_draw_code_cfg (MonoCompile
*cfg
, FILE *fp
)
271 fprintf (fp
, "digraph %s {\n", convert_name (cfg
->method
->name
));
272 fprintf (fp
, "node [fontsize=12.0]\nedge [len=1,color=red]\n");
273 fprintf (fp
, "label=\"CFG for %s\";\n", mono_method_full_name (cfg
->method
, TRUE
));
275 fprintf (fp
, "BB0 [shape=doublecircle];\n");
276 fprintf (fp
, "BB1 [color=red];\n");
278 for (bb
= cfg
->bb_entry
->next_bb
; bb
; bb
= bb
->next_bb
) {
282 if (bb
== cfg
->bb_exit
)
285 if ((cfg
->comp_done
& MONO_COMP_REACHABILITY
) && (bb
->flags
& BB_REACHABLE
))
286 color
= "color=red,";
290 fprintf (fp
, "BB%d [%sshape=record,labeljust=l,label=\"{BB%d|", bb
->block_num
, color
, bb
->block_num
);
292 for (inst
= bb
->code
; inst
; inst
= inst
->next
) {
293 mono_print_label (fp
, inst
);
297 fprintf (fp
, "}\"];\n");
300 cfg_emit_one_loop_level (cfg
, fp
, NULL
);
306 mono_draw_graph (MonoCompile
*cfg
, MonoGraphOptions draw_options
)
312 fn
= "/tmp/minidtree.graph";
313 fp
= fopen (fn
, "w+");
316 switch (draw_options
) {
317 case MONO_GRAPH_DTREE
:
318 mono_draw_dtree (cfg
, fp
);
321 mono_draw_cfg (cfg
, fp
);
323 case MONO_GRAPH_CFG_CODE
:
324 case MONO_GRAPH_CFG_OPTCODE
:
325 case MONO_GRAPH_CFG_SSA
:
326 mono_draw_code_cfg (cfg
, fp
);
332 //com = g_strdup_printf ("dot %s -Tpng -o %s.png; eog %s.png", fn, fn, fn);
333 com
= g_strdup_printf ("dot %s -Tps -o %s.ps;gv %s.ps", fn
, fn
, fn
);