With MULT and DIV operations
[pspdecompiler.git] / outgraph.c
blob6fc284bd2fde0563e724f8c1e4d0285104a8a6a4
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");
20 break;
21 case CONTROL_MAIN:
22 fprintf (out, "MAIN");
23 break;
24 case CONTROL_LOOP:
25 fprintf (out, "LOOP");
26 break;
27 case CONTROL_SWITCH:
28 fprintf (out, "SWITCH");
29 break;
31 fprintf (out, " start %d", st->start->node.dfsnum);
32 if (st->end)
33 fprintf (out, " end %d", st->end->node.dfsnum);
34 if (st->hasendgoto)
35 fprintf (out, " goto");
36 if (st->endfollow)
37 fprintf (out, " endfollow");
39 switch (st->type) {
40 case CONTROL_IF:
41 fprintf (out, " %s", block->blockcond ? "TRUE" : "FALSE");
42 break;
43 case CONTROL_MAIN:
44 break;
45 case CONTROL_LOOP:
46 break;
47 case CONTROL_SWITCH:
48 fprintf (out, " %d", block->blockcond);
50 fprintf (out, "\\l");
52 st = st->parent;
53 if (++count > 100) break;
57 static
58 void print_block_code (FILE *out, struct basicblock *block)
60 if (block->type == BLOCK_SIMPLE) {
61 struct location *loc;
62 for (loc = block->info.simple.begin; ; loc++) {
63 fprintf (out, "%s\\l", allegrex_disassemble (loc->opc, loc->address, FALSE));
64 if (loc == block->info.simple.end) break;
69 static
70 void print_dominator (FILE *out, struct basicblock *block, int reverse, const char *color)
72 struct basicblock *dominator;
74 if (reverse) {
75 if (list_size (block->outrefs) <= 1) return;
76 dominator = element_getvalue (block->revnode.dominator->blockel);
77 } else {
78 if (list_size (block->inrefs) <= 1) return;
79 dominator = element_getvalue (block->node.dominator->blockel);
81 fprintf (out, " %3d -> %3d [color=%s];\n",
82 block->node.dfsnum, dominator->node.dfsnum, color);
85 static
86 void print_frontier (FILE *out, struct basicblock *block, list frontier, const char *color)
88 element ref;
89 if (list_size (frontier) == 0) return;
91 fprintf (out, " %3d -> { ", block->node.dfsnum);
92 ref = list_head (frontier);
93 while (ref) {
94 struct basicblocknode *refnode;
95 struct basicblock *refblock;
97 refnode = element_getvalue (ref);
98 refblock = element_getvalue (refnode->blockel);
100 fprintf (out, "%3d ", refblock->node.dfsnum);
101 ref = element_next (ref);
103 fprintf (out, " } [color=%s];\n", color);
106 static
107 void print_subroutine_graph (FILE *out, struct code *c, struct subroutine *sub)
109 struct basicblock *block;
110 element el, ref;
112 fprintf (out, "digraph ");
113 print_subroutine_name (out, sub);
114 fprintf (out, " {\n rankdir=LR;\n");
116 el = list_head (sub->blocks);
118 while (el) {
119 block = element_getvalue (el);
121 fprintf (out, " %3d ", block->node.dfsnum);
122 fprintf (out, "[label=\"");
124 if (g_printoptions & OUT_PRINT_STRUCTURES)
125 print_structures (out, block);
127 if (g_printoptions & OUT_PRINT_DFS)
128 fprintf (out, "(%d) ", block->node.dfsnum);
130 if (g_printoptions & OUT_PRINT_RDFS)
131 fprintf (out, "(%d) ", block->revnode.dfsnum);
133 switch (block->type) {
134 case BLOCK_START: fprintf (out, "Start"); break;
135 case BLOCK_END: fprintf (out, "End"); break;
136 case BLOCK_CALL: fprintf (out, "Call"); break;
137 case BLOCK_SIMPLE: fprintf (out, "0x%08X-0x%08X",
138 block->info.simple.begin->address, block->info.simple.end->address);
140 if (block->status & BLOCK_STAT_HASLABEL) fprintf (out, "(*)");
141 fprintf (out, "\\l");
143 if (g_printoptions & OUT_PRINT_CODE)
144 print_block_code (out, block);
146 fprintf (out, "\"];\n");
149 if (g_printoptions & OUT_PRINT_DOMINATOR)
150 print_dominator (out, block, FALSE, "green");
152 if (g_printoptions & OUT_PRINT_RDOMINATOR)
153 print_dominator (out, block, TRUE, "yellow");
155 if (g_printoptions & OUT_PRINT_FRONTIER)
156 print_frontier (out, block, block->node.frontier, "orange");
158 if (g_printoptions & OUT_PRINT_RFRONTIER)
159 print_frontier (out, block, block->revnode.frontier, "blue");
162 if (list_size (block->outrefs) != 0) {
163 ref = list_head (block->outrefs);
164 while (ref) {
165 struct basicedge *edge;
166 struct basicblock *refblock;
167 edge = element_getvalue (ref);
168 refblock = edge->to;
169 fprintf (out, " %3d -> %3d ", block->node.dfsnum, refblock->node.dfsnum);
170 if (ref != list_head (block->outrefs))
171 fprintf (out, "[arrowtail=dot]");
173 if (element_getvalue (refblock->node.parent->blockel) == block) {
174 fprintf (out, "[style=bold]");
175 } else if (block->node.dfsnum >= refblock->node.dfsnum) {
176 fprintf (out, "[color=red]");
178 if (g_printoptions & OUT_PRINT_EDGE_TYPES) {
179 fprintf (out, "[label=\"");
180 switch (edge->type) {
181 case EDGE_UNKNOWN: fprintf (out, "UNK"); break;
182 case EDGE_CONTINUE: fprintf (out, "CONTINUE"); break;
183 case EDGE_BREAK: fprintf (out, "BREAK"); break;
184 case EDGE_NEXT: fprintf (out, "NEXT"); break;
185 case EDGE_INVALID: fprintf (out, "INVALID"); break;
186 case EDGE_GOTO: fprintf (out, "GOTO"); break;
187 case EDGE_CASE: fprintf (out, "CASE"); break;
188 case EDGE_IFENTER: fprintf (out, "IFENTER"); break;
189 case EDGE_IFEXIT: fprintf (out, "IFEXIT"); break;
190 case EDGE_RETURN: fprintf (out, "RETURN"); break;
192 fprintf (out, "\"]");
194 fprintf (out, " ;\n");
195 ref = element_next (ref);
198 el = element_next (el);
200 fprintf (out, "}\n");
204 int print_graph (struct code *c, char *prxname)
206 char buffer[128];
207 char basename[32];
208 element el;
209 FILE *fp;
210 int ret = 1;
212 get_base_name (prxname, basename, sizeof (basename));
214 el = list_head (c->subroutines);
215 while (el) {
216 struct subroutine *sub = element_getvalue (el);
217 if (!sub->haserror && !sub->import) {
218 if (sub->export) {
219 if (sub->export->name) {
220 sprintf (buffer, "%s_%-.64s.dot", basename, sub->export->name);
221 } else
222 sprintf (buffer, "%s_nid_%08X.dot", basename, sub->export->nid);
223 } else
224 sprintf (buffer, "%s_%08X.dot", basename, sub->begin->address);
225 fp = fopen (buffer, "w");
226 if (!fp) {
227 xerror (__FILE__ ": can't open file for writing `%s'", buffer);
228 ret = 0;
229 } else {
230 print_subroutine_graph (fp, c, sub);
231 fclose (fp);
233 } else {
234 if (sub->haserror) report ("Skipping subroutine at 0x%08X\n", sub->begin->address);
236 el = element_next (el);
239 return ret;