[ci] Bump timeout in ms-test-suite
[mono-project.git] / mono / mini / graph.c
blob95e1fff2bb42a59abeb32870870b8c718163494f
1 /*
2 * graph.c: Helper routines to graph various internal states of the code generator
4 * Author:
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2003 Ximian, Inc.
8 */
10 #include <config.h>
11 #include <mono/utils/mono-compiler.h>
13 #ifndef DISABLE_JIT
15 #include <string.h>
16 #include <mono/metadata/debug-helpers.h>
18 #include "mini.h"
20 static char *
21 convert_name (const char *str)
23 int i, j, len = strlen (str);
24 char *res = (char *)g_malloc (len * 2);
26 j = 0;
27 for (i = 0; i < len; i++) {
28 char c = str [i];
30 switch (c) {
31 case '.':
32 res [j++] = '_';
33 break;
34 default:
35 res [j++] = c;
39 res [j] = 0;
41 return res;
44 static void
45 dtree_emit_one_loop_level (MonoCompile *cfg, FILE *fp, MonoBasicBlock *h)
47 MonoBasicBlock *bb;
48 int i, level = 0;
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);
56 for (i = 1; i < cfg->num_bblocks; ++i) {
57 bb = cfg->bblocks [i];
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);
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);
71 if (h) {
72 fprintf (fp, "}\n");
76 static void
77 cfg_emit_one_loop_level (MonoCompile *cfg, FILE *fp, MonoBasicBlock *h)
79 MonoBasicBlock *bb;
80 int j, level = 0;
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);
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;
106 if (!h || (g_list_find (h->loop_blocks, bb) && bb != h)) {
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);
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);
121 if (h) {
122 fprintf (fp, "}\n");
126 static void
127 mono_draw_dtree (MonoCompile *cfg, FILE *fp)
129 g_assert ((cfg->comp_done & MONO_COMP_IDOM));
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));
135 fprintf (fp, "BB0 [shape=doublecircle];\n");
136 fprintf (fp, "BB1 [color=red];\n");
138 dtree_emit_one_loop_level (cfg, fp, NULL);
140 fprintf (fp, "}\n");
143 static void
144 mono_draw_cfg (MonoCompile *cfg, FILE *fp)
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));
150 fprintf (fp, "BB0 [shape=doublecircle];\n");
151 fprintf (fp, "BB1 [color=red];\n");
153 cfg_emit_one_loop_level (cfg, fp, NULL);
155 fprintf (fp, "}\n");
158 #if 0
160 static void
161 mono_print_label (FILE *fp, MonoInst *tree) {
162 int arity;
164 if (!tree)
165 return;
167 arity = mono_burg_arity [tree->opcode];
169 fprintf (fp, "\\ %s%s", arity? "(": "", mono_inst_name (tree->opcode));
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);
213 fprintf (fp, "[%s]", call->method->name);
215 break;
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]);
225 fprintf (fp, ")]");
226 break;
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);
264 break;
267 if (arity)
268 fprintf (fp, ")");
271 #endif
273 static void
274 mono_draw_code_cfg (MonoCompile *cfg, FILE *fp)
276 MonoBasicBlock *bb;
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));
282 fprintf (fp, "BB0 [shape=doublecircle];\n");
283 fprintf (fp, "BB1 [color=red];\n");
285 for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
286 MonoInst *inst;
287 const char *color;
289 if (bb == cfg->bb_exit)
290 continue;
292 if ((cfg->comp_done & MONO_COMP_REACHABILITY) && (bb->flags & BB_REACHABLE))
293 color = "color=red,";
294 else
295 color = "";
297 fprintf (fp, "BB%d [%sshape=record,labeljust=l,label=\"{BB%d|", bb->block_num, color, bb->block_num);
299 MONO_BB_FOR_EACH_INS (bb, inst) {
300 //mono_print_label (fp, inst);
301 fprintf (fp, "\\n");
304 fprintf (fp, "}\"];\n");
307 cfg_emit_one_loop_level (cfg, fp, NULL);
309 fprintf (fp, "}\n");
312 void
313 mono_draw_graph (MonoCompile *cfg, MonoGraphOptions draw_options)
315 char *com;
316 const char *fn;
317 FILE *fp;
318 int _i G_GNUC_UNUSED;
320 fn = "/tmp/minidtree.graph";
321 fp = fopen (fn, "w+");
322 g_assert (fp);
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;
338 fclose (fp);
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
350 #else /* !DISABLE_JIT */
352 MONO_EMPTY_SOURCE_FILE (graph);
354 #endif /* !DISABLE_JIT */