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_step (struct basicblock
*block
)
161 struct basicedge
*edge
;
163 block
->status
&= ~BLOCK_STAT_HASLABEL
;
164 ref
= list_head (block
->inrefs
);
166 edge
= element_getvalue (ref
);
167 edge
->type
= EDGE_RETURN
;
168 if (list_size (edge
->from
->outrefs
) == 1) {
169 extract_returns_step (edge
->from
);
171 ref
= element_next (ref
);
176 void extract_returns (struct subroutine
*sub
)
178 extract_returns_step (sub
->endblock
);
182 void structure_search (struct basicblock
*block
, struct ctrlstruct
*parentst
, int blockcond
)
184 block
->st
= parentst
;
186 block
->blockcond
= blockcond
;
189 if (block
->loopst
->start
== block
) {
190 if (block
->loopst
->end
) {
191 if (block
->loopst
->end
->mark1
) {
192 if (parentst
->end
!= block
->loopst
->end
) {
193 block
->loopst
->hasendgoto
= TRUE
;
194 block
->loopst
->end
->status
|= BLOCK_STAT_HASLABEL
;
197 block
->loopst
->endfollow
= TRUE
;
198 structure_search (block
->loopst
->end
, parentst
, blockcond
);
202 block
->st
= block
->loopst
;
203 block
->st
->parent
= parentst
;
204 block
->st
->identsize
= parentst
->identsize
+ 1;
208 if (block
->status
& BLOCK_STAT_ISSWITCH
) {
209 struct ctrlstruct
*nst
;
212 nst
= alloc_ctrlstruct (block
, CONTROL_SWITCH
);
213 nst
->end
= element_getvalue (block
->revnode
.dominator
->blockel
);
214 nst
->parent
= block
->st
;
215 nst
->identsize
= block
->st
->identsize
+ 1;
218 ref
= list_head (block
->outrefs
);
220 struct basicedge
*edge
= element_getvalue (ref
);
222 if (edge
->type
== EDGE_UNKNOWN
) {
223 edge
->type
= EDGE_CASE
;
224 if (!edge
->to
->mark1
) {
225 structure_search (edge
->to
, nst
, edge
->fromnum
);
227 if (edge
->to
->st
!= nst
) {
228 edge
->type
= EDGE_GOTO
;
229 edge
->to
->status
|= BLOCK_STAT_HASLABEL
;
233 ref
= element_next (ref
);
235 } else if (list_size (block
->outrefs
) == 2) {
236 struct basicblock
*end
;
237 struct basicedge
*edge1
, *edge2
;
239 end
= element_getvalue (block
->revnode
.dominator
->blockel
);
240 edge1
= list_tailvalue (block
->outrefs
);
241 edge2
= list_headvalue (block
->outrefs
);
243 if (edge1
->to
!= end
&& edge1
->to
->mark1
&& edge1
->type
== EDGE_UNKNOWN
) {
244 edge1
->type
= EDGE_GOTO
;
245 edge1
->to
->status
|= BLOCK_STAT_HASLABEL
;
248 if (edge2
->to
!= end
&& edge2
->to
->mark1
&& edge2
->type
== EDGE_UNKNOWN
) {
249 edge2
->type
= EDGE_GOTO
;
250 edge2
->to
->status
|= BLOCK_STAT_HASLABEL
;
253 if (edge1
->type
== EDGE_UNKNOWN
&& edge2
->type
== EDGE_UNKNOWN
) {
254 struct ctrlstruct
*nst
= alloc_ctrlstruct (block
, CONTROL_IF
);
256 nst
->parent
= block
->st
;
257 nst
->identsize
= block
->st
->identsize
+ 1;
261 nst
->endfollow
= TRUE
;
264 if (block
->st
->end
!= end
) {
265 nst
->hasendgoto
= TRUE
;
266 end
->status
|= BLOCK_STAT_HASLABEL
;
270 if (edge1
->to
== end
) {
271 edge1
->type
= EDGE_IFEXIT
;
273 edge1
->type
= EDGE_IFENTER
;
274 structure_search (edge1
->to
, nst
, TRUE
);
277 if (edge2
->to
== end
) {
278 edge2
->type
= EDGE_IFEXIT
;
280 if (edge2
->to
->mark1
) {
281 edge2
->type
= EDGE_GOTO
;
282 edge2
->to
->status
|= BLOCK_STAT_HASLABEL
;
284 edge2
->type
= EDGE_IFENTER
;
285 structure_search (edge2
->to
, nst
, FALSE
);
289 if (edge2
->type
!= EDGE_IFEXIT
) {
290 if (edge1
->type
== EDGE_IFEXIT
)
291 block
->status
|= BLOCK_STAT_REVCOND
;
293 block
->status
|= BLOCK_STAT_HASELSE
;
296 if (nst
->endfollow
) {
298 structure_search (end
, block
->st
, blockcond
);
301 } else if (edge1
->type
== EDGE_UNKNOWN
|| edge2
->type
== EDGE_UNKNOWN
) {
302 struct basicedge
*edge
;
304 if (edge1
->type
== EDGE_UNKNOWN
) {
305 block
->status
|= BLOCK_STAT_REVCOND
;
311 if (edge
->to
== block
->st
->end
&& block
->st
->type
== CONTROL_IF
) {
312 edge
->type
= EDGE_IFEXIT
;
314 if (edge
->to
->mark1
) {
315 edge
->type
= EDGE_GOTO
;
316 edge
->to
->status
|= BLOCK_STAT_HASLABEL
;
318 edge
->type
= EDGE_NEXT
;
319 structure_search (edge
->to
, block
->st
, blockcond
);
324 struct basicedge
*edge
;
325 edge
= list_headvalue (block
->outrefs
);
327 if (edge
->type
== EDGE_UNKNOWN
) {
328 if (edge
->to
== block
->st
->end
&& block
->st
->type
== CONTROL_IF
) {
329 edge
->type
= EDGE_IFEXIT
;
331 if (edge
->to
->mark1
) {
332 edge
->type
= EDGE_GOTO
;
333 edge
->to
->status
|= BLOCK_STAT_HASLABEL
;
335 edge
->type
= EDGE_NEXT
;
336 structure_search (edge
->to
, block
->st
, blockcond
);
344 void reset_marks (struct subroutine
*sub
)
346 element el
= list_head (sub
->blocks
);
348 struct basicblock
*block
= element_getvalue (el
);
349 block
->mark1
= block
->mark2
= 0;
350 el
= element_next (el
);
354 void extract_structures (struct subroutine
*sub
)
357 struct ctrlstruct
*st
= fixedpool_alloc (sub
->code
->ctrlspool
);
359 st
->type
= CONTROL_MAIN
;
360 st
->start
= sub
->startblock
;
361 st
->end
= sub
->endblock
;
366 /* extract_returns (sub); */
369 el
= list_head (sub
->blocks
);
371 struct basicblock
*block
= element_getvalue (el
);
373 structure_search (block
, st
, 0);
374 el
= element_next (el
);