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