2 * Author: Humberto Naves (hsnaves@gmail.com)
11 void print_structures (FILE *out
, struct basicblock
*block
)
13 struct ctrlstruct
*st
= block
->st
;
19 fprintf (out
, "IF start %d end %d %s\\l", st
->start
->node
.dfsnum
,
20 st
->end
->node
.dfsnum
, block
->blockcond
? "TRUE" : "FALSE");
23 fprintf (out
, "MAIN\\l");
26 fprintf (out
, "LOOP start %d\\l", st
->start
->node
.dfsnum
);
29 fprintf (out
, "SWITCH start %d end %d %d\\l", st
->start
->node
.dfsnum
,
30 st
->end
->node
.dfsnum
, block
->blockcond
);
34 if (++count
> 100) break;
39 void print_block_code (FILE *out
, struct basicblock
*block
)
41 if (block
->type
== BLOCK_SIMPLE
) {
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;
51 void print_block_phis (FILE *out
, struct basicblock
*block
)
54 opsel
= list_head (block
->operations
);
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
);
62 struct value
*val
= element_getvalue (argel
);
63 if (val
->type
!= VAL_CONSTANT
) {
64 if (count1
++ == 0) fprintf (out
, "<");
65 print_value (out
, val
);
68 argel
= element_next (argel
);
70 if (count1
> 0) fprintf (out
, "> = ");
72 if (op
->type
== OP_PHI
) {
75 argel
= list_head (op
->operands
);
77 struct value
*val
= element_getvalue (argel
);
78 if (val
->type
!= VAL_CONSTANT
) {
79 if (count2
++ == 0) fprintf (out
, "<");
80 print_value (out
, val
);
83 argel
= element_next (argel
);
85 if (count2
> 0) fprintf (out
, ">");
86 if (count1
|| count2
) fprintf (out
, "\\l");
88 opsel
= element_next (opsel
);
93 void print_dominator (FILE *out
, struct basicblock
*block
, int reverse
, const char *color
)
95 struct basicblock
*dominator
;
98 if (list_size (block
->outrefs
) <= 1) return;
99 dominator
= element_getvalue (block
->revnode
.dominator
->blockel
);
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
);
109 void print_frontier (FILE *out
, struct basicblock
*block
, list frontier
, const char *color
)
112 if (list_size (frontier
) == 0) return;
114 fprintf (out
, " %3d -> { ", block
->node
.dfsnum
);
115 ref
= list_head (frontier
);
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
);
130 void print_subroutine_graph (FILE *out
, struct code
*c
, struct subroutine
*sub
, int options
)
132 struct basicblock
*block
;
135 fprintf (out
, "digraph ");
136 print_subroutine_name (out
, sub
);
137 fprintf (out
, " {\n rankdir=LR;\n");
139 el
= list_head (sub
->blocks
);
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
);
191 struct basicedge
*edge
;
192 struct basicblock
*refblock
;
193 edge
= element_getvalue (ref
);
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
)
237 get_base_name (prxname
, basename
, sizeof (basename
));
239 el
= list_head (c
->subroutines
);
241 struct subroutine
*sub
= element_getvalue (el
);
242 if (!sub
->haserror
&& !sub
->import
) {
244 if (sub
->export
->name
) {
245 sprintf (buffer
, "%s_%-.64s.dot", basename
, sub
->export
->name
);
247 sprintf (buffer
, "%s_nid_%08X.dot", basename
, sub
->export
->nid
);
249 sprintf (buffer
, "%s_%08X.dot", basename
, sub
->begin
->address
);
250 fp
= fopen (buffer
, "w");
252 xerror (__FILE__
": can't open file for writing `%s'", buffer
);
255 print_subroutine_graph (fp
, c
, sub
, options
);
259 if (sub
->haserror
) report ("Skipping subroutine at 0x%08X\n", sub
->begin
->address
);
261 el
= element_next (el
);