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
20 #include "expression.h"
21 #include "linearize.h"
25 pseudo_t
linearize_statement(struct entrypoint
*ep
, struct statement
*stmt
);
26 pseudo_t
linearize_expression(struct entrypoint
*ep
, struct expression
*expr
);
28 static pseudo_t
add_binary_op(struct entrypoint
*ep
, struct symbol
*ctype
, int op
, pseudo_t left
, pseudo_t right
);
29 static pseudo_t
add_setval(struct entrypoint
*ep
, struct symbol
*ctype
, struct expression
*val
);
30 static pseudo_t
linearize_one_symbol(struct entrypoint
*ep
, struct symbol
*sym
);
33 static pseudo_t
add_load(struct entrypoint
*ep
, struct access_data
*);
34 static pseudo_t
linearize_initializer(struct entrypoint
*ep
, struct expression
*initializer
, struct access_data
*);
35 static pseudo_t
cast_pseudo(struct entrypoint
*ep
, pseudo_t src
, struct symbol
*from
, struct symbol
*to
);
37 struct pseudo void_pseudo
= {};
39 static struct position current_pos
;
41 ALLOCATOR(pseudo_user
, "pseudo_user");
43 static struct instruction
*alloc_instruction(int opcode
, int size
)
45 struct instruction
* insn
= __alloc_instruction(0);
46 insn
->opcode
= opcode
;
48 insn
->pos
= current_pos
;
52 static inline int type_size(struct symbol
*type
)
54 return type
? type
->bit_size
> 0 ? type
->bit_size
: 0 : 0;
57 static struct instruction
*alloc_typed_instruction(int opcode
, struct symbol
*type
)
59 struct instruction
*insn
= alloc_instruction(opcode
, type_size(type
));
64 static struct entrypoint
*alloc_entrypoint(void)
66 return __alloc_entrypoint(0);
69 static struct basic_block
*alloc_basic_block(struct entrypoint
*ep
, struct position pos
)
72 struct basic_block
*bb
= __alloc_basic_block(0);
80 static struct multijmp
*alloc_multijmp(struct basic_block
*target
, int begin
, int end
)
82 struct multijmp
*multijmp
= __alloc_multijmp(0);
83 multijmp
->target
= target
;
84 multijmp
->begin
= begin
;
89 static inline int regno(pseudo_t n
)
92 if (n
&& n
->type
== PSEUDO_REG
)
97 const char *show_pseudo(pseudo_t pseudo
)
100 static char buffer
[4][64];
108 buf
= buffer
[3 & ++n
];
109 switch(pseudo
->type
) {
111 struct symbol
*sym
= pseudo
->sym
;
112 struct expression
*expr
;
114 if (sym
->bb_target
) {
115 snprintf(buf
, 64, ".L%u", sym
->bb_target
->nr
);
119 snprintf(buf
, 64, "%s", show_ident(sym
->ident
));
122 expr
= sym
->initializer
;
123 snprintf(buf
, 64, "<anon symbol:%p>", sym
);
125 switch (expr
->type
) {
127 snprintf(buf
, 64, "<symbol value: %lld>", expr
->value
);
130 return show_string(expr
->string
);
138 i
= snprintf(buf
, 64, "%%r%d", pseudo
->nr
);
140 sprintf(buf
+i
, "(%s)", show_ident(pseudo
->ident
));
143 long long value
= pseudo
->value
;
144 if (value
> 1000 || value
< -1000)
145 snprintf(buf
, 64, "$%#llx", value
);
147 snprintf(buf
, 64, "$%lld", value
);
151 snprintf(buf
, 64, "%%arg%d", pseudo
->nr
);
154 i
= snprintf(buf
, 64, "%%phi%d", pseudo
->nr
);
156 sprintf(buf
+i
, "(%s)", show_ident(pseudo
->ident
));
159 snprintf(buf
, 64, "<bad pseudo type %d>", pseudo
->type
);
164 static const char *opcodes
[] = {
165 [OP_BADOP
] = "bad_op",
168 [OP_ENTRY
] = "<entry-point>",
174 [OP_SWITCH
] = "switch",
175 [OP_INVOKE
] = "invoke",
176 [OP_COMPUTEDGOTO
] = "jmp *",
177 [OP_UNWIND
] = "unwind",
196 [OP_AND_BOOL
] = "and-bool",
197 [OP_OR_BOOL
] = "or-bool",
199 /* Binary comparison */
200 [OP_SET_EQ
] = "seteq",
201 [OP_SET_NE
] = "setne",
202 [OP_SET_LE
] = "setle",
203 [OP_SET_GE
] = "setge",
204 [OP_SET_LT
] = "setlt",
205 [OP_SET_GT
] = "setgt",
208 [OP_SET_BE
] = "setbe",
209 [OP_SET_AE
] = "setae",
215 /* Special three-input */
219 [OP_MALLOC
] = "malloc",
221 [OP_ALLOCA
] = "alloca",
223 [OP_STORE
] = "store",
225 [OP_SYMADDR
] = "symaddr",
226 [OP_GET_ELEMENT_PTR
] = "getelem",
230 [OP_PHISOURCE
] = "phisrc",
232 [OP_SCAST
] = "scast",
233 [OP_FPCAST
] = "fpcast",
234 [OP_PTRCAST
] = "ptrcast",
235 [OP_INLINED_CALL
] = "# call",
237 [OP_VANEXT
] = "va_next",
238 [OP_VAARG
] = "va_arg",
239 [OP_SLICE
] = "slice",
243 [OP_DEATHNOTE
] = "dead",
246 /* Sparse tagging (line numbers, context, whatever) */
247 [OP_CONTEXT
] = "context",
248 [OP_RANGE
] = "range-check",
253 static char *show_asm_constraints(char *buf
, const char *sep
, struct asm_constraint_list
*list
)
255 struct asm_constraint
*entry
;
257 FOR_EACH_PTR(list
, entry
) {
258 buf
+= sprintf(buf
, "%s\"%s\"", sep
, entry
->constraint
);
260 buf
+= sprintf(buf
, " (%s)", show_pseudo(entry
->pseudo
));
262 buf
+= sprintf(buf
, " [%s]", show_ident(entry
->ident
));
264 } END_FOR_EACH_PTR(entry
);
268 static char *show_asm(char *buf
, struct instruction
*insn
)
270 struct asm_rules
*rules
= insn
->asm_rules
;
272 buf
+= sprintf(buf
, "\"%s\"", insn
->string
);
273 buf
= show_asm_constraints(buf
, "\n\t\tout: ", rules
->outputs
);
274 buf
= show_asm_constraints(buf
, "\n\t\tin: ", rules
->inputs
);
275 buf
= show_asm_constraints(buf
, "\n\t\tclobber: ", rules
->clobbers
);
279 const char *show_instruction(struct instruction
*insn
)
281 int opcode
= insn
->opcode
;
282 static char buffer
[4096];
287 buf
+= sprintf(buf
, "# ");
289 if (opcode
< ARRAY_SIZE(opcodes
)) {
290 const char *op
= opcodes
[opcode
];
292 buf
+= sprintf(buf
, "opcode:%d", opcode
);
294 buf
+= sprintf(buf
, "%s", op
);
296 buf
+= sprintf(buf
, ".%d", insn
->size
);
297 memset(buf
, ' ', 20);
301 if (buf
< buffer
+ 12)
305 if (insn
->src
&& insn
->src
!= VOID
)
306 buf
+= sprintf(buf
, "%s", show_pseudo(insn
->src
));
310 buf
+= sprintf(buf
, "%s, .L%u, .L%u", show_pseudo(insn
->cond
), insn
->bb_true
->nr
, insn
->bb_false
->nr
);
314 buf
+= sprintf(buf
, ".L%u", insn
->bb_true
->nr
);
318 struct symbol
*sym
= insn
->symbol
->sym
;
319 buf
+= sprintf(buf
, "%s <- ", show_pseudo(insn
->target
));
321 if (!insn
->bb
&& !sym
)
323 if (sym
->bb_target
) {
324 buf
+= sprintf(buf
, ".L%u", sym
->bb_target
->nr
);
328 buf
+= sprintf(buf
, "%s", show_ident(sym
->ident
));
331 buf
+= sprintf(buf
, "<anon symbol:%p>", sym
);
336 struct expression
*expr
= insn
->val
;
338 buf
+= sprintf(buf
, "%s <- ", show_pseudo(insn
->target
));
341 buf
+= sprintf(buf
, "%s", "<none>");
345 switch (expr
->type
) {
347 buf
+= sprintf(buf
, "%lld", expr
->value
);
350 buf
+= sprintf(buf
, "%Lf", expr
->fvalue
);
353 buf
+= sprintf(buf
, "%.40s", show_string(expr
->string
));
356 buf
+= sprintf(buf
, "%s", show_ident(expr
->symbol
->ident
));
361 buf
+= sprintf(buf
, ".L%u", sym
->bb_target
->nr
);
364 buf
+= sprintf(buf
, "SETVAL EXPR TYPE %d", expr
->type
);
369 struct multijmp
*jmp
;
370 buf
+= sprintf(buf
, "%s", show_pseudo(insn
->cond
));
371 FOR_EACH_PTR(insn
->multijmp_list
, jmp
) {
372 if (jmp
->begin
== jmp
->end
)
373 buf
+= sprintf(buf
, ", %d -> .L%u", jmp
->begin
, jmp
->target
->nr
);
374 else if (jmp
->begin
< jmp
->end
)
375 buf
+= sprintf(buf
, ", %d ... %d -> .L%u", jmp
->begin
, jmp
->end
, jmp
->target
->nr
);
377 buf
+= sprintf(buf
, ", default -> .L%u", jmp
->target
->nr
);
378 } END_FOR_EACH_PTR(jmp
);
381 case OP_COMPUTEDGOTO
: {
382 struct multijmp
*jmp
;
383 buf
+= sprintf(buf
, "%s", show_pseudo(insn
->target
));
384 FOR_EACH_PTR(insn
->multijmp_list
, jmp
) {
385 buf
+= sprintf(buf
, ", .L%u", jmp
->target
->nr
);
386 } END_FOR_EACH_PTR(jmp
);
391 struct instruction
*phi
;
392 buf
+= sprintf(buf
, "%s <- %s ", show_pseudo(insn
->target
), show_pseudo(insn
->phi_src
));
393 FOR_EACH_PTR(insn
->phi_users
, phi
) {
394 buf
+= sprintf(buf
, " (%s)", show_pseudo(phi
->target
));
395 } END_FOR_EACH_PTR(phi
);
401 const char *s
= " <-";
402 buf
+= sprintf(buf
, "%s", show_pseudo(insn
->target
));
403 FOR_EACH_PTR(insn
->phi_list
, phi
) {
404 buf
+= sprintf(buf
, "%s %s", s
, show_pseudo(phi
));
406 } END_FOR_EACH_PTR(phi
);
409 case OP_LOAD
: case OP_LNOP
:
410 buf
+= sprintf(buf
, "%s <- %d[%s]", show_pseudo(insn
->target
), insn
->offset
, show_pseudo(insn
->src
));
412 case OP_STORE
: case OP_SNOP
:
413 buf
+= sprintf(buf
, "%s -> %d[%s]", show_pseudo(insn
->target
), insn
->offset
, show_pseudo(insn
->src
));
415 case OP_INLINED_CALL
:
418 if (insn
->target
&& insn
->target
!= VOID
)
419 buf
+= sprintf(buf
, "%s <- ", show_pseudo(insn
->target
));
420 buf
+= sprintf(buf
, "%s", show_pseudo(insn
->func
));
421 FOR_EACH_PTR(insn
->arguments
, arg
) {
422 buf
+= sprintf(buf
, ", %s", show_pseudo(arg
));
423 } END_FOR_EACH_PTR(arg
);
430 buf
+= sprintf(buf
, "%s <- (%d) %s",
431 show_pseudo(insn
->target
),
432 type_size(insn
->orig_type
),
433 show_pseudo(insn
->src
));
435 case OP_BINARY
... OP_BINARY_END
:
436 case OP_BINCMP
... OP_BINCMP_END
:
437 buf
+= sprintf(buf
, "%s <- %s, %s", show_pseudo(insn
->target
), show_pseudo(insn
->src1
), show_pseudo(insn
->src2
));
441 buf
+= sprintf(buf
, "%s <- %s, %s, %s", show_pseudo(insn
->target
),
442 show_pseudo(insn
->src1
), show_pseudo(insn
->src2
), show_pseudo(insn
->src3
));
446 buf
+= sprintf(buf
, "%s <- %s, %d, %d", show_pseudo(insn
->target
), show_pseudo(insn
->base
), insn
->from
, insn
->len
);
449 case OP_NOT
: case OP_NEG
:
450 buf
+= sprintf(buf
, "%s <- %s", show_pseudo(insn
->target
), show_pseudo(insn
->src1
));
454 buf
+= sprintf(buf
, "%s%d", insn
->check
? "check: " : "", insn
->increment
);
457 buf
+= sprintf(buf
, "%s between %s..%s", show_pseudo(insn
->src1
), show_pseudo(insn
->src2
), show_pseudo(insn
->src3
));
460 buf
+= sprintf(buf
, "%s <- %s", show_pseudo(insn
->target
), show_pseudo(insn
->src1
));
463 buf
+= sprintf(buf
, "%s", show_pseudo(insn
->target
));
466 buf
= show_asm(buf
, insn
);
469 buf
+= sprintf(buf
, "%s <- %s", show_pseudo(insn
->target
), show_pseudo(insn
->src
));
475 if (buf
>= buffer
+ sizeof(buffer
))
476 die("instruction buffer overflowed %td\n", buf
- buffer
);
477 do { --buf
; } while (*buf
== ' ');
482 void show_bb(struct basic_block
*bb
)
484 struct instruction
*insn
;
486 printf(".L%u:\n", bb
->nr
);
488 pseudo_t needs
, defines
;
489 printf("%s:%d\n", stream_name(bb
->pos
.stream
), bb
->pos
.line
);
491 FOR_EACH_PTR(bb
->needs
, needs
) {
492 struct instruction
*def
= needs
->def
;
493 if (def
->opcode
!= OP_PHI
) {
494 printf(" **uses %s (from .L%u)**\n", show_pseudo(needs
), def
->bb
->nr
);
497 const char *sep
= " ";
498 printf(" **uses %s (from", show_pseudo(needs
));
499 FOR_EACH_PTR(def
->phi_list
, phi
) {
502 printf("%s(%s:.L%u)", sep
, show_pseudo(phi
), phi
->def
->bb
->nr
);
504 } END_FOR_EACH_PTR(phi
);
507 } END_FOR_EACH_PTR(needs
);
509 FOR_EACH_PTR(bb
->defines
, defines
) {
510 printf(" **defines %s **\n", show_pseudo(defines
));
511 } END_FOR_EACH_PTR(defines
);
514 struct basic_block
*from
;
515 FOR_EACH_PTR(bb
->parents
, from
) {
516 printf(" **from .L%u (%s:%d:%d)**\n", from
->nr
,
517 stream_name(from
->pos
.stream
), from
->pos
.line
, from
->pos
.pos
);
518 } END_FOR_EACH_PTR(from
);
522 struct basic_block
*to
;
523 FOR_EACH_PTR(bb
->children
, to
) {
524 printf(" **to .L%u (%s:%d:%d)**\n", to
->nr
,
525 stream_name(to
->pos
.stream
), to
->pos
.line
, to
->pos
.pos
);
526 } END_FOR_EACH_PTR(to
);
530 FOR_EACH_PTR(bb
->insns
, insn
) {
531 if (!insn
->bb
&& verbose
< 2)
533 printf("\t%s\n", show_instruction(insn
));
534 } END_FOR_EACH_PTR(insn
);
535 if (!bb_terminated(bb
))
539 static void show_symbol_usage(pseudo_t pseudo
)
541 struct pseudo_user
*pu
;
544 FOR_EACH_PTR(pseudo
->users
, pu
) {
545 printf("\t%s\n", show_instruction(pu
->insn
));
546 } END_FOR_EACH_PTR(pu
);
550 void show_entry(struct entrypoint
*ep
)
553 struct basic_block
*bb
;
555 printf("%s:\n", show_ident(ep
->name
->ident
));
558 printf("ep %p: %s\n", ep
, show_ident(ep
->name
->ident
));
560 FOR_EACH_PTR(ep
->syms
, sym
) {
563 if (!sym
->pseudo
->users
)
565 printf(" sym: %p %s\n", sym
, show_ident(sym
->ident
));
566 if (sym
->ctype
.modifiers
& (MOD_EXTERN
| MOD_STATIC
| MOD_ADDRESSABLE
))
567 printf("\texternal visibility\n");
568 show_symbol_usage(sym
->pseudo
);
569 } END_FOR_EACH_PTR(sym
);
574 FOR_EACH_PTR(ep
->bbs
, bb
) {
577 if (!bb
->parents
&& !bb
->children
&& !bb
->insns
&& verbose
< 2)
581 } END_FOR_EACH_PTR(bb
);
586 static void bind_label(struct symbol
*label
, struct basic_block
*bb
, struct position pos
)
588 if (label
->bb_target
)
589 warning(pos
, "label '%s' already bound", show_ident(label
->ident
));
590 label
->bb_target
= bb
;
593 static struct basic_block
* get_bound_block(struct entrypoint
*ep
, struct symbol
*label
)
595 struct basic_block
*bb
= label
->bb_target
;
598 bb
= alloc_basic_block(ep
, label
->pos
);
599 label
->bb_target
= bb
;
604 static void finish_block(struct entrypoint
*ep
)
606 struct basic_block
*src
= ep
->active
;
607 if (bb_reachable(src
))
611 static void add_goto(struct entrypoint
*ep
, struct basic_block
*dst
)
613 struct basic_block
*src
= ep
->active
;
614 if (bb_reachable(src
)) {
615 struct instruction
*br
= alloc_instruction(OP_BR
, 0);
617 add_bb(&dst
->parents
, src
);
618 add_bb(&src
->children
, dst
);
620 add_instruction(&src
->insns
, br
);
625 static void add_one_insn(struct entrypoint
*ep
, struct instruction
*insn
)
627 struct basic_block
*bb
= ep
->active
;
629 if (bb_reachable(bb
)) {
631 add_instruction(&bb
->insns
, insn
);
635 static void set_activeblock(struct entrypoint
*ep
, struct basic_block
*bb
)
637 if (!bb_terminated(ep
->active
))
641 if (bb_reachable(bb
))
642 add_bb(&ep
->bbs
, bb
);
645 static void remove_parent(struct basic_block
*child
, struct basic_block
*parent
)
647 remove_bb_from_list(&child
->parents
, parent
, 1);
649 repeat_phase
|= REPEAT_CFG_CLEANUP
;
652 /* Change a "switch" or a conditional branch into a branch */
653 void insert_branch(struct basic_block
*bb
, struct instruction
*jmp
, struct basic_block
*target
)
655 struct instruction
*br
, *old
;
656 struct basic_block
*child
;
658 /* Remove the switch */
659 old
= delete_last_instruction(&bb
->insns
);
661 kill_instruction(old
);
663 br
= alloc_instruction(OP_BR
, 0);
665 br
->bb_true
= target
;
666 add_instruction(&bb
->insns
, br
);
668 FOR_EACH_PTR(bb
->children
, child
) {
669 if (child
== target
) {
670 target
= NULL
; /* Trigger just once */
673 DELETE_CURRENT_PTR(child
);
674 remove_parent(child
, bb
);
675 } END_FOR_EACH_PTR(child
);
676 PACK_PTR_LIST(&bb
->children
);
680 void insert_select(struct basic_block
*bb
, struct instruction
*br
, struct instruction
*phi_node
, pseudo_t if_true
, pseudo_t if_false
)
683 struct instruction
*select
;
685 /* Remove the 'br' */
686 delete_last_instruction(&bb
->insns
);
688 select
= alloc_instruction(OP_SEL
, phi_node
->size
);
692 use_pseudo(select
, br
->cond
, &select
->src1
);
694 target
= phi_node
->target
;
695 assert(target
->def
== phi_node
);
696 select
->target
= target
;
697 target
->def
= select
;
699 use_pseudo(select
, if_true
, &select
->src2
);
700 use_pseudo(select
, if_false
, &select
->src3
);
702 add_instruction(&bb
->insns
, select
);
703 add_instruction(&bb
->insns
, br
);
706 static inline int bb_empty(struct basic_block
*bb
)
711 /* Add a label to the currently active block, return new active block */
712 static struct basic_block
* add_label(struct entrypoint
*ep
, struct symbol
*label
)
714 struct basic_block
*bb
= label
->bb_target
;
717 set_activeblock(ep
, bb
);
721 if (!bb_reachable(bb
) || !bb_empty(bb
)) {
722 bb
= alloc_basic_block(ep
, label
->pos
);
723 set_activeblock(ep
, bb
);
725 label
->bb_target
= bb
;
729 static void add_branch(struct entrypoint
*ep
, struct expression
*expr
, pseudo_t cond
, struct basic_block
*bb_true
, struct basic_block
*bb_false
)
731 struct basic_block
*bb
= ep
->active
;
732 struct instruction
*br
;
734 if (bb_reachable(bb
)) {
735 br
= alloc_instruction(OP_CBR
, 0);
736 use_pseudo(br
, cond
, &br
->cond
);
737 br
->bb_true
= bb_true
;
738 br
->bb_false
= bb_false
;
739 add_bb(&bb_true
->parents
, bb
);
740 add_bb(&bb_false
->parents
, bb
);
741 add_bb(&bb
->children
, bb_true
);
742 add_bb(&bb
->children
, bb_false
);
743 add_one_insn(ep
, br
);
747 /* Dummy pseudo allocator */
748 pseudo_t
alloc_pseudo(struct instruction
*def
)
751 struct pseudo
* pseudo
= __alloc_pseudo(0);
752 pseudo
->type
= PSEUDO_REG
;
758 static void clear_symbol_pseudos(struct entrypoint
*ep
)
762 FOR_EACH_PTR(ep
->accesses
, pseudo
) {
763 pseudo
->sym
->pseudo
= NULL
;
764 } END_FOR_EACH_PTR(pseudo
);
767 static pseudo_t
symbol_pseudo(struct entrypoint
*ep
, struct symbol
*sym
)
774 pseudo
= sym
->pseudo
;
776 pseudo
= __alloc_pseudo(0);
778 pseudo
->type
= PSEUDO_SYM
;
780 pseudo
->ident
= sym
->ident
;
781 sym
->pseudo
= pseudo
;
782 add_pseudo(&ep
->accesses
, pseudo
);
784 /* Symbol pseudos have neither nr, usage nor def */
788 pseudo_t
value_pseudo(struct symbol
*type
, long long val
)
790 #define MAX_VAL_HASH 64
791 static struct pseudo_list
*prev
[MAX_VAL_HASH
];
792 int hash
= val
& (MAX_VAL_HASH
-1);
793 struct pseudo_list
**list
= prev
+ hash
;
794 int size
= type
? type
->bit_size
: value_size(val
);
798 FOR_EACH_PTR(*list
, pseudo
) {
799 if (pseudo
->value
== val
&& pseudo
->size
== size
)
801 } END_FOR_EACH_PTR(pseudo
);
803 pseudo
= __alloc_pseudo(0);
804 pseudo
->type
= PSEUDO_VAL
;
807 add_pseudo(list
, pseudo
);
809 /* Value pseudos have neither nr, usage nor def */
813 static pseudo_t
argument_pseudo(struct entrypoint
*ep
, int nr
)
815 pseudo_t pseudo
= __alloc_pseudo(0);
816 struct instruction
*entry
= ep
->entry
;
818 pseudo
->type
= PSEUDO_ARG
;
821 add_pseudo(&entry
->arg_list
, pseudo
);
823 /* Argument pseudos have neither usage nor def */
827 pseudo_t
alloc_phi(struct basic_block
*source
, pseudo_t pseudo
, int size
)
829 struct instruction
*insn
;
836 insn
= alloc_instruction(OP_PHISOURCE
, size
);
837 phi
= __alloc_pseudo(0);
838 phi
->type
= PSEUDO_PHI
;
842 use_pseudo(insn
, pseudo
, &insn
->phi_src
);
845 add_instruction(&source
->insns
, insn
);
850 * We carry the "access_data" structure around for any accesses,
851 * which simplifies things a lot. It contains all the access
852 * information in one place.
855 struct symbol
*result_type
; // result ctype
856 struct symbol
*source_type
; // source ctype
857 pseudo_t address
; // pseudo containing address ..
858 unsigned int offset
; // byte offset
862 static void finish_address_gen(struct entrypoint
*ep
, struct access_data
*ad
)
866 static int linearize_simple_address(struct entrypoint
*ep
,
867 struct expression
*addr
,
868 struct access_data
*ad
)
870 if (addr
->type
== EXPR_SYMBOL
) {
871 linearize_one_symbol(ep
, addr
->symbol
);
872 ad
->address
= symbol_pseudo(ep
, addr
->symbol
);
875 if (addr
->type
== EXPR_BINOP
) {
876 if (addr
->right
->type
== EXPR_VALUE
) {
877 if (addr
->op
== '+') {
878 ad
->offset
+= get_expression_value(addr
->right
);
879 return linearize_simple_address(ep
, addr
->left
, ad
);
883 ad
->address
= linearize_expression(ep
, addr
);
887 static struct symbol
*base_type(struct symbol
*sym
)
889 struct symbol
*base
= sym
;
892 if (sym
->type
== SYM_NODE
)
893 base
= base
->ctype
.base_type
;
894 if (base
->type
== SYM_BITFIELD
)
895 return base
->ctype
.base_type
;
900 static int linearize_address_gen(struct entrypoint
*ep
,
901 struct expression
*expr
,
902 struct access_data
*ad
)
904 struct symbol
*ctype
= expr
->ctype
;
909 ad
->result_type
= ctype
;
910 ad
->source_type
= base_type(ctype
);
911 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '*')
912 return linearize_simple_address(ep
, expr
->unop
, ad
);
914 warning(expr
->pos
, "generating address of non-lvalue (%d)", expr
->type
);
918 static pseudo_t
add_load(struct entrypoint
*ep
, struct access_data
*ad
)
920 struct instruction
*insn
;
923 insn
= alloc_typed_instruction(OP_LOAD
, ad
->source_type
);
924 new = alloc_pseudo(insn
);
927 insn
->offset
= ad
->offset
;
928 use_pseudo(insn
, ad
->address
, &insn
->src
);
929 add_one_insn(ep
, insn
);
933 static void add_store(struct entrypoint
*ep
, struct access_data
*ad
, pseudo_t value
)
935 struct basic_block
*bb
= ep
->active
;
937 if (bb_reachable(bb
)) {
938 struct instruction
*store
= alloc_typed_instruction(OP_STORE
, ad
->source_type
);
939 store
->offset
= ad
->offset
;
940 use_pseudo(store
, value
, &store
->target
);
941 use_pseudo(store
, ad
->address
, &store
->src
);
942 add_one_insn(ep
, store
);
946 static pseudo_t
linearize_store_gen(struct entrypoint
*ep
,
948 struct access_data
*ad
)
950 pseudo_t store
= value
;
952 if (type_size(ad
->source_type
) != type_size(ad
->result_type
)) {
953 struct symbol
*ctype
= ad
->result_type
;
954 unsigned int shift
= ctype
->bit_offset
;
955 unsigned int size
= ctype
->bit_size
;
956 pseudo_t orig
= add_load(ep
, ad
);
957 unsigned long long mask
= (1ULL << size
) - 1;
960 store
= add_binary_op(ep
, ad
->source_type
, OP_SHL
, value
, value_pseudo(ctype
, shift
));
963 orig
= add_binary_op(ep
, ad
->source_type
, OP_AND
, orig
, value_pseudo(ctype
, ~mask
));
964 store
= add_binary_op(ep
, ad
->source_type
, OP_OR
, orig
, store
);
966 add_store(ep
, ad
, store
);
970 static pseudo_t
add_binary_op(struct entrypoint
*ep
, struct symbol
*ctype
, int op
, pseudo_t left
, pseudo_t right
)
972 struct instruction
*insn
= alloc_typed_instruction(op
, ctype
);
973 pseudo_t target
= alloc_pseudo(insn
);
974 insn
->target
= target
;
975 use_pseudo(insn
, left
, &insn
->src1
);
976 use_pseudo(insn
, right
, &insn
->src2
);
977 add_one_insn(ep
, insn
);
981 static pseudo_t
add_setval(struct entrypoint
*ep
, struct symbol
*ctype
, struct expression
*val
)
983 struct instruction
*insn
= alloc_typed_instruction(OP_SETVAL
, ctype
);
984 pseudo_t target
= alloc_pseudo(insn
);
985 insn
->target
= target
;
987 add_one_insn(ep
, insn
);
991 static pseudo_t
add_symbol_address(struct entrypoint
*ep
, struct symbol
*sym
)
993 struct instruction
*insn
= alloc_instruction(OP_SYMADDR
, bits_in_pointer
);
994 pseudo_t target
= alloc_pseudo(insn
);
996 insn
->target
= target
;
997 use_pseudo(insn
, symbol_pseudo(ep
, sym
), &insn
->symbol
);
998 add_one_insn(ep
, insn
);
1002 static pseudo_t
linearize_load_gen(struct entrypoint
*ep
, struct access_data
*ad
)
1004 struct symbol
*ctype
= ad
->result_type
;
1005 pseudo_t
new = add_load(ep
, ad
);
1007 if (ctype
->bit_offset
) {
1008 pseudo_t shift
= value_pseudo(ctype
, ctype
->bit_offset
);
1009 pseudo_t newval
= add_binary_op(ep
, ad
->source_type
, OP_LSR
, new, shift
);
1012 if (ctype
->bit_size
!= type_size(ad
->source_type
))
1013 new = cast_pseudo(ep
, new, ad
->source_type
, ad
->result_type
);
1017 static pseudo_t
linearize_access(struct entrypoint
*ep
, struct expression
*expr
)
1019 struct access_data ad
= { NULL
, };
1022 if (!linearize_address_gen(ep
, expr
, &ad
))
1024 value
= linearize_load_gen(ep
, &ad
);
1025 finish_address_gen(ep
, &ad
);
1030 static pseudo_t
linearize_inc_dec(struct entrypoint
*ep
, struct expression
*expr
, int postop
)
1032 struct access_data ad
= { NULL
, };
1033 pseudo_t old
, new, one
;
1034 int op
= expr
->op
== SPECIAL_INCREMENT
? OP_ADD
: OP_SUB
;
1036 if (!linearize_address_gen(ep
, expr
->unop
, &ad
))
1039 old
= linearize_load_gen(ep
, &ad
);
1040 one
= value_pseudo(expr
->ctype
, expr
->op_value
);
1041 new = add_binary_op(ep
, expr
->ctype
, op
, old
, one
);
1042 linearize_store_gen(ep
, new, &ad
);
1043 finish_address_gen(ep
, &ad
);
1044 return postop
? old
: new;
1047 static pseudo_t
add_uniop(struct entrypoint
*ep
, struct expression
*expr
, int op
, pseudo_t src
)
1049 struct instruction
*insn
= alloc_typed_instruction(op
, expr
->ctype
);
1050 pseudo_t
new = alloc_pseudo(insn
);
1053 use_pseudo(insn
, src
, &insn
->src1
);
1054 add_one_insn(ep
, insn
);
1058 static pseudo_t
linearize_slice(struct entrypoint
*ep
, struct expression
*expr
)
1060 pseudo_t pre
= linearize_expression(ep
, expr
->base
);
1061 struct instruction
*insn
= alloc_typed_instruction(OP_SLICE
, expr
->ctype
);
1062 pseudo_t
new = alloc_pseudo(insn
);
1065 insn
->from
= expr
->r_bitpos
;
1066 insn
->len
= expr
->r_nrbits
;
1067 use_pseudo(insn
, pre
, &insn
->base
);
1068 add_one_insn(ep
, insn
);
1072 static pseudo_t
linearize_regular_preop(struct entrypoint
*ep
, struct expression
*expr
)
1074 pseudo_t pre
= linearize_expression(ep
, expr
->unop
);
1079 pseudo_t zero
= value_pseudo(expr
->ctype
, 0);
1080 return add_binary_op(ep
, expr
->ctype
, OP_SET_EQ
, pre
, zero
);
1083 return add_uniop(ep
, expr
, OP_NOT
, pre
);
1085 return add_uniop(ep
, expr
, OP_NEG
, pre
);
1090 static pseudo_t
linearize_preop(struct entrypoint
*ep
, struct expression
*expr
)
1093 * '*' is an lvalue access, and is fundamentally different
1094 * from an arithmetic operation. Maybe it should have an
1095 * expression type of its own..
1097 if (expr
->op
== '*')
1098 return linearize_access(ep
, expr
);
1099 if (expr
->op
== SPECIAL_INCREMENT
|| expr
->op
== SPECIAL_DECREMENT
)
1100 return linearize_inc_dec(ep
, expr
, 0);
1101 return linearize_regular_preop(ep
, expr
);
1104 static pseudo_t
linearize_postop(struct entrypoint
*ep
, struct expression
*expr
)
1106 return linearize_inc_dec(ep
, expr
, 1);
1110 * Casts to pointers are "less safe" than other casts, since
1111 * they imply type-unsafe accesses. "void *" is a special
1112 * case, since you can't access through it anyway without another
1115 static struct instruction
*alloc_cast_instruction(struct symbol
*src
, struct symbol
*ctype
)
1117 int opcode
= OP_CAST
;
1118 struct symbol
*base
= ctype
;
1120 if (src
->ctype
.modifiers
& MOD_SIGNED
)
1122 if (base
->type
== SYM_NODE
)
1123 base
= base
->ctype
.base_type
;
1124 if (base
->type
== SYM_PTR
) {
1125 base
= base
->ctype
.base_type
;
1126 if (base
!= &void_ctype
)
1127 opcode
= OP_PTRCAST
;
1128 } else if (base
->ctype
.base_type
== &fp_type
)
1130 return alloc_typed_instruction(opcode
, ctype
);
1133 static pseudo_t
cast_pseudo(struct entrypoint
*ep
, pseudo_t src
, struct symbol
*from
, struct symbol
*to
)
1136 struct instruction
*insn
;
1142 if (from
->bit_size
< 0 || to
->bit_size
< 0)
1144 insn
= alloc_cast_instruction(from
, to
);
1145 result
= alloc_pseudo(insn
);
1146 insn
->target
= result
;
1147 insn
->orig_type
= from
;
1148 use_pseudo(insn
, src
, &insn
->src
);
1149 add_one_insn(ep
, insn
);
1153 static int opcode_sign(int opcode
, struct symbol
*ctype
)
1155 if (ctype
&& (ctype
->ctype
.modifiers
& MOD_SIGNED
)) {
1157 case OP_MULU
: case OP_DIVU
: case OP_MODU
: case OP_LSR
:
1164 static inline pseudo_t
add_convert_to_bool(struct entrypoint
*ep
, pseudo_t src
, struct symbol
*type
)
1169 if (is_bool_type(type
))
1171 zero
= value_pseudo(type
, 0);
1173 return add_binary_op(ep
, &bool_ctype
, op
, src
, zero
);
1176 static pseudo_t
linearize_expression_to_bool(struct entrypoint
*ep
, struct expression
*expr
)
1179 dst
= linearize_expression(ep
, expr
);
1180 dst
= add_convert_to_bool(ep
, dst
, expr
->ctype
);
1184 static pseudo_t
linearize_assignment(struct entrypoint
*ep
, struct expression
*expr
)
1186 struct access_data ad
= { NULL
, };
1187 struct expression
*target
= expr
->left
;
1188 struct expression
*src
= expr
->right
;
1189 struct symbol
*ctype
;
1192 value
= linearize_expression(ep
, src
);
1193 if (!target
|| !linearize_address_gen(ep
, target
, &ad
))
1195 if (expr
->op
!= '=') {
1196 pseudo_t oldvalue
= linearize_load_gen(ep
, &ad
);
1198 static const int op_trans
[] = {
1199 [SPECIAL_ADD_ASSIGN
- SPECIAL_BASE
] = OP_ADD
,
1200 [SPECIAL_SUB_ASSIGN
- SPECIAL_BASE
] = OP_SUB
,
1201 [SPECIAL_MUL_ASSIGN
- SPECIAL_BASE
] = OP_MULU
,
1202 [SPECIAL_DIV_ASSIGN
- SPECIAL_BASE
] = OP_DIVU
,
1203 [SPECIAL_MOD_ASSIGN
- SPECIAL_BASE
] = OP_MODU
,
1204 [SPECIAL_SHL_ASSIGN
- SPECIAL_BASE
] = OP_SHL
,
1205 [SPECIAL_SHR_ASSIGN
- SPECIAL_BASE
] = OP_LSR
,
1206 [SPECIAL_AND_ASSIGN
- SPECIAL_BASE
] = OP_AND
,
1207 [SPECIAL_OR_ASSIGN
- SPECIAL_BASE
] = OP_OR
,
1208 [SPECIAL_XOR_ASSIGN
- SPECIAL_BASE
] = OP_XOR
1216 oldvalue
= cast_pseudo(ep
, oldvalue
, target
->ctype
, ctype
);
1217 opcode
= opcode_sign(op_trans
[expr
->op
- SPECIAL_BASE
], ctype
);
1218 dst
= add_binary_op(ep
, ctype
, opcode
, oldvalue
, value
);
1219 value
= cast_pseudo(ep
, dst
, ctype
, expr
->ctype
);
1221 value
= linearize_store_gen(ep
, value
, &ad
);
1222 finish_address_gen(ep
, &ad
);
1226 static pseudo_t
linearize_call_expression(struct entrypoint
*ep
, struct expression
*expr
)
1228 struct expression
*arg
, *fn
;
1229 struct instruction
*insn
= alloc_typed_instruction(OP_CALL
, expr
->ctype
);
1230 pseudo_t retval
, call
;
1231 struct ctype
*ctype
= NULL
;
1232 struct symbol
*fntype
;
1233 struct context
*context
;
1236 warning(expr
->pos
, "call with no type!");
1240 FOR_EACH_PTR(expr
->args
, arg
) {
1241 pseudo_t
new = linearize_expression(ep
, arg
);
1242 use_pseudo(insn
, new, add_pseudo(&insn
->arguments
, new));
1243 } END_FOR_EACH_PTR(arg
);
1248 ctype
= &fn
->ctype
->ctype
;
1252 if (fntype
->type
== SYM_NODE
)
1253 fntype
= fntype
->ctype
.base_type
;
1255 insn
->fntype
= fntype
;
1257 if (fn
->type
== EXPR_PREOP
) {
1258 if (fn
->unop
->type
== EXPR_SYMBOL
) {
1259 struct symbol
*sym
= fn
->unop
->symbol
;
1260 if (sym
->ctype
.base_type
->type
== SYM_FN
)
1264 if (fn
->type
== EXPR_SYMBOL
) {
1265 call
= symbol_pseudo(ep
, fn
->symbol
);
1267 call
= linearize_expression(ep
, fn
);
1269 use_pseudo(insn
, call
, &insn
->func
);
1271 if (expr
->ctype
!= &void_ctype
)
1272 retval
= alloc_pseudo(insn
);
1273 insn
->target
= retval
;
1274 add_one_insn(ep
, insn
);
1277 FOR_EACH_PTR(ctype
->contexts
, context
) {
1278 int in
= context
->in
;
1279 int out
= context
->out
;
1290 context_diff
= out
- in
;
1291 if (check
|| context_diff
) {
1292 insn
= alloc_instruction(OP_CONTEXT
, 0);
1293 insn
->increment
= context_diff
;
1294 insn
->check
= check
;
1295 insn
->context_expr
= context
->context
;
1296 add_one_insn(ep
, insn
);
1298 } END_FOR_EACH_PTR(context
);
1304 static pseudo_t
linearize_binop_bool(struct entrypoint
*ep
, struct expression
*expr
)
1306 pseudo_t src1
, src2
, dst
;
1307 int op
= (expr
->op
== SPECIAL_LOGICAL_OR
) ? OP_OR_BOOL
: OP_AND_BOOL
;
1309 src1
= linearize_expression_to_bool(ep
, expr
->left
);
1310 src2
= linearize_expression_to_bool(ep
, expr
->right
);
1311 dst
= add_binary_op(ep
, &bool_ctype
, op
, src1
, src2
);
1312 if (expr
->ctype
!= &bool_ctype
)
1313 dst
= cast_pseudo(ep
, dst
, &bool_ctype
, expr
->ctype
);
1317 static pseudo_t
linearize_binop(struct entrypoint
*ep
, struct expression
*expr
)
1319 pseudo_t src1
, src2
, dst
;
1320 static const int opcode
[] = {
1321 ['+'] = OP_ADD
, ['-'] = OP_SUB
,
1322 ['*'] = OP_MULU
, ['/'] = OP_DIVU
,
1323 ['%'] = OP_MODU
, ['&'] = OP_AND
,
1324 ['|'] = OP_OR
, ['^'] = OP_XOR
,
1325 [SPECIAL_LEFTSHIFT
] = OP_SHL
,
1326 [SPECIAL_RIGHTSHIFT
] = OP_LSR
,
1330 src1
= linearize_expression(ep
, expr
->left
);
1331 src2
= linearize_expression(ep
, expr
->right
);
1332 op
= opcode_sign(opcode
[expr
->op
], expr
->ctype
);
1333 dst
= add_binary_op(ep
, expr
->ctype
, op
, src1
, src2
);
1337 static pseudo_t
linearize_logical_branch(struct entrypoint
*ep
, struct expression
*expr
, struct basic_block
*bb_true
, struct basic_block
*bb_false
);
1339 pseudo_t
linearize_cond_branch(struct entrypoint
*ep
, struct expression
*expr
, struct basic_block
*bb_true
, struct basic_block
*bb_false
);
1341 static pseudo_t
linearize_select(struct entrypoint
*ep
, struct expression
*expr
)
1343 pseudo_t cond
, true, false, res
;
1344 struct instruction
*insn
;
1346 true = linearize_expression(ep
, expr
->cond_true
);
1347 false = linearize_expression(ep
, expr
->cond_false
);
1348 cond
= linearize_expression(ep
, expr
->conditional
);
1350 insn
= alloc_typed_instruction(OP_SEL
, expr
->ctype
);
1351 if (!expr
->cond_true
)
1353 use_pseudo(insn
, cond
, &insn
->src1
);
1354 use_pseudo(insn
, true, &insn
->src2
);
1355 use_pseudo(insn
, false, &insn
->src3
);
1357 res
= alloc_pseudo(insn
);
1359 add_one_insn(ep
, insn
);
1363 static pseudo_t
add_join_conditional(struct entrypoint
*ep
, struct expression
*expr
,
1364 pseudo_t phi1
, pseudo_t phi2
)
1367 struct instruction
*phi_node
;
1374 phi_node
= alloc_typed_instruction(OP_PHI
, expr
->ctype
);
1375 use_pseudo(phi_node
, phi1
, add_pseudo(&phi_node
->phi_list
, phi1
));
1376 use_pseudo(phi_node
, phi2
, add_pseudo(&phi_node
->phi_list
, phi2
));
1377 phi_node
->target
= target
= alloc_pseudo(phi_node
);
1378 add_one_insn(ep
, phi_node
);
1382 static pseudo_t
linearize_short_conditional(struct entrypoint
*ep
, struct expression
*expr
,
1383 struct expression
*cond
,
1384 struct expression
*expr_false
)
1386 pseudo_t src1
, src2
;
1387 struct basic_block
*bb_false
;
1388 struct basic_block
*merge
= alloc_basic_block(ep
, expr
->pos
);
1389 pseudo_t phi1
, phi2
;
1390 int size
= type_size(expr
->ctype
);
1392 if (!expr_false
|| !ep
->active
)
1395 bb_false
= alloc_basic_block(ep
, expr_false
->pos
);
1396 src1
= linearize_expression(ep
, cond
);
1397 phi1
= alloc_phi(ep
->active
, src1
, size
);
1398 add_branch(ep
, expr
, src1
, merge
, bb_false
);
1400 set_activeblock(ep
, bb_false
);
1401 src2
= linearize_expression(ep
, expr_false
);
1402 phi2
= alloc_phi(ep
->active
, src2
, size
);
1403 set_activeblock(ep
, merge
);
1405 return add_join_conditional(ep
, expr
, phi1
, phi2
);
1408 static pseudo_t
linearize_conditional(struct entrypoint
*ep
, struct expression
*expr
,
1409 struct expression
*cond
,
1410 struct expression
*expr_true
,
1411 struct expression
*expr_false
)
1413 pseudo_t src1
, src2
;
1414 pseudo_t phi1
, phi2
;
1415 struct basic_block
*bb_true
, *bb_false
, *merge
;
1416 int size
= type_size(expr
->ctype
);
1418 if (!cond
|| !expr_true
|| !expr_false
|| !ep
->active
)
1420 bb_true
= alloc_basic_block(ep
, expr_true
->pos
);
1421 bb_false
= alloc_basic_block(ep
, expr_false
->pos
);
1422 merge
= alloc_basic_block(ep
, expr
->pos
);
1424 linearize_cond_branch(ep
, cond
, bb_true
, bb_false
);
1426 set_activeblock(ep
, bb_true
);
1427 src1
= linearize_expression(ep
, expr_true
);
1428 phi1
= alloc_phi(ep
->active
, src1
, size
);
1429 add_goto(ep
, merge
);
1431 set_activeblock(ep
, bb_false
);
1432 src2
= linearize_expression(ep
, expr_false
);
1433 phi2
= alloc_phi(ep
->active
, src2
, size
);
1434 set_activeblock(ep
, merge
);
1436 return add_join_conditional(ep
, expr
, phi1
, phi2
);
1439 static pseudo_t
linearize_logical(struct entrypoint
*ep
, struct expression
*expr
)
1441 struct expression
*shortcut
;
1443 shortcut
= alloc_const_expression(expr
->pos
, expr
->op
== SPECIAL_LOGICAL_OR
);
1444 shortcut
->ctype
= expr
->ctype
;
1445 if (expr
->op
== SPECIAL_LOGICAL_OR
)
1446 return linearize_conditional(ep
, expr
, expr
->left
, shortcut
, expr
->right
);
1447 return linearize_conditional(ep
, expr
, expr
->left
, expr
->right
, shortcut
);
1450 static pseudo_t
linearize_compare(struct entrypoint
*ep
, struct expression
*expr
)
1452 static const int cmpop
[] = {
1453 ['>'] = OP_SET_GT
, ['<'] = OP_SET_LT
,
1454 [SPECIAL_EQUAL
] = OP_SET_EQ
,
1455 [SPECIAL_NOTEQUAL
] = OP_SET_NE
,
1456 [SPECIAL_GTE
] = OP_SET_GE
,
1457 [SPECIAL_LTE
] = OP_SET_LE
,
1458 [SPECIAL_UNSIGNED_LT
] = OP_SET_B
,
1459 [SPECIAL_UNSIGNED_GT
] = OP_SET_A
,
1460 [SPECIAL_UNSIGNED_LTE
] = OP_SET_BE
,
1461 [SPECIAL_UNSIGNED_GTE
] = OP_SET_AE
,
1464 pseudo_t src1
= linearize_expression(ep
, expr
->left
);
1465 pseudo_t src2
= linearize_expression(ep
, expr
->right
);
1466 pseudo_t dst
= add_binary_op(ep
, expr
->ctype
, cmpop
[expr
->op
], src1
, src2
);
1471 pseudo_t
linearize_cond_branch(struct entrypoint
*ep
, struct expression
*expr
, struct basic_block
*bb_true
, struct basic_block
*bb_false
)
1475 if (!expr
|| !bb_reachable(ep
->active
))
1478 switch (expr
->type
) {
1482 add_goto(ep
, expr
->value
? bb_true
: bb_false
);
1486 add_goto(ep
, expr
->fvalue
? bb_true
: bb_false
);
1490 linearize_logical_branch(ep
, expr
, bb_true
, bb_false
);
1494 cond
= linearize_compare(ep
, expr
);
1495 add_branch(ep
, expr
, cond
, bb_true
, bb_false
);
1499 if (expr
->op
== '!')
1500 return linearize_cond_branch(ep
, expr
->unop
, bb_false
, bb_true
);
1503 cond
= linearize_expression(ep
, expr
);
1504 add_branch(ep
, expr
, cond
, bb_true
, bb_false
);
1514 static pseudo_t
linearize_logical_branch(struct entrypoint
*ep
, struct expression
*expr
, struct basic_block
*bb_true
, struct basic_block
*bb_false
)
1516 struct basic_block
*next
= alloc_basic_block(ep
, expr
->pos
);
1518 if (expr
->op
== SPECIAL_LOGICAL_OR
)
1519 linearize_cond_branch(ep
, expr
->left
, bb_true
, next
);
1521 linearize_cond_branch(ep
, expr
->left
, next
, bb_false
);
1522 set_activeblock(ep
, next
);
1523 linearize_cond_branch(ep
, expr
->right
, bb_true
, bb_false
);
1527 static pseudo_t
linearize_cast(struct entrypoint
*ep
, struct expression
*expr
)
1530 struct expression
*orig
= expr
->cast_expression
;
1535 src
= linearize_expression(ep
, orig
);
1536 return cast_pseudo(ep
, src
, orig
->ctype
, expr
->ctype
);
1539 static pseudo_t
linearize_position(struct entrypoint
*ep
, struct expression
*pos
, struct access_data
*ad
)
1541 struct expression
*init_expr
= pos
->init_expr
;
1543 ad
->offset
= pos
->init_offset
;
1544 ad
->source_type
= base_type(init_expr
->ctype
);
1545 ad
->result_type
= init_expr
->ctype
;
1546 return linearize_initializer(ep
, init_expr
, ad
);
1549 static pseudo_t
linearize_initializer(struct entrypoint
*ep
, struct expression
*initializer
, struct access_data
*ad
)
1551 switch (initializer
->type
) {
1552 case EXPR_INITIALIZER
: {
1553 struct expression
*expr
;
1554 FOR_EACH_PTR(initializer
->expr_list
, expr
) {
1555 linearize_initializer(ep
, expr
, ad
);
1556 } END_FOR_EACH_PTR(expr
);
1560 linearize_position(ep
, initializer
, ad
);
1563 pseudo_t value
= linearize_expression(ep
, initializer
);
1564 ad
->source_type
= base_type(initializer
->ctype
);
1565 ad
->result_type
= initializer
->ctype
;
1566 linearize_store_gen(ep
, value
, ad
);
1574 static void linearize_argument(struct entrypoint
*ep
, struct symbol
*arg
, int nr
)
1576 struct access_data ad
= { NULL
, };
1578 ad
.source_type
= arg
;
1579 ad
.result_type
= arg
;
1580 ad
.address
= symbol_pseudo(ep
, arg
);
1581 linearize_store_gen(ep
, argument_pseudo(ep
, nr
), &ad
);
1582 finish_address_gen(ep
, &ad
);
1585 pseudo_t
linearize_expression(struct entrypoint
*ep
, struct expression
*expr
)
1590 current_pos
= expr
->pos
;
1591 switch (expr
->type
) {
1593 linearize_one_symbol(ep
, expr
->symbol
);
1594 return add_symbol_address(ep
, expr
->symbol
);
1597 return value_pseudo(expr
->ctype
, expr
->value
);
1599 case EXPR_STRING
: case EXPR_FVALUE
: case EXPR_LABEL
:
1600 return add_setval(ep
, expr
->ctype
, expr
);
1602 case EXPR_STATEMENT
:
1603 return linearize_statement(ep
, expr
->statement
);
1606 return linearize_call_expression(ep
, expr
);
1609 if (expr
->op
== SPECIAL_LOGICAL_AND
|| expr
->op
== SPECIAL_LOGICAL_OR
)
1610 return linearize_binop_bool(ep
, expr
);
1611 return linearize_binop(ep
, expr
);
1614 return linearize_logical(ep
, expr
);
1617 return linearize_compare(ep
, expr
);
1620 return linearize_select(ep
, expr
);
1622 case EXPR_CONDITIONAL
:
1623 if (!expr
->cond_true
)
1624 return linearize_short_conditional(ep
, expr
, expr
->conditional
, expr
->cond_false
);
1626 return linearize_conditional(ep
, expr
, expr
->conditional
,
1627 expr
->cond_true
, expr
->cond_false
);
1630 linearize_expression(ep
, expr
->left
);
1631 return linearize_expression(ep
, expr
->right
);
1633 case EXPR_ASSIGNMENT
:
1634 return linearize_assignment(ep
, expr
);
1637 return linearize_preop(ep
, expr
);
1640 return linearize_postop(ep
, expr
);
1643 case EXPR_FORCE_CAST
:
1644 case EXPR_IMPLIED_CAST
:
1645 return linearize_cast(ep
, expr
);
1648 return linearize_slice(ep
, expr
);
1650 case EXPR_INITIALIZER
:
1652 warning(expr
->pos
, "unexpected initializer expression (%d %d)", expr
->type
, expr
->op
);
1655 warning(expr
->pos
, "unknown expression (%d %d)", expr
->type
, expr
->op
);
1661 static pseudo_t
linearize_one_symbol(struct entrypoint
*ep
, struct symbol
*sym
)
1663 struct access_data ad
= { NULL
, };
1666 if (!sym
|| !sym
->initializer
|| sym
->initialized
)
1669 /* We need to output these puppies some day too.. */
1670 if (sym
->ctype
.modifiers
& (MOD_STATIC
| MOD_TOPLEVEL
))
1673 sym
->initialized
= 1;
1674 ad
.address
= symbol_pseudo(ep
, sym
);
1676 if (sym
->initializer
&& !is_scalar_type(sym
)) {
1677 // default zero initialization [6.7.9.21]
1678 // FIXME: this init the whole aggregate while
1679 // only the existing fields need to be initialized.
1680 // FIXME: this init the whole aggregate even if
1681 // all fields arelater explicitely initialized.
1682 struct expression
*expr
= sym
->initializer
;
1684 ad
.result_type
= sym
;
1685 ad
.source_type
= base_type(sym
);
1686 ad
.address
= symbol_pseudo(ep
, sym
);
1687 linearize_store_gen(ep
, value_pseudo(sym
, 0), &ad
);
1690 value
= linearize_initializer(ep
, sym
->initializer
, &ad
);
1691 finish_address_gen(ep
, &ad
);
1695 static pseudo_t
linearize_compound_statement(struct entrypoint
*ep
, struct statement
*stmt
)
1698 struct statement
*s
;
1699 struct symbol
*ret
= stmt
->ret
;
1702 FOR_EACH_PTR(stmt
->stmts
, s
) {
1703 pseudo
= linearize_statement(ep
, s
);
1704 } END_FOR_EACH_PTR(s
);
1707 struct basic_block
*bb
= add_label(ep
, ret
);
1708 struct instruction
*phi_node
= first_instruction(bb
->insns
);
1713 if (pseudo_list_size(phi_node
->phi_list
)==1) {
1714 pseudo
= first_pseudo(phi_node
->phi_list
);
1715 assert(pseudo
->type
== PSEUDO_PHI
);
1716 return pseudo
->def
->src1
;
1718 return phi_node
->target
;
1724 static pseudo_t
linearize_inlined_call(struct entrypoint
*ep
, struct statement
*stmt
)
1726 struct instruction
*insn
= alloc_instruction(OP_INLINED_CALL
, 0);
1727 struct statement
*args
= stmt
->args
;
1728 struct basic_block
*bb
;
1734 concat_symbol_list(args
->declaration
, &ep
->syms
);
1735 FOR_EACH_PTR(args
->declaration
, sym
) {
1736 pseudo_t value
= linearize_one_symbol(ep
, sym
);
1737 use_pseudo(insn
, value
, add_pseudo(&insn
->arguments
, value
));
1738 } END_FOR_EACH_PTR(sym
);
1741 insn
->target
= pseudo
= linearize_compound_statement(ep
, stmt
);
1742 use_pseudo(insn
, symbol_pseudo(ep
, stmt
->inline_fn
), &insn
->func
);
1744 if (bb
&& !bb
->insns
)
1745 bb
->pos
= stmt
->pos
;
1746 add_one_insn(ep
, insn
);
1750 static pseudo_t
linearize_context(struct entrypoint
*ep
, struct statement
*stmt
)
1752 struct instruction
*insn
= alloc_instruction(OP_CONTEXT
, 0);
1753 struct expression
*expr
= stmt
->expression
;
1756 if (expr
->type
== EXPR_VALUE
)
1757 value
= expr
->value
;
1759 insn
->increment
= value
;
1760 insn
->context_expr
= stmt
->context
;
1761 add_one_insn(ep
, insn
);
1765 static pseudo_t
linearize_range(struct entrypoint
*ep
, struct statement
*stmt
)
1767 struct instruction
*insn
= alloc_instruction(OP_RANGE
, 0);
1769 use_pseudo(insn
, linearize_expression(ep
, stmt
->range_expression
), &insn
->src1
);
1770 use_pseudo(insn
, linearize_expression(ep
, stmt
->range_low
), &insn
->src2
);
1771 use_pseudo(insn
, linearize_expression(ep
, stmt
->range_high
), &insn
->src3
);
1772 add_one_insn(ep
, insn
);
1776 ALLOCATOR(asm_rules
, "asm rules");
1777 ALLOCATOR(asm_constraint
, "asm constraints");
1779 static void add_asm_input(struct entrypoint
*ep
, struct instruction
*insn
, struct expression
*expr
,
1780 const char *constraint
, const struct ident
*ident
)
1782 pseudo_t pseudo
= linearize_expression(ep
, expr
);
1783 struct asm_constraint
*rule
= __alloc_asm_constraint(0);
1785 rule
->ident
= ident
;
1786 rule
->constraint
= constraint
;
1787 use_pseudo(insn
, pseudo
, &rule
->pseudo
);
1788 add_ptr_list(&insn
->asm_rules
->inputs
, rule
);
1791 static void add_asm_output(struct entrypoint
*ep
, struct instruction
*insn
, struct expression
*expr
,
1792 const char *constraint
, const struct ident
*ident
)
1794 struct access_data ad
= { NULL
, };
1795 pseudo_t pseudo
= alloc_pseudo(insn
);
1796 struct asm_constraint
*rule
;
1798 if (!expr
|| !linearize_address_gen(ep
, expr
, &ad
))
1800 linearize_store_gen(ep
, pseudo
, &ad
);
1801 finish_address_gen(ep
, &ad
);
1802 rule
= __alloc_asm_constraint(0);
1803 rule
->ident
= ident
;
1804 rule
->constraint
= constraint
;
1805 use_pseudo(insn
, pseudo
, &rule
->pseudo
);
1806 add_ptr_list(&insn
->asm_rules
->outputs
, rule
);
1809 static pseudo_t
linearize_asm_statement(struct entrypoint
*ep
, struct statement
*stmt
)
1812 struct expression
*expr
;
1813 struct instruction
*insn
;
1814 struct asm_rules
*rules
;
1815 const char *constraint
;
1816 struct ident
*ident
;
1818 insn
= alloc_instruction(OP_ASM
, 0);
1819 expr
= stmt
->asm_string
;
1820 if (!expr
|| expr
->type
!= EXPR_STRING
) {
1821 warning(stmt
->pos
, "expected string in inline asm");
1824 insn
->string
= expr
->string
->data
;
1826 rules
= __alloc_asm_rules(0);
1827 insn
->asm_rules
= rules
;
1829 /* Gather the inputs.. */
1833 FOR_EACH_PTR(stmt
->asm_inputs
, expr
) {
1835 case 0: /* Identifier */
1837 ident
= (struct ident
*)expr
;
1840 case 1: /* Constraint */
1842 constraint
= expr
? expr
->string
->data
: "";
1845 case 2: /* Expression */
1847 add_asm_input(ep
, insn
, expr
, constraint
, ident
);
1849 } END_FOR_EACH_PTR(expr
);
1851 add_one_insn(ep
, insn
);
1853 /* Assign the outputs */
1857 FOR_EACH_PTR(stmt
->asm_outputs
, expr
) {
1859 case 0: /* Identifier */
1861 ident
= (struct ident
*)expr
;
1864 case 1: /* Constraint */
1866 constraint
= expr
? expr
->string
->data
: "";
1871 add_asm_output(ep
, insn
, expr
, constraint
, ident
);
1873 } END_FOR_EACH_PTR(expr
);
1878 static int multijmp_cmp(const void *_a
, const void *_b
)
1880 const struct multijmp
*a
= _a
;
1881 const struct multijmp
*b
= _b
;
1884 if (a
->begin
> a
->end
) {
1885 if (b
->begin
> b
->end
)
1889 if (b
->begin
> b
->end
)
1891 if (a
->begin
== b
->begin
) {
1892 if (a
->end
== b
->end
)
1894 return (a
->end
< b
->end
) ? -1 : 1;
1896 return a
->begin
< b
->begin
? -1 : 1;
1899 static void sort_switch_cases(struct instruction
*insn
)
1901 sort_list((struct ptr_list
**)&insn
->multijmp_list
, multijmp_cmp
);
1904 static pseudo_t
linearize_declaration(struct entrypoint
*ep
, struct statement
*stmt
)
1908 concat_symbol_list(stmt
->declaration
, &ep
->syms
);
1910 FOR_EACH_PTR(stmt
->declaration
, sym
) {
1911 linearize_one_symbol(ep
, sym
);
1912 } END_FOR_EACH_PTR(sym
);
1916 static pseudo_t
linearize_return(struct entrypoint
*ep
, struct statement
*stmt
)
1918 struct expression
*expr
= stmt
->expression
;
1919 struct basic_block
*bb_return
= get_bound_block(ep
, stmt
->ret_target
);
1920 struct basic_block
*active
;
1921 pseudo_t src
= linearize_expression(ep
, expr
);
1922 active
= ep
->active
;
1923 if (active
&& src
!= VOID
) {
1924 struct instruction
*phi_node
= first_instruction(bb_return
->insns
);
1927 phi_node
= alloc_typed_instruction(OP_PHI
, expr
->ctype
);
1928 phi_node
->target
= alloc_pseudo(phi_node
);
1929 phi_node
->bb
= bb_return
;
1930 add_instruction(&bb_return
->insns
, phi_node
);
1932 phi
= alloc_phi(active
, src
, type_size(expr
->ctype
));
1933 phi
->ident
= &return_ident
;
1934 use_pseudo(phi_node
, phi
, add_pseudo(&phi_node
->phi_list
, phi
));
1936 add_goto(ep
, bb_return
);
1940 static pseudo_t
linearize_switch(struct entrypoint
*ep
, struct statement
*stmt
)
1943 struct instruction
*switch_ins
;
1944 struct basic_block
*switch_end
= alloc_basic_block(ep
, stmt
->pos
);
1945 struct basic_block
*active
, *default_case
;
1946 struct multijmp
*jmp
;
1949 pseudo
= linearize_expression(ep
, stmt
->switch_expression
);
1951 active
= ep
->active
;
1952 if (!bb_reachable(active
))
1955 switch_ins
= alloc_instruction(OP_SWITCH
, 0);
1956 use_pseudo(switch_ins
, pseudo
, &switch_ins
->cond
);
1957 add_one_insn(ep
, switch_ins
);
1960 default_case
= NULL
;
1961 FOR_EACH_PTR(stmt
->switch_case
->symbol_list
, sym
) {
1962 struct statement
*case_stmt
= sym
->stmt
;
1963 struct basic_block
*bb_case
= get_bound_block(ep
, sym
);
1965 if (!case_stmt
->case_expression
) {
1966 default_case
= bb_case
;
1971 begin
= end
= case_stmt
->case_expression
->value
;
1972 if (case_stmt
->case_to
)
1973 end
= case_stmt
->case_to
->value
;
1975 jmp
= alloc_multijmp(bb_case
, end
, begin
);
1977 jmp
= alloc_multijmp(bb_case
, begin
, end
);
1980 add_multijmp(&switch_ins
->multijmp_list
, jmp
);
1981 add_bb(&bb_case
->parents
, active
);
1982 add_bb(&active
->children
, bb_case
);
1983 } END_FOR_EACH_PTR(sym
);
1985 bind_label(stmt
->switch_break
, switch_end
, stmt
->pos
);
1987 /* And linearize the actual statement */
1988 linearize_statement(ep
, stmt
->switch_statement
);
1989 set_activeblock(ep
, switch_end
);
1992 default_case
= switch_end
;
1994 jmp
= alloc_multijmp(default_case
, 1, 0);
1995 add_multijmp(&switch_ins
->multijmp_list
, jmp
);
1996 add_bb(&default_case
->parents
, active
);
1997 add_bb(&active
->children
, default_case
);
1998 sort_switch_cases(switch_ins
);
2003 static pseudo_t
linearize_iterator(struct entrypoint
*ep
, struct statement
*stmt
)
2005 struct statement
*pre_statement
= stmt
->iterator_pre_statement
;
2006 struct expression
*pre_condition
= stmt
->iterator_pre_condition
;
2007 struct statement
*statement
= stmt
->iterator_statement
;
2008 struct statement
*post_statement
= stmt
->iterator_post_statement
;
2009 struct expression
*post_condition
= stmt
->iterator_post_condition
;
2010 struct basic_block
*loop_top
, *loop_body
, *loop_continue
, *loop_end
;
2013 FOR_EACH_PTR(stmt
->iterator_syms
, sym
) {
2014 linearize_one_symbol(ep
, sym
);
2015 } END_FOR_EACH_PTR(sym
);
2016 concat_symbol_list(stmt
->iterator_syms
, &ep
->syms
);
2017 linearize_statement(ep
, pre_statement
);
2019 loop_body
= loop_top
= alloc_basic_block(ep
, stmt
->pos
);
2020 loop_continue
= alloc_basic_block(ep
, stmt
->pos
);
2021 loop_end
= alloc_basic_block(ep
, stmt
->pos
);
2023 /* An empty post-condition means that it's the same as the pre-condition */
2024 if (!post_condition
) {
2025 loop_top
= alloc_basic_block(ep
, stmt
->pos
);
2026 set_activeblock(ep
, loop_top
);
2030 linearize_cond_branch(ep
, pre_condition
, loop_body
, loop_end
);
2032 bind_label(stmt
->iterator_continue
, loop_continue
, stmt
->pos
);
2033 bind_label(stmt
->iterator_break
, loop_end
, stmt
->pos
);
2035 set_activeblock(ep
, loop_body
);
2036 linearize_statement(ep
, statement
);
2037 add_goto(ep
, loop_continue
);
2039 set_activeblock(ep
, loop_continue
);
2040 linearize_statement(ep
, post_statement
);
2041 if (!post_condition
)
2042 add_goto(ep
, loop_top
);
2044 linearize_cond_branch(ep
, post_condition
, loop_top
, loop_end
);
2045 set_activeblock(ep
, loop_end
);
2050 pseudo_t
linearize_statement(struct entrypoint
*ep
, struct statement
*stmt
)
2052 struct basic_block
*bb
;
2058 if (bb
&& !bb
->insns
)
2059 bb
->pos
= stmt
->pos
;
2060 current_pos
= stmt
->pos
;
2062 switch (stmt
->type
) {
2066 case STMT_DECLARATION
:
2067 return linearize_declaration(ep
, stmt
);
2070 return linearize_context(ep
, stmt
);
2073 return linearize_range(ep
, stmt
);
2075 case STMT_EXPRESSION
:
2076 return linearize_expression(ep
, stmt
->expression
);
2079 return linearize_asm_statement(ep
, stmt
);
2082 return linearize_return(ep
, stmt
);
2085 add_label(ep
, stmt
->case_label
);
2086 linearize_statement(ep
, stmt
->case_statement
);
2091 struct symbol
*label
= stmt
->label_identifier
;
2094 add_label(ep
, label
);
2096 return linearize_statement(ep
, stmt
->label_statement
);
2101 struct expression
*expr
;
2102 struct instruction
*goto_ins
;
2103 struct basic_block
*active
;
2106 active
= ep
->active
;
2107 if (!bb_reachable(active
))
2110 if (stmt
->goto_label
) {
2111 add_goto(ep
, get_bound_block(ep
, stmt
->goto_label
));
2115 expr
= stmt
->goto_expression
;
2119 /* This can happen as part of simplification */
2120 if (expr
->type
== EXPR_LABEL
) {
2121 add_goto(ep
, get_bound_block(ep
, expr
->label_symbol
));
2125 pseudo
= linearize_expression(ep
, expr
);
2126 goto_ins
= alloc_instruction(OP_COMPUTEDGOTO
, 0);
2127 use_pseudo(goto_ins
, pseudo
, &goto_ins
->target
);
2128 add_one_insn(ep
, goto_ins
);
2130 FOR_EACH_PTR(stmt
->target_list
, sym
) {
2131 struct basic_block
*bb_computed
= get_bound_block(ep
, sym
);
2132 struct multijmp
*jmp
= alloc_multijmp(bb_computed
, 1, 0);
2133 add_multijmp(&goto_ins
->multijmp_list
, jmp
);
2134 add_bb(&bb_computed
->parents
, ep
->active
);
2135 add_bb(&active
->children
, bb_computed
);
2136 } END_FOR_EACH_PTR(sym
);
2143 if (stmt
->inline_fn
)
2144 return linearize_inlined_call(ep
, stmt
);
2145 return linearize_compound_statement(ep
, stmt
);
2148 * This could take 'likely/unlikely' into account, and
2149 * switch the arms around appropriately..
2152 struct basic_block
*bb_true
, *bb_false
, *endif
;
2153 struct expression
*cond
= stmt
->if_conditional
;
2155 bb_true
= alloc_basic_block(ep
, stmt
->pos
);
2156 bb_false
= endif
= alloc_basic_block(ep
, stmt
->pos
);
2158 linearize_cond_branch(ep
, cond
, bb_true
, bb_false
);
2160 set_activeblock(ep
, bb_true
);
2161 linearize_statement(ep
, stmt
->if_true
);
2163 if (stmt
->if_false
) {
2164 endif
= alloc_basic_block(ep
, stmt
->pos
);
2165 add_goto(ep
, endif
);
2166 set_activeblock(ep
, bb_false
);
2167 linearize_statement(ep
, stmt
->if_false
);
2169 set_activeblock(ep
, endif
);
2174 return linearize_switch(ep
, stmt
);
2177 return linearize_iterator(ep
, stmt
);
2185 static struct entrypoint
*linearize_fn(struct symbol
*sym
, struct symbol
*base_type
)
2187 struct entrypoint
*ep
;
2188 struct basic_block
*bb
;
2190 struct instruction
*entry
;
2194 if (!base_type
->stmt
)
2197 ep
= alloc_entrypoint();
2198 bb
= alloc_basic_block(ep
, sym
->pos
);
2202 set_activeblock(ep
, bb
);
2204 entry
= alloc_instruction(OP_ENTRY
, 0);
2205 add_one_insn(ep
, entry
);
2208 concat_symbol_list(base_type
->arguments
, &ep
->syms
);
2210 /* FIXME!! We should do something else about varargs.. */
2212 FOR_EACH_PTR(base_type
->arguments
, arg
) {
2213 linearize_argument(ep
, arg
, ++i
);
2214 } END_FOR_EACH_PTR(arg
);
2216 result
= linearize_statement(ep
, base_type
->stmt
);
2217 if (bb_reachable(ep
->active
) && !bb_terminated(ep
->active
)) {
2218 struct symbol
*ret_type
= base_type
->ctype
.base_type
;
2219 struct instruction
*insn
= alloc_typed_instruction(OP_RET
, ret_type
);
2221 if (type_size(ret_type
) > 0)
2222 use_pseudo(insn
, result
, &insn
->src
);
2223 add_one_insn(ep
, insn
);
2226 if (fdump_linearize
) {
2227 if (fdump_linearize
== 2)
2233 * Do trivial flow simplification - branches to
2234 * branches, kill dead basicblocks etc
2236 kill_unreachable_bbs(ep
);
2239 * Turn symbols into pseudos
2241 simplify_symbol_usage(ep
);
2245 * Remove trivial instructions, and try to CSE
2249 cleanup_and_cse(ep
);
2250 pack_basic_blocks(ep
);
2251 } while (repeat_phase
& REPEAT_CSE
);
2253 kill_unreachable_bbs(ep
);
2257 clear_symbol_pseudos(ep
);
2259 /* And track pseudo register usage */
2260 track_pseudo_liveness(ep
);
2263 * Some flow optimizations can only effectively
2264 * be done when we've done liveness analysis. But
2265 * if they trigger, we need to start all over
2268 if (simplify_flow(ep
)) {
2273 /* Finally, add deathnotes to pseudos now that we have them */
2275 track_pseudo_death(ep
);
2280 struct entrypoint
*linearize_symbol(struct symbol
*sym
)
2282 struct symbol
*base_type
;
2286 current_pos
= sym
->pos
;
2287 base_type
= sym
->ctype
.base_type
;
2290 if (base_type
->type
== SYM_FN
)
2291 return linearize_fn(sym
, base_type
);