8 void print_structures (FILE *out
, struct basicblock
*block
)
11 fprintf (out
, "LOOP start %d", block
->loopst
->start
->node
.dfsnum
);
12 if (block
->loopst
->end
)
13 fprintf (out
, " end %d", block
->loopst
->end
->node
.dfsnum
);
20 fprintf (out
, " end %d", block
->st
->end
->node
.dfsnum
);
26 void print_block_code (FILE *out
, struct basicblock
*block
)
28 if (block
->type
== BLOCK_SIMPLE
) {
30 for (loc
= block
->info
.simple
.begin
; ; loc
++) {
31 fprintf (out
, "%s\\l", allegrex_disassemble (loc
->opc
, loc
->address
, FALSE
));
32 if (loc
== block
->info
.simple
.end
) break;
38 void print_block_phis (FILE *out
, struct basicblock
*block
)
41 opsel
= list_head (block
->operations
);
43 struct operation
*op
= element_getvalue (opsel
);
44 int count1
= 0, count2
= 0;
46 if (op
->type
!= OP_START
&& op
->type
!= OP_END
) {
47 argel
= list_head (op
->results
);
49 struct value
*val
= element_getvalue (argel
);
50 if (val
->type
!= VAL_CONSTANT
) {
51 if (count1
++ == 0) fprintf (out
, "<");
52 print_value (out
, val
);
55 argel
= element_next (argel
);
57 if (count1
> 0) fprintf (out
, "> = ");
59 if (op
->type
== OP_PHI
) {
62 argel
= list_head (op
->operands
);
64 struct value
*val
= element_getvalue (argel
);
65 if (val
->type
!= VAL_CONSTANT
) {
66 if (count2
++ == 0) fprintf (out
, "<");
67 print_value (out
, val
);
70 argel
= element_next (argel
);
72 if (count2
> 0) fprintf (out
, ">");
73 if (count1
|| count2
) fprintf (out
, "\\l");
75 opsel
= element_next (opsel
);
80 void print_dominator (FILE *out
, struct basicblock
*block
, int reverse
, const char *color
)
82 struct basicblock
*dominator
;
85 if (list_size (block
->outrefs
) <= 1) return;
86 dominator
= element_getvalue (block
->revnode
.dominator
->blockel
);
88 if (list_size (block
->inrefs
) <= 1) return;
89 dominator
= element_getvalue (block
->node
.dominator
->blockel
);
91 fprintf (out
, " %3d -> %3d [color=%s];\n",
92 block
->node
.dfsnum
, dominator
->node
.dfsnum
, color
);
96 void print_frontier (FILE *out
, struct basicblock
*block
, list frontier
, const char *color
)
99 if (list_size (frontier
) == 0) return;
101 fprintf (out
, " %3d -> { ", block
->node
.dfsnum
);
102 ref
= list_head (frontier
);
104 struct basicblocknode
*refnode
;
105 struct basicblock
*refblock
;
107 refnode
= element_getvalue (ref
);
108 refblock
= element_getvalue (refnode
->blockel
);
110 fprintf (out
, "%3d ", refblock
->node
.dfsnum
);
111 ref
= element_next (ref
);
113 fprintf (out
, " } [color=%s];\n", color
);
117 void print_subroutine_graph (FILE *out
, struct code
*c
, struct subroutine
*sub
, int options
)
119 struct basicblock
*block
;
122 fprintf (out
, "digraph ");
123 print_subroutine_name (out
, sub
);
124 fprintf (out
, " {\n rankdir=LR;\n");
126 el
= list_head (sub
->blocks
);
129 block
= element_getvalue (el
);
131 fprintf (out
, " %3d ", block
->node
.dfsnum
);
132 fprintf (out
, "[label=\"");
134 if (options
& OUT_PRINT_STRUCTURES
)
135 print_structures (out
, block
);
137 if (options
& OUT_PRINT_DFS
)
138 fprintf (out
, "(%d) ", block
->node
.dfsnum
);
140 if (options
& OUT_PRINT_RDFS
)
141 fprintf (out
, "(%d) ", block
->revnode
.dfsnum
);
143 switch (block
->type
) {
144 case BLOCK_START
: fprintf (out
, "Start"); break;
145 case BLOCK_END
: fprintf (out
, "End"); break;
146 case BLOCK_CALL
: fprintf (out
, "Call"); break;
147 case BLOCK_SIMPLE
: fprintf (out
, "0x%08X-0x%08X",
148 block
->info
.simple
.begin
->address
, block
->info
.simple
.end
->address
);
150 if (block
->haslabel
) fprintf (out
, "(*)");
151 fprintf (out
, "\\l");
153 if (options
& OUT_PRINT_PHIS
)
154 print_block_phis (out
, block
);
156 if (options
& OUT_PRINT_CODE
)
157 print_block_code (out
, block
);
159 fprintf (out
, "\"];\n");
162 if (options
& OUT_PRINT_DOMINATOR
)
163 print_dominator (out
, block
, FALSE
, "green");
165 if (options
& OUT_PRINT_RDOMINATOR
)
166 print_dominator (out
, block
, TRUE
, "yellow");
168 if (options
& OUT_PRINT_FRONTIER
)
169 print_frontier (out
, block
, block
->node
.frontier
, "orange");
171 if (options
& OUT_PRINT_RFRONTIER
)
172 print_frontier (out
, block
, block
->revnode
.frontier
, "blue");
175 if (list_size (block
->outrefs
) != 0) {
176 ref
= list_head (block
->outrefs
);
178 struct basicedge
*edge
;
179 struct basicblock
*refblock
;
180 edge
= element_getvalue (ref
);
182 fprintf (out
, " %3d -> %3d ", block
->node
.dfsnum
, refblock
->node
.dfsnum
);
183 if (ref
!= list_head (block
->outrefs
))
184 fprintf (out
, "[arrowtail=dot]");
186 if (element_getvalue (refblock
->node
.parent
->blockel
) == block
) {
187 fprintf (out
, "[style=bold]");
188 } else if (block
->node
.dfsnum
>= refblock
->node
.dfsnum
) {
189 fprintf (out
, "[color=red]");
191 if (options
& OUT_PRINT_EDGE_TYPES
) {
192 fprintf (out
, "[label=\"");
193 switch (edge
->type
) {
194 case EDGE_UNKNOWN
: fprintf (out
, "UNK"); break;
195 case EDGE_CONTINUE
: fprintf (out
, "CONTINUE"); break;
196 case EDGE_BREAK
: fprintf (out
, "BREAK"); break;
197 case EDGE_FOLLOW
: fprintf (out
, "FOLLOW"); break;
198 case EDGE_GOTO
: fprintf (out
, "GOTO"); break;
199 case EDGE_IFEXIT
: fprintf (out
, "IFEXIT"); break;
201 fprintf (out
, "\"]");
203 fprintf (out
, " ;\n");
204 ref
= element_next (ref
);
207 el
= element_next (el
);
209 fprintf (out
, "}\n");
213 int print_graph (struct code
*c
, char *prxname
, int options
)
221 get_base_name (prxname
, basename
, sizeof (basename
));
223 el
= list_head (c
->subroutines
);
225 struct subroutine
*sub
= element_getvalue (el
);
226 if (!sub
->haserror
&& !sub
->import
) {
228 if (sub
->export
->name
) {
229 sprintf (buffer
, "%s_%-.64s.dot", basename
, sub
->export
->name
);
231 sprintf (buffer
, "%s_nid_%08X.dot", basename
, sub
->export
->nid
);
233 sprintf (buffer
, "%s_%08X.dot", basename
, sub
->begin
->address
);
234 fp
= fopen (buffer
, "w");
236 xerror (__FILE__
": can't open file for writing `%s'", buffer
);
239 print_subroutine_graph (fp
, c
, sub
, options
);
243 if (sub
->haserror
) report ("Skipping subroutine at 0x%08X\n", sub
->begin
->address
);
245 el
= element_next (el
);