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