2 * Example of how to write a compiler with sparse
11 #include "expression.h"
12 #include "linearize.h"
17 static const char *opcodes
[] = {
18 [OP_BADOP
] = "bad_op",
21 [OP_ENTRY
] = "<entry-point>",
27 [OP_SWITCH
] = "switch",
28 [OP_COMPUTEDGOTO
] = "jmp *",
47 /* Binary comparison */
48 [OP_SET_EQ
] = "seteq",
49 [OP_SET_NE
] = "setne",
50 [OP_SET_LE
] = "setle",
51 [OP_SET_GE
] = "setge",
52 [OP_SET_LT
] = "setlt",
53 [OP_SET_GT
] = "setgt",
56 [OP_SET_BE
] = "setbe",
57 [OP_SET_AE
] = "setae",
63 /* Special three-input */
74 [OP_PHISOURCE
] = "phisrc",
86 [OP_PTRCAST
] = "ptrcast",
90 [OP_DEATHNOTE
] = "dead",
93 /* Sparse tagging (line numbers, context, whatever) */
94 [OP_CONTEXT
] = "context",
97 static int last_reg
, stack_offset
;
101 struct pseudo_list
*contains
;
110 /* Our "switch" generation is very very stupid. */
111 #define SWITCH_REG (1)
113 static void output_bb(struct basic_block
*bb
, unsigned long generation
);
116 * We only know about the caller-clobbered registers
119 static struct hardreg hardregs
[] = {
136 struct storage_hash_list
*inputs
;
137 struct storage_hash_list
*outputs
;
138 struct storage_hash_list
*internal
;
141 int cc_opcode
, cc_dead
;
159 struct /* OP_MEM and OP_ADDR */ {
163 struct hardreg
*base
;
164 struct hardreg
*index
;
169 static const char *show_op(struct bb_state
*state
, struct operand
*op
)
171 static char buf
[256][4];
176 nr
= (bufnr
+ 1) & 3;
184 return op
->reg
->name
;
186 sprintf(p
, "$%lld", op
->value
);
191 p
+= sprintf(p
, "%d", op
->offset
);
193 p
+= sprintf(p
, "%s%s",
194 op
->offset
? "+" : "",
195 show_ident(op
->sym
->ident
));
196 if (op
->base
|| op
->index
) {
197 p
+= sprintf(p
, "(%s%s%s",
198 op
->base
? op
->base
->name
: "",
199 (op
->base
&& op
->index
) ? "," : "",
200 op
->index
? op
->index
->name
: "");
202 p
+= sprintf(p
, ",%d", op
->scale
);
211 static struct storage_hash
*find_storage_hash(pseudo_t pseudo
, struct storage_hash_list
*list
)
213 struct storage_hash
*entry
;
214 FOR_EACH_PTR(list
, entry
) {
215 if (entry
->pseudo
== pseudo
)
217 } END_FOR_EACH_PTR(entry
);
221 static struct storage_hash
*find_or_create_hash(pseudo_t pseudo
, struct storage_hash_list
**listp
)
223 struct storage_hash
*entry
;
225 entry
= find_storage_hash(pseudo
, *listp
);
227 entry
= alloc_storage_hash(alloc_storage());
228 entry
->pseudo
= pseudo
;
229 add_ptr_list(listp
, entry
);
234 /* Eventually we should just build it up in memory */
235 static void FORMAT_ATTR(2) output_line(struct bb_state
*state
, const char *fmt
, ...)
244 static void FORMAT_ATTR(2) output_label(struct bb_state
*state
, const char *fmt
, ...)
246 static char buffer
[512];
250 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
253 output_line(state
, "%s:\n", buffer
);
256 static void FORMAT_ATTR(2) output_insn(struct bb_state
*state
, const char *fmt
, ...)
258 static char buffer
[512];
262 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
265 output_line(state
, "\t%s\n", buffer
);
268 #define output_insn(state, fmt, arg...) \
269 output_insn(state, fmt "\t\t# %s" , ## arg , __FUNCTION__)
271 static void FORMAT_ATTR(2) output_comment(struct bb_state
*state
, const char *fmt
, ...)
273 static char buffer
[512];
279 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
282 output_line(state
, "\t# %s\n", buffer
);
285 static const char *show_memop(struct storage
*storage
)
287 static char buffer
[1000];
291 switch (storage
->type
) {
293 sprintf(buffer
, "%d(FP)", storage
->offset
);
296 sprintf(buffer
, "%d(SP)", storage
->offset
);
299 return hardregs
[storage
->regno
].name
;
301 return show_storage(storage
);
306 static int alloc_stack_offset(int size
)
308 int ret
= stack_offset
;
309 stack_offset
= ret
+ size
;
313 static void alloc_stack(struct bb_state
*state
, struct storage
*storage
)
315 storage
->type
= REG_STACK
;
316 storage
->offset
= alloc_stack_offset(4);
320 * Can we re-generate the pseudo, so that we don't need to
321 * flush it to memory? We can regenerate:
322 * - immediates and symbol addresses
323 * - pseudos we got as input in non-registers
324 * - pseudos we've already saved off earlier..
326 static int can_regenerate(struct bb_state
*state
, pseudo_t pseudo
)
328 struct storage_hash
*in
;
330 switch (pseudo
->type
) {
336 in
= find_storage_hash(pseudo
, state
->inputs
);
337 if (in
&& in
->storage
->type
!= REG_REG
)
339 in
= find_storage_hash(pseudo
, state
->internal
);
346 static void flush_one_pseudo(struct bb_state
*state
, struct hardreg
*hardreg
, pseudo_t pseudo
)
348 struct storage_hash
*out
;
349 struct storage
*storage
;
351 if (can_regenerate(state
, pseudo
))
354 output_comment(state
, "flushing %s from %s", show_pseudo(pseudo
), hardreg
->name
);
355 out
= find_storage_hash(pseudo
, state
->internal
);
357 out
= find_storage_hash(pseudo
, state
->outputs
);
359 out
= find_or_create_hash(pseudo
, &state
->internal
);
361 storage
= out
->storage
;
362 switch (storage
->type
) {
365 * Aieee - the next user wants it in a register, but we
366 * need to flush it to memory in between. Which means that
367 * we need to allocate an internal one, dammit..
369 out
= find_or_create_hash(pseudo
, &state
->internal
);
370 storage
= out
->storage
;
373 alloc_stack(state
, storage
);
376 output_insn(state
, "movl %s,%s", hardreg
->name
, show_memop(storage
));
381 /* Flush a hardreg out to the storage it has.. */
382 static void flush_reg(struct bb_state
*state
, struct hardreg
*reg
)
387 output_comment(state
, "reg %s flushed while busy is %d!", reg
->name
, reg
->busy
);
392 FOR_EACH_PTR_TAG(reg
->contains
, pseudo
) {
393 if (CURRENT_TAG(pseudo
) & TAG_DEAD
)
395 if (!(CURRENT_TAG(pseudo
) & TAG_DIRTY
))
397 flush_one_pseudo(state
, reg
, pseudo
);
398 } END_FOR_EACH_PTR(pseudo
);
399 free_ptr_list(®
->contains
);
402 static struct storage_hash
*find_pseudo_storage(struct bb_state
*state
, pseudo_t pseudo
, struct hardreg
*reg
)
404 struct storage_hash
*src
;
406 src
= find_storage_hash(pseudo
, state
->internal
);
408 src
= find_storage_hash(pseudo
, state
->inputs
);
410 src
= find_storage_hash(pseudo
, state
->outputs
);
411 /* Undefined? Screw it! */
416 * If we found output storage, it had better be local stack
417 * that we flushed to earlier..
419 if (src
->storage
->type
!= REG_STACK
)
425 * Incoming pseudo with out any pre-set storage allocation?
426 * We can make up our own, and obviously prefer to get it
427 * in the register we already selected (if it hasn't been
430 if (src
->storage
->type
== REG_UDEF
) {
431 if (reg
&& !reg
->used
) {
432 src
->storage
->type
= REG_REG
;
433 src
->storage
->regno
= reg
- hardregs
;
436 alloc_stack(state
, src
->storage
);
441 static void mark_reg_dead(struct bb_state
*state
, pseudo_t pseudo
, struct hardreg
*reg
)
445 FOR_EACH_PTR_TAG(reg
->contains
, p
) {
448 if (CURRENT_TAG(p
) & TAG_DEAD
)
450 output_comment(state
, "marking pseudo %s in reg %s dead", show_pseudo(pseudo
), reg
->name
);
451 TAG_CURRENT(p
, TAG_DEAD
);
453 } END_FOR_EACH_PTR(p
);
456 static void add_pseudo_reg(struct bb_state
*state
, pseudo_t pseudo
, struct hardreg
*reg
)
458 output_comment(state
, "added pseudo %s to reg %s", show_pseudo(pseudo
), reg
->name
);
459 add_ptr_list_tag(®
->contains
, pseudo
, TAG_DIRTY
);
462 static struct hardreg
*preferred_reg(struct bb_state
*state
, pseudo_t target
)
464 struct storage_hash
*dst
;
466 dst
= find_storage_hash(target
, state
->outputs
);
468 struct storage
*storage
= dst
->storage
;
469 if (storage
->type
== REG_REG
)
470 return hardregs
+ storage
->regno
;
475 static struct hardreg
*empty_reg(struct bb_state
*state
)
478 struct hardreg
*reg
= hardregs
;
480 for (i
= 0; i
< REGNO
; i
++, reg
++) {
487 static struct hardreg
*target_reg(struct bb_state
*state
, pseudo_t pseudo
, pseudo_t target
)
490 int unable_to_find_reg
= 0;
493 /* First, see if we have a preferred target register.. */
494 reg
= preferred_reg(state
, target
);
495 if (reg
&& !reg
->contains
)
498 reg
= empty_reg(state
);
509 flush_reg(state
, reg
);
513 } while (i
!= last_reg
);
514 assert(unable_to_find_reg
);
517 add_pseudo_reg(state
, pseudo
, reg
);
521 static struct hardreg
*find_in_reg(struct bb_state
*state
, pseudo_t pseudo
)
526 for (i
= 0; i
< REGNO
; i
++) {
530 FOR_EACH_PTR_TAG(reg
->contains
, p
) {
533 output_comment(state
, "found pseudo %s in reg %s (busy=%d)", show_pseudo(pseudo
), reg
->name
, reg
->busy
);
536 } END_FOR_EACH_PTR(p
);
541 static void flush_pseudo(struct bb_state
*state
, pseudo_t pseudo
, struct storage
*storage
)
543 struct hardreg
*reg
= find_in_reg(state
, pseudo
);
546 flush_reg(state
, reg
);
549 static void flush_cc_cache_to_reg(struct bb_state
*state
, pseudo_t pseudo
, struct hardreg
*reg
)
551 int opcode
= state
->cc_opcode
;
553 state
->cc_opcode
= 0;
554 state
->cc_target
= NULL
;
555 output_insn(state
, "%s %s", opcodes
[opcode
], reg
->name
);
558 static void flush_cc_cache(struct bb_state
*state
)
560 pseudo_t pseudo
= state
->cc_target
;
565 state
->cc_target
= NULL
;
567 if (!state
->cc_dead
) {
568 dst
= target_reg(state
, pseudo
, pseudo
);
569 flush_cc_cache_to_reg(state
, pseudo
, dst
);
574 static void add_cc_cache(struct bb_state
*state
, int opcode
, pseudo_t pseudo
)
576 assert(!state
->cc_target
);
577 state
->cc_target
= pseudo
;
578 state
->cc_opcode
= opcode
;
580 output_comment(state
, "caching %s", opcodes
[opcode
]);
583 /* Fill a hardreg with the pseudo it has */
584 static struct hardreg
*fill_reg(struct bb_state
*state
, struct hardreg
*hardreg
, pseudo_t pseudo
)
586 struct storage_hash
*src
;
587 struct instruction
*def
;
589 if (state
->cc_target
== pseudo
) {
590 flush_cc_cache_to_reg(state
, pseudo
, hardreg
);
594 switch (pseudo
->type
) {
596 output_insn(state
, "movl $%lld,%s", pseudo
->value
, hardreg
->name
);
599 src
= find_pseudo_storage(state
, pseudo
, NULL
);
602 output_insn(state
, "movl $<%s>,%s", show_pseudo(pseudo
), hardreg
->name
);
605 switch (src
->storage
->type
) {
607 /* Aiaiaiaiaii! Need to flush it to temporary memory */
608 src
= find_or_create_hash(pseudo
, &state
->internal
);
611 alloc_stack(state
, src
->storage
);
615 flush_pseudo(state
, pseudo
, src
->storage
);
616 output_insn(state
, "leal %s,%s", show_memop(src
->storage
), hardreg
->name
);
623 if (def
&& (def
->opcode
== OP_SETVAL
|| def
->opcode
== OP_LABEL
)) {
624 output_insn(state
, "movl $<%s>,%s", show_pseudo(def
->target
), hardreg
->name
);
627 src
= find_pseudo_storage(state
, pseudo
, hardreg
);
630 if (src
->flags
& TAG_DEAD
)
631 mark_reg_dead(state
, pseudo
, hardreg
);
632 output_insn(state
, "mov.%d %s,%s", 32, show_memop(src
->storage
), hardreg
->name
);
635 output_insn(state
, "reload %s from %s", hardreg
->name
, show_pseudo(pseudo
));
641 static struct hardreg
*getreg(struct bb_state
*state
, pseudo_t pseudo
, pseudo_t target
)
645 reg
= find_in_reg(state
, pseudo
);
648 reg
= target_reg(state
, pseudo
, target
);
649 return fill_reg(state
, reg
, pseudo
);
652 static void move_reg(struct bb_state
*state
, struct hardreg
*src
, struct hardreg
*dst
)
654 output_insn(state
, "movl %s,%s", src
->name
, dst
->name
);
657 static struct hardreg
*copy_reg(struct bb_state
*state
, struct hardreg
*src
, pseudo_t target
)
662 /* If the container has been killed off, just re-use it */
666 /* If "src" only has one user, and the contents are dead, we can re-use it */
667 if (src
->busy
== 1 && src
->dead
== 1)
670 reg
= preferred_reg(state
, target
);
671 if (reg
&& !reg
->contains
) {
672 output_comment(state
, "copying %s to preferred target %s", show_pseudo(target
), reg
->name
);
673 move_reg(state
, src
, reg
);
677 for (i
= 0; i
< REGNO
; i
++) {
679 if (!reg
->contains
) {
680 output_comment(state
, "copying %s to %s", show_pseudo(target
), reg
->name
);
681 output_insn(state
, "movl %s,%s", src
->name
, reg
->name
);
686 flush_reg(state
, src
);
690 static void put_operand(struct bb_state
*state
, struct operand
*op
)
708 static struct operand
*alloc_op(void)
710 struct operand
*op
= malloc(sizeof(*op
));
711 memset(op
, 0, sizeof(*op
));
715 static struct operand
*get_register_operand(struct bb_state
*state
, pseudo_t pseudo
, pseudo_t target
)
717 struct operand
*op
= alloc_op();
719 op
->reg
= getreg(state
, pseudo
, target
);
724 static int get_sym_frame_offset(struct bb_state
*state
, pseudo_t pseudo
)
726 int offset
= pseudo
->nr
;
728 offset
= alloc_stack_offset(4);
734 static struct operand
*get_generic_operand(struct bb_state
*state
, pseudo_t pseudo
)
738 struct storage_hash
*hash
;
739 struct operand
*op
= malloc(sizeof(*op
));
741 memset(op
, 0, sizeof(*op
));
742 switch (pseudo
->type
) {
745 op
->value
= pseudo
->value
;
749 struct symbol
*sym
= pseudo
->sym
;
751 if (sym
->ctype
.modifiers
& MOD_NONLOCAL
) {
755 op
->base
= hardregs
+ REG_EBP
;
756 op
->offset
= get_sym_frame_offset(state
, pseudo
);
761 reg
= find_in_reg(state
, pseudo
);
768 hash
= find_pseudo_storage(state
, pseudo
, NULL
);
775 op
->reg
= hardregs
+ src
->regno
;
780 op
->offset
= src
->offset
;
781 op
->base
= hardregs
+ REG_EBP
;
785 op
->offset
= src
->offset
;
786 op
->base
= hardregs
+ REG_ESP
;
795 /* Callers should be made to use the proper "operand" formats */
796 static const char *generic(struct bb_state
*state
, pseudo_t pseudo
)
799 struct operand
*op
= get_generic_operand(state
, pseudo
);
800 static char buf
[100];
805 if (!op
->offset
&& op
->base
&& !op
->sym
)
806 return op
->base
->name
;
807 if (op
->sym
&& !op
->base
) {
808 int len
= sprintf(buf
, "$ %s", show_op(state
, op
));
810 sprintf(buf
+ len
, " + %d", op
->offset
);
813 str
= show_op(state
, op
);
814 put_operand(state
, op
);
815 reg
= target_reg(state
, pseudo
, NULL
);
816 output_insn(state
, "lea %s,%s", show_op(state
, op
), reg
->name
);
820 str
= show_op(state
, op
);
822 put_operand(state
, op
);
826 static struct operand
*get_address_operand(struct bb_state
*state
, struct instruction
*memop
)
828 struct hardreg
*base
;
829 struct operand
*op
= get_generic_operand(state
, memop
->src
);
833 op
->offset
+= memop
->offset
;
836 put_operand(state
, op
);
837 base
= getreg(state
, memop
->src
, NULL
);
841 op
->offset
= memop
->offset
;
847 static const char *address(struct bb_state
*state
, struct instruction
*memop
)
849 struct operand
*op
= get_address_operand(state
, memop
);
850 const char *str
= show_op(state
, op
);
851 put_operand(state
, op
);
855 static const char *reg_or_imm(struct bb_state
*state
, pseudo_t pseudo
)
857 switch(pseudo
->type
) {
859 return show_pseudo(pseudo
);
861 return getreg(state
, pseudo
, NULL
)->name
;
865 static void kill_dead_reg(struct hardreg
*reg
)
870 FOR_EACH_PTR_TAG(reg
->contains
, p
) {
871 if (CURRENT_TAG(p
) & TAG_DEAD
) {
872 DELETE_CURRENT_PTR(p
);
875 } END_FOR_EACH_PTR(p
);
876 PACK_PTR_LIST(®
->contains
);
881 static struct hardreg
*target_copy_reg(struct bb_state
*state
, struct hardreg
*src
, pseudo_t target
)
884 return copy_reg(state
, src
, target
);
887 static void do_binop(struct bb_state
*state
, struct instruction
*insn
, pseudo_t val1
, pseudo_t val2
)
889 const char *op
= opcodes
[insn
->opcode
];
890 struct operand
*src
= get_register_operand(state
, val1
, insn
->target
);
891 struct operand
*src2
= get_generic_operand(state
, val2
);
894 dst
= target_copy_reg(state
, src
->reg
, insn
->target
);
895 output_insn(state
, "%s.%d %s,%s", op
, insn
->size
, show_op(state
, src2
), dst
->name
);
896 put_operand(state
, src
);
897 put_operand(state
, src2
);
898 add_pseudo_reg(state
, insn
->target
, dst
);
901 static void generate_binop(struct bb_state
*state
, struct instruction
*insn
)
903 flush_cc_cache(state
);
904 do_binop(state
, insn
, insn
->src1
, insn
->src2
);
907 static int is_dead_reg(struct bb_state
*state
, pseudo_t pseudo
, struct hardreg
*reg
)
910 FOR_EACH_PTR_TAG(reg
->contains
, p
) {
912 return CURRENT_TAG(p
) & TAG_DEAD
;
913 } END_FOR_EACH_PTR(p
);
918 * Commutative binops are much more flexible, since we can switch the
919 * sources around to satisfy the target register, or to avoid having
920 * to load one of them into a register..
922 static void generate_commutative_binop(struct bb_state
*state
, struct instruction
*insn
)
925 struct hardreg
*reg1
, *reg2
;
927 flush_cc_cache(state
);
930 reg2
= find_in_reg(state
, src2
);
933 reg1
= find_in_reg(state
, src1
);
936 if (!is_dead_reg(state
, src2
, reg2
))
938 if (!is_dead_reg(state
, src1
, reg1
))
941 /* Both are dead. Is one preferable? */
942 if (reg2
!= preferred_reg(state
, insn
->target
))
949 do_binop(state
, insn
, src1
, src2
);
953 * This marks a pseudo dead. It still stays on the hardreg list (the hardreg
954 * still has its value), but it's scheduled to be killed after the next
955 * "sequence point" when we call "kill_read_pseudos()"
957 static void mark_pseudo_dead(struct bb_state
*state
, pseudo_t pseudo
)
960 struct storage_hash
*src
;
962 if (state
->cc_target
== pseudo
)
964 src
= find_pseudo_storage(state
, pseudo
, NULL
);
966 src
->flags
|= TAG_DEAD
;
967 for (i
= 0; i
< REGNO
; i
++)
968 mark_reg_dead(state
, pseudo
, hardregs
+ i
);
971 static void kill_dead_pseudos(struct bb_state
*state
)
975 for (i
= 0; i
< REGNO
; i
++) {
976 kill_dead_reg(hardregs
+ i
);
980 static void generate_store(struct instruction
*insn
, struct bb_state
*state
)
982 output_insn(state
, "mov.%d %s,%s", insn
->size
, reg_or_imm(state
, insn
->target
), address(state
, insn
));
985 static void generate_load(struct instruction
*insn
, struct bb_state
*state
)
987 const char *input
= address(state
, insn
);
990 kill_dead_pseudos(state
);
991 dst
= target_reg(state
, insn
->target
, NULL
);
992 output_insn(state
, "mov.%d %s,%s", insn
->size
, input
, dst
->name
);
995 static void kill_pseudo(struct bb_state
*state
, pseudo_t pseudo
)
1000 output_comment(state
, "killing pseudo %s", show_pseudo(pseudo
));
1001 for (i
= 0; i
< REGNO
; i
++) {
1005 FOR_EACH_PTR_TAG(reg
->contains
, p
) {
1008 if (CURRENT_TAG(p
) & TAG_DEAD
)
1010 output_comment(state
, "removing pseudo %s from reg %s",
1011 show_pseudo(pseudo
), reg
->name
);
1012 DELETE_CURRENT_PTR(p
);
1013 } END_FOR_EACH_PTR(p
);
1014 PACK_PTR_LIST(®
->contains
);
1018 static void generate_copy(struct bb_state
*state
, struct instruction
*insn
)
1020 struct hardreg
*src
= getreg(state
, insn
->src
, insn
->target
);
1021 kill_pseudo(state
, insn
->target
);
1022 add_pseudo_reg(state
, insn
->target
, src
);
1025 static void generate_cast(struct bb_state
*state
, struct instruction
*insn
)
1027 struct hardreg
*src
= getreg(state
, insn
->src
, insn
->target
);
1028 struct hardreg
*dst
;
1029 unsigned int old
= insn
->orig_type
? insn
->orig_type
->bit_size
: 0;
1030 unsigned int new = insn
->size
;
1033 * Cast to smaller type? Ignore the high bits, we
1034 * just keep both pseudos in the same register.
1037 add_pseudo_reg(state
, insn
->target
, src
);
1041 dst
= target_copy_reg(state
, src
, insn
->target
);
1043 if (insn
->orig_type
&& (insn
->orig_type
->ctype
.modifiers
& MOD_SIGNED
)) {
1044 output_insn(state
, "sext.%d.%d %s", old
, new, dst
->name
);
1046 unsigned long long mask
;
1047 mask
= ~(~0ULL << old
);
1048 mask
&= ~(~0ULL << new);
1049 output_insn(state
, "andl.%d $%#llx,%s", insn
->size
, mask
, dst
->name
);
1051 add_pseudo_reg(state
, insn
->target
, dst
);
1054 static void generate_output_storage(struct bb_state
*state
);
1056 static const char *conditional
[] = {
1070 static void generate_branch(struct bb_state
*state
, struct instruction
*br
)
1072 const char *cond
= "XXX";
1073 struct basic_block
*target
;
1076 if (state
->cc_target
== br
->cond
) {
1077 cond
= conditional
[state
->cc_opcode
];
1079 struct hardreg
*reg
= getreg(state
, br
->cond
, NULL
);
1080 output_insn(state
, "testl %s,%s", reg
->name
, reg
->name
);
1084 generate_output_storage(state
);
1085 target
= br
->bb_true
;
1087 output_insn(state
, "j%s .L%p", cond
, target
);
1088 target
= br
->bb_false
;
1090 output_insn(state
, "jmp .L%p", target
);
1093 /* We've made sure that there is a dummy reg live for the output */
1094 static void generate_switch(struct bb_state
*state
, struct instruction
*insn
)
1096 struct hardreg
*reg
= hardregs
+ SWITCH_REG
;
1098 generate_output_storage(state
);
1099 output_insn(state
, "switch on %s", reg
->name
);
1100 output_insn(state
, "unimplemented: %s", show_instruction(insn
));
1103 static void generate_ret(struct bb_state
*state
, struct instruction
*ret
)
1105 if (ret
->src
&& ret
->src
!= VOID
) {
1106 struct hardreg
*wants
= hardregs
+0;
1107 struct hardreg
*reg
= getreg(state
, ret
->src
, NULL
);
1109 output_insn(state
, "movl %s,%s", reg
->name
, wants
->name
);
1111 output_insn(state
, "ret");
1115 * Fake "call" linearization just as a taster..
1117 static void generate_call(struct bb_state
*state
, struct instruction
*insn
)
1122 FOR_EACH_PTR(insn
->arguments
, arg
) {
1123 output_insn(state
, "pushl %s", generic(state
, arg
));
1125 } END_FOR_EACH_PTR(arg
);
1126 flush_reg(state
, hardregs
+0);
1127 flush_reg(state
, hardregs
+1);
1128 flush_reg(state
, hardregs
+2);
1129 output_insn(state
, "call %s", show_pseudo(insn
->func
));
1131 output_insn(state
, "addl $%d,%%esp", offset
);
1132 if (insn
->target
&& insn
->target
!= VOID
)
1133 add_pseudo_reg(state
, insn
->target
, hardregs
+0);
1136 static void generate_select(struct bb_state
*state
, struct instruction
*insn
)
1139 struct hardreg
*src1
, *src2
, *dst
;
1141 src1
= getreg(state
, insn
->src2
, NULL
);
1142 dst
= copy_reg(state
, src1
, insn
->target
);
1143 add_pseudo_reg(state
, insn
->target
, dst
);
1144 src2
= getreg(state
, insn
->src3
, insn
->target
);
1146 if (state
->cc_target
== insn
->src1
) {
1147 cond
= conditional
[state
->cc_opcode
];
1149 struct hardreg
*reg
= getreg(state
, insn
->src1
, NULL
);
1150 output_insn(state
, "testl %s,%s", reg
->name
, reg
->name
);
1154 output_insn(state
, "sel%s %s,%s", cond
, src2
->name
, dst
->name
);
1158 const struct ident
*name
;
1161 struct hardreg
*reg
;
1164 static void replace_asm_arg(char **dst_p
, struct asm_arg
*arg
)
1167 int len
= strlen(arg
->value
);
1169 memcpy(dst
, arg
->value
, len
);
1173 static void replace_asm_percent(const char **src_p
, char **dst_p
, struct asm_arg
*args
, int nr
)
1175 const char *src
= *src_p
;
1184 replace_asm_arg(dst_p
, args
+index
);
1191 static void replace_asm_named(const char **src_p
, char **dst_p
, struct asm_arg
*args
, int nr
)
1193 const char *src
= *src_p
;
1194 const char *end
= src
;
1204 for (i
= 0; i
< nr
; i
++) {
1205 const struct ident
*ident
= args
[i
].name
;
1210 if (memcmp(src
, ident
->name
, len
))
1212 replace_asm_arg(dst_p
, args
+i
);
1219 static const char *replace_asm_args(const char *str
, struct asm_arg
*args
, int nr
)
1221 static char buffer
[1000];
1237 replace_asm_percent(&str
, &p
, args
, nr
);
1240 replace_asm_named(&str
, &p
, args
, nr
);
1249 #define MAX_ASM_ARG (50)
1250 static struct asm_arg asm_arguments
[MAX_ASM_ARG
];
1252 static struct asm_arg
*generate_asm_inputs(struct bb_state
*state
, struct asm_constraint_list
*list
, struct asm_arg
*arg
)
1254 struct asm_constraint
*entry
;
1256 FOR_EACH_PTR(list
, entry
) {
1257 const char *constraint
= entry
->constraint
;
1258 pseudo_t pseudo
= entry
->pseudo
;
1259 struct hardreg
*reg
, *orig
;
1264 switch (*constraint
) {
1266 string
= getreg(state
, pseudo
, NULL
)->name
;
1269 index
= *constraint
- '0';
1270 reg
= asm_arguments
[index
].reg
;
1271 orig
= find_in_reg(state
, pseudo
);
1273 move_reg(state
, orig
, reg
);
1275 fill_reg(state
, reg
, pseudo
);
1279 string
= generic(state
, pseudo
);
1283 output_insn(state
, "# asm input \"%s\": %s : %s", constraint
, show_pseudo(pseudo
), string
);
1285 arg
->name
= entry
->ident
;
1286 arg
->value
= string
;
1290 } END_FOR_EACH_PTR(entry
);
1294 static struct asm_arg
*generate_asm_outputs(struct bb_state
*state
, struct asm_constraint_list
*list
, struct asm_arg
*arg
)
1296 struct asm_constraint
*entry
;
1298 FOR_EACH_PTR(list
, entry
) {
1299 const char *constraint
= entry
->constraint
;
1300 pseudo_t pseudo
= entry
->pseudo
;
1301 struct hardreg
*reg
;
1304 while (*constraint
== '=' || *constraint
== '+')
1308 switch (*constraint
) {
1311 reg
= target_reg(state
, pseudo
, NULL
);
1312 arg
->pseudo
= pseudo
;
1318 output_insn(state
, "# asm output \"%s\": %s : %s", constraint
, show_pseudo(pseudo
), string
);
1320 arg
->name
= entry
->ident
;
1321 arg
->value
= string
;
1323 } END_FOR_EACH_PTR(entry
);
1327 static void generate_asm(struct bb_state
*state
, struct instruction
*insn
)
1329 const char *str
= insn
->string
;
1331 if (insn
->asm_rules
->outputs
|| insn
->asm_rules
->inputs
) {
1332 struct asm_arg
*arg
;
1334 arg
= generate_asm_outputs(state
, insn
->asm_rules
->outputs
, asm_arguments
);
1335 arg
= generate_asm_inputs(state
, insn
->asm_rules
->inputs
, arg
);
1336 str
= replace_asm_args(str
, asm_arguments
, arg
- asm_arguments
);
1338 output_insn(state
, "%s", str
);
1341 static void generate_compare(struct bb_state
*state
, struct instruction
*insn
)
1343 struct hardreg
*src
;
1347 flush_cc_cache(state
);
1348 opcode
= insn
->opcode
;
1351 * We should try to switch these around if necessary,
1352 * and update the opcode to match..
1354 src
= getreg(state
, insn
->src1
, insn
->target
);
1355 src2
= generic(state
, insn
->src2
);
1357 output_insn(state
, "cmp.%d %s,%s", insn
->size
, src2
, src
->name
);
1359 add_cc_cache(state
, opcode
, insn
->target
);
1362 static void generate_one_insn(struct instruction
*insn
, struct bb_state
*state
)
1365 output_comment(state
, "%s", show_instruction(insn
));
1367 switch (insn
->opcode
) {
1369 struct symbol
*sym
= insn
->bb
->ep
->name
;
1370 const char *name
= show_ident(sym
->ident
);
1371 if (sym
->ctype
.modifiers
& MOD_STATIC
)
1372 printf("\n\n%s:\n", name
);
1374 printf("\n\n.globl %s\n%s:\n", name
, name
);
1379 * OP_LABEL & OP_SETVAL likewise doesn't actually generate any
1380 * code. On use, the "def" of the pseudo will be
1388 generate_store(insn
, state
);
1392 generate_load(insn
, state
);
1396 mark_pseudo_dead(state
, insn
->target
);
1400 generate_copy(state
, insn
);
1403 case OP_ADD
: case OP_MUL
:
1404 case OP_AND
: case OP_OR
: case OP_XOR
:
1405 generate_commutative_binop(state
, insn
);
1408 case OP_SUB
: case OP_DIVU
: case OP_DIVS
:
1409 case OP_MODU
: case OP_MODS
:
1410 case OP_SHL
: case OP_LSR
: case OP_ASR
:
1411 generate_binop(state
, insn
);
1414 case OP_BINCMP
... OP_BINCMP_END
:
1415 generate_compare(state
, insn
);
1418 case OP_SEXT
: case OP_ZEXT
:
1423 case OP_FCVTU
: case OP_FCVTS
:
1424 case OP_UCVTF
: case OP_SCVTF
:
1426 generate_cast(state
, insn
);
1430 generate_select(state
, insn
);
1435 generate_branch(state
, insn
);
1439 generate_switch(state
, insn
);
1443 generate_call(state
, insn
);
1447 generate_ret(state
, insn
);
1451 generate_asm(state
, insn
);
1457 output_insn(state
, "unimplemented: %s", show_instruction(insn
));
1460 kill_dead_pseudos(state
);
1463 #define VERY_BUSY 1000
1464 #define REG_FIXED 2000
1466 static void write_reg_to_storage(struct bb_state
*state
, struct hardreg
*reg
, pseudo_t pseudo
, struct storage
*storage
)
1469 struct hardreg
*out
;
1471 switch (storage
->type
) {
1473 out
= hardregs
+ storage
->regno
;
1476 output_insn(state
, "movl %s,%s", reg
->name
, out
->name
);
1479 if (reg
->busy
< VERY_BUSY
) {
1480 storage
->type
= REG_REG
;
1481 storage
->regno
= reg
- hardregs
;
1482 reg
->busy
= REG_FIXED
;
1486 /* Try to find a non-busy register.. */
1487 for (i
= 0; i
< REGNO
; i
++) {
1491 output_insn(state
, "movl %s,%s", reg
->name
, out
->name
);
1492 storage
->type
= REG_REG
;
1494 out
->busy
= REG_FIXED
;
1498 /* Fall back on stack allocation ... */
1499 alloc_stack(state
, storage
);
1502 output_insn(state
, "movl %s,%s", reg
->name
, show_memop(storage
));
1507 static void write_val_to_storage(struct bb_state
*state
, pseudo_t src
, struct storage
*storage
)
1509 struct hardreg
*out
;
1511 switch (storage
->type
) {
1513 alloc_stack(state
, storage
);
1515 output_insn(state
, "movl %s,%s", show_pseudo(src
), show_memop(storage
));
1518 out
= hardregs
+ storage
->regno
;
1519 output_insn(state
, "movl %s,%s", show_pseudo(src
), out
->name
);
1523 static void fill_output(struct bb_state
*state
, pseudo_t pseudo
, struct storage
*out
)
1526 struct storage_hash
*in
;
1527 struct instruction
*def
;
1529 /* Is that pseudo a constant value? */
1530 switch (pseudo
->type
) {
1532 write_val_to_storage(state
, pseudo
, out
);
1536 if (def
&& (def
->opcode
== OP_SETVAL
|| def
->opcode
== OP_LABEL
)) {
1537 write_val_to_storage(state
, pseudo
, out
);
1544 /* See if we have that pseudo in a register.. */
1545 for (i
= 0; i
< REGNO
; i
++) {
1546 struct hardreg
*reg
= hardregs
+ i
;
1549 FOR_EACH_PTR_TAG(reg
->contains
, p
) {
1551 write_reg_to_storage(state
, reg
, pseudo
, out
);
1554 } END_FOR_EACH_PTR(p
);
1557 /* Do we have it in another storage? */
1558 in
= find_storage_hash(pseudo
, state
->internal
);
1560 in
= find_storage_hash(pseudo
, state
->inputs
);
1565 switch (out
->type
) {
1567 *out
= *in
->storage
;
1570 output_insn(state
, "movl %s,%s", show_memop(in
->storage
), hardregs
[out
->regno
].name
);
1573 if (out
== in
->storage
)
1575 if ((out
->type
== in
->storage
->type
) && (out
->regno
== in
->storage
->regno
))
1577 output_insn(state
, "movl %s,%s", show_memop(in
->storage
), show_memop(out
));
1583 static int final_pseudo_flush(struct bb_state
*state
, pseudo_t pseudo
, struct hardreg
*reg
)
1585 struct storage_hash
*hash
;
1586 struct storage
*out
;
1587 struct hardreg
*dst
;
1590 * Since this pseudo is live at exit, we'd better have output
1593 hash
= find_storage_hash(pseudo
, state
->outputs
);
1596 out
= hash
->storage
;
1598 /* If the output is in a register, try to get it there.. */
1599 if (out
->type
== REG_REG
) {
1600 dst
= hardregs
+ out
->regno
;
1602 * Two good cases: nobody is using the right register,
1603 * or we've already set it aside for output..
1605 if (!dst
->contains
|| dst
->busy
> VERY_BUSY
)
1608 /* Aiee. Try to keep it in a register.. */
1609 dst
= empty_reg(state
);
1616 /* If the output is undefined, let's see if we can put it in a register.. */
1617 if (out
->type
== REG_UDEF
) {
1618 dst
= empty_reg(state
);
1620 out
->type
= REG_REG
;
1621 out
->regno
= dst
- hardregs
;
1624 /* Uhhuh. Not so good. No empty registers right now */
1628 /* If we know we need to flush it, just do so already .. */
1629 output_insn(state
, "movl %s,%s", reg
->name
, show_memop(out
));
1635 output_insn(state
, "movl %s,%s", reg
->name
, dst
->name
);
1636 add_pseudo_reg(state
, pseudo
, dst
);
1641 * This tries to make sure that we put all the pseudos that are
1642 * live on exit into the proper storage
1644 static void generate_output_storage(struct bb_state
*state
)
1646 struct storage_hash
*entry
;
1648 /* Go through the fixed outputs, making sure we have those regs free */
1649 FOR_EACH_PTR(state
->outputs
, entry
) {
1650 struct storage
*out
= entry
->storage
;
1651 if (out
->type
== REG_REG
) {
1652 struct hardreg
*reg
= hardregs
+ out
->regno
;
1656 reg
->busy
= REG_FIXED
;
1657 FOR_EACH_PTR_TAG(reg
->contains
, p
) {
1658 if (p
== entry
->pseudo
) {
1662 if (CURRENT_TAG(p
) & TAG_DEAD
)
1665 /* Try to write back the pseudo to where it should go ... */
1666 if (final_pseudo_flush(state
, p
, reg
)) {
1667 DELETE_CURRENT_PTR(p
);
1671 } END_FOR_EACH_PTR(p
);
1672 PACK_PTR_LIST(®
->contains
);
1674 flush_reg(state
, reg
);
1676 } END_FOR_EACH_PTR(entry
);
1678 FOR_EACH_PTR(state
->outputs
, entry
) {
1679 fill_output(state
, entry
->pseudo
, entry
->storage
);
1680 } END_FOR_EACH_PTR(entry
);
1683 static void generate(struct basic_block
*bb
, struct bb_state
*state
)
1686 struct storage_hash
*entry
;
1687 struct instruction
*insn
;
1689 for (i
= 0; i
< REGNO
; i
++) {
1690 free_ptr_list(&hardregs
[i
].contains
);
1691 hardregs
[i
].busy
= 0;
1692 hardregs
[i
].dead
= 0;
1693 hardregs
[i
].used
= 0;
1696 FOR_EACH_PTR(state
->inputs
, entry
) {
1697 struct storage
*storage
= entry
->storage
;
1698 const char *name
= show_storage(storage
);
1699 output_comment(state
, "incoming %s in %s", show_pseudo(entry
->pseudo
), name
);
1700 if (storage
->type
== REG_REG
) {
1701 int regno
= storage
->regno
;
1702 add_pseudo_reg(state
, entry
->pseudo
, hardregs
+ regno
);
1703 name
= hardregs
[regno
].name
;
1705 } END_FOR_EACH_PTR(entry
);
1707 output_label(state
, ".L%p", bb
);
1708 FOR_EACH_PTR(bb
->insns
, insn
) {
1711 generate_one_insn(insn
, state
);
1712 } END_FOR_EACH_PTR(insn
);
1715 output_comment(state
, "--- in ---");
1716 FOR_EACH_PTR(state
->inputs
, entry
) {
1717 output_comment(state
, "%s <- %s", show_pseudo(entry
->pseudo
), show_storage(entry
->storage
));
1718 } END_FOR_EACH_PTR(entry
);
1719 output_comment(state
, "--- spill ---");
1720 FOR_EACH_PTR(state
->internal
, entry
) {
1721 output_comment(state
, "%s <-> %s", show_pseudo(entry
->pseudo
), show_storage(entry
->storage
));
1722 } END_FOR_EACH_PTR(entry
);
1723 output_comment(state
, "--- out ---");
1724 FOR_EACH_PTR(state
->outputs
, entry
) {
1725 output_comment(state
, "%s -> %s", show_pseudo(entry
->pseudo
), show_storage(entry
->storage
));
1726 } END_FOR_EACH_PTR(entry
);
1731 static void generate_list(struct basic_block_list
*list
, unsigned long generation
)
1733 struct basic_block
*bb
;
1734 FOR_EACH_PTR(list
, bb
) {
1735 if (bb
->generation
== generation
)
1737 output_bb(bb
, generation
);
1738 } END_FOR_EACH_PTR(bb
);
1742 * Mark all the output registers of all the parents
1743 * as being "used" - this does not mean that we cannot
1744 * re-use them, but it means that we cannot ask the
1745 * parents to pass in another pseudo in one of those
1746 * registers that it already uses for another child.
1748 static void mark_used_registers(struct basic_block
*bb
, struct bb_state
*state
)
1750 struct basic_block
*parent
;
1752 FOR_EACH_PTR(bb
->parents
, parent
) {
1753 struct storage_hash_list
*outputs
= gather_storage(parent
, STOR_OUT
);
1754 struct storage_hash
*entry
;
1756 FOR_EACH_PTR(outputs
, entry
) {
1757 struct storage
*s
= entry
->storage
;
1758 if (s
->type
== REG_REG
) {
1759 struct hardreg
*reg
= hardregs
+ s
->regno
;
1762 } END_FOR_EACH_PTR(entry
);
1763 } END_FOR_EACH_PTR(parent
);
1766 static void output_bb(struct basic_block
*bb
, unsigned long generation
)
1768 struct bb_state state
;
1770 bb
->generation
= generation
;
1772 /* Make sure all parents have been generated first */
1773 generate_list(bb
->parents
, generation
);
1775 state
.pos
= bb
->pos
;
1776 state
.inputs
= gather_storage(bb
, STOR_IN
);
1777 state
.outputs
= gather_storage(bb
, STOR_OUT
);
1778 state
.internal
= NULL
;
1779 state
.cc_opcode
= 0;
1780 state
.cc_target
= NULL
;
1782 /* Mark incoming registers used */
1783 mark_used_registers(bb
, &state
);
1785 generate(bb
, &state
);
1787 free_ptr_list(&state
.inputs
);
1788 free_ptr_list(&state
.outputs
);
1790 /* Generate all children... */
1791 generate_list(bb
->children
, generation
);
1795 * We should set up argument sources here..
1797 * Things like "first three arguments in registers" etc
1798 * are all for this place.
1800 * On x86, we default to stack, unless it's a static
1801 * function that doesn't have its address taken.
1803 * I should implement the -mregparm=X cmd line option.
1805 static void set_up_arch_entry(struct entrypoint
*ep
, struct instruction
*entry
)
1808 struct symbol
*sym
, *argtype
;
1809 int i
, offset
, regparm
;
1813 if (!(sym
->ctype
.modifiers
& MOD_ADDRESSABLE
))
1815 sym
= sym
->ctype
.base_type
;
1818 PREPARE_PTR_LIST(sym
->arguments
, argtype
);
1819 FOR_EACH_PTR(entry
->arg_list
, arg
) {
1820 struct storage
*in
= lookup_storage(entry
->bb
, arg
, STOR_IN
);
1822 in
= alloc_storage();
1823 add_storage(in
, entry
->bb
, arg
, STOR_IN
);
1829 int bits
= argtype
? argtype
->bit_size
: 0;
1831 if (bits
< bits_in_int
)
1834 in
->type
= REG_FRAME
;
1835 in
->offset
= offset
;
1837 offset
+= bits_to_bytes(bits
);
1840 NEXT_PTR_LIST(argtype
);
1841 } END_FOR_EACH_PTR(arg
);
1842 FINISH_PTR_LIST(argtype
);
1846 * Set up storage information for "return"
1848 * Not strictly necessary, since the code generator will
1849 * certainly move the return value to the right register,
1850 * but it can help register allocation if the allocator
1851 * sees that the target register is going to return in %eax.
1853 static void set_up_arch_exit(struct basic_block
*bb
, struct instruction
*ret
)
1855 pseudo_t pseudo
= ret
->src
;
1857 if (pseudo
&& pseudo
!= VOID
) {
1858 struct storage
*out
= lookup_storage(bb
, pseudo
, STOR_OUT
);
1860 out
= alloc_storage();
1861 add_storage(out
, bb
, pseudo
, STOR_OUT
);
1863 out
->type
= REG_REG
;
1869 * Set up dummy/silly output storage information for a switch
1870 * instruction. We need to make sure that a register is available
1871 * when we generate code for switch, so force that by creating
1872 * a dummy output rule.
1874 static void set_up_arch_switch(struct basic_block
*bb
, struct instruction
*insn
)
1876 pseudo_t pseudo
= insn
->cond
;
1877 struct storage
*out
= lookup_storage(bb
, pseudo
, STOR_OUT
);
1879 out
= alloc_storage();
1880 add_storage(out
, bb
, pseudo
, STOR_OUT
);
1882 out
->type
= REG_REG
;
1883 out
->regno
= SWITCH_REG
;
1886 static void arch_set_up_storage(struct entrypoint
*ep
)
1888 struct basic_block
*bb
;
1890 /* Argument storage etc.. */
1891 set_up_arch_entry(ep
, ep
->entry
);
1893 FOR_EACH_PTR(ep
->bbs
, bb
) {
1894 struct instruction
*insn
= last_instruction(bb
->insns
);
1897 switch (insn
->opcode
) {
1899 set_up_arch_exit(bb
, insn
);
1902 set_up_arch_switch(bb
, insn
);
1907 } END_FOR_EACH_PTR(bb
);
1910 static void output(struct entrypoint
*ep
)
1912 unsigned long generation
= ++bb_generation
;
1917 /* Get rid of SSA form (phinodes etc) */
1920 /* Set up initial inter-bb storage links */
1923 /* Architecture-specific storage rules.. */
1924 arch_set_up_storage(ep
);
1926 /* Show the results ... */
1927 output_bb(ep
->entry
->bb
, generation
);
1929 /* Clear the storage hashes for the next function.. */
1933 static int compile(struct symbol_list
*list
)
1936 FOR_EACH_PTR(list
, sym
) {
1937 struct entrypoint
*ep
;
1939 ep
= linearize_symbol(sym
);
1942 } END_FOR_EACH_PTR(sym
);
1947 int main(int argc
, char **argv
)
1949 struct string_list
*filelist
= NULL
;
1952 compile(sparse_initialize(argc
, argv
, &filelist
));
1954 FOR_EACH_PTR(filelist
, file
) {
1955 compile(sparse(file
));
1956 } END_FOR_EACH_PTR(file
);