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
);
155 mono_print_label (FILE *fp
, MonoInst
*tree
) {
161 arity
= mono_burg_arity
[tree
->opcode
];
163 fprintf (fp
, "\\ %s%s", arity
? "(": "", mono_inst_name (tree
->opcode
));
165 switch (tree
->opcode
) {
167 fprintf (fp
, "[%ld]", (long)tree
->inst_c0
);
170 fprintf (fp
, "[%lld]", (long long)tree
->inst_l
);
173 fprintf (fp
, "[%f]", *(double*)tree
->inst_p0
);
176 fprintf (fp
, "[%f]", *(float*)tree
->inst_p0
);
180 fprintf (fp
, "[%d]", (int)tree
->inst_c0
);
183 fprintf (fp
, "[0x%x(%s)]", (int)tree
->inst_offset
, mono_arch_regname (tree
->inst_basereg
));
186 fprintf (fp
, "[%s]", mono_arch_regname (tree
->dreg
));
189 fprintf (fp
, "[%s]", tree
->inst_newa_class
->name
);
190 mono_print_label (fp
, tree
->inst_newa_len
);
201 case OP_VOIDCALLVIRT
: {
202 MonoCallInst
*call
= (MonoCallInst
*)tree
;
204 if (mono_method_signature (call
->method
)->hasthis
&& tree
->inst_left
) {
205 mono_print_label (fp
, tree
->inst_left
);
207 fprintf (fp
, "[%s]", call
->method
->name
);
213 fprintf (fp
, "[%d\\ (", (int)tree
->inst_c0
);
214 for (i
= 0; i
< tree
->inst_phi_args
[0]; i
++) {
216 fprintf (fp
, ",\\ ");
217 fprintf (fp
, "%d", tree
->inst_phi_args
[i
+ 1]);
227 fprintf (fp
, "[B%d]", tree
->inst_target_bb
->block_num
);
236 case OP_VOIDCALL_REG
:
237 mono_print_label (fp
, tree
->inst_left
);
249 fprintf (fp
, "[B%dB%d]", tree
->inst_true_bb
->block_num
, tree
->inst_false_bb
->block_num
);
250 mono_print_label (fp
, tree
->inst_left
);
254 mono_print_label (fp
, tree
->inst_left
);
256 mono_print_label (fp
, tree
->inst_right
);
268 mono_draw_code_cfg (MonoCompile
*cfg
, FILE *fp
)
272 fprintf (fp
, "digraph %s {\n", convert_name (cfg
->method
->name
));
273 fprintf (fp
, "node [fontsize=12.0]\nedge [len=1,color=red]\n");
274 fprintf (fp
, "label=\"CFG for %s\";\n", mono_method_full_name (cfg
->method
, TRUE
));
276 fprintf (fp
, "BB0 [shape=doublecircle];\n");
277 fprintf (fp
, "BB1 [color=red];\n");
279 for (bb
= cfg
->bb_entry
->next_bb
; bb
; bb
= bb
->next_bb
) {
283 if (bb
== cfg
->bb_exit
)
286 if ((cfg
->comp_done
& MONO_COMP_REACHABILITY
) && (bb
->flags
& BB_REACHABLE
))
287 color
= "color=red,";
291 fprintf (fp
, "BB%d [%sshape=record,labeljust=l,label=\"{BB%d|", bb
->block_num
, color
, bb
->block_num
);
293 MONO_BB_FOR_EACH_INS (bb
, inst
) {
294 //mono_print_label (fp, inst);
298 fprintf (fp
, "}\"];\n");
301 cfg_emit_one_loop_level (cfg
, fp
, NULL
);
307 mono_draw_graph (MonoCompile
*cfg
, MonoGraphOptions draw_options
)
313 fn
= "/tmp/minidtree.graph";
314 fp
= fopen (fn
, "w+");
317 switch (draw_options
) {
318 case MONO_GRAPH_DTREE
:
319 mono_draw_dtree (cfg
, fp
);
322 mono_draw_cfg (cfg
, fp
);
324 case MONO_GRAPH_CFG_CODE
:
325 case MONO_GRAPH_CFG_OPTCODE
:
326 case MONO_GRAPH_CFG_SSA
:
327 mono_draw_code_cfg (cfg
, fp
);
333 //com = g_strdup_printf ("dot %s -Tpng -o %s.png; eog %s.png", fn, fn, fn);
334 com
= g_strdup_printf ("dot %s -Tps -o %s.ps;gv %s.ps", fn
, fn
, fn
);