2 * Author: Humberto Naves (hsnaves@gmail.com)
9 struct ctrlstruct
*alloc_ctrlstruct (struct basicblock
*block
, enum ctrltype type
)
11 struct ctrlstruct
*st
= fixedpool_alloc (block
->sub
->code
->ctrlspool
);
18 int mark_backward (struct basicblock
*start
, list worklist
, int num
)
20 struct basicblock
*block
;
24 while (list_size (worklist
) != 0) {
25 block
= list_removetail (worklist
);
26 if (block
->mark1
== num
) continue;
30 ref
= list_head (block
->inrefs
);
32 struct basicedge
*edge
= element_getvalue (ref
);
33 struct basicblock
*next
= edge
->from
;
34 ref
= element_next (ref
);
36 if (next
->node
.dfsnum
< start
->node
.dfsnum
)
39 if (next
->node
.dfsnum
>= block
->node
.dfsnum
)
40 if (!dom_isancestor (&block
->node
, &next
->node
) ||
41 !dom_isancestor (&block
->revnode
, &next
->revnode
))
44 if (next
->mark1
!= num
) {
45 list_inserthead (worklist
, next
);
54 void mark_forward (struct basicblock
*start
, struct ctrlstruct
*loop
, int num
, int count
)
58 el
= start
->node
.blockel
;
60 struct basicblock
*block
= element_getvalue (el
);
61 if (block
->mark1
== num
) {
62 block
->loopst
= loop
; count
--;
63 ref
= list_head (block
->outrefs
);
65 struct basicedge
*edge
= element_getvalue (ref
);
66 struct basicblock
*next
= edge
->to
;
67 if (next
->mark1
!= num
) {
68 /* edge->type = EDGE_GOTO;
69 next->status |= BLOCK_STAT_HASLABEL; */
70 if (!loop
->end
) loop
->end
= next
;
71 if (list_size (loop
->end
->inrefs
) < list_size (next
->inrefs
))
74 ref
= element_next (ref
);
78 el
= element_next (el
);
83 void mark_loop (struct ctrlstruct
*loop
, int num
)
89 worklist
= list_alloc (loop
->start
->sub
->code
->lstpool
);
90 el
= list_head (loop
->info
.loopctrl
.edges
);
92 struct basicedge
*edge
= element_getvalue (el
);
93 struct basicblock
*block
= edge
->from
;
95 list_inserttail (worklist
, block
);
96 el
= element_next (el
);
98 count
= mark_backward (loop
->start
, worklist
, num
);
100 mark_forward (loop
->start
, loop
, num
, count
);
102 /* loop->end->status &= ~BLOCK_STAT_HASLABEL; */
103 el
= list_head (loop
->end
->inrefs
);
105 struct basicedge
*edge
= element_getvalue (el
);
106 if (edge
->from
->loopst
== loop
)
107 edge
->type
= EDGE_BREAK
;
108 el
= element_next (el
);
112 list_free (worklist
);
116 void extract_loops (struct subroutine
*sub
)
118 struct basicblock
*block
;
119 struct basicedge
*edge
;
120 struct ctrlstruct
*loop
;
124 el
= list_head (sub
->dfsblocks
);
126 block
= element_getvalue (el
);
129 ref
= list_head (block
->inrefs
);
131 edge
= element_getvalue (ref
);
132 if (edge
->from
->node
.dfsnum
>= block
->node
.dfsnum
) {
133 edge
->type
= EDGE_CONTINUE
;
134 if (!dom_isancestor (&block
->node
, &edge
->from
->node
)) {
135 error (__FILE__
": graph of sub 0x%08X is not reducible (using goto)", sub
->begin
->address
);
136 edge
->type
= EDGE_INVALID
;
137 edge
->to
->status
|= BLOCK_STAT_HASLABEL
;
138 } else if (block
->loopst
== edge
->from
->loopst
) {
140 loop
= alloc_ctrlstruct (block
, CONTROL_LOOP
);
141 loop
->info
.loopctrl
.edges
= list_alloc (sub
->code
->lstpool
);
143 list_inserttail (loop
->info
.loopctrl
.edges
, edge
);
145 edge->type = EDGE_GOTO;
146 edge->to->status |= BLOCK_STAT_HASLABEL;
149 ref
= element_next (ref
);
152 mark_loop (loop
, ++num
);
153 el
= element_next (el
);
158 void extract_returns (struct subroutine
*sub
)
164 int struct_isancestor (struct ctrlstruct
*ancestor
, struct ctrlstruct
*st
)
167 if (st
== ancestor
) return TRUE
;
174 void structure_search (struct basicblock
*block
, struct ctrlstruct
*parentst
, int blockcond
)
176 block
->st
= parentst
;
178 block
->blockcond
= blockcond
;
181 if (block
->loopst
->start
== block
) {
182 block
->st
= block
->loopst
;
183 block
->st
->parent
= parentst
;
184 block
->st
->identsize
= parentst
->identsize
+ 1;
188 if (block
->status
& BLOCK_STAT_ISSWITCH
) {
189 struct ctrlstruct
*nst
;
192 nst
= alloc_ctrlstruct (block
, CONTROL_SWITCH
);
193 nst
->end
= element_getvalue (block
->revnode
.dominator
->blockel
);
194 nst
->parent
= block
->st
;
195 nst
->identsize
= block
->st
->identsize
+ 1;
198 ref
= list_head (block
->outrefs
);
200 struct basicedge
*edge
= element_getvalue (ref
);
202 if (edge
->type
== EDGE_UNKNOWN
) {
203 edge
->type
= EDGE_CASE
;
204 if (!edge
->to
->mark1
) {
205 structure_search (edge
->to
, nst
, edge
->fromnum
);
207 if (edge
->to
->st
!= nst
) {
208 edge
->type
= EDGE_GOTO
;
209 edge
->to
->status
|= BLOCK_STAT_HASLABEL
;
213 ref
= element_next (ref
);
215 } else if (list_size (block
->outrefs
) == 2) {
216 struct basicblock
*end
;
217 struct basicedge
*edge1
, *edge2
;
219 end
= element_getvalue (block
->revnode
.dominator
->blockel
);
220 edge1
= list_tailvalue (block
->outrefs
);
221 edge2
= list_headvalue (block
->outrefs
);
223 if (edge1
->to
!= end
) {
224 if (edge1
->to
->mark1
) {
225 edge1
->type
= EDGE_GOTO
;
226 edge1
->to
->status
|= BLOCK_STAT_HASLABEL
;
230 if (edge2
->to
!= end
) {
231 if (edge2
->to
->mark1
) {
232 edge2
->type
= EDGE_GOTO
;
233 edge2
->to
->status
|= BLOCK_STAT_HASLABEL
;
237 if (edge1
->type
== EDGE_UNKNOWN
&& edge2
->type
== EDGE_UNKNOWN
) {
238 struct ctrlstruct
*nst
= alloc_ctrlstruct (block
, CONTROL_IF
);
240 nst
->parent
= block
->st
;
241 nst
->identsize
= block
->st
->identsize
+ 1;
245 nst
->info
.ifctrl
.endfollow
= TRUE
;
248 if (!struct_isancestor (end
->st
, block
->st
)) {
249 nst
->hasendgoto
= TRUE
;
250 end
->status
|= BLOCK_STAT_HASLABEL
;
254 if (edge1
->to
== end
) {
255 edge1
->type
= EDGE_IFEXIT
;
257 edge1
->type
= EDGE_IFENTER
;
258 structure_search (edge1
->to
, nst
, TRUE
);
261 if (edge2
->to
== end
) {
262 edge2
->type
= EDGE_IFEXIT
;
264 if (edge2
->to
->mark1
) {
265 edge2
->type
= EDGE_GOTO
;
266 edge2
->to
->status
|= BLOCK_STAT_HASLABEL
;
268 edge2
->type
= EDGE_IFENTER
;
269 structure_search (edge2
->to
, nst
, FALSE
);
273 if (edge2
->type
!= EDGE_IFEXIT
) {
274 if (edge1
->type
== EDGE_IFEXIT
)
275 block
->status
|= BLOCK_STAT_REVCOND
;
277 block
->status
|= BLOCK_STAT_HASELSE
;
280 if (nst
->info
.ifctrl
.endfollow
) {
282 structure_search (end
, block
->st
, blockcond
);
285 } else if (edge1
->type
== EDGE_UNKNOWN
|| edge2
->type
== EDGE_UNKNOWN
) {
286 struct basicedge
*edge
;
288 if (edge1
->type
== EDGE_UNKNOWN
) {
289 block
->status
|= BLOCK_STAT_REVCOND
;
295 if (edge
->to
== block
->st
->end
&& block
->st
->type
== CONTROL_IF
) {
296 edge
->type
= EDGE_IFEXIT
;
298 if (edge
->to
->mark1
) {
299 edge
->type
= EDGE_GOTO
;
300 edge
->to
->status
|= BLOCK_STAT_HASLABEL
;
302 edge
->type
= EDGE_NEXT
;
303 structure_search (edge
->to
, block
->st
, blockcond
);
308 struct basicedge
*edge
;
309 edge
= list_headvalue (block
->outrefs
);
311 if (edge
->type
== EDGE_UNKNOWN
) {
312 if (edge
->to
== block
->st
->end
&& block
->st
->type
== CONTROL_IF
) {
313 edge
->type
= EDGE_IFEXIT
;
315 if (edge
->to
->mark1
) {
316 edge
->type
= EDGE_GOTO
;
317 edge
->to
->status
|= BLOCK_STAT_HASLABEL
;
319 edge
->type
= EDGE_NEXT
;
320 structure_search (edge
->to
, block
->st
, blockcond
);
328 if (block
->loopst
->start
== block
&& block
->loopst
->end
) {
329 if (block
->loopst
->end
->mark1
) {
330 block
->loopst
->hasendgoto
= TRUE
;
331 block
->loopst
->end
->status
|= BLOCK_STAT_HASLABEL
;
333 structure_search (block
->loopst
->end
, parentst
, blockcond
);
339 void reset_marks (struct subroutine
*sub
)
341 element el
= list_head (sub
->blocks
);
343 struct basicblock
*block
= element_getvalue (el
);
344 block
->mark1
= block
->mark2
= 0;
345 el
= element_next (el
);
349 void extract_structures (struct subroutine
*sub
)
352 struct ctrlstruct
*st
= fixedpool_alloc (sub
->code
->ctrlspool
);
354 st
->type
= CONTROL_MAIN
;
355 st
->start
= sub
->startblock
;
356 st
->end
= sub
->endblock
;
361 extract_returns (sub
);
364 el
= list_head (sub
->blocks
);
366 struct basicblock
*block
= element_getvalue (el
);
368 structure_search (block
, st
, 0);
369 el
= element_next (el
);