Com o autor
[pspdecompiler.git] / outgraph.c
blobd4f7602b6816bffac64efa415007f3a9f8c3c0e9
1 /**
2 * Author: Humberto Naves (hsnaves@gmail.com)
3 */
5 #include <stdio.h>
7 #include "output.h"
8 #include "utils.h"
10 static
11 void print_structures (FILE *out, struct basicblock *block)
13 struct ctrlstruct *st = block->st;
14 int count = 0;
16 while (st) {
17 switch (st->type) {
18 case CONTROL_IF:
19 fprintf (out, "IF start %d end %d %s\\l", st->start->node.dfsnum,
20 st->end->node.dfsnum, block->blockcond ? "TRUE" : "FALSE");
21 break;
22 case CONTROL_MAIN:
23 fprintf (out, "MAIN\\l");
24 break;
25 case CONTROL_LOOP:
26 fprintf (out, "LOOP start %d\\l", st->start->node.dfsnum);
27 break;
28 case CONTROL_SWITCH:
29 fprintf (out, "SWITCH start %d end %d %d\\l", st->start->node.dfsnum,
30 st->end->node.dfsnum, block->blockcond);
31 break;
33 st = st->parent;
34 if (++count > 100) break;
38 static
39 void print_block_code (FILE *out, struct basicblock *block)
41 if (block->type == BLOCK_SIMPLE) {
42 struct location *loc;
43 for (loc = block->info.simple.begin; ; loc++) {
44 fprintf (out, "%s\\l", allegrex_disassemble (loc->opc, loc->address, FALSE));
45 if (loc == block->info.simple.end) break;
50 static
51 void print_block_phis (FILE *out, struct basicblock *block)
53 element opsel, argel;
54 opsel = list_head (block->operations);
55 while (opsel) {
56 struct operation *op = element_getvalue (opsel);
57 int count1 = 0, count2 = 0;
59 if (op->type != OP_START && op->type != OP_END) {
60 argel = list_head (op->results);
61 while (argel) {
62 struct value *val = element_getvalue (argel);
63 if (val->type != VAL_CONSTANT) {
64 if (count1++ == 0) fprintf (out, "<");
65 print_value (out, val);
66 fprintf (out, " ");
68 argel = element_next (argel);
70 if (count1 > 0) fprintf (out, "> = ");
72 if (op->type == OP_PHI) {
73 fprintf (out, "PHI");
75 argel = list_head (op->operands);
76 while (argel) {
77 struct value *val = element_getvalue (argel);
78 if (val->type != VAL_CONSTANT) {
79 if (count2++ == 0) fprintf (out, "<");
80 print_value (out, val);
81 fprintf (out, " ");
83 argel = element_next (argel);
85 if (count2 > 0) fprintf (out, ">");
86 if (count1 || count2) fprintf (out, "\\l");
88 opsel = element_next (opsel);
92 static
93 void print_dominator (FILE *out, struct basicblock *block, int reverse, const char *color)
95 struct basicblock *dominator;
97 if (reverse) {
98 if (list_size (block->outrefs) <= 1) return;
99 dominator = element_getvalue (block->revnode.dominator->blockel);
100 } else {
101 if (list_size (block->inrefs) <= 1) return;
102 dominator = element_getvalue (block->node.dominator->blockel);
104 fprintf (out, " %3d -> %3d [color=%s];\n",
105 block->node.dfsnum, dominator->node.dfsnum, color);
108 static
109 void print_frontier (FILE *out, struct basicblock *block, list frontier, const char *color)
111 element ref;
112 if (list_size (frontier) == 0) return;
114 fprintf (out, " %3d -> { ", block->node.dfsnum);
115 ref = list_head (frontier);
116 while (ref) {
117 struct basicblocknode *refnode;
118 struct basicblock *refblock;
120 refnode = element_getvalue (ref);
121 refblock = element_getvalue (refnode->blockel);
123 fprintf (out, "%3d ", refblock->node.dfsnum);
124 ref = element_next (ref);
126 fprintf (out, " } [color=%s];\n", color);
129 static
130 void print_subroutine_graph (FILE *out, struct code *c, struct subroutine *sub, int options)
132 struct basicblock *block;
133 element el, ref;
135 fprintf (out, "digraph ");
136 print_subroutine_name (out, sub);
137 fprintf (out, " {\n rankdir=LR;\n");
139 el = list_head (sub->blocks);
141 while (el) {
142 block = element_getvalue (el);
144 fprintf (out, " %3d ", block->node.dfsnum);
145 fprintf (out, "[label=\"");
147 if (options & OUT_PRINT_STRUCTURES)
148 print_structures (out, block);
150 if (options & OUT_PRINT_DFS)
151 fprintf (out, "(%d) ", block->node.dfsnum);
153 if (options & OUT_PRINT_RDFS)
154 fprintf (out, "(%d) ", block->revnode.dfsnum);
156 switch (block->type) {
157 case BLOCK_START: fprintf (out, "Start"); break;
158 case BLOCK_END: fprintf (out, "End"); break;
159 case BLOCK_CALL: fprintf (out, "Call"); break;
160 case BLOCK_SIMPLE: fprintf (out, "0x%08X-0x%08X",
161 block->info.simple.begin->address, block->info.simple.end->address);
163 if (block->status & BLOCK_STAT_HASLABEL) fprintf (out, "(*)");
164 fprintf (out, "\\l");
166 if (options & OUT_PRINT_PHIS)
167 print_block_phis (out, block);
169 if (options & OUT_PRINT_CODE)
170 print_block_code (out, block);
172 fprintf (out, "\"];\n");
175 if (options & OUT_PRINT_DOMINATOR)
176 print_dominator (out, block, FALSE, "green");
178 if (options & OUT_PRINT_RDOMINATOR)
179 print_dominator (out, block, TRUE, "yellow");
181 if (options & OUT_PRINT_FRONTIER)
182 print_frontier (out, block, block->node.frontier, "orange");
184 if (options & OUT_PRINT_RFRONTIER)
185 print_frontier (out, block, block->revnode.frontier, "blue");
188 if (list_size (block->outrefs) != 0) {
189 ref = list_head (block->outrefs);
190 while (ref) {
191 struct basicedge *edge;
192 struct basicblock *refblock;
193 edge = element_getvalue (ref);
194 refblock = edge->to;
195 fprintf (out, " %3d -> %3d ", block->node.dfsnum, refblock->node.dfsnum);
196 if (ref != list_head (block->outrefs))
197 fprintf (out, "[arrowtail=dot]");
199 if (element_getvalue (refblock->node.parent->blockel) == block) {
200 fprintf (out, "[style=bold]");
201 } else if (block->node.dfsnum >= refblock->node.dfsnum) {
202 fprintf (out, "[color=red]");
204 if (options & OUT_PRINT_EDGE_TYPES) {
205 fprintf (out, "[label=\"");
206 switch (edge->type) {
207 case EDGE_UNKNOWN: fprintf (out, "UNK"); break;
208 case EDGE_CONTINUE: fprintf (out, "CONTINUE"); break;
209 case EDGE_BREAK: fprintf (out, "BREAK"); break;
210 case EDGE_NEXT: fprintf (out, "NEXT"); break;
211 case EDGE_INVALID: fprintf (out, "INVALID"); break;
212 case EDGE_GOTO: fprintf (out, "GOTO"); break;
213 case EDGE_CASE: fprintf (out, "CASE"); break;
214 case EDGE_IFENTER: fprintf (out, "IFENTER"); break;
215 case EDGE_IFEXIT: fprintf (out, "IFEXIT"); break;
217 fprintf (out, "\"]");
219 fprintf (out, " ;\n");
220 ref = element_next (ref);
223 el = element_next (el);
225 fprintf (out, "}\n");
229 int print_graph (struct code *c, char *prxname, int options)
231 char buffer[128];
232 char basename[32];
233 element el;
234 FILE *fp;
235 int ret = 1;
237 get_base_name (prxname, basename, sizeof (basename));
239 el = list_head (c->subroutines);
240 while (el) {
241 struct subroutine *sub = element_getvalue (el);
242 if (!sub->haserror && !sub->import) {
243 if (sub->export) {
244 if (sub->export->name) {
245 sprintf (buffer, "%s_%-.64s.dot", basename, sub->export->name);
246 } else
247 sprintf (buffer, "%s_nid_%08X.dot", basename, sub->export->nid);
248 } else
249 sprintf (buffer, "%s_%08X.dot", basename, sub->begin->address);
250 fp = fopen (buffer, "w");
251 if (!fp) {
252 xerror (__FILE__ ": can't open file for writing `%s'", buffer);
253 ret = 0;
254 } else {
255 print_subroutine_graph (fp, c, sub, options);
256 fclose (fp);
258 } else {
259 if (sub->haserror) report ("Skipping subroutine at 0x%08X\n", sub->begin->address);
261 el = element_next (el);
264 return ret;