2 * Linearize - walk the statement tree (but _not_ the expressions)
3 * to generate a linear version of it and the basic blocks.
5 * NOTE! We're not interested in the actual sub-expressions yet,
6 * even though they can generate conditional branches and
7 * subroutine calls. That's all "local" behaviour.
9 * Copyright (C) 2004 Linus Torvalds
10 * Copyright (C) 2004 Christopher Li
19 #include "expression.h"
20 #include "linearize.h"
22 pseudo_t
linearize_statement(struct entrypoint
*ep
, struct statement
*stmt
);
23 pseudo_t
linearize_expression(struct entrypoint
*ep
, struct expression
*expr
);
25 static struct instruction
*alloc_instruction(int opcode
, struct symbol
*type
)
27 struct instruction
* insn
= __alloc_instruction(0);
29 insn
->opcode
= opcode
;
33 static struct entrypoint
*alloc_entrypoint(void)
35 return __alloc_entrypoint(0);
38 static struct basic_block
*alloc_basic_block(void)
40 return __alloc_basic_block(0);
43 static struct multijmp
* alloc_multijmp(struct basic_block
*target
, int begin
, int end
)
45 struct multijmp
*multijmp
= __alloc_multijmp(0);
46 multijmp
->target
= target
;
47 multijmp
->begin
= begin
;
52 static struct phi
* alloc_phi(struct basic_block
*source
, pseudo_t pseudo
)
54 struct phi
*phi
= __alloc_phi(0);
60 static void show_instruction(struct instruction
*insn
)
62 int op
= insn
->opcode
;
66 printf("\tAIEEE! (%d %d)\n", insn
->target
.nr
, insn
->src
.nr
);
69 printf("\tret %%r%d\n", insn
->src
.nr
);
72 if (insn
->bb_true
&& insn
->bb_false
) {
73 printf("\tbr\t%%r%d, .L%p, .L%p\n", insn
->cond
.nr
, insn
->bb_true
, insn
->bb_false
);
76 printf("\tbr\t.L%p\n", insn
->bb_true
? insn
->bb_true
: insn
->bb_false
);
80 struct expression
*expr
= insn
->val
;
83 printf("\t%%r%d <- %lld\n",
84 insn
->target
.nr
, expr
->value
);
87 printf("\t%%r%d <- %s\n",
88 insn
->target
.nr
, show_string(expr
->string
));
91 printf("\t%%r%d <- %s\n",
92 insn
->target
.nr
, show_ident(expr
->symbol
->ident
));
95 printf("\t SETVAL ?? ");
100 struct multijmp
*jmp
;
101 printf("\tswitch %%r%d", insn
->cond
.nr
);
102 FOR_EACH_PTR(insn
->multijmp_list
, jmp
) {
103 if (jmp
->begin
== jmp
->end
)
104 printf(", %d -> .L%p", jmp
->begin
, jmp
->target
);
105 else if (jmp
->begin
< jmp
->end
)
106 printf(", %d ... %d -> .L%p", jmp
->begin
, jmp
->end
, jmp
->target
);
108 printf(", default -> .L%p\n", jmp
->target
);
117 printf("\t%%r%d <- phi", insn
->target
.nr
);
118 FOR_EACH_PTR(insn
->phi_list
, phi
) {
119 printf("%s(%%r%d, .L%p)", s
, phi
->pseudo
.nr
, phi
->source
);
126 printf("\tload %%r%d <- [%%r%d]\n", insn
->target
.nr
, insn
->src
.nr
);
129 printf("\tstore %%r%d -> [%%r%d]\n", insn
->target
.nr
, insn
->src
.nr
);
132 printf("\tpush %%r%d\n", insn
->src
.nr
);
135 printf("\t%%r%d <- CALL %s\n", insn
->target
.nr
, show_ident(insn
->address
->ident
));
138 printf("\t%%r%d <- CALL [%%r%d]\n", insn
->target
.nr
, insn
->src
.nr
);
141 printf("\t%%r%d <- CAST(%d->%d) %%r%d\n",
143 insn
->orig_type
->bit_size
, insn
->type
->bit_size
,
146 case OP_BINARY
... OP_BINARY_END
:
147 case OP_LOGICAL
... OP_LOGICAL_END
: {
148 static const char *opname
[] = {
149 [OP_ADD
- OP_BINARY
] = "add", [OP_SUB
- OP_BINARY
] = "sub",
150 [OP_MUL
- OP_BINARY
] = "mul", [OP_DIV
- OP_BINARY
] = "div",
151 [OP_MOD
- OP_BINARY
] = "mod", [OP_AND
- OP_BINARY
] = "and",
152 [OP_OR
- OP_BINARY
] = "or", [OP_XOR
- OP_BINARY
] = "xor"
154 printf("\t%%r%d <- %s %%r%d, %%r%d\n",
156 opname
[op
- OP_BINARY
], insn
->src1
.nr
, insn
->src2
.nr
);
160 case OP_BINCMP
... OP_BINCMP_END
: {
161 static const char *opname
[] = {
162 [OP_SET_EQ
- OP_BINCMP
] = "seteq",
163 [OP_SET_NE
- OP_BINCMP
] = "setne",
164 [OP_SET_LE
- OP_BINCMP
] = "setle",
165 [OP_SET_GE
- OP_BINCMP
] = "setge",
166 [OP_SET_LT
- OP_BINCMP
] = "setlt",
167 [OP_SET_GT
- OP_BINCMP
] = "setgt",
169 printf("\t%%r%d <- %s %%r%d, %%r%d\n",
171 opname
[op
- OP_BINCMP
], insn
->src1
.nr
, insn
->src2
.nr
);
175 case OP_UNOP
... OP_LASTUNOP
:
176 printf("\t%%r%d <- %s %%r%d\n",
178 show_special(op
- OP_UNOP
), insn
->src
.nr
);
181 printf("\top %d ???\n", op
);
185 static void show_bb(struct basic_block
*bb
)
187 struct instruction
*insn
;
189 printf("bb: %p\n", bb
);
191 struct basic_block
*from
;
192 FOR_EACH_PTR(bb
->parents
, from
) {
193 printf(" **from %p**\n", from
);
196 FOR_EACH_PTR(bb
->insns
, insn
) {
197 show_instruction(insn
);
199 if (!bb_terminated(bb
))
204 static void show_entry(struct entrypoint
*ep
)
207 struct basic_block
*bb
;
209 printf("ep %p: %s\n", ep
, show_ident(ep
->name
->ident
));
211 FOR_EACH_PTR(ep
->syms
, sym
) {
212 printf(" sym: %p %s\n", sym
, show_ident(sym
->ident
));
217 FOR_EACH_PTR(ep
->bbs
, bb
) {
224 static void bind_label(struct symbol
*label
, struct basic_block
*bb
, struct position pos
)
226 if (label
->bb_target
)
227 warn(pos
, "label already bound\n");
228 label
->bb_target
= bb
;
231 static struct basic_block
* get_bound_block(struct entrypoint
*ep
, struct symbol
*label
)
233 struct basic_block
*bb
= label
->bb_target
;
236 label
->bb_target
= bb
= alloc_basic_block();
237 bb
->flags
|= BB_REACHABLE
;
242 static void add_goto(struct entrypoint
*ep
, struct basic_block
*dst
)
244 struct basic_block
*src
= ep
->active
;
245 if (bb_reachable(src
)) {
246 struct instruction
*br
= alloc_instruction(OP_BR
, NULL
);
248 add_bb(&dst
->parents
, src
);
249 add_instruction(&src
->insns
, br
);
254 static void add_one_insn(struct entrypoint
*ep
, struct position pos
, struct instruction
*insn
)
256 struct basic_block
*bb
= ep
->active
;
258 if (bb_reachable(bb
))
259 add_instruction(&bb
->insns
, insn
);
262 static void set_activeblock(struct entrypoint
*ep
, struct basic_block
*bb
)
264 if (!bb_terminated(ep
->active
))
268 if (bb_reachable(bb
))
269 add_bb(&ep
->bbs
, bb
);
272 static void add_branch(struct entrypoint
*ep
, struct expression
*expr
, pseudo_t cond
, struct basic_block
*bb_true
, struct basic_block
*bb_false
)
274 struct basic_block
*bb
= ep
->active
;
275 struct instruction
*br
;
277 if (bb_reachable(bb
)) {
278 br
= alloc_instruction(OP_BR
, expr
->ctype
);
280 br
->bb_true
= bb_true
;
281 br
->bb_false
= bb_false
;
282 add_bb(&bb_true
->parents
, bb
);
283 add_bb(&bb_false
->parents
, bb
);
284 add_one_insn(ep
, expr
->pos
, br
);
288 /* Dummy pseudo allocator */
289 static pseudo_t
alloc_pseudo(void)
292 return to_pseudo(++nr
);
296 * FIXME! Not all accesses are memory loads. We should
297 * check what kind of symbol is behind the dereference.
299 static pseudo_t
linearize_address_gen(struct entrypoint
*ep
, struct expression
*expr
)
301 if (expr
->type
== EXPR_PREOP
)
302 return linearize_expression(ep
, expr
->unop
);
303 if (expr
->type
== EXPR_BITFIELD
)
304 return linearize_expression(ep
, expr
->address
);
305 warn(expr
->pos
, "generating address of non-lvalue");
309 static void linearize_store_gen(struct entrypoint
*ep
, pseudo_t value
, struct expression
*expr
, pseudo_t addr
)
311 struct instruction
*store
= alloc_instruction(OP_STORE
, expr
->ctype
);
312 store
->target
= value
;
314 add_one_insn(ep
, expr
->pos
, store
);
317 static pseudo_t
linearize_load_gen(struct entrypoint
*ep
, struct expression
*expr
, pseudo_t addr
)
319 pseudo_t
new = alloc_pseudo();
320 struct instruction
*insn
= alloc_instruction(OP_LOAD
, expr
->ctype
);
324 add_one_insn(ep
, expr
->pos
, insn
);
325 if (expr
->type
== EXPR_PREOP
)
329 /* FIXME! Add shift and mask!!! */
333 static pseudo_t
linearize_access(struct entrypoint
*ep
, struct expression
*expr
)
335 pseudo_t addr
= linearize_address_gen(ep
, expr
);
336 return linearize_load_gen(ep
, expr
, addr
);
339 static pseudo_t
linearize_inc_dec(struct entrypoint
*ep
, struct expression
*expr
, int postop
)
341 pseudo_t addr
= linearize_address_gen(ep
, expr
->unop
);
342 pseudo_t retval
, new;
343 struct instruction
*insn
;
345 retval
= linearize_load_gen(ep
, expr
->unop
, addr
);
348 new = alloc_pseudo();
350 /* Generate the inc/dec */
351 insn
= alloc_instruction(OP_UNOP
+ expr
->op
, expr
->ctype
);
354 add_one_insn(ep
, expr
->pos
, insn
);
356 /* Store back value */
357 linearize_store_gen(ep
, new, expr
->unop
, addr
);
361 static pseudo_t
linearize_regular_preop(struct entrypoint
*ep
, struct expression
*expr
)
363 pseudo_t target
= linearize_expression(ep
, expr
->unop
);
364 pseudo_t
new = alloc_pseudo();
365 struct instruction
*insn
= alloc_instruction(OP_UNOP
+ expr
->op
, expr
->ctype
);
371 static pseudo_t
linearize_preop(struct entrypoint
*ep
, struct expression
*expr
)
374 * '*' is an lvalue access, and is fundamentally different
375 * from an arithmetic operation. Maybe it should have an
376 * expression type of its own..
379 return linearize_access(ep
, expr
);
380 if (expr
->op
== SPECIAL_INCREMENT
|| expr
->op
== SPECIAL_DECREMENT
)
381 return linearize_inc_dec(ep
, expr
, 0);
382 return linearize_regular_preop(ep
, expr
);
385 static pseudo_t
linearize_postop(struct entrypoint
*ep
, struct expression
*expr
)
387 return linearize_inc_dec(ep
, expr
, 1);
390 static pseudo_t
linearize_assignment(struct entrypoint
*ep
, struct expression
*expr
)
392 struct expression
*target
= expr
->left
;
393 pseudo_t value
, address
;
395 value
= linearize_expression(ep
, expr
->right
);
396 address
= linearize_address_gen(ep
, target
);
397 linearize_store_gen(ep
, value
, target
, address
);
401 static void push_argument(struct entrypoint
*ep
, struct expression
*expr
, pseudo_t pseudo
)
403 struct instruction
*insn
= alloc_instruction(OP_ARGUMENT
, expr
->ctype
);
405 add_one_insn(ep
, expr
->pos
, insn
);
408 static pseudo_t
linearize_direct_call(struct entrypoint
*ep
, struct expression
*expr
, struct symbol
*direct
)
410 struct instruction
*insn
= alloc_instruction(OP_CALL
, expr
->ctype
);
411 pseudo_t retval
= alloc_pseudo();
413 insn
->target
= retval
;
414 insn
->address
= direct
;
415 add_one_insn(ep
, expr
->pos
, insn
);
419 static pseudo_t
linearize_indirect_call(struct entrypoint
*ep
, struct expression
*expr
, pseudo_t pseudo
)
421 struct instruction
*insn
= alloc_instruction(OP_INDCALL
, expr
->ctype
);
422 pseudo_t retval
= alloc_pseudo();
424 insn
->target
= retval
;
426 add_one_insn(ep
, expr
->pos
, insn
);
430 static pseudo_t
linearize_call_expression(struct entrypoint
*ep
, struct expression
*expr
)
432 struct symbol
*direct
;
433 struct expression
*arg
, *fn
;
437 warn(expr
->pos
, "\tcall with no type!");
441 FOR_EACH_PTR_REVERSE(expr
->args
, arg
) {
442 pseudo_t
new = linearize_expression(ep
, arg
);
443 push_argument(ep
, arg
, new);
444 } END_FOR_EACH_PTR_REVERSE
;
448 /* Remove dereference, if any */
450 if (fn
->type
== EXPR_PREOP
) {
451 if (fn
->unop
->type
== EXPR_SYMBOL
) {
452 struct symbol
*sym
= fn
->unop
->symbol
;
453 if (sym
->ctype
.base_type
->type
== SYM_FN
)
458 retval
= linearize_direct_call(ep
, expr
, direct
);
460 pseudo_t fncall
= linearize_expression(ep
, fn
);
461 retval
= linearize_indirect_call(ep
, expr
, fncall
);
466 static pseudo_t
linearize_binop(struct entrypoint
*ep
, struct expression
*expr
)
468 pseudo_t src1
, src2
, result
;
469 struct instruction
*insn
;
470 static const int opcode
[] = {
471 ['+'] = OP_ADD
, ['-'] = OP_SUB
,
472 ['*'] = OP_MUL
, ['/'] = OP_DIV
,
473 ['%'] = OP_MOD
, ['&'] = OP_AND
,
474 ['|'] = OP_OR
, ['^'] = OP_XOR
,
477 src1
= linearize_expression(ep
, expr
->left
);
478 src2
= linearize_expression(ep
, expr
->right
);
479 result
= alloc_pseudo();
481 insn
= alloc_instruction(opcode
[expr
->op
], expr
->ctype
);
482 insn
->target
= result
;
485 add_one_insn(ep
, expr
->pos
, insn
);
489 static pseudo_t
linearize_logical_branch(struct entrypoint
*ep
, struct expression
*expr
, struct basic_block
*bb_true
, struct basic_block
*bb_false
);
491 pseudo_t
linearize_cond_branch(struct entrypoint
*ep
, struct expression
*expr
, struct basic_block
*bb_true
, struct basic_block
*bb_false
);
493 static pseudo_t
linearize_logical(struct entrypoint
*ep
, struct expression
*expr
)
495 pseudo_t src1
, src2
, target
;
496 struct basic_block
*bb_true
= alloc_basic_block();
497 struct basic_block
*bb_false
= alloc_basic_block();
498 struct basic_block
*merge
= alloc_basic_block();
499 struct basic_block
*first
= bb_true
;
500 struct basic_block
*second
= bb_false
;
501 struct instruction
*insn
;
503 if (expr
->op
== SPECIAL_LOGICAL_OR
) {
508 linearize_cond_branch(ep
, expr
->left
, bb_true
, bb_false
);
510 set_activeblock(ep
, first
);
511 src1
= linearize_expression(ep
, expr
->right
);
514 set_activeblock(ep
, second
);
515 insn
= alloc_instruction(OP_SETVAL
, expr
->ctype
);
516 insn
->target
= src2
= alloc_pseudo();
517 insn
->val
= alloc_const_expression(expr
->pos
, expr
->op
== SPECIAL_LOGICAL_OR
);
518 add_one_insn(ep
, expr
->pos
,insn
);
520 set_activeblock(ep
, merge
);
522 if (bb_reachable(bb_true
) && bb_reachable(bb_false
)) {
523 struct instruction
*phi_node
= alloc_instruction(OP_PHI
, expr
->ctype
);
524 add_phi(&phi_node
->phi_list
, alloc_phi(first
, src1
));
525 add_phi(&phi_node
->phi_list
, alloc_phi(second
, src2
));
526 phi_node
->target
= target
= alloc_pseudo();
527 add_one_insn(ep
, expr
->pos
, phi_node
);
528 set_activeblock(ep
, alloc_basic_block());
532 return bb_reachable(first
) ? src1
: src2
;
535 static pseudo_t
linearize_compare(struct entrypoint
*ep
, struct expression
*expr
)
537 static const int cmpop
[] = {
538 ['>'] = OP_SET_GT
, ['<'] = OP_SET_LT
,
539 [SPECIAL_EQUAL
] = OP_SET_EQ
,
540 [SPECIAL_NOTEQUAL
] = OP_SET_NE
,
541 [SPECIAL_GTE
] = OP_SET_GE
,
542 [SPECIAL_LTE
] = OP_SET_LE
,
544 struct instruction
*insn
= alloc_instruction(cmpop
[expr
->op
], expr
->ctype
);
546 insn
->src1
= linearize_expression(ep
, expr
->left
);
547 insn
->src2
= linearize_expression(ep
, expr
->right
);
548 insn
->target
= target
= alloc_pseudo();
549 add_one_insn(ep
, expr
->pos
, insn
);
554 pseudo_t
linearize_cond_branch(struct entrypoint
*ep
, struct expression
*expr
, struct basic_block
*bb_true
, struct basic_block
*bb_false
)
558 if (!expr
|| !bb_reachable(ep
->active
))
561 switch (expr
->type
) {
565 add_goto(ep
, expr
->value
? bb_true
: bb_false
);
569 linearize_logical_branch(ep
, expr
, bb_true
, bb_false
);
573 cond
= linearize_compare(ep
, expr
);
574 add_branch(ep
, expr
, cond
, bb_true
, bb_false
);
579 return linearize_cond_branch(ep
, expr
->unop
, bb_false
, bb_true
);
582 cond
= linearize_expression(ep
, expr
);
583 add_branch(ep
, expr
, cond
, bb_true
, bb_false
);
593 static pseudo_t
linearize_logical_branch(struct entrypoint
*ep
, struct expression
*expr
, struct basic_block
*bb_true
, struct basic_block
*bb_false
)
595 struct basic_block
*next
= alloc_basic_block();
597 if (expr
->op
== SPECIAL_LOGICAL_OR
)
598 linearize_cond_branch(ep
, expr
->left
, bb_true
, next
);
600 linearize_cond_branch(ep
, expr
->left
, next
, bb_false
);
601 set_activeblock(ep
, next
);
602 linearize_cond_branch(ep
, expr
->right
, bb_true
, bb_false
);
606 pseudo_t
linearize_cast(struct entrypoint
*ep
, struct expression
*expr
)
608 pseudo_t src
, result
;
609 struct instruction
*insn
;
611 src
= linearize_expression(ep
, expr
->cast_expression
);
612 insn
= alloc_instruction(OP_CAST
, expr
->ctype
);
613 result
= alloc_pseudo();
614 insn
->target
= result
;
616 insn
->orig_type
= expr
->cast_expression
->ctype
;
617 add_one_insn(ep
, expr
->pos
, insn
);
621 pseudo_t
linearize_expression(struct entrypoint
*ep
, struct expression
*expr
)
626 switch (expr
->type
) {
627 case EXPR_VALUE
: case EXPR_STRING
: case EXPR_SYMBOL
: {
629 struct instruction
*insn
= alloc_instruction(OP_SETVAL
, expr
->ctype
);
630 insn
->target
= pseudo
= alloc_pseudo();
632 add_one_insn(ep
, expr
->pos
,insn
);
637 return linearize_statement(ep
, expr
->statement
);
640 return linearize_call_expression(ep
, expr
);
643 return linearize_binop(ep
, expr
);
646 return linearize_logical(ep
, expr
);
649 return linearize_compare(ep
, expr
);
652 linearize_expression(ep
, expr
->left
);
653 return linearize_expression(ep
, expr
->right
);
656 case EXPR_ASSIGNMENT
:
657 return linearize_assignment(ep
, expr
);
660 return linearize_preop(ep
, expr
);
663 return linearize_postop(ep
, expr
);
666 return linearize_cast(ep
, expr
);
669 struct instruction
*bad
= alloc_instruction(OP_BADOP
, expr
->ctype
);
670 bad
->target
.nr
= expr
->type
;
671 bad
->src
.nr
= expr
->op
;
672 add_one_insn(ep
, expr
->pos
, bad
);
679 pseudo_t
linearize_statement(struct entrypoint
*ep
, struct statement
*stmt
)
684 switch (stmt
->type
) {
688 case STMT_EXPRESSION
:
689 return linearize_expression(ep
, stmt
->expression
);
696 struct expression
*expr
= stmt
->expression
;
697 struct instruction
*ret
= alloc_instruction(OP_RET
, expr
->ctype
);
698 ret
->src
= linearize_expression(ep
, expr
);
699 add_one_insn(ep
, stmt
->pos
, ret
);
705 struct basic_block
*bb
= get_bound_block(ep
, stmt
->case_label
);
706 set_activeblock(ep
, bb
);
707 linearize_statement(ep
, stmt
->case_statement
);
712 struct symbol
*label
= stmt
->label_identifier
;
713 struct basic_block
*bb
;
716 bb
= get_bound_block(ep
, stmt
->label_identifier
);
717 set_activeblock(ep
, bb
);
718 linearize_statement(ep
, stmt
->label_statement
);
724 add_goto(ep
, get_bound_block(ep
, stmt
->goto_label
));
728 case STMT_COMPOUND
: {
731 concat_symbol_list(stmt
->syms
, &ep
->syms
);
732 FOR_EACH_PTR(stmt
->stmts
, s
) {
733 pseudo
= linearize_statement(ep
, s
);
739 * This could take 'likely/unlikely' into account, and
740 * switch the arms around appropriately..
743 struct basic_block
*bb_true
, *bb_false
, *endif
;
744 struct expression
*cond
= stmt
->if_conditional
;
746 bb_true
= alloc_basic_block();
747 bb_false
= endif
= alloc_basic_block();
749 linearize_cond_branch(ep
, cond
, bb_true
, bb_false
);
751 set_activeblock(ep
, bb_true
);
752 linearize_statement(ep
, stmt
->if_true
);
754 if (stmt
->if_false
) {
755 endif
= alloc_basic_block();
757 set_activeblock(ep
, bb_false
);
758 linearize_statement(ep
, stmt
->if_false
);
760 set_activeblock(ep
, endif
);
766 struct instruction
*switch_ins
;
767 struct basic_block
*switch_end
= alloc_basic_block();
770 pseudo
= linearize_expression(ep
, stmt
->switch_expression
);
771 switch_ins
= alloc_instruction(OP_SWITCH
, NULL
);
772 switch_ins
->cond
= pseudo
;
773 add_one_insn(ep
, stmt
->pos
, switch_ins
);
775 FOR_EACH_PTR(stmt
->switch_case
->symbol_list
, sym
) {
776 struct statement
*case_stmt
= sym
->stmt
;
777 struct basic_block
*bb_case
= get_bound_block(ep
, sym
);
778 struct multijmp
*jmp
;
780 if (!case_stmt
->case_expression
) {
781 jmp
= alloc_multijmp(bb_case
, 1, 0);
783 if (case_stmt
->case_expression
)
784 begin
= end
= case_stmt
->case_expression
->value
;
785 if (case_stmt
->case_to
)
786 end
= case_stmt
->case_to
->value
;
788 jmp
= alloc_multijmp(bb_case
, end
, begin
);
790 jmp
= alloc_multijmp(bb_case
, begin
, end
);
793 add_multijmp(&switch_ins
->multijmp_list
, jmp
);
794 add_bb(&bb_case
->parents
, ep
->active
);
797 bind_label(stmt
->switch_break
, switch_end
, stmt
->pos
);
799 /* And linearize the actual statement */
800 linearize_statement(ep
, stmt
->switch_statement
);
801 set_activeblock(ep
, switch_end
);
806 case STMT_ITERATOR
: {
807 struct statement
*pre_statement
= stmt
->iterator_pre_statement
;
808 struct expression
*pre_condition
= stmt
->iterator_pre_condition
;
809 struct statement
*statement
= stmt
->iterator_statement
;
810 struct statement
*post_statement
= stmt
->iterator_post_statement
;
811 struct expression
*post_condition
= stmt
->iterator_post_condition
;
812 struct basic_block
*loop_top
, *loop_body
, *loop_continue
, *loop_end
;
814 concat_symbol_list(stmt
->iterator_syms
, &ep
->syms
);
815 linearize_statement(ep
, pre_statement
);
817 loop_body
= loop_top
= alloc_basic_block();
818 loop_continue
= alloc_basic_block();
819 loop_end
= alloc_basic_block();
821 if (!post_statement
&& (pre_condition
== post_condition
)) {
823 * If it is a while loop, optimize away the post_condition.
825 post_condition
= NULL
;
826 loop_body
= loop_continue
;
827 loop_continue
= loop_top
;
828 loop_top
->flags
|= BB_REACHABLE
;
829 set_activeblock(ep
, loop_top
);
832 loop_top
->flags
|= BB_REACHABLE
;
834 linearize_cond_branch(ep
, pre_condition
, loop_body
, loop_end
);
836 bind_label(stmt
->iterator_continue
, loop_continue
, stmt
->pos
);
837 bind_label(stmt
->iterator_break
, loop_end
, stmt
->pos
);
839 set_activeblock(ep
, loop_body
);
840 linearize_statement(ep
, statement
);
841 add_goto(ep
, loop_continue
);
843 if (post_condition
) {
844 set_activeblock(ep
, loop_continue
);
845 linearize_statement(ep
, post_statement
);
846 linearize_cond_branch(ep
, post_condition
, loop_top
, loop_end
);
849 set_activeblock(ep
, loop_end
);
859 void mark_bb_reachable(struct basic_block
*bb
)
861 struct basic_block
*child
;
862 struct terminator_iterator term
;
863 struct basic_block_list
*bbstack
= NULL
;
865 if (!bb
|| bb
->flags
& BB_REACHABLE
)
868 add_bb(&bbstack
, bb
);
870 bb
= delete_last_basic_block(&bbstack
);
871 if (bb
->flags
& BB_REACHABLE
)
873 bb
->flags
|= BB_REACHABLE
;
874 init_terminator_iterator(last_instruction(bb
->insns
), &term
);
875 while ((child
=next_terminator_bb(&term
))) {
876 if (!(child
->flags
& BB_REACHABLE
))
877 add_bb(&bbstack
, child
);
882 void remove_unreachable_bbs(struct basic_block_list
**bblist
)
884 struct basic_block
*bb
, *child
;
885 struct list_iterator iterator
;
886 struct terminator_iterator term
;
888 init_iterator((struct ptr_list
**) bblist
, &iterator
, 0);
889 while((bb
=next_basic_block(&iterator
)))
890 bb
->flags
&= ~BB_REACHABLE
;
892 init_iterator((struct ptr_list
**) bblist
, &iterator
, 0);
893 mark_bb_reachable(next_basic_block(&iterator
));
894 while((bb
=next_basic_block(&iterator
))) {
895 if (bb
->flags
& BB_REACHABLE
)
897 init_terminator_iterator(last_instruction(bb
->insns
), &term
);
898 while ((child
=next_terminator_bb(&term
)))
899 replace_basic_block_list(&child
->parents
, bb
, NULL
);
900 delete_iterator(&iterator
);
904 void pack_basic_blocks(struct basic_block_list
**bblist
)
906 struct basic_block
*child
, *bb
, *parent
;
907 struct list_iterator iterator
;
908 struct terminator_iterator term
;
909 struct instruction
*jmp
;
911 remove_unreachable_bbs(bblist
);
912 init_bb_iterator(bblist
, &iterator
, 0);
913 while((bb
=next_basic_block(&iterator
))) {
914 if (is_branch_goto(jmp
=first_instruction(bb
->insns
))) {
916 * This is an empty goto block. Transfer the parents' terminator
917 * to target directly.
919 struct list_iterator it_parents
;
920 struct basic_block
*target
;
922 target
= jmp
->bb_true
? jmp
->bb_true
: jmp
->bb_false
;
923 replace_basic_block_list(&target
->parents
, bb
, NULL
);
924 init_bb_iterator(&bb
->parents
, &it_parents
, 0);
925 while((parent
=next_basic_block(&it_parents
))) {
926 init_terminator_iterator(last_instruction(parent
->insns
), &term
);
927 while ((child
=next_terminator_bb(&term
))) {
929 replace_terminator_bb(&term
, target
);
930 add_bb(&target
->parents
, parent
);
934 delete_iterator(&iterator
);
938 if (bb_list_size(bb
->parents
)!=1)
940 parent
= first_basic_block(bb
->parents
);
941 if (parent
!=bb
&& is_branch_goto(last_instruction(parent
->insns
))) {
943 * Combine this block with the parent.
945 delete_last_instruction(&parent
->insns
);
946 concat_instruction_list(bb
->insns
, &parent
->insns
);
947 init_terminator_iterator(last_instruction(bb
->insns
), &term
);
948 while ((child
=next_terminator_bb(&term
)))
949 replace_basic_block_list(&child
->parents
, bb
, parent
);
950 delete_iterator(&iterator
);
955 void linearize_symbol(struct symbol
*sym
)
957 struct symbol
*base_type
;
961 base_type
= sym
->ctype
.base_type
;
964 if (base_type
->type
== SYM_FN
) {
965 if (base_type
->stmt
) {
966 struct entrypoint
*ep
= alloc_entrypoint();
967 struct basic_block
*bb
= alloc_basic_block();
970 bb
->flags
|= BB_REACHABLE
;
971 set_activeblock(ep
, bb
);
972 concat_symbol_list(base_type
->arguments
, &ep
->syms
);
973 linearize_statement(ep
, base_type
->stmt
);
974 pack_basic_blocks(&ep
->bbs
);