6 struct basicblock
*alloc_block (struct subroutine
*sub
)
8 struct basicblock
*block
;
9 block
= fixedpool_alloc (sub
->code
->blockspool
);
11 block
->inrefs
= list_alloc (sub
->code
->lstpool
);
12 block
->outrefs
= list_alloc (sub
->code
->lstpool
);
13 block
->node
.children
= list_alloc (sub
->code
->lstpool
);
14 block
->revnode
.children
= list_alloc (sub
->code
->lstpool
);
15 block
->node
.domchildren
= list_alloc (sub
->code
->lstpool
);
16 block
->revnode
.domchildren
= list_alloc (sub
->code
->lstpool
);
17 block
->node
.frontier
= list_alloc (sub
->code
->lstpool
);
18 block
->revnode
.frontier
= list_alloc (sub
->code
->lstpool
);
25 void extract_blocks (struct subroutine
*sub
)
27 struct location
*begin
, *next
;
28 struct basicblock
*block
;
29 int prevlikely
= FALSE
;
31 sub
->blocks
= list_alloc (sub
->code
->lstpool
);
32 sub
->revdfsblocks
= list_alloc (sub
->code
->lstpool
);
33 sub
->dfsblocks
= list_alloc (sub
->code
->lstpool
);
35 block
= alloc_block (sub
);
36 block
->blockel
= list_inserttail (sub
->blocks
, block
);
37 block
->type
= BLOCK_START
;
38 sub
->startblock
= block
;
43 block
= alloc_block (sub
);
44 block
->blockel
= list_inserttail (sub
->blocks
, block
);
49 block
->type
= BLOCK_SIMPLE
;
50 block
->info
.simple
.begin
= begin
;
52 for (; next
!= sub
->end
; next
++) {
58 if (next
->references
&& (next
!= begin
)) {
63 if (next
->insn
->flags
& (INSN_JUMP
| INSN_BRANCH
)) {
64 block
->info
.simple
.jumploc
= next
;
65 if (next
->insn
->flags
& INSN_BRANCHLIKELY
)
67 if (!(next
->insn
->flags
& INSN_BRANCHLIKELY
) &&
68 !next
[1].references
&& location_branch_may_swap (next
)) {
74 block
->info
.simple
.end
= next
;
78 } while (begin
++ != next
);
81 while (next
++ != sub
->end
) {
82 if (next
->reachable
== LOCATION_DELAY_SLOT
) {
87 } else if (next
->reachable
== LOCATION_REACHABLE
) {
88 if (next
!= &block
->info
.simple
.end
[1])
95 block
->type
= BLOCK_END
;
96 sub
->endblock
= block
;
101 void make_link (struct basicblock
*from
, struct basicblock
*to
)
103 struct basicedge
*edge
= fixedpool_alloc (from
->sub
->code
->edgespool
);
106 edge
->fromnum
= list_size (from
->outrefs
);
108 edge
->tonum
= list_size (to
->inrefs
);
110 edge
->fromel
= list_inserttail (from
->outrefs
, edge
);
111 edge
->toel
= list_inserttail (to
->inrefs
, edge
);
115 struct basicblock
*make_link_and_insert (struct basicblock
*from
, struct basicblock
*to
, element el
)
117 struct basicblock
*block
= alloc_block (from
->sub
);
118 block
->blockel
= element_alloc (from
->sub
->code
->lstpool
, block
);
119 element_insertbefore (el
, block
->blockel
);
120 make_link (from
, block
);
121 make_link (block
, to
);
126 void make_call (struct basicblock
*block
, struct location
*loc
)
128 block
->type
= BLOCK_CALL
;
130 block
->info
.call
.calltarget
= loc
->target
->sub
;
131 list_inserttail (loc
->target
->sub
->whereused
, block
);
137 void link_blocks (struct subroutine
*sub
)
139 struct basicblock
*block
, *next
;
140 struct basicblock
*target
;
141 struct location
*loc
;
144 el
= list_head (sub
->blocks
);
147 block
= element_getvalue (el
);
148 if (block
->type
== BLOCK_END
) break;
149 if (block
->type
== BLOCK_START
) {
150 el
= element_next (el
);
151 make_link (block
, element_getvalue (el
));
155 el
= element_next (el
);
156 next
= element_getvalue (el
);
159 if (block
->info
.simple
.jumploc
) {
160 loc
= block
->info
.simple
.jumploc
;
161 if (loc
->insn
->flags
& INSN_BRANCH
) {
162 if (!loc
->branchalways
) {
163 if (loc
->insn
->flags
& INSN_BRANCHLIKELY
) {
164 make_link (block
, loc
[2].block
);
166 make_link (block
, next
);
170 if (loc
== block
->info
.simple
.end
) {
171 struct basicblock
*slot
= alloc_block (sub
);
172 slot
->blockel
= element_alloc (sub
->code
->lstpool
, slot
);
173 element_insertbefore (el
, slot
->blockel
);
175 slot
->type
= BLOCK_SIMPLE
;
176 slot
->info
.simple
.begin
= &block
->info
.simple
.end
[1];
177 slot
->info
.simple
.end
= slot
->info
.simple
.begin
;
178 make_link (block
, slot
);
182 if (loc
->insn
->flags
& INSN_LINK
) {
183 target
= make_link_and_insert (block
, loc
[2].block
, el
);
184 make_call (target
, loc
);
185 } else if (loc
->target
->sub
->begin
== loc
->target
) {
186 target
= make_link_and_insert (block
, sub
->endblock
, el
);
187 make_call (target
, loc
);
189 make_link (block
, loc
->target
->block
);
193 if (loc
->insn
->flags
& (INSN_LINK
| INSN_WRITE_GPR_D
)) {
194 target
= make_link_and_insert (block
, next
, el
);
195 make_call (target
, loc
);
198 if (loc
->target
->sub
->begin
== loc
->target
) {
199 target
= make_link_and_insert (block
, sub
->endblock
, el
);
200 make_call (target
, loc
);
202 make_link (block
, loc
->target
->block
);
206 if (loc
->cswitch
&& loc
->cswitch
->jumplocation
== loc
) {
207 ref
= list_head (loc
->cswitch
->references
);
209 struct location
*switchtarget
= element_getvalue (ref
);
210 make_link (block
, switchtarget
->block
);
211 ref
= element_next (ref
);
214 make_link (block
, sub
->endblock
);
219 make_link (block
, next
);
224 void extract_cfg (struct subroutine
*sub
)
226 extract_blocks (sub
);
228 if (!cfg_dfs (sub
, 0)) {
229 error (__FILE__
": unreachable code at subroutine 0x%08X", sub
->begin
->address
);
230 sub
->haserror
= TRUE
;
233 if (!cfg_dfs (sub
, 1)) {
234 error (__FILE__
": infinite loop at subroutine 0x%08X", sub
->begin
->address
);
235 sub
->haserror
= TRUE
;
239 cfg_dominance (sub
, 0);
240 cfg_frontier (sub
, 0);
242 cfg_dominance (sub
, 1);
243 cfg_frontier (sub
, 1);
248 void mark_backward (struct subroutine
*sub
, struct basicblock
*block
, int num
, int end
)
253 el
= block
->node
.blockel
;
254 while (el
&& count
) {
255 struct basicblock
*block
= element_getvalue (el
);
256 if (block
->node
.dfsnum
< end
) break;
257 if (block
->mark1
== num
) {
259 ref
= list_head (block
->inrefs
);
261 struct basicedge
*edge
= element_getvalue (ref
);
262 struct basicblock
*next
= edge
->from
;
263 if (next
->node
.dfsnum
>= end
&&
264 next
->node
.dfsnum
< block
->node
.dfsnum
) {
265 if (next
->mark1
!= num
) count
++;
268 ref
= element_next (ref
);
272 el
= element_previous (el
);
277 void mark_forward (struct subroutine
*sub
, struct basicblock
*block
,
278 struct loopstructure
*loop
, int num
, int end
)
282 el
= block
->node
.blockel
;
284 struct basicblock
*block
= element_getvalue (el
);
285 if (block
->node
.dfsnum
> end
) break;
286 if (block
->mark2
== num
) {
287 block
->loopst
= loop
;
288 ref
= list_head (block
->outrefs
);
290 struct basicedge
*edge
= element_getvalue (ref
);
291 struct basicblock
*next
= edge
->to
;
292 if (next
->node
.dfsnum
> block
->node
.dfsnum
) {
293 if (next
->mark1
== num
) next
->mark2
= num
;
295 if (!loop
->end
) loop
->end
= next
;
296 if (list_size (loop
->end
->inrefs
) < list_size (next
->inrefs
))
300 ref
= element_next (ref
);
304 el
= element_next (el
);
310 void mark_loop (struct subroutine
*sub
, struct loopstructure
*loop
)
313 int num
= ++sub
->temp
;
316 el
= list_head (loop
->edges
);
318 struct basicedge
*edge
= element_getvalue (el
);
319 struct basicblock
*block
= edge
->from
;
321 if (maxdfs
< block
->node
.dfsnum
)
322 maxdfs
= block
->node
.dfsnum
;
324 if (block
->mark1
!= num
) {
326 mark_backward (sub
, block
, num
, loop
->start
->node
.dfsnum
);
328 el
= element_next (el
);
331 loop
->start
->mark2
= num
;
332 mark_forward (sub
, loop
->start
, loop
, num
, maxdfs
);
335 el
= list_head (loop
->end
->inrefs
);
337 struct basicedge
*edge
= element_getvalue (el
);
338 struct basicblock
*block
= edge
->from
;
339 if (block
->loopst
== loop
)
340 edge
->type
= EDGE_BREAK
;
341 el
= element_next (el
);
347 void extract_loops (struct subroutine
*sub
)
349 struct basicblock
*block
;
350 struct basicedge
*edge
;
351 struct loopstructure
*loop
;
354 el
= list_head (sub
->dfsblocks
);
356 block
= element_getvalue (el
);
359 ref
= list_head (block
->inrefs
);
361 edge
= element_getvalue (ref
);
362 if (edge
->from
->node
.dfsnum
>= block
->node
.dfsnum
) {
363 edge
->type
= EDGE_CONTINUE
;
364 if (!dom_isancestor (&block
->node
, &edge
->from
->node
)) {
365 error (__FILE__
": graph of sub 0x%08X is not reducible (using goto)", sub
->begin
->address
);
366 edge
->type
= EDGE_GOTO
;
367 edge
->to
->haslabel
= TRUE
;
368 } else if (block
->loopst
== edge
->from
->loopst
||
369 dom_isancestor (&block
->revnode
, &edge
->from
->revnode
)) {
371 loop
= fixedpool_alloc (sub
->code
->loopspool
);
373 loop
->edges
= list_alloc (sub
->code
->lstpool
);
375 list_inserttail (loop
->edges
, edge
);
377 edge
->type
= EDGE_GOTO
;
378 edge
->to
->haslabel
= TRUE
;
381 ref
= element_next (ref
);
383 if (loop
) mark_loop (sub
, loop
);
384 el
= element_next (el
);
389 void extract_ifs (struct subroutine
*sub
)
391 struct basicblock
*block
;
392 struct ifstructure
*ifst
;
396 unresolved
= list_alloc (sub
->code
->lstpool
);
398 el
= list_tail (sub
->dfsblocks
);
400 int hasswitch
= FALSE
;
401 block
= element_getvalue (el
);
403 if (block
->type
== BLOCK_SIMPLE
) {
404 if (block
->info
.simple
.jumploc
) {
405 if (block
->info
.simple
.jumploc
->cswitch
)
410 if (list_size (block
->outrefs
) == 2 && !hasswitch
) {
411 struct basicedge
*edge1
, *edge2
;
413 ifst
= fixedpool_alloc (sub
->code
->ifspool
);
416 edge1
= list_headvalue (block
->outrefs
);
417 edge2
= list_tailvalue (block
->outrefs
);
418 if (edge1
->type
== EDGE_UNKNOWN
|| edge2
->type
== EDGE_UNKNOWN
) {
421 list_inserthead (unresolved
, block
);
422 domel
= list_head (block
->node
.domchildren
);
425 struct basicblocknode
*dom
= element_getvalue (domel
);
426 struct basicblock
*domblock
= element_getvalue (dom
->blockel
);
429 ref
= list_head (domblock
->inrefs
);
431 struct basicedge
*edge
= element_getvalue (ref
);
432 if (edge
->from
->node
.dfsnum
< domblock
->node
.dfsnum
)
434 ref
= element_next (ref
);
438 block
->ifst
->outermost
= TRUE
;
439 while (list_size (unresolved
) != 0) {
440 struct basicblock
*ifblock
= list_removehead (unresolved
);
441 ifblock
->ifst
->end
= domblock
;
445 domel
= element_next (domel
);
450 el
= element_previous (el
);
453 list_free (unresolved
);
457 void structure_search (struct basicblock
*block
, int identsize
, struct ifstructure
*ifst
)
459 struct basicedge
*edge
;
460 struct basicblock
*ifend
= NULL
;
467 if (block
->ifst
->end
)
468 ifend
= block
->ifst
->end
;
473 if (block
->loopst
->start
== block
) {
475 if (block
->loopst
->end
) {
476 if (!block
->loopst
->end
->mark1
)
477 structure_search (block
->loopst
->end
, identsize
- 1, ifst
);
479 block
->loopst
->end
->haslabel
= TRUE
;
480 block
->loopst
->hasendgoto
= TRUE
;
487 if (block
->ifst
->end
&& block
->ifst
->outermost
) {
488 if (!block
->ifst
->end
->mark1
)
489 structure_search (block
->ifst
->end
, identsize
, ifst
);
491 block
->ifst
->end
->haslabel
= TRUE
;
492 block
->ifst
->hasendgoto
= TRUE
;
497 block
->identsize
= identsize
;
499 ref
= list_head (block
->outrefs
);
501 edge
= element_getvalue (ref
);
502 if (edge
->type
== EDGE_UNKNOWN
) {
503 if (edge
->to
->loopst
!= block
->loopst
) {
504 if (edge
->to
->loopst
) {
505 if (edge
->to
->loopst
->start
!= edge
->to
) {
506 edge
->type
= EDGE_GOTO
;
507 edge
->to
->haslabel
= TRUE
;
510 edge
->type
= EDGE_GOTO
;
511 edge
->to
->haslabel
= TRUE
;
516 if (edge
->type
== EDGE_UNKNOWN
) {
517 if (edge
->to
== ifend
) {
518 edge
->type
= EDGE_IFEXIT
;
520 if (edge
->to
->mark1
) {
521 edge
->type
= EDGE_GOTO
;
522 edge
->to
->haslabel
= TRUE
;
524 edge
->type
= EDGE_FOLLOW
;
526 structure_search (edge
->to
, identsize
+ 1, block
->ifst
);
528 structure_search (edge
->to
, identsize
, ifst
);
533 ref
= element_next (ref
);
537 void reset_marks (struct subroutine
*sub
)
539 element el
= list_head (sub
->blocks
);
541 struct basicblock
*block
= element_getvalue (el
);
542 block
->mark1
= block
->mark2
= 0;
543 el
= element_next (el
);
547 void extract_structures (struct subroutine
*sub
)
559 el
= list_head (sub
->blocks
);
561 struct basicblock
*block
= element_getvalue (el
);
563 structure_search (block
, 0, NULL
);
564 el
= element_next (el
);