2008-03-14 Mark Probst <mark.probst@gmail.com>
[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 static char *
15 convert_name (const char *str)
16 {
17         int i, j, len = strlen (str);
18         char *res = g_malloc (len * 2);
19
20         j = 0;
21         for (i = 0; i < len; i++) {
22                 char c = str [i];
23
24                 switch (c) {
25                 case '.':
26                         res [j++] = '_';
27                         break;
28                 default:
29                         res [j++] = c;
30                 }
31         }
32
33         res [j] = 0;
34
35         return res;
36 }
37
38 static void
39 dtree_emit_one_loop_level (MonoCompile *cfg, FILE *fp, MonoBasicBlock *h)
40 {
41         MonoBasicBlock *bb;
42         int i, level = 0;
43
44         if (h) {
45                 level = h->nesting;
46                 fprintf (fp, "subgraph cluster_%d {\n", h->block_num);
47                 fprintf (fp, "label=\"loop_%d\"\n", h->block_num);
48         } 
49
50         for (i = 1; i < cfg->num_bblocks; ++i) {
51                 bb = cfg->bblocks [i];
52
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);
56                         }
57                 
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);
61                         }
62                 }
63         }
64         
65         if (h) {
66                 fprintf (fp, "}\n");
67         }
68 }
69
70 static void
71 cfg_emit_one_loop_level (MonoCompile *cfg, FILE *fp, MonoBasicBlock *h)
72 {
73         MonoBasicBlock *bb;
74         int j, level = 0;
75
76         if (h) {
77                 level = h->nesting;
78                 fprintf (fp, "subgraph cluster_%d {\n", h->block_num);
79                 fprintf (fp, "label=\"loop_%d\"\n", h->block_num);
80         } 
81
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);;
87                                 break;
88                         case MONO_REGION_FINALLY:
89                                 fprintf (fp, "BB%d [color=green];\n", bb->block_num);;
90                                 break;
91                         case MONO_REGION_FAULT:
92                         case MONO_REGION_FILTER:
93                                 fprintf (fp, "BB%d [color=yellow];\n", bb->block_num);;
94                                 break;
95                         default:
96                                 break;
97                         }
98                 }
99
100                 if (!h || (g_list_find (h->loop_blocks, bb) && bb != h)) {
101
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);
105                         }
106                 
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);
111                         }
112                 }
113         }
114         
115         if (h) {
116                 fprintf (fp, "}\n");
117         }
118 }
119
120 static void
121 mono_draw_dtree (MonoCompile *cfg, FILE *fp)
122 {
123         g_assert ((cfg->comp_done & MONO_COMP_IDOM));
124
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));
128
129         fprintf (fp, "BB0 [shape=doublecircle];\n");
130         fprintf (fp, "BB1 [color=red];\n");
131
132         dtree_emit_one_loop_level (cfg, fp, NULL);
133
134         fprintf (fp, "}\n");
135 }
136
137 static void
138 mono_draw_cfg (MonoCompile *cfg, FILE *fp)
139 {
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));
143
144         fprintf (fp, "BB0 [shape=doublecircle];\n");
145         fprintf (fp, "BB1 [color=red];\n");
146
147         cfg_emit_one_loop_level (cfg, fp, NULL);
148
149         fprintf (fp, "}\n");
150 }
151
152 static void
153 mono_print_label (FILE *fp, MonoInst *tree) {
154         int arity;
155
156         if (!tree)
157                 return;
158
159         arity = mono_burg_arity [tree->opcode];
160
161         fprintf (fp, "\\ %s%s", arity? "(": "",  mono_inst_name (tree->opcode));
162
163         switch (tree->opcode) {
164         case OP_ICONST:
165                 fprintf (fp, "[%ld]", (long)tree->inst_c0);
166                 break;
167         case OP_I8CONST:
168                 fprintf (fp, "[%lld]", (long long)tree->inst_l);
169                 break;
170         case OP_R8CONST:
171                 fprintf (fp, "[%f]", *(double*)tree->inst_p0);
172                 break;
173         case OP_R4CONST:
174                 fprintf (fp, "[%f]", *(float*)tree->inst_p0);
175                 break;
176         case OP_ARG:
177         case OP_LOCAL:
178                 fprintf (fp, "[%d]", (int)tree->inst_c0);
179                 break;
180         case OP_REGOFFSET:
181                 fprintf (fp, "[0x%x(%s)]", (int)tree->inst_offset, mono_arch_regname (tree->inst_basereg));
182                 break;
183         case OP_REGVAR:
184                 fprintf (fp, "[%s]", mono_arch_regname (tree->dreg));
185                 break;
186         case CEE_NEWARR:
187                 fprintf (fp, "[%s]",  tree->inst_newa_class->name);
188                 mono_print_label (fp, tree->inst_newa_len);
189                 break;
190         case OP_CALL:
191         case OP_CALLVIRT:
192         case OP_FCALL:
193         case OP_FCALLVIRT:
194         case OP_LCALL:
195         case OP_LCALLVIRT:
196         case OP_VCALL:
197         case OP_VCALLVIRT:
198         case OP_VOIDCALL:
199         case OP_VOIDCALLVIRT: {
200                 MonoCallInst *call = (MonoCallInst*)tree;
201                 if (call->method) {
202                         if (mono_method_signature (call->method)->hasthis && tree->inst_left) {
203                                 mono_print_label (fp, tree->inst_left);
204                         }
205                         fprintf (fp, "[%s]", call->method->name);
206                 }
207                 break;
208         }
209         case OP_PHI: {
210                 int i;
211                 fprintf (fp, "[%d\\ (", (int)tree->inst_c0);
212                 for (i = 0; i < tree->inst_phi_args [0]; i++) {
213                         if (i)
214                                 fprintf (fp, ",\\ ");
215                         fprintf (fp, "%d", tree->inst_phi_args [i + 1]);
216                 }
217                 fprintf (fp, ")]");
218                 break;
219         }
220         case OP_RENAME:
221         case OP_RETARG:
222         case OP_NOP:
223         case OP_JMP:
224         case OP_BREAK:
225                 break;
226         case OP_BR:
227                 fprintf (fp, "[B%d]", tree->inst_target_bb->block_num);
228                 break;
229         case OP_SWITCH:
230         case CEE_ISINST:
231         case CEE_CASTCLASS:
232         case OP_OUTARG:
233         case OP_CALL_REG:
234         case OP_FCALL_REG:
235         case OP_LCALL_REG:
236         case OP_VCALL_REG:
237         case OP_VOIDCALL_REG:
238         case OP_TRAMPCALL_VTABLE:
239         case OP_CALL_RGCTX:
240         case OP_FCALL_RGCTX:
241         case OP_VOIDCALL_RGCTX:
242         case OP_LCALL_RGCTX:
243         case OP_VCALL_RGCTX:
244                 mono_print_label (fp, tree->inst_left);
245                 break;
246         case CEE_BNE_UN:
247         case CEE_BEQ:
248         case CEE_BLT:
249         case CEE_BLT_UN:
250         case CEE_BGT:
251         case CEE_BGT_UN:
252         case CEE_BGE:
253         case CEE_BGE_UN:
254         case CEE_BLE:
255         case CEE_BLE_UN:
256                 fprintf (fp, "[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
257                 mono_print_label (fp, tree->inst_left);
258                 break;
259         default:
260                 if (arity) {
261                         mono_print_label (fp, tree->inst_left);
262                         if (arity > 1)
263                                 mono_print_label (fp, tree->inst_right);
264                 }
265                 break;
266         }
267
268         if (arity)
269                 fprintf (fp, ")");
270 }
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
318         fn = "/tmp/minidtree.graph";
319         fp = fopen (fn, "w+");
320         g_assert (fp);
321
322         switch (draw_options) {
323         case MONO_GRAPH_DTREE:
324                 mono_draw_dtree (cfg, fp);
325                 break;
326         case MONO_GRAPH_CFG:
327                 mono_draw_cfg (cfg, fp);
328                 break;
329         case MONO_GRAPH_CFG_CODE:
330         case MONO_GRAPH_CFG_OPTCODE:
331         case MONO_GRAPH_CFG_SSA:
332                 mono_draw_code_cfg (cfg, fp);
333                 break;
334         }
335
336         fclose (fp);
337
338         //com = g_strdup_printf ("dot %s -Tpng -o %s.png; eog %s.png", fn, fn, fn);
339         com = g_strdup_printf ("dot %s -Tps -o %s.ps;gv %s.ps", fn, fn, fn);
340         system (com);
341         g_free (com);
342 }
343