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
);
133 printf("\t%%r%d <- CALL %%r%d", insn
->target
->nr
, insn
->func
->nr
);
134 FOR_EACH_PTR(insn
->arguments
, arg
) {
135 printf(", %%r%d", arg
->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",
153 [OP_SHL
- OP_BINARY
] = "shl", [OP_SHR
- OP_BINARY
] = "shr",
155 printf("\t%%r%d <- %s %%r%d, %%r%d\n",
157 opname
[op
- OP_BINARY
], insn
->src1
->nr
, insn
->src2
->nr
);
161 case OP_BINCMP
... OP_BINCMP_END
: {
162 static const char *opname
[] = {
163 [OP_SET_EQ
- OP_BINCMP
] = "seteq",
164 [OP_SET_NE
- OP_BINCMP
] = "setne",
165 [OP_SET_LE
- OP_BINCMP
] = "setle",
166 [OP_SET_GE
- OP_BINCMP
] = "setge",
167 [OP_SET_LT
- OP_BINCMP
] = "setlt",
168 [OP_SET_GT
- OP_BINCMP
] = "setgt",
170 printf("\t%%r%d <- %s %%r%d, %%r%d\n",
172 opname
[op
- OP_BINCMP
], insn
->src1
->nr
, insn
->src2
->nr
);
176 case OP_NOT
: case OP_NEG
:
177 printf("\t%%r%d <- %s %%r%d\n",
179 op
== OP_NOT
? "not" : "neg", insn
->src1
->nr
);
182 printf("\top %d ???\n", op
);
186 static void show_bb(struct basic_block
*bb
)
188 struct instruction
*insn
;
190 printf("bb: %p\n", bb
);
192 struct basic_block
*from
;
193 FOR_EACH_PTR(bb
->parents
, from
) {
194 printf(" **from %p**\n", from
);
197 FOR_EACH_PTR(bb
->insns
, insn
) {
198 show_instruction(insn
);
200 if (!bb_terminated(bb
))
205 static void show_entry(struct entrypoint
*ep
)
208 struct basic_block
*bb
;
210 printf("ep %p: %s\n", ep
, show_ident(ep
->name
->ident
));
212 FOR_EACH_PTR(ep
->syms
, sym
) {
213 printf(" sym: %p %s\n", sym
, show_ident(sym
->ident
));
218 FOR_EACH_PTR(ep
->bbs
, bb
) {
225 static void bind_label(struct symbol
*label
, struct basic_block
*bb
, struct position pos
)
227 if (label
->bb_target
)
228 warn(pos
, "label already bound\n");
229 label
->bb_target
= bb
;
232 static struct basic_block
* get_bound_block(struct entrypoint
*ep
, struct symbol
*label
)
234 struct basic_block
*bb
= label
->bb_target
;
237 label
->bb_target
= bb
= alloc_basic_block();
238 bb
->flags
|= BB_REACHABLE
;
243 static void add_goto(struct entrypoint
*ep
, struct basic_block
*dst
)
245 struct basic_block
*src
= ep
->active
;
246 if (bb_reachable(src
)) {
247 struct instruction
*br
= alloc_instruction(OP_BR
, NULL
);
249 add_bb(&dst
->parents
, src
);
250 add_instruction(&src
->insns
, br
);
255 static void add_one_insn(struct entrypoint
*ep
, struct position pos
, struct instruction
*insn
)
257 struct basic_block
*bb
= ep
->active
;
259 if (bb_reachable(bb
))
260 add_instruction(&bb
->insns
, insn
);
263 static void set_activeblock(struct entrypoint
*ep
, struct basic_block
*bb
)
265 if (!bb_terminated(ep
->active
))
269 if (bb_reachable(bb
))
270 add_bb(&ep
->bbs
, bb
);
273 static void add_branch(struct entrypoint
*ep
, struct expression
*expr
, pseudo_t cond
, struct basic_block
*bb_true
, struct basic_block
*bb_false
)
275 struct basic_block
*bb
= ep
->active
;
276 struct instruction
*br
;
278 if (bb_reachable(bb
)) {
279 br
= alloc_instruction(OP_BR
, expr
->ctype
);
281 br
->bb_true
= bb_true
;
282 br
->bb_false
= bb_false
;
283 add_bb(&bb_true
->parents
, bb
);
284 add_bb(&bb_false
->parents
, bb
);
285 add_one_insn(ep
, expr
->pos
, br
);
289 /* Dummy pseudo allocator */
290 static pseudo_t
alloc_pseudo(void)
293 struct pseudo
* pseudo
= __alloc_pseudo(0);
299 * FIXME! Not all accesses are memory loads. We should
300 * check what kind of symbol is behind the dereference.
302 static pseudo_t
linearize_address_gen(struct entrypoint
*ep
, struct expression
*expr
)
304 if (expr
->type
== EXPR_PREOP
)
305 return linearize_expression(ep
, expr
->unop
);
306 if (expr
->type
== EXPR_BITFIELD
)
307 return linearize_expression(ep
, expr
->address
);
308 warn(expr
->pos
, "generating address of non-lvalue");
312 static void linearize_store_gen(struct entrypoint
*ep
, pseudo_t value
, struct expression
*expr
, pseudo_t addr
)
314 struct instruction
*store
= alloc_instruction(OP_STORE
, expr
->ctype
);
315 store
->target
= value
;
317 add_one_insn(ep
, expr
->pos
, store
);
320 static pseudo_t
add_binary_op(struct entrypoint
*ep
, struct expression
*expr
, int op
, pseudo_t left
, pseudo_t right
)
322 struct instruction
*insn
= alloc_instruction(op
, expr
->ctype
);
323 pseudo_t target
= alloc_pseudo();
324 insn
->target
= target
;
327 add_one_insn(ep
, expr
->pos
, insn
);
331 static pseudo_t
add_setval(struct entrypoint
*ep
, struct symbol
*ctype
, struct expression
*val
)
333 struct instruction
*insn
= alloc_instruction(OP_SETVAL
, ctype
);
334 pseudo_t target
= alloc_pseudo();
335 insn
->target
= target
;
337 add_one_insn(ep
, val
->pos
, insn
);
341 static pseudo_t
linearize_load_gen(struct entrypoint
*ep
, struct expression
*expr
, pseudo_t addr
)
343 pseudo_t
new = alloc_pseudo();
344 struct instruction
*insn
= alloc_instruction(OP_LOAD
, expr
->ctype
);
348 add_one_insn(ep
, expr
->pos
, insn
);
349 if (expr
->type
== EXPR_PREOP
)
353 /* FIXME! Add shift and mask!!! */
357 static pseudo_t
linearize_access(struct entrypoint
*ep
, struct expression
*expr
)
359 pseudo_t addr
= linearize_address_gen(ep
, expr
);
360 return linearize_load_gen(ep
, expr
, addr
);
363 static pseudo_t
linearize_inc_dec(struct entrypoint
*ep
, struct expression
*expr
, int postop
)
365 pseudo_t addr
= linearize_address_gen(ep
, expr
->unop
);
366 pseudo_t old
, new, one
;
367 int op
= expr
->op
== SPECIAL_INCREMENT
? OP_ADD
: OP_SUB
;
369 old
= linearize_load_gen(ep
, expr
->unop
, addr
);
370 one
= add_setval(ep
, expr
->ctype
, alloc_const_expression(expr
->pos
, 1));
371 new = add_binary_op(ep
, expr
, op
, old
, one
);
372 linearize_store_gen(ep
, new, expr
->unop
, addr
);
373 return postop
? old
: new;
376 static pseudo_t
add_uniop(struct entrypoint
*ep
, struct expression
*expr
, int op
, pseudo_t src
)
378 pseudo_t
new = alloc_pseudo();
379 struct instruction
*insn
= alloc_instruction(op
, expr
->ctype
);
382 add_one_insn(ep
, expr
->pos
, insn
);
386 static pseudo_t
linearize_regular_preop(struct entrypoint
*ep
, struct expression
*expr
)
388 pseudo_t pre
= linearize_expression(ep
, expr
->unop
);
393 struct expression
* zeroval
= alloc_const_expression(expr
->pos
, 0);
394 pseudo_t zero
= add_setval(ep
, expr
->ctype
, zeroval
);
395 return add_binary_op(ep
, expr
, OP_SET_EQ
, pre
, zero
);
398 return add_uniop(ep
, expr
, OP_NOT
, pre
);
400 return add_uniop(ep
, expr
, OP_NEG
, pre
);
405 static pseudo_t
linearize_preop(struct entrypoint
*ep
, struct expression
*expr
)
408 * '*' is an lvalue access, and is fundamentally different
409 * from an arithmetic operation. Maybe it should have an
410 * expression type of its own..
413 return linearize_access(ep
, expr
);
414 if (expr
->op
== SPECIAL_INCREMENT
|| expr
->op
== SPECIAL_DECREMENT
)
415 return linearize_inc_dec(ep
, expr
, 0);
416 return linearize_regular_preop(ep
, expr
);
419 static pseudo_t
linearize_postop(struct entrypoint
*ep
, struct expression
*expr
)
421 return linearize_inc_dec(ep
, expr
, 1);
424 static pseudo_t
linearize_assignment(struct entrypoint
*ep
, struct expression
*expr
)
426 struct expression
*target
= expr
->left
;
427 pseudo_t value
, address
;
429 value
= linearize_expression(ep
, expr
->right
);
430 address
= linearize_address_gen(ep
, target
);
431 if (expr
->op
!= '=') {
432 static const int opcode
[] = {
433 [SPECIAL_ADD_ASSIGN
- SPECIAL_BASE
] = OP_ADD
,
434 [SPECIAL_SUB_ASSIGN
- SPECIAL_BASE
] = OP_SUB
,
435 [SPECIAL_MUL_ASSIGN
- SPECIAL_BASE
] = OP_MUL
,
436 [SPECIAL_DIV_ASSIGN
- SPECIAL_BASE
] = OP_DIV
,
437 [SPECIAL_MOD_ASSIGN
- SPECIAL_BASE
] = OP_MOD
,
438 [SPECIAL_SHL_ASSIGN
- SPECIAL_BASE
] = OP_SHL
,
439 [SPECIAL_SHR_ASSIGN
- SPECIAL_BASE
] = OP_SHR
,
440 [SPECIAL_AND_ASSIGN
- SPECIAL_BASE
] = OP_AND
,
441 [SPECIAL_OR_ASSIGN
- SPECIAL_BASE
] = OP_OR
,
442 [SPECIAL_XOR_ASSIGN
- SPECIAL_BASE
] = OP_XOR
444 pseudo_t left
= linearize_load_gen(ep
, expr
->left
, address
);
445 value
= add_binary_op(ep
, expr
, opcode
[expr
->op
- SPECIAL_BASE
], left
, value
);
447 linearize_store_gen(ep
, value
, target
, address
);
451 static pseudo_t
linearize_call_expression(struct entrypoint
*ep
, struct expression
*expr
)
453 struct expression
*arg
, *fn
;
454 struct instruction
*insn
= alloc_instruction(OP_CALL
, expr
->ctype
);
458 warn(expr
->pos
, "\tcall with no type!");
462 FOR_EACH_PTR(expr
->args
, arg
) {
463 pseudo_t
new = linearize_expression(ep
, arg
);
464 add_pseudo(&insn
->arguments
, new);
468 if (fn
->type
== EXPR_PREOP
) {
469 if (fn
->unop
->type
== EXPR_SYMBOL
) {
470 struct symbol
*sym
= fn
->unop
->symbol
;
471 if (sym
->ctype
.base_type
->type
== SYM_FN
)
475 insn
->func
= linearize_expression(ep
, fn
);
476 insn
->target
= retval
= alloc_pseudo();
477 add_one_insn(ep
, expr
->pos
, insn
);
482 static pseudo_t
linearize_binop(struct entrypoint
*ep
, struct expression
*expr
)
485 static const int opcode
[] = {
486 ['+'] = OP_ADD
, ['-'] = OP_SUB
,
487 ['*'] = OP_MUL
, ['/'] = OP_DIV
,
488 ['%'] = OP_MOD
, ['&'] = OP_AND
,
489 ['|'] = OP_OR
, ['^'] = OP_XOR
,
490 [SPECIAL_LEFTSHIFT
] = OP_SHL
,
491 [SPECIAL_RIGHTSHIFT
] = OP_SHR
,
494 src1
= linearize_expression(ep
, expr
->left
);
495 src2
= linearize_expression(ep
, expr
->right
);
496 return add_binary_op(ep
, expr
, opcode
[expr
->op
], src1
, src2
);
499 static pseudo_t
linearize_logical_branch(struct entrypoint
*ep
, struct expression
*expr
, struct basic_block
*bb_true
, struct basic_block
*bb_false
);
501 pseudo_t
linearize_cond_branch(struct entrypoint
*ep
, struct expression
*expr
, struct basic_block
*bb_true
, struct basic_block
*bb_false
);
503 static pseudo_t
linearize_logical(struct entrypoint
*ep
, struct expression
*expr
)
505 pseudo_t src1
, src2
, target
;
506 struct basic_block
*bb_true
= alloc_basic_block();
507 struct basic_block
*bb_false
= alloc_basic_block();
508 struct basic_block
*merge
= alloc_basic_block();
509 struct basic_block
*first
= bb_true
;
510 struct basic_block
*second
= bb_false
;
512 if (expr
->op
== SPECIAL_LOGICAL_OR
) {
517 linearize_cond_branch(ep
, expr
->left
, bb_true
, bb_false
);
519 set_activeblock(ep
, first
);
520 src1
= linearize_expression(ep
, expr
->right
);
523 set_activeblock(ep
, second
);
524 src2
= add_setval(ep
, expr
->ctype
, alloc_const_expression(expr
->pos
, expr
->op
== SPECIAL_LOGICAL_OR
));
526 set_activeblock(ep
, merge
);
528 if (bb_reachable(bb_true
) && bb_reachable(bb_false
)) {
529 struct instruction
*phi_node
= alloc_instruction(OP_PHI
, expr
->ctype
);
530 add_phi(&phi_node
->phi_list
, alloc_phi(first
, src1
));
531 add_phi(&phi_node
->phi_list
, alloc_phi(second
, src2
));
532 phi_node
->target
= target
= alloc_pseudo();
533 add_one_insn(ep
, expr
->pos
, phi_node
);
534 set_activeblock(ep
, alloc_basic_block());
538 return bb_reachable(first
) ? src1
: src2
;
541 static pseudo_t
linearize_compare(struct entrypoint
*ep
, struct expression
*expr
)
543 static const int cmpop
[] = {
544 ['>'] = OP_SET_GT
, ['<'] = OP_SET_LT
,
545 [SPECIAL_EQUAL
] = OP_SET_EQ
,
546 [SPECIAL_NOTEQUAL
] = OP_SET_NE
,
547 [SPECIAL_GTE
] = OP_SET_GE
,
548 [SPECIAL_LTE
] = OP_SET_LE
,
551 pseudo_t src1
= linearize_expression(ep
, expr
->left
);
552 pseudo_t src2
= linearize_expression(ep
, expr
->right
);
553 return add_binary_op(ep
, expr
, cmpop
[expr
->op
], src1
, src2
);
557 pseudo_t
linearize_cond_branch(struct entrypoint
*ep
, struct expression
*expr
, struct basic_block
*bb_true
, struct basic_block
*bb_false
)
561 if (!expr
|| !bb_reachable(ep
->active
))
564 switch (expr
->type
) {
568 add_goto(ep
, expr
->value
? bb_true
: bb_false
);
572 linearize_logical_branch(ep
, expr
, bb_true
, bb_false
);
576 cond
= linearize_compare(ep
, expr
);
577 add_branch(ep
, expr
, cond
, bb_true
, bb_false
);
582 return linearize_cond_branch(ep
, expr
->unop
, bb_false
, bb_true
);
585 cond
= linearize_expression(ep
, expr
);
586 add_branch(ep
, expr
, cond
, bb_true
, bb_false
);
596 static pseudo_t
linearize_logical_branch(struct entrypoint
*ep
, struct expression
*expr
, struct basic_block
*bb_true
, struct basic_block
*bb_false
)
598 struct basic_block
*next
= alloc_basic_block();
600 if (expr
->op
== SPECIAL_LOGICAL_OR
)
601 linearize_cond_branch(ep
, expr
->left
, bb_true
, next
);
603 linearize_cond_branch(ep
, expr
->left
, next
, bb_false
);
604 set_activeblock(ep
, next
);
605 linearize_cond_branch(ep
, expr
->right
, bb_true
, bb_false
);
609 pseudo_t
linearize_cast(struct entrypoint
*ep
, struct expression
*expr
)
611 pseudo_t src
, result
;
612 struct instruction
*insn
;
614 src
= linearize_expression(ep
, expr
->cast_expression
);
615 insn
= alloc_instruction(OP_CAST
, expr
->ctype
);
616 result
= alloc_pseudo();
617 insn
->target
= result
;
619 insn
->orig_type
= expr
->cast_expression
->ctype
;
620 add_one_insn(ep
, expr
->pos
, insn
);
624 pseudo_t
linearize_expression(struct entrypoint
*ep
, struct expression
*expr
)
629 switch (expr
->type
) {
630 case EXPR_VALUE
: case EXPR_STRING
: case EXPR_SYMBOL
:
631 return add_setval(ep
, expr
->ctype
, expr
);
634 return linearize_statement(ep
, expr
->statement
);
637 return linearize_call_expression(ep
, expr
);
640 return linearize_binop(ep
, expr
);
643 return linearize_logical(ep
, expr
);
646 return linearize_compare(ep
, expr
);
649 linearize_expression(ep
, expr
->left
);
650 return linearize_expression(ep
, expr
->right
);
653 case EXPR_ASSIGNMENT
:
654 return linearize_assignment(ep
, expr
);
657 return linearize_preop(ep
, expr
);
660 return linearize_postop(ep
, expr
);
663 return linearize_cast(ep
, expr
);
666 struct instruction
*bad
= alloc_instruction(OP_BADOP
, expr
->ctype
);
667 bad
->target
->nr
= expr
->type
;
668 bad
->src
->nr
= expr
->op
;
669 add_one_insn(ep
, expr
->pos
, bad
);
676 pseudo_t
linearize_statement(struct entrypoint
*ep
, struct statement
*stmt
)
681 switch (stmt
->type
) {
685 case STMT_EXPRESSION
:
686 return linearize_expression(ep
, stmt
->expression
);
693 struct expression
*expr
= stmt
->expression
;
694 struct instruction
*ret
= alloc_instruction(OP_RET
, expr
->ctype
);
695 ret
->src
= linearize_expression(ep
, expr
);
696 add_one_insn(ep
, stmt
->pos
, ret
);
702 struct basic_block
*bb
= get_bound_block(ep
, stmt
->case_label
);
703 set_activeblock(ep
, bb
);
704 linearize_statement(ep
, stmt
->case_statement
);
709 struct symbol
*label
= stmt
->label_identifier
;
710 struct basic_block
*bb
;
713 bb
= get_bound_block(ep
, stmt
->label_identifier
);
714 set_activeblock(ep
, bb
);
715 linearize_statement(ep
, stmt
->label_statement
);
721 add_goto(ep
, get_bound_block(ep
, stmt
->goto_label
));
725 case STMT_COMPOUND
: {
728 concat_symbol_list(stmt
->syms
, &ep
->syms
);
729 FOR_EACH_PTR(stmt
->stmts
, s
) {
730 pseudo
= linearize_statement(ep
, s
);
736 * This could take 'likely/unlikely' into account, and
737 * switch the arms around appropriately..
740 struct basic_block
*bb_true
, *bb_false
, *endif
;
741 struct expression
*cond
= stmt
->if_conditional
;
743 bb_true
= alloc_basic_block();
744 bb_false
= endif
= alloc_basic_block();
746 linearize_cond_branch(ep
, cond
, bb_true
, bb_false
);
748 set_activeblock(ep
, bb_true
);
749 linearize_statement(ep
, stmt
->if_true
);
751 if (stmt
->if_false
) {
752 endif
= alloc_basic_block();
754 set_activeblock(ep
, bb_false
);
755 linearize_statement(ep
, stmt
->if_false
);
757 set_activeblock(ep
, endif
);
763 struct instruction
*switch_ins
;
764 struct basic_block
*switch_end
= alloc_basic_block();
767 pseudo
= linearize_expression(ep
, stmt
->switch_expression
);
768 switch_ins
= alloc_instruction(OP_SWITCH
, NULL
);
769 switch_ins
->cond
= pseudo
;
770 add_one_insn(ep
, stmt
->pos
, switch_ins
);
772 FOR_EACH_PTR(stmt
->switch_case
->symbol_list
, sym
) {
773 struct statement
*case_stmt
= sym
->stmt
;
774 struct basic_block
*bb_case
= get_bound_block(ep
, sym
);
775 struct multijmp
*jmp
;
777 if (!case_stmt
->case_expression
) {
778 jmp
= alloc_multijmp(bb_case
, 1, 0);
780 if (case_stmt
->case_expression
)
781 begin
= end
= case_stmt
->case_expression
->value
;
782 if (case_stmt
->case_to
)
783 end
= case_stmt
->case_to
->value
;
785 jmp
= alloc_multijmp(bb_case
, end
, begin
);
787 jmp
= alloc_multijmp(bb_case
, begin
, end
);
790 add_multijmp(&switch_ins
->multijmp_list
, jmp
);
791 add_bb(&bb_case
->parents
, ep
->active
);
794 bind_label(stmt
->switch_break
, switch_end
, stmt
->pos
);
796 /* And linearize the actual statement */
797 linearize_statement(ep
, stmt
->switch_statement
);
798 set_activeblock(ep
, switch_end
);
803 case STMT_ITERATOR
: {
804 struct statement
*pre_statement
= stmt
->iterator_pre_statement
;
805 struct expression
*pre_condition
= stmt
->iterator_pre_condition
;
806 struct statement
*statement
= stmt
->iterator_statement
;
807 struct statement
*post_statement
= stmt
->iterator_post_statement
;
808 struct expression
*post_condition
= stmt
->iterator_post_condition
;
809 struct basic_block
*loop_top
, *loop_body
, *loop_continue
, *loop_end
;
811 concat_symbol_list(stmt
->iterator_syms
, &ep
->syms
);
812 linearize_statement(ep
, pre_statement
);
814 loop_body
= loop_top
= alloc_basic_block();
815 loop_continue
= alloc_basic_block();
816 loop_end
= alloc_basic_block();
818 if (!post_statement
&& (pre_condition
== post_condition
)) {
820 * If it is a while loop, optimize away the post_condition.
822 post_condition
= NULL
;
823 loop_body
= loop_continue
;
824 loop_continue
= loop_top
;
825 loop_top
->flags
|= BB_REACHABLE
;
826 set_activeblock(ep
, loop_top
);
829 loop_top
->flags
|= BB_REACHABLE
;
831 linearize_cond_branch(ep
, pre_condition
, loop_body
, loop_end
);
833 bind_label(stmt
->iterator_continue
, loop_continue
, stmt
->pos
);
834 bind_label(stmt
->iterator_break
, loop_end
, stmt
->pos
);
836 set_activeblock(ep
, loop_body
);
837 linearize_statement(ep
, statement
);
838 add_goto(ep
, loop_continue
);
840 if (post_condition
) {
841 set_activeblock(ep
, loop_continue
);
842 linearize_statement(ep
, post_statement
);
843 linearize_cond_branch(ep
, post_condition
, loop_top
, loop_end
);
846 set_activeblock(ep
, loop_end
);
856 void mark_bb_reachable(struct basic_block
*bb
)
858 struct basic_block
*child
;
859 struct terminator_iterator term
;
860 struct basic_block_list
*bbstack
= NULL
;
862 if (!bb
|| bb
->flags
& BB_REACHABLE
)
865 add_bb(&bbstack
, bb
);
867 bb
= delete_last_basic_block(&bbstack
);
868 if (bb
->flags
& BB_REACHABLE
)
870 bb
->flags
|= BB_REACHABLE
;
871 init_terminator_iterator(last_instruction(bb
->insns
), &term
);
872 while ((child
=next_terminator_bb(&term
))) {
873 if (!(child
->flags
& BB_REACHABLE
))
874 add_bb(&bbstack
, child
);
879 void remove_unreachable_bbs(struct basic_block_list
**bblist
)
881 struct basic_block
*bb
, *child
;
882 struct list_iterator iterator
;
883 struct terminator_iterator term
;
885 init_iterator((struct ptr_list
**) bblist
, &iterator
, 0);
886 while((bb
=next_basic_block(&iterator
)))
887 bb
->flags
&= ~BB_REACHABLE
;
889 init_iterator((struct ptr_list
**) bblist
, &iterator
, 0);
890 mark_bb_reachable(next_basic_block(&iterator
));
891 while((bb
=next_basic_block(&iterator
))) {
892 if (bb
->flags
& BB_REACHABLE
)
894 init_terminator_iterator(last_instruction(bb
->insns
), &term
);
895 while ((child
=next_terminator_bb(&term
)))
896 replace_basic_block_list(&child
->parents
, bb
, NULL
);
897 delete_iterator(&iterator
);
901 void pack_basic_blocks(struct basic_block_list
**bblist
)
903 struct basic_block
*bb
;
904 struct list_iterator iterator
;
906 remove_unreachable_bbs(bblist
);
907 init_bb_iterator(bblist
, &iterator
, 0);
908 while((bb
=next_basic_block(&iterator
))) {
909 struct list_iterator it_parents
;
910 struct terminator_iterator term
;
911 struct instruction
*jmp
;
912 struct basic_block
*target
, *sibling
, *parent
;
914 if (!is_branch_goto(jmp
=last_instruction(bb
->insns
)))
917 target
= jmp
->bb_true
? jmp
->bb_true
: jmp
->bb_false
;
920 if (bb_list_size(target
->parents
) != 1 && jmp
!= first_instruction(bb
->insns
))
923 /* Transfer the parents' terminator to target directly. */
924 replace_basic_block_list(&target
->parents
, bb
, NULL
);
925 init_bb_iterator(&bb
->parents
, &it_parents
, 0);
926 while((parent
=next_basic_block(&it_parents
))) {
927 init_terminator_iterator(last_instruction(parent
->insns
), &term
);
928 while ((sibling
=next_terminator_bb(&term
))) {
930 replace_terminator_bb(&term
, target
);
931 add_bb(&target
->parents
, parent
);
936 /* Move the instructions to the target block. */
937 delete_last_instruction(&bb
->insns
);
939 concat_instruction_list(target
->insns
, &bb
->insns
);
940 free_instruction_list(&target
->insns
);
941 target
->insns
= bb
->insns
;
943 delete_iterator(&iterator
);
947 void linearize_symbol(struct symbol
*sym
)
949 struct symbol
*base_type
;
953 base_type
= sym
->ctype
.base_type
;
956 if (base_type
->type
== SYM_FN
) {
957 if (base_type
->stmt
) {
958 struct entrypoint
*ep
= alloc_entrypoint();
959 struct basic_block
*bb
= alloc_basic_block();
962 bb
->flags
|= BB_REACHABLE
;
963 set_activeblock(ep
, bb
);
964 concat_symbol_list(base_type
->arguments
, &ep
->syms
);
965 linearize_statement(ep
, base_type
->stmt
);
966 pack_basic_blocks(&ep
->bbs
);