* TextControl.cs: Make PageUp and PageDown more like the
[mono-project.git] / mono / mini / graph.c
blob469aa2fc7338de934ad200f22cb6efb720ff7b49
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 */
9 #include <string.h>
10 #include <mono/metadata/debug-helpers.h>
12 #include "mini.h"
14 static char *
15 convert_name (const char *str)
17 int i, j, len = strlen (str);
18 char *res = g_malloc (len * 2);
20 j = 0;
21 for (i = 0; i < len; i++) {
22 char c = str [i];
24 switch (c) {
25 case '.':
26 res [j++] = '_';
27 break;
28 default:
29 res [j++] = c;
33 res [j] = 0;
35 return res;
38 static void
39 dtree_emit_one_loop_level (MonoCompile *cfg, FILE *fp, MonoBasicBlock *h)
41 MonoBasicBlock *bb;
42 int i, level = 0;
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);
50 for (i = 1; i < cfg->num_bblocks; ++i) {
51 bb = cfg->bblocks [i];
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);
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);
65 if (h) {
66 fprintf (fp, "}\n");
70 static void
71 cfg_emit_one_loop_level (MonoCompile *cfg, FILE *fp, MonoBasicBlock *h)
73 MonoBasicBlock *bb;
74 int j, level = 0;
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);
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;
100 if (!h || (g_list_find (h->loop_blocks, bb) && bb != h)) {
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);
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);
115 if (h) {
116 fprintf (fp, "}\n");
120 static void
121 mono_draw_dtree (MonoCompile *cfg, FILE *fp)
123 g_assert ((cfg->comp_done & MONO_COMP_IDOM));
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));
129 fprintf (fp, "BB0 [shape=doublecircle];\n");
130 fprintf (fp, "BB1 [color=red];\n");
132 dtree_emit_one_loop_level (cfg, fp, NULL);
134 fprintf (fp, "}\n");
137 static void
138 mono_draw_cfg (MonoCompile *cfg, FILE *fp)
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));
144 fprintf (fp, "BB0 [shape=doublecircle];\n");
145 fprintf (fp, "BB1 [color=red];\n");
147 cfg_emit_one_loop_level (cfg, fp, NULL);
149 fprintf (fp, "}\n");
152 static void
153 mono_print_label (FILE *fp, MonoInst *tree) {
154 int arity;
156 if (!tree)
157 return;
159 arity = mono_burg_arity [tree->opcode];
161 fprintf (fp, "\\ %s%s", arity? "(": "", mono_inst_name (tree->opcode));
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 CEE_CALL:
191 case CEE_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);
205 fprintf (fp, "[%s]", call->method->name);
207 break;
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]);
217 fprintf (fp, ")]");
218 break;
220 case OP_RENAME:
221 case OP_RETARG:
222 case CEE_NOP:
223 case CEE_JMP:
224 case CEE_BREAK:
225 break;
226 case CEE_BR:
227 fprintf (fp, "[B%d]", tree->inst_target_bb->block_num);
228 break;
229 case CEE_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 mono_print_label (fp, tree->inst_left);
239 break;
240 case CEE_BNE_UN:
241 case CEE_BEQ:
242 case CEE_BLT:
243 case CEE_BLT_UN:
244 case CEE_BGT:
245 case CEE_BGT_UN:
246 case CEE_BGE:
247 case CEE_BGE_UN:
248 case CEE_BLE:
249 case CEE_BLE_UN:
250 fprintf (fp, "[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
251 mono_print_label (fp, tree->inst_left);
252 break;
253 default:
254 if (arity) {
255 mono_print_label (fp, tree->inst_left);
256 if (arity > 1)
257 mono_print_label (fp, tree->inst_right);
259 break;
262 if (arity)
263 fprintf (fp, ")");
266 static void
267 mono_draw_code_cfg (MonoCompile *cfg, FILE *fp)
269 MonoBasicBlock *bb;
271 fprintf (fp, "digraph %s {\n", convert_name (cfg->method->name));
272 fprintf (fp, "node [fontsize=12.0]\nedge [len=1,color=red]\n");
273 fprintf (fp, "label=\"CFG for %s\";\n", mono_method_full_name (cfg->method, TRUE));
275 fprintf (fp, "BB0 [shape=doublecircle];\n");
276 fprintf (fp, "BB1 [color=red];\n");
278 for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
279 MonoInst *inst;
280 const char *color;
282 if (bb == cfg->bb_exit)
283 continue;
285 if ((cfg->comp_done & MONO_COMP_REACHABILITY) && (bb->flags & BB_REACHABLE))
286 color = "color=red,";
287 else
288 color = "";
290 fprintf (fp, "BB%d [%sshape=record,labeljust=l,label=\"{BB%d|", bb->block_num, color, bb->block_num);
292 for (inst = bb->code; inst; inst = inst->next) {
293 mono_print_label (fp, inst);
294 fprintf (fp, "\\n");
297 fprintf (fp, "}\"];\n");
300 cfg_emit_one_loop_level (cfg, fp, NULL);
302 fprintf (fp, "}\n");
305 void
306 mono_draw_graph (MonoCompile *cfg, MonoGraphOptions draw_options)
308 char *com;
309 const char *fn;
310 FILE *fp;
312 fn = "/tmp/minidtree.graph";
313 fp = fopen (fn, "w+");
314 g_assert (fp);
316 switch (draw_options) {
317 case MONO_GRAPH_DTREE:
318 mono_draw_dtree (cfg, fp);
319 break;
320 case MONO_GRAPH_CFG:
321 mono_draw_cfg (cfg, fp);
322 break;
323 case MONO_GRAPH_CFG_CODE:
324 case MONO_GRAPH_CFG_OPTCODE:
325 case MONO_GRAPH_CFG_SSA:
326 mono_draw_code_cfg (cfg, fp);
327 break;
330 fclose (fp);
332 //com = g_strdup_printf ("dot %s -Tpng -o %s.png; eog %s.png", fn, fn, fn);
333 com = g_strdup_printf ("dot %s -Tps -o %s.ps;gv %s.ps", fn, fn, fn);
334 system (com);
335 g_free (com);