Merge pull request #4433 from kumpera/android-fixes
[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 static void
159 mono_draw_code_cfg (MonoCompile *cfg, FILE *fp)
160 {
161         MonoBasicBlock *bb;
162                 
163         fprintf (fp, "digraph %s {\n", convert_name (cfg->method->name));
164         fprintf (fp, "node [fontsize=12.0]\nedge [len=1,color=red]\n");
165         fprintf (fp, "label=\"CFG for %s\";\n", mono_method_full_name (cfg->method, TRUE));
166
167         fprintf (fp, "BB0 [shape=doublecircle];\n");
168         fprintf (fp, "BB1 [color=red];\n");
169
170         for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
171                 MonoInst *inst;
172                 const char *color;
173
174                 if (bb == cfg->bb_exit)
175                         continue;
176
177                 if ((cfg->comp_done & MONO_COMP_REACHABILITY) && (bb->flags & BB_REACHABLE))
178                         color = "color=red,";
179                 else
180                         color = "";
181
182                 fprintf (fp, "BB%d [%sshape=record,labeljust=l,label=\"{BB%d|", bb->block_num, color, bb->block_num);
183                         
184                 MONO_BB_FOR_EACH_INS (bb, inst) {
185                         //mono_print_label (fp, inst);
186                         fprintf (fp, "\\n");                    
187                 }
188
189                 fprintf (fp, "}\"];\n");                        
190         }
191
192         cfg_emit_one_loop_level (cfg, fp, NULL);
193
194         fprintf (fp, "}\n");
195 }
196
197 void
198 mono_draw_graph (MonoCompile *cfg, MonoGraphOptions draw_options)
199 {
200         char *com;
201         const char *fn;
202         FILE *fp;
203         int _i G_GNUC_UNUSED;
204
205         fn = "/tmp/minidtree.graph";
206         fp = fopen (fn, "w+");
207         g_assert (fp);
208
209         switch (draw_options) {
210         case MONO_GRAPH_DTREE:
211                 mono_draw_dtree (cfg, fp);
212                 break;
213         case MONO_GRAPH_CFG:
214                 mono_draw_cfg (cfg, fp);
215                 break;
216         case MONO_GRAPH_CFG_CODE:
217         case MONO_GRAPH_CFG_OPTCODE:
218         case MONO_GRAPH_CFG_SSA:
219                 mono_draw_code_cfg (cfg, fp);
220                 break;
221         }
222
223         fclose (fp);
224
225 #ifdef HAVE_SYSTEM
226         //com = g_strdup_printf ("dot %s -Tpng -o %s.png; eog %s.png", fn, fn, fn);
227         com = g_strdup_printf ("dot %s -Tps -o %s.ps;gv %s.ps", fn, fn, fn);
228         _i = system (com);
229         g_free (com);
230 #else
231         g_assert_not_reached ();
232 #endif
233 }
234
235 #else /* !DISABLE_JIT */
236
237 MONO_EMPTY_SOURCE_FILE (graph);
238
239 #endif /* !DISABLE_JIT */
240