2005-07-20 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / mini / graph.c
1 /*
2  * graph.c: Helper routines to graph various internal states of the code generator
3  *
4  * Author:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *
7  * (C) 2003 Ximian, Inc.
8  */
9 #include <string.h>
10 #include <mono/metadata/debug-helpers.h>
11
12 #include "mini.h"
13
14 extern guint8 mono_burg_arity [];
15
16 static char *
17 convert_name (const char *str)
18 {
19         int i, j, len = strlen (str);
20         char *res = g_malloc (len * 2);
21
22         j = 0;
23         for (i = 0; i < len; i++) {
24                 char c = str [i];
25
26                 switch (c) {
27                 case '.':
28                         res [j++] = '_';
29                         break;
30                 default:
31                         res [j++] = c;
32                 }
33         }
34
35         res [j] = 0;
36
37         return res;
38 }
39
40 static void
41 dtree_emit_one_loop_level (MonoCompile *cfg, FILE *fp, MonoBasicBlock *h)
42 {
43         MonoBasicBlock *bb;
44         int i, level = 0;
45
46         if (h) {
47                 level = h->nesting;
48                 fprintf (fp, "subgraph cluster_%d {\n", h->block_num);
49                 fprintf (fp, "label=\"loop_%d\"\n", h->block_num);
50         } 
51
52         for (i = 1; i < cfg->num_bblocks; ++i) {
53                 bb = cfg->bblocks [i];
54
55                 if (!h || (g_list_find (h->loop_blocks, bb) && bb != h)) {
56                         if (bb->nesting == level) {
57                                 fprintf (fp, "BB%d -> BB%d;\n", bb->idom->block_num, bb->block_num);
58                         }
59                 
60                         if (bb->nesting == (level + 1) && bb->loop_blocks) {
61                                 fprintf (fp, "BB%d -> BB%d;\n", bb->idom->block_num, bb->block_num);
62                                 dtree_emit_one_loop_level (cfg, fp, bb);
63                         }
64                 }
65         }
66         
67         if (h) {
68                 fprintf (fp, "}\n");
69         }
70 }
71
72 static void
73 cfg_emit_one_loop_level (MonoCompile *cfg, FILE *fp, MonoBasicBlock *h)
74 {
75         MonoBasicBlock *bb;
76         int j, level = 0;
77
78         if (h) {
79                 level = h->nesting;
80                 fprintf (fp, "subgraph cluster_%d {\n", h->block_num);
81                 fprintf (fp, "label=\"loop_%d\"\n", h->block_num);
82         } 
83
84         for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
85                 if (bb->region != -1) {
86                         switch (bb->region & (MONO_REGION_FINALLY|MONO_REGION_CATCH|MONO_REGION_FAULT|MONO_REGION_FILTER)) {
87                         case MONO_REGION_CATCH:
88                                 fprintf (fp, "BB%d [color=blue];\n", bb->block_num);;
89                                 break;
90                         case MONO_REGION_FINALLY:
91                                 fprintf (fp, "BB%d [color=green];\n", bb->block_num);;
92                                 break;
93                         case MONO_REGION_FAULT:
94                         case MONO_REGION_FILTER:
95                                 fprintf (fp, "BB%d [color=yellow];\n", bb->block_num);;
96                                 break;
97                         default:
98                                 break;
99                         }
100                 }
101
102                 if (!h || (g_list_find (h->loop_blocks, bb) && bb != h)) {
103
104                         if (bb->nesting == level) {
105                                 for (j = 0; j < bb->in_count; j++) 
106                                         fprintf (fp, "BB%d -> BB%d;\n", bb->in_bb [j]->block_num, bb->block_num);
107                         }
108                 
109                         if (bb->nesting == (level + 1) && bb->loop_blocks) {
110                                 for (j = 0; j < bb->in_count; j++) 
111                                         fprintf (fp, "BB%d -> BB%d;\n", bb->in_bb [j]->block_num, bb->block_num);
112                                 cfg_emit_one_loop_level (cfg, fp, bb);
113                         }
114                 }
115         }
116         
117         if (h) {
118                 fprintf (fp, "}\n");
119         }
120 }
121
122 static void
123 mono_draw_dtree (MonoCompile *cfg, FILE *fp)
124 {
125         g_assert ((cfg->comp_done & MONO_COMP_IDOM));
126
127         fprintf (fp, "digraph %s {\n", convert_name (cfg->method->name));
128         fprintf (fp, "node [fontsize=12.0]\nedge [len=1,color=red]\n");
129         fprintf (fp, "label=\"Dominator tree for %s\";\n", mono_method_full_name (cfg->method, TRUE));
130
131         fprintf (fp, "BB0 [shape=doublecircle];\n");
132         fprintf (fp, "BB1 [color=red];\n");
133
134         dtree_emit_one_loop_level (cfg, fp, NULL);
135
136         fprintf (fp, "}\n");
137 }
138
139 static void
140 mono_draw_cfg (MonoCompile *cfg, FILE *fp)
141 {
142         fprintf (fp, "digraph %s {\n", convert_name (cfg->method->name));
143         fprintf (fp, "node [fontsize=12.0]\nedge [len=1,color=red]\n");
144         fprintf (fp, "label=\"CFG for %s\";\n", mono_method_full_name (cfg->method, TRUE));
145
146         fprintf (fp, "BB0 [shape=doublecircle];\n");
147         fprintf (fp, "BB1 [color=red];\n");
148
149         cfg_emit_one_loop_level (cfg, fp, NULL);
150
151         fprintf (fp, "}\n");
152 }
153
154 static void
155 mono_print_label (FILE *fp, MonoInst *tree) {
156         int arity;
157
158         if (!tree)
159                 return;
160
161         arity = mono_burg_arity [tree->opcode];
162
163         fprintf (fp, "\\ %s%s", arity? "(": "",  mono_inst_name (tree->opcode));
164
165         switch (tree->opcode) {
166         case OP_ICONST:
167                 fprintf (fp, "[%ld]", (long)tree->inst_c0);
168                 break;
169         case OP_I8CONST:
170                 fprintf (fp, "[%lld]", (long long)tree->inst_l);
171                 break;
172         case OP_R8CONST:
173                 fprintf (fp, "[%f]", *(double*)tree->inst_p0);
174                 break;
175         case OP_R4CONST:
176                 fprintf (fp, "[%f]", *(float*)tree->inst_p0);
177                 break;
178         case OP_ARG:
179         case OP_LOCAL:
180                 fprintf (fp, "[%d]", (int)tree->inst_c0);
181                 break;
182         case OP_REGOFFSET:
183                 fprintf (fp, "[0x%x(%s)]", (int)tree->inst_offset, mono_arch_regname (tree->inst_basereg));
184                 break;
185         case OP_REGVAR:
186                 fprintf (fp, "[%s]", mono_arch_regname (tree->dreg));
187                 break;
188         case CEE_NEWARR:
189                 fprintf (fp, "[%s]",  tree->inst_newa_class->name);
190                 mono_print_label (fp, tree->inst_newa_len);
191                 break;
192         case CEE_CALL:
193         case CEE_CALLVIRT:
194         case OP_FCALL:
195         case OP_FCALLVIRT:
196         case OP_LCALL:
197         case OP_LCALLVIRT:
198         case OP_VCALL:
199         case OP_VCALLVIRT:
200         case OP_VOIDCALL:
201         case OP_VOIDCALLVIRT: {
202                 MonoCallInst *call = (MonoCallInst*)tree;
203                 if (call->method) {
204                         if (mono_method_signature (call->method)->hasthis && tree->inst_left) {
205                                 mono_print_label (fp, tree->inst_left);
206                         }
207                         fprintf (fp, "[%s]", call->method->name);
208                 }
209                 break;
210         }
211         case OP_PHI: {
212                 int i;
213                 fprintf (fp, "[%d\\ (", (int)tree->inst_c0);
214                 for (i = 0; i < tree->inst_phi_args [0]; i++) {
215                         if (i)
216                                 fprintf (fp, ",\\ ");
217                         fprintf (fp, "%d", tree->inst_phi_args [i + 1]);
218                 }
219                 fprintf (fp, ")]");
220                 break;
221         }
222         case OP_RENAME:
223         case OP_RETARG:
224         case CEE_NOP:
225         case CEE_JMP:
226         case CEE_BREAK:
227                 break;
228         case CEE_BR:
229                 fprintf (fp, "[B%d]", tree->inst_target_bb->block_num);
230                 break;
231         case CEE_SWITCH:
232         case CEE_ISINST:
233         case CEE_CASTCLASS:
234         case OP_OUTARG:
235         case OP_CALL_REG:
236         case OP_FCALL_REG:
237         case OP_LCALL_REG:
238         case OP_VCALL_REG:
239         case OP_VOIDCALL_REG:
240                 mono_print_label (fp, tree->inst_left);
241                 break;
242         case CEE_BNE_UN:
243         case CEE_BEQ:
244         case CEE_BLT:
245         case CEE_BLT_UN:
246         case CEE_BGT:
247         case CEE_BGT_UN:
248         case CEE_BGE:
249         case CEE_BGE_UN:
250         case CEE_BLE:
251         case CEE_BLE_UN:
252                 fprintf (fp, "[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
253                 mono_print_label (fp, tree->inst_left);
254                 break;
255         default:
256                 if (arity) {
257                         mono_print_label (fp, tree->inst_left);
258                         if (arity > 1)
259                                 mono_print_label (fp, tree->inst_right);
260                 }
261                 break;
262         }
263
264         if (arity)
265                 fprintf (fp, ")");
266 }
267
268 static void
269 mono_draw_code_cfg (MonoCompile *cfg, FILE *fp)
270 {
271         MonoBasicBlock *bb;
272                 
273         fprintf (fp, "digraph %s {\n", convert_name (cfg->method->name));
274         fprintf (fp, "node [fontsize=12.0]\nedge [len=1,color=red]\n");
275         fprintf (fp, "label=\"CFG for %s\";\n", mono_method_full_name (cfg->method, TRUE));
276
277         fprintf (fp, "BB0 [shape=doublecircle];\n");
278         fprintf (fp, "BB1 [color=red];\n");
279
280         for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
281                 MonoInst *inst;
282                 const char *color;
283
284                 if (bb == cfg->bb_exit)
285                         continue;
286
287                 if ((cfg->comp_done & MONO_COMP_REACHABILITY) && (bb->flags & BB_REACHABLE))
288                         color = "color=red,";
289                 else
290                         color = "";
291
292                 fprintf (fp, "BB%d [%sshape=record,labeljust=l,label=\"{BB%d|", bb->block_num, color, bb->block_num);
293                         
294                 for (inst = bb->code; inst; inst = inst->next) {
295                         mono_print_label (fp, inst);
296                         fprintf (fp, "\\n");                    
297                 }
298
299                 fprintf (fp, "}\"];\n");                        
300         }
301
302         cfg_emit_one_loop_level (cfg, fp, NULL);
303
304         fprintf (fp, "}\n");
305 }
306
307 void
308 mono_draw_graph (MonoCompile *cfg, MonoGraphOptions draw_options)
309 {
310         char *com;
311         const char *fn;
312         FILE *fp;
313
314         fn = "/tmp/minidtree.graph";
315         fp = fopen (fn, "w+");
316         g_assert (fp);
317
318         switch (draw_options) {
319         case MONO_GRAPH_DTREE:
320                 mono_draw_dtree (cfg, fp);
321                 break;
322         case MONO_GRAPH_CFG:
323                 mono_draw_cfg (cfg, fp);
324                 break;
325         case MONO_GRAPH_CFG_CODE:
326         case MONO_GRAPH_CFG_OPTCODE:
327         case MONO_GRAPH_CFG_SSA:
328                 mono_draw_code_cfg (cfg, fp);
329                 break;
330         }
331
332         fclose (fp);
333
334         //com = g_strdup_printf ("dot %s -Tpng -o %s.png; eog %s.png", fn, fn, fn);
335         com = g_strdup_printf ("dot %s -Tps -o %s.ps;gv %s.ps", fn, fn, fn);
336         system (com);
337         g_free (com);
338 }
339