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>",
26 [OP_SWITCH
] = "switch",
27 [OP_INVOKE
] = "invoke",
28 [OP_COMPUTEDGOTO
] = "jmp *",
29 [OP_UNWIND
] = "unwind",
44 [OP_AND_BOOL
] = "and-bool",
45 [OP_OR_BOOL
] = "or-bool",
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 */
67 [OP_MALLOC
] = "malloc",
69 [OP_ALLOCA
] = "alloca",
73 [OP_GET_ELEMENT_PTR
] = "getelem",
77 [OP_PHISOURCE
] = "phisrc",
79 [OP_PTRCAST
] = "ptrcast",
81 [OP_VANEXT
] = "va_next",
82 [OP_VAARG
] = "va_arg",
87 [OP_DEATHNOTE
] = "dead",
90 /* Sparse tagging (line numbers, context, whatever) */
91 [OP_CONTEXT
] = "context",
94 static int last_reg
, stack_offset
;
98 struct pseudo_list
*contains
;
107 /* Our "switch" generation is very very stupid. */
108 #define SWITCH_REG (1)
110 static void output_bb(struct basic_block
*bb
, unsigned long generation
);
113 * We only know about the caller-clobbered registers
116 static struct hardreg hardregs
[] = {
133 struct storage_hash_list
*inputs
;
134 struct storage_hash_list
*outputs
;
135 struct storage_hash_list
*internal
;
138 int cc_opcode
, cc_dead
;
156 struct /* OP_MEM and OP_ADDR */ {
160 struct hardreg
*base
;
161 struct hardreg
*index
;
166 static const char *show_op(struct bb_state
*state
, struct operand
*op
)
168 static char buf
[256][4];
173 nr
= (bufnr
+ 1) & 3;
181 return op
->reg
->name
;
183 sprintf(p
, "$%lld", op
->value
);
188 p
+= sprintf(p
, "%d", op
->offset
);
190 p
+= sprintf(p
, "%s%s",
191 op
->offset
? "+" : "",
192 show_ident(op
->sym
->ident
));
193 if (op
->base
|| op
->index
) {
194 p
+= sprintf(p
, "(%s%s%s",
195 op
->base
? op
->base
->name
: "",
196 (op
->base
&& op
->index
) ? "," : "",
197 op
->index
? op
->index
->name
: "");
199 p
+= sprintf(p
, ",%d", op
->scale
);
208 static struct storage_hash
*find_storage_hash(pseudo_t pseudo
, struct storage_hash_list
*list
)
210 struct storage_hash
*entry
;
211 FOR_EACH_PTR(list
, entry
) {
212 if (entry
->pseudo
== pseudo
)
214 } END_FOR_EACH_PTR(entry
);
218 static struct storage_hash
*find_or_create_hash(pseudo_t pseudo
, struct storage_hash_list
**listp
)
220 struct storage_hash
*entry
;
222 entry
= find_storage_hash(pseudo
, *listp
);
224 entry
= alloc_storage_hash(alloc_storage());
225 entry
->pseudo
= pseudo
;
226 add_ptr_list(listp
, entry
);
231 /* Eventually we should just build it up in memory */
232 static void output_line(struct bb_state
*state
, const char *fmt
, ...)
241 static void output_label(struct bb_state
*state
, const char *fmt
, ...)
243 static char buffer
[512];
247 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
250 output_line(state
, "%s:\n", buffer
);
253 static void output_insn(struct bb_state
*state
, const char *fmt
, ...)
255 static char buffer
[512];
259 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
262 output_line(state
, "\t%s\n", buffer
);
265 #define output_insn(state, fmt, arg...) \
266 output_insn(state, fmt "\t\t# %s" , ## arg , __FUNCTION__)
268 static void output_comment(struct bb_state
*state
, const char *fmt
, ...)
270 static char buffer
[512];
276 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
279 output_line(state
, "\t# %s\n", buffer
);
282 static const char *show_memop(struct storage
*storage
)
284 static char buffer
[1000];
288 switch (storage
->type
) {
290 sprintf(buffer
, "%d(FP)", storage
->offset
);
293 sprintf(buffer
, "%d(SP)", storage
->offset
);
296 return hardregs
[storage
->regno
].name
;
298 return show_storage(storage
);
303 static void alloc_stack(struct bb_state
*state
, struct storage
*storage
)
305 storage
->type
= REG_STACK
;
306 storage
->offset
= stack_offset
;
311 * Can we re-generate the pseudo, so that we don't need to
312 * flush it to memory? We can regenerate:
313 * - immediates and symbol addresses
314 * - pseudos we got as input in non-registers
315 * - pseudos we've already saved off earlier..
317 static int can_regenerate(struct bb_state
*state
, pseudo_t pseudo
)
319 struct storage_hash
*in
;
321 switch (pseudo
->type
) {
327 in
= find_storage_hash(pseudo
, state
->inputs
);
328 if (in
&& in
->storage
->type
!= REG_REG
)
330 in
= find_storage_hash(pseudo
, state
->internal
);
337 static void flush_one_pseudo(struct bb_state
*state
, struct hardreg
*hardreg
, pseudo_t pseudo
)
339 struct storage_hash
*out
;
340 struct storage
*storage
;
342 if (can_regenerate(state
, pseudo
))
345 output_comment(state
, "flushing %s from %s", show_pseudo(pseudo
), hardreg
->name
);
346 out
= find_storage_hash(pseudo
, state
->internal
);
348 out
= find_storage_hash(pseudo
, state
->outputs
);
350 out
= find_or_create_hash(pseudo
, &state
->internal
);
352 storage
= out
->storage
;
353 switch (storage
->type
) {
356 * Aieee - the next user wants it in a register, but we
357 * need to flush it to memory in between. Which means that
358 * we need to allocate an internal one, dammit..
360 out
= find_or_create_hash(pseudo
, &state
->internal
);
361 storage
= out
->storage
;
364 alloc_stack(state
, storage
);
367 output_insn(state
, "movl %s,%s", hardreg
->name
, show_memop(storage
));
372 /* Flush a hardreg out to the storage it has.. */
373 static void flush_reg(struct bb_state
*state
, struct hardreg
*reg
)
378 output_comment(state
, "reg %s flushed while busy is %d!", reg
->name
, reg
->busy
);
383 FOR_EACH_PTR(reg
->contains
, pseudo
) {
384 if (CURRENT_TAG(pseudo
) & TAG_DEAD
)
386 if (!(CURRENT_TAG(pseudo
) & TAG_DIRTY
))
388 flush_one_pseudo(state
, reg
, pseudo
);
389 } END_FOR_EACH_PTR(pseudo
);
390 free_ptr_list(®
->contains
);
393 static struct storage_hash
*find_pseudo_storage(struct bb_state
*state
, pseudo_t pseudo
, struct hardreg
*reg
)
395 struct storage_hash
*src
;
397 src
= find_storage_hash(pseudo
, state
->internal
);
399 src
= find_storage_hash(pseudo
, state
->inputs
);
401 src
= find_storage_hash(pseudo
, state
->outputs
);
402 /* Undefined? Screw it! */
407 * If we found output storage, it had better be local stack
408 * that we flushed to earlier..
410 if (src
->storage
->type
!= REG_STACK
)
416 * Incoming pseudo with out any pre-set storage allocation?
417 * We can make up our own, and obviously prefer to get it
418 * in the register we already selected (if it hasn't been
421 if (src
->storage
->type
== REG_UDEF
) {
422 if (reg
&& !reg
->used
) {
423 src
->storage
->type
= REG_REG
;
424 src
->storage
->regno
= reg
- hardregs
;
427 alloc_stack(state
, src
->storage
);
432 static void mark_reg_dead(struct bb_state
*state
, pseudo_t pseudo
, struct hardreg
*reg
)
436 FOR_EACH_PTR(reg
->contains
, p
) {
439 if (CURRENT_TAG(p
) & TAG_DEAD
)
441 output_comment(state
, "marking pseudo %s in reg %s dead", show_pseudo(pseudo
), reg
->name
);
442 TAG_CURRENT(p
, TAG_DEAD
);
444 } END_FOR_EACH_PTR(p
);
447 static void add_pseudo_reg(struct bb_state
*state
, pseudo_t pseudo
, struct hardreg
*reg
)
449 output_comment(state
, "added pseudo %s to reg %s", show_pseudo(pseudo
), reg
->name
);
450 add_ptr_list_tag(®
->contains
, pseudo
, TAG_DIRTY
);
453 static struct hardreg
*preferred_reg(struct bb_state
*state
, pseudo_t target
)
455 struct storage_hash
*dst
;
457 dst
= find_storage_hash(target
, state
->outputs
);
459 struct storage
*storage
= dst
->storage
;
460 if (storage
->type
== REG_REG
)
461 return hardregs
+ storage
->regno
;
466 static struct hardreg
*empty_reg(struct bb_state
*state
)
469 struct hardreg
*reg
= hardregs
;
471 for (i
= 0; i
< REGNO
; i
++, reg
++) {
478 static struct hardreg
*target_reg(struct bb_state
*state
, pseudo_t pseudo
, pseudo_t target
)
481 int unable_to_find_reg
= 0;
484 /* First, see if we have a preferred target register.. */
485 reg
= preferred_reg(state
, target
);
486 if (reg
&& !reg
->contains
)
489 reg
= empty_reg(state
);
500 flush_reg(state
, reg
);
504 } while (i
!= last_reg
);
505 assert(unable_to_find_reg
);
508 add_pseudo_reg(state
, pseudo
, reg
);
512 static struct hardreg
*find_in_reg(struct bb_state
*state
, pseudo_t pseudo
)
517 for (i
= 0; i
< REGNO
; i
++) {
521 FOR_EACH_PTR(reg
->contains
, p
) {
524 output_comment(state
, "found pseudo %s in reg %s (busy=%d)", show_pseudo(pseudo
), reg
->name
, reg
->busy
);
527 } END_FOR_EACH_PTR(p
);
532 static void flush_pseudo(struct bb_state
*state
, pseudo_t pseudo
, struct storage
*storage
)
534 struct hardreg
*reg
= find_in_reg(state
, pseudo
);
537 flush_reg(state
, reg
);
540 static void flush_cc_cache_to_reg(struct bb_state
*state
, pseudo_t pseudo
, struct hardreg
*reg
)
542 int opcode
= state
->cc_opcode
;
544 state
->cc_opcode
= 0;
545 state
->cc_target
= NULL
;
546 output_insn(state
, "%s %s", opcodes
[opcode
], reg
->name
);
549 static void flush_cc_cache(struct bb_state
*state
)
551 pseudo_t pseudo
= state
->cc_target
;
556 state
->cc_target
= NULL
;
558 if (!state
->cc_dead
) {
559 dst
= target_reg(state
, pseudo
, pseudo
);
560 flush_cc_cache_to_reg(state
, pseudo
, dst
);
565 static void add_cc_cache(struct bb_state
*state
, int opcode
, pseudo_t pseudo
)
567 assert(!state
->cc_target
);
568 state
->cc_target
= pseudo
;
569 state
->cc_opcode
= opcode
;
571 output_comment(state
, "caching %s", opcodes
[opcode
]);
574 /* Fill a hardreg with the pseudo it has */
575 static struct hardreg
*fill_reg(struct bb_state
*state
, struct hardreg
*hardreg
, pseudo_t pseudo
)
577 struct storage_hash
*src
;
578 struct instruction
*def
;
580 if (state
->cc_target
== pseudo
) {
581 flush_cc_cache_to_reg(state
, pseudo
, hardreg
);
585 switch (pseudo
->type
) {
587 output_insn(state
, "movl $%lld,%s", pseudo
->value
, hardreg
->name
);
590 src
= find_pseudo_storage(state
, pseudo
, NULL
);
593 output_insn(state
, "movl $<%s>,%s", show_pseudo(pseudo
), hardreg
->name
);
596 switch (src
->storage
->type
) {
598 /* Aiaiaiaiaii! Need to flush it to temporary memory */
599 src
= find_or_create_hash(pseudo
, &state
->internal
);
602 alloc_stack(state
, src
->storage
);
606 flush_pseudo(state
, pseudo
, src
->storage
);
607 output_insn(state
, "leal %s,%s", show_memop(src
->storage
), hardreg
->name
);
614 if (def
->opcode
== OP_SETVAL
) {
615 output_insn(state
, "movl $<%s>,%s", show_pseudo(def
->target
), hardreg
->name
);
618 src
= find_pseudo_storage(state
, pseudo
, hardreg
);
621 if (src
->flags
& TAG_DEAD
)
622 mark_reg_dead(state
, pseudo
, hardreg
);
623 output_insn(state
, "mov.%d %s,%s", 32, show_memop(src
->storage
), hardreg
->name
);
626 output_insn(state
, "reload %s from %s", hardreg
->name
, show_pseudo(pseudo
));
632 static struct hardreg
*getreg(struct bb_state
*state
, pseudo_t pseudo
, pseudo_t target
)
636 reg
= find_in_reg(state
, pseudo
);
639 reg
= target_reg(state
, pseudo
, target
);
640 return fill_reg(state
, reg
, pseudo
);
643 static void move_reg(struct bb_state
*state
, struct hardreg
*src
, struct hardreg
*dst
)
645 output_insn(state
, "movl %s,%s", src
->name
, dst
->name
);
648 static struct hardreg
*copy_reg(struct bb_state
*state
, struct hardreg
*src
, pseudo_t target
)
653 /* If the container has been killed off, just re-use it */
657 /* If "src" only has one user, and the contents are dead, we can re-use it */
658 if (src
->busy
== 1 && src
->dead
== 1)
661 reg
= preferred_reg(state
, target
);
662 if (reg
&& !reg
->contains
) {
663 output_comment(state
, "copying %s to preferred target %s", show_pseudo(target
), reg
->name
);
664 move_reg(state
, src
, reg
);
668 for (i
= 0; i
< REGNO
; i
++) {
669 struct hardreg
*reg
= hardregs
+ i
;
670 if (!reg
->contains
) {
671 output_comment(state
, "copying %s to %s", show_pseudo(target
), reg
->name
);
672 output_insn(state
, "movl %s,%s", src
->name
, reg
->name
);
677 flush_reg(state
, src
);
681 static void put_operand(struct bb_state
*state
, struct operand
*op
)
699 static struct operand
*alloc_op(void)
701 struct operand
*op
= malloc(sizeof(*op
));
702 memset(op
, 0, sizeof(*op
));
706 static struct operand
*get_register_operand(struct bb_state
*state
, pseudo_t pseudo
, pseudo_t target
)
708 struct operand
*op
= alloc_op();
710 op
->reg
= getreg(state
, pseudo
, target
);
715 static struct operand
*get_generic_operand(struct bb_state
*state
, pseudo_t pseudo
)
719 struct storage_hash
*hash
;
720 struct operand
*op
= malloc(sizeof(*op
));
722 memset(op
, 0, sizeof(*op
));
723 switch (pseudo
->type
) {
726 op
->value
= pseudo
->value
;
731 op
->sym
= pseudo
->sym
;
735 reg
= find_in_reg(state
, pseudo
);
742 hash
= find_pseudo_storage(state
, pseudo
, NULL
);
749 op
->reg
= hardregs
+ src
->regno
;
754 op
->offset
= src
->offset
;
755 op
->base
= hardregs
+ REG_EBP
;
759 op
->offset
= src
->offset
;
760 op
->base
= hardregs
+ REG_ESP
;
769 /* Callers should be made to use the proper "operand" formats */
770 static const char *generic(struct bb_state
*state
, pseudo_t pseudo
)
772 struct operand
*op
= get_generic_operand(state
, pseudo
);
773 const char *str
= show_op(state
, op
);
774 put_operand(state
, op
);
778 static const char *address(struct bb_state
*state
, struct instruction
*memop
)
781 struct hardreg
*base
;
782 static char buffer
[100];
783 pseudo_t addr
= memop
->src
;
788 if (sym
->ctype
.modifiers
& MOD_NONLOCAL
) {
789 sprintf(buffer
, "%s+%d", show_ident(sym
->ident
), memop
->offset
);
792 sprintf(buffer
, "%d+%s(SP)", memop
->offset
, show_ident(sym
->ident
));
795 base
= getreg(state
, addr
, NULL
);
796 sprintf(buffer
, "%d(%s)", memop
->offset
, base
->name
);
801 static const char *reg_or_imm(struct bb_state
*state
, pseudo_t pseudo
)
803 switch(pseudo
->type
) {
805 return show_pseudo(pseudo
);
807 return getreg(state
, pseudo
, NULL
)->name
;
811 static void kill_dead_reg(struct hardreg
*reg
)
816 FOR_EACH_PTR(reg
->contains
, p
) {
817 if (CURRENT_TAG(p
) & TAG_DEAD
) {
818 DELETE_CURRENT_PTR(p
);
821 } END_FOR_EACH_PTR(p
);
822 PACK_PTR_LIST(®
->contains
);
827 static struct hardreg
*target_copy_reg(struct bb_state
*state
, struct hardreg
*src
, pseudo_t target
)
830 return copy_reg(state
, src
, target
);
833 static void do_binop(struct bb_state
*state
, struct instruction
*insn
, pseudo_t val1
, pseudo_t val2
)
835 const char *op
= opcodes
[insn
->opcode
];
836 struct operand
*src
= get_register_operand(state
, val1
, insn
->target
);
837 struct operand
*src2
= get_generic_operand(state
, val2
);
840 dst
= target_copy_reg(state
, src
->reg
, insn
->target
);
841 output_insn(state
, "%s.%d %s,%s", op
, insn
->size
, show_op(state
, src2
), dst
->name
);
842 put_operand(state
, src
);
843 put_operand(state
, src2
);
844 add_pseudo_reg(state
, insn
->target
, dst
);
847 static void generate_binop(struct bb_state
*state
, struct instruction
*insn
)
849 flush_cc_cache(state
);
850 do_binop(state
, insn
, insn
->src1
, insn
->src2
);
853 static int is_dead_reg(struct bb_state
*state
, pseudo_t pseudo
, struct hardreg
*reg
)
856 FOR_EACH_PTR(reg
->contains
, p
) {
858 return CURRENT_TAG(p
) & TAG_DEAD
;
859 } END_FOR_EACH_PTR(p
);
864 * Commutative binops are much more flexible, since we can switch the
865 * sources around to satisfy the target register, or to avoid having
866 * to load one of them into a register..
868 static void generate_commutative_binop(struct bb_state
*state
, struct instruction
*insn
)
871 struct hardreg
*reg1
, *reg2
;
873 flush_cc_cache(state
);
876 reg2
= find_in_reg(state
, src2
);
879 reg1
= find_in_reg(state
, src1
);
882 if (!is_dead_reg(state
, src2
, reg2
))
884 if (!is_dead_reg(state
, src1
, reg1
))
887 /* Both are dead. Is one preferrable? */
888 if (reg2
!= preferred_reg(state
, insn
->target
))
895 do_binop(state
, insn
, src1
, src2
);
899 * This marks a pseudo dead. It still stays on the hardreg list (the hardreg
900 * still has its value), but it's scheduled to be killed after the next
901 * "sequence point" when we call "kill_read_pseudos()"
903 static void mark_pseudo_dead(struct bb_state
*state
, pseudo_t pseudo
)
906 struct storage_hash
*src
;
908 if (state
->cc_target
== pseudo
)
910 src
= find_pseudo_storage(state
, pseudo
, NULL
);
912 src
->flags
|= TAG_DEAD
;
913 for (i
= 0; i
< REGNO
; i
++)
914 mark_reg_dead(state
, pseudo
, hardregs
+ i
);
917 static void kill_dead_pseudos(struct bb_state
*state
)
921 for (i
= 0; i
< REGNO
; i
++) {
922 kill_dead_reg(hardregs
+ i
);
927 * A PHI source can define a pseudo that we already
928 * have in another register. We need to invalidate the
929 * old register so that we don't end up with the same
930 * pseudo in "two places".
932 static void remove_pseudo_reg(struct bb_state
*state
, pseudo_t pseudo
)
936 output_comment(state
, "pseudo %s died", show_pseudo(pseudo
));
937 for (i
= 0; i
< REGNO
; i
++) {
938 struct hardreg
*reg
= hardregs
+ i
;
940 FOR_EACH_PTR(reg
->contains
, p
) {
943 if (CURRENT_TAG(p
) & TAG_DEAD
)
945 DELETE_CURRENT_PTR(p
);
946 output_comment(state
, "removed pseudo %s from reg %s", show_pseudo(pseudo
), reg
->name
);
947 } END_FOR_EACH_PTR(p
);
948 PACK_PTR_LIST(®
->contains
);
952 static void generate_store(struct instruction
*insn
, struct bb_state
*state
)
954 output_insn(state
, "mov.%d %s,%s", insn
->size
, reg_or_imm(state
, insn
->target
), address(state
, insn
));
957 static void generate_load(struct instruction
*insn
, struct bb_state
*state
)
959 const char *input
= address(state
, insn
);
962 kill_dead_pseudos(state
);
963 dst
= target_reg(state
, insn
->target
, NULL
);
964 output_insn(state
, "mov.%d %s,%s", insn
->size
, input
, dst
->name
);
967 static void generate_phisource(struct instruction
*insn
, struct bb_state
*state
)
969 struct instruction
*user
;
972 /* Mark all the target pseudos dead first */
973 FOR_EACH_PTR(insn
->phi_users
, user
) {
974 mark_pseudo_dead(state
, user
->target
);
975 } END_FOR_EACH_PTR(user
);
978 FOR_EACH_PTR(insn
->phi_users
, user
) {
980 reg
= getreg(state
, insn
->phi_src
, user
->target
);
981 remove_pseudo_reg(state
, user
->target
);
982 add_pseudo_reg(state
, user
->target
, reg
);
983 } END_FOR_EACH_PTR(user
);
986 static void generate_cast(struct bb_state
*state
, struct instruction
*insn
)
988 struct hardreg
*src
= getreg(state
, insn
->src
, insn
->target
);
990 unsigned int old
= insn
->orig_type
? insn
->orig_type
->bit_size
: 0;
991 unsigned int new = insn
->size
;
994 * Cast to smaller type? Ignore the high bits, we
995 * just keep both pseudos in the same register.
998 add_pseudo_reg(state
, insn
->target
, src
);
1002 dst
= target_copy_reg(state
, src
, insn
->target
);
1004 if (insn
->orig_type
&& (insn
->orig_type
->ctype
.modifiers
& MOD_SIGNED
)) {
1005 output_insn(state
, "sext.%d.%d %s", old
, new, dst
->name
);
1007 unsigned long long mask
;
1008 mask
= ~(~0ULL << old
);
1009 mask
&= ~(~0ULL << new);
1010 output_insn(state
, "andl.%d $%#llx,%s", insn
->size
, mask
, dst
->name
);
1012 add_pseudo_reg(state
, insn
->target
, dst
);
1015 static void generate_output_storage(struct bb_state
*state
);
1017 static const char *conditional
[] = {
1031 static void generate_branch(struct bb_state
*state
, struct instruction
*br
)
1033 const char *cond
= "XXX";
1034 struct basic_block
*target
;
1037 if (state
->cc_target
== br
->cond
) {
1038 cond
= conditional
[state
->cc_opcode
];
1040 struct hardreg
*reg
= getreg(state
, br
->cond
, NULL
);
1041 output_insn(state
, "testl %s,%s", reg
->name
, reg
->name
);
1045 generate_output_storage(state
);
1046 target
= br
->bb_true
;
1048 output_insn(state
, "j%s .L%p", cond
, target
);
1049 target
= br
->bb_false
;
1051 output_insn(state
, "jmp .L%p", target
);
1054 /* We've made sure that there is a dummy reg live for the output */
1055 static void generate_switch(struct bb_state
*state
, struct instruction
*insn
)
1057 struct hardreg
*reg
= hardregs
+ SWITCH_REG
;
1059 generate_output_storage(state
);
1060 output_insn(state
, "switch on %s", reg
->name
);
1061 output_insn(state
, "unimplemented: %s", show_instruction(insn
));
1064 static void generate_ret(struct bb_state
*state
, struct instruction
*ret
)
1066 if (ret
->src
&& ret
->src
!= VOID
) {
1067 struct hardreg
*wants
= hardregs
+0;
1068 struct hardreg
*reg
= getreg(state
, ret
->src
, NULL
);
1070 output_insn(state
, "movl %s,%s", reg
->name
, wants
->name
);
1072 output_insn(state
, "ret");
1076 * Fake "call" linearization just as a taster..
1078 static void generate_call(struct bb_state
*state
, struct instruction
*insn
)
1083 FOR_EACH_PTR(insn
->arguments
, arg
) {
1084 output_insn(state
, "pushl %s", generic(state
, arg
));
1086 } END_FOR_EACH_PTR(arg
);
1087 flush_reg(state
, hardregs
+0);
1088 flush_reg(state
, hardregs
+1);
1089 flush_reg(state
, hardregs
+2);
1090 output_insn(state
, "call %s", show_pseudo(insn
->func
));
1092 output_insn(state
, "addl $%d,%%esp", offset
);
1093 add_pseudo_reg(state
, insn
->target
, hardregs
+0);
1096 static void generate_select(struct bb_state
*state
, struct instruction
*insn
)
1099 struct hardreg
*src1
, *src2
, *dst
;
1101 src1
= getreg(state
, insn
->src2
, NULL
);
1102 dst
= copy_reg(state
, src1
, insn
->target
);
1103 add_pseudo_reg(state
, insn
->target
, dst
);
1104 src2
= getreg(state
, insn
->src3
, insn
->target
);
1106 if (state
->cc_target
== insn
->src1
) {
1107 cond
= conditional
[state
->cc_opcode
];
1109 struct hardreg
*reg
= getreg(state
, insn
->src1
, NULL
);
1110 output_insn(state
, "testl %s,%s", reg
->name
, reg
->name
);
1114 output_insn(state
, "sel%s %s,%s", cond
, src2
->name
, dst
->name
);
1118 const struct ident
*name
;
1121 struct hardreg
*reg
;
1124 static void replace_asm_arg(char **dst_p
, struct asm_arg
*arg
)
1127 int len
= strlen(arg
->value
);
1129 memcpy(dst
, arg
->value
, len
);
1133 static void replace_asm_percent(const char **src_p
, char **dst_p
, struct asm_arg
*args
, int nr
)
1135 const char *src
= *src_p
;
1144 replace_asm_arg(dst_p
, args
+index
);
1151 static void replace_asm_named(const char **src_p
, char **dst_p
, struct asm_arg
*args
, int nr
)
1153 const char *src
= *src_p
;
1154 const char *end
= src
;
1164 for (i
= 0; i
< nr
; i
++) {
1165 const struct ident
*ident
= args
[i
].name
;
1170 if (memcmp(src
, ident
->name
, len
))
1172 replace_asm_arg(dst_p
, args
+i
);
1179 static const char *replace_asm_args(const char *str
, struct asm_arg
*args
, int nr
)
1181 static char buffer
[1000];
1197 replace_asm_percent(&str
, &p
, args
, nr
);
1200 replace_asm_named(&str
, &p
, args
, nr
);
1209 #define MAX_ASM_ARG (50)
1210 static struct asm_arg asm_arguments
[MAX_ASM_ARG
];
1212 static struct asm_arg
*generate_asm_inputs(struct bb_state
*state
, struct asm_constraint_list
*list
, struct asm_arg
*arg
)
1214 struct asm_constraint
*entry
;
1216 FOR_EACH_PTR(list
, entry
) {
1217 const char *constraint
= entry
->constraint
;
1218 pseudo_t pseudo
= entry
->pseudo
;
1219 struct hardreg
*reg
, *orig
;
1224 switch (*constraint
) {
1226 string
= getreg(state
, pseudo
, NULL
)->name
;
1229 index
= *constraint
- '0';
1230 reg
= asm_arguments
[index
].reg
;
1231 orig
= find_in_reg(state
, pseudo
);
1233 move_reg(state
, orig
, reg
);
1235 fill_reg(state
, reg
, pseudo
);
1239 string
= generic(state
, pseudo
);
1243 output_insn(state
, "# asm input \"%s\": %s : %s", constraint
, show_pseudo(pseudo
), string
);
1245 arg
->name
= entry
->ident
;
1246 arg
->value
= string
;
1250 } END_FOR_EACH_PTR(entry
);
1254 static struct asm_arg
*generate_asm_outputs(struct bb_state
*state
, struct asm_constraint_list
*list
, struct asm_arg
*arg
)
1256 struct asm_constraint
*entry
;
1258 FOR_EACH_PTR(list
, entry
) {
1259 const char *constraint
= entry
->constraint
;
1260 pseudo_t pseudo
= entry
->pseudo
;
1261 struct hardreg
*reg
;
1264 while (*constraint
== '=' || *constraint
== '+')
1268 switch (*constraint
) {
1271 reg
= target_reg(state
, pseudo
, NULL
);
1272 arg
->pseudo
= pseudo
;
1278 output_insn(state
, "# asm output \"%s\": %s : %s", constraint
, show_pseudo(pseudo
), string
);
1280 arg
->name
= entry
->ident
;
1281 arg
->value
= string
;
1283 } END_FOR_EACH_PTR(entry
);
1287 static void generate_asm(struct bb_state
*state
, struct instruction
*insn
)
1289 const char *str
= insn
->string
;
1291 if (insn
->asm_rules
->outputs
|| insn
->asm_rules
->inputs
) {
1292 struct asm_arg
*arg
;
1294 arg
= generate_asm_outputs(state
, insn
->asm_rules
->outputs
, asm_arguments
);
1295 arg
= generate_asm_inputs(state
, insn
->asm_rules
->inputs
, arg
);
1296 str
= replace_asm_args(str
, asm_arguments
, arg
- asm_arguments
);
1298 output_insn(state
, "%s", str
);
1301 static void generate_compare(struct bb_state
*state
, struct instruction
*insn
)
1303 struct hardreg
*src
;
1307 flush_cc_cache(state
);
1308 opcode
= insn
->opcode
;
1311 * We should try to switch these around if necessary,
1312 * and update the opcode to match..
1314 src
= getreg(state
, insn
->src1
, insn
->target
);
1315 src2
= generic(state
, insn
->src2
);
1317 output_insn(state
, "cmp.%d %s,%s", insn
->size
, src2
, src
->name
);
1319 add_cc_cache(state
, opcode
, insn
->target
);
1322 static void generate_one_insn(struct instruction
*insn
, struct bb_state
*state
)
1325 output_comment(state
, "%s", show_instruction(insn
));
1327 switch (insn
->opcode
) {
1329 struct symbol
*sym
= insn
->bb
->ep
->name
;
1330 const char *name
= show_ident(sym
->ident
);
1331 if (sym
->ctype
.modifiers
& MOD_STATIC
)
1332 printf("\n\n%s:\n", name
);
1334 printf("\n\n.globl %s\n%s:\n", name
, name
);
1339 * OP_PHI doesn't actually generate any code. It has been
1340 * done by the storage allocator and the OP_PHISOURCE.
1346 generate_phisource(insn
, state
);
1350 * OP_SETVAL likewise doesn't actually generate any
1351 * code. On use, the "def" of the pseudo will be
1358 generate_store(insn
, state
);
1362 generate_load(insn
, state
);
1366 mark_pseudo_dead(state
, insn
->target
);
1369 case OP_ADD
: case OP_MUL
:
1370 case OP_AND
: case OP_OR
: case OP_XOR
:
1371 case OP_AND_BOOL
: case OP_OR_BOOL
:
1372 generate_commutative_binop(state
, insn
);
1375 case OP_SUB
: case OP_DIV
: case OP_MOD
:
1376 case OP_SHL
: case OP_SHR
:
1377 generate_binop(state
, insn
);
1380 case OP_BINCMP
... OP_BINCMP_END
:
1381 generate_compare(state
, insn
);
1384 case OP_CAST
: case OP_PTRCAST
:
1385 generate_cast(state
, insn
);
1389 generate_select(state
, insn
);
1393 generate_branch(state
, insn
);
1397 generate_switch(state
, insn
);
1401 generate_call(state
, insn
);
1405 generate_ret(state
, insn
);
1409 generate_asm(state
, insn
);
1413 output_insn(state
, "unimplemented: %s", show_instruction(insn
));
1416 kill_dead_pseudos(state
);
1419 #define VERY_BUSY 1000
1420 #define REG_FIXED 2000
1422 static void write_reg_to_storage(struct bb_state
*state
, struct hardreg
*reg
, pseudo_t pseudo
, struct storage
*storage
)
1425 struct hardreg
*out
;
1427 switch (storage
->type
) {
1429 out
= hardregs
+ storage
->regno
;
1432 output_insn(state
, "movl %s,%s", reg
->name
, out
->name
);
1435 if (reg
->busy
< VERY_BUSY
) {
1436 storage
->type
= REG_REG
;
1437 storage
->regno
= reg
- hardregs
;
1438 reg
->busy
= REG_FIXED
;
1442 /* Try to find a non-busy register.. */
1443 for (i
= 0; i
< REGNO
; i
++) {
1447 output_insn(state
, "movl %s,%s", reg
->name
, out
->name
);
1448 storage
->type
= REG_REG
;
1450 out
->busy
= REG_FIXED
;
1454 /* Fall back on stack allocation ... */
1455 alloc_stack(state
, storage
);
1458 output_insn(state
, "movl %s,%s", reg
->name
, show_memop(storage
));
1463 static void write_val_to_storage(struct bb_state
*state
, pseudo_t src
, struct storage
*storage
)
1465 struct hardreg
*out
;
1467 switch (storage
->type
) {
1469 alloc_stack(state
, storage
);
1471 output_insn(state
, "movl %s,%s", show_pseudo(src
), show_memop(storage
));
1474 out
= hardregs
+ storage
->regno
;
1475 output_insn(state
, "movl %s,%s", show_pseudo(src
), out
->name
);
1479 static void fill_output(struct bb_state
*state
, pseudo_t pseudo
, struct storage
*out
)
1482 struct storage_hash
*in
;
1483 struct instruction
*def
;
1485 /* Is that pseudo a constant value? */
1486 switch (pseudo
->type
) {
1488 write_val_to_storage(state
, pseudo
, out
);
1492 if (def
->opcode
== OP_SETVAL
) {
1493 write_val_to_storage(state
, pseudo
, out
);
1500 /* See if we have that pseudo in a register.. */
1501 for (i
= 0; i
< REGNO
; i
++) {
1502 struct hardreg
*reg
= hardregs
+ i
;
1505 FOR_EACH_PTR(reg
->contains
, p
) {
1507 write_reg_to_storage(state
, reg
, pseudo
, out
);
1510 } END_FOR_EACH_PTR(p
);
1513 /* Do we have it in another storage? */
1514 in
= find_storage_hash(pseudo
, state
->internal
);
1516 in
= find_storage_hash(pseudo
, state
->inputs
);
1521 switch (out
->type
) {
1523 *out
= *in
->storage
;
1526 output_insn(state
, "movl %s,%s", show_memop(in
->storage
), hardregs
[out
->regno
].name
);
1529 if (out
== in
->storage
)
1531 if (out
->type
== in
->storage
->type
== out
->regno
== in
->storage
->regno
)
1533 output_insn(state
, "movl %s,%s", show_memop(in
->storage
), show_memop(out
));
1539 static int final_pseudo_flush(struct bb_state
*state
, pseudo_t pseudo
, struct hardreg
*reg
)
1541 struct storage_hash
*hash
;
1542 struct storage
*out
;
1543 struct hardreg
*dst
;
1546 * Since this pseudo is live at exit, we'd better have output
1549 hash
= find_storage_hash(pseudo
, state
->outputs
);
1552 out
= hash
->storage
;
1554 /* If the output is in a register, try to get it there.. */
1555 if (out
->type
== REG_REG
) {
1556 dst
= hardregs
+ out
->regno
;
1558 * Two good cases: nobody is using the right register,
1559 * or we've already set it aside for output..
1561 if (!dst
->contains
|| dst
->busy
> VERY_BUSY
)
1564 /* Aiee. Try to keep it in a register.. */
1565 dst
= empty_reg(state
);
1572 /* If the output is undefined, let's see if we can put it in a register.. */
1573 if (out
->type
== REG_UDEF
) {
1574 dst
= empty_reg(state
);
1576 out
->type
= REG_REG
;
1577 out
->regno
= dst
- hardregs
;
1580 /* Uhhuh. Not so good. No empty registers right now */
1584 /* If we know we need to flush it, just do so already .. */
1585 output_insn(state
, "movl %s,%s", reg
->name
, show_memop(out
));
1591 output_insn(state
, "movl %s,%s", reg
->name
, dst
->name
);
1592 add_pseudo_reg(state
, pseudo
, dst
);
1597 * This tries to make sure that we put all the pseudos that are
1598 * live on exit into the proper storage
1600 static void generate_output_storage(struct bb_state
*state
)
1602 struct storage_hash
*entry
;
1604 /* Go through the fixed outputs, making sure we have those regs free */
1605 FOR_EACH_PTR(state
->outputs
, entry
) {
1606 struct storage
*out
= entry
->storage
;
1607 if (out
->type
== REG_REG
) {
1608 struct hardreg
*reg
= hardregs
+ out
->regno
;
1612 reg
->busy
= REG_FIXED
;
1613 FOR_EACH_PTR(reg
->contains
, p
) {
1614 if (p
== entry
->pseudo
) {
1618 if (CURRENT_TAG(p
) & TAG_DEAD
)
1621 /* Try to write back the pseudo to where it should go ... */
1622 if (final_pseudo_flush(state
, p
, reg
)) {
1623 DELETE_CURRENT_PTR(p
);
1627 } END_FOR_EACH_PTR(p
);
1628 PACK_PTR_LIST(®
->contains
);
1630 flush_reg(state
, reg
);
1632 } END_FOR_EACH_PTR(entry
);
1634 FOR_EACH_PTR(state
->outputs
, entry
) {
1635 fill_output(state
, entry
->pseudo
, entry
->storage
);
1636 } END_FOR_EACH_PTR(entry
);
1639 static void generate(struct basic_block
*bb
, struct bb_state
*state
)
1642 struct storage_hash
*entry
;
1643 struct instruction
*insn
;
1645 for (i
= 0; i
< REGNO
; i
++) {
1646 free_ptr_list(&hardregs
[i
].contains
);
1647 hardregs
[i
].busy
= 0;
1648 hardregs
[i
].dead
= 0;
1649 hardregs
[i
].used
= 0;
1652 FOR_EACH_PTR(state
->inputs
, entry
) {
1653 struct storage
*storage
= entry
->storage
;
1654 const char *name
= show_storage(storage
);
1655 output_comment(state
, "incoming %s in %s", show_pseudo(entry
->pseudo
), name
);
1656 if (storage
->type
== REG_REG
) {
1657 int regno
= storage
->regno
;
1658 add_pseudo_reg(state
, entry
->pseudo
, hardregs
+ regno
);
1659 name
= hardregs
[regno
].name
;
1661 } END_FOR_EACH_PTR(entry
);
1663 output_label(state
, ".L%p", bb
);
1664 FOR_EACH_PTR(bb
->insns
, insn
) {
1667 generate_one_insn(insn
, state
);
1668 } END_FOR_EACH_PTR(insn
);
1671 output_comment(state
, "--- in ---");
1672 FOR_EACH_PTR(state
->inputs
, entry
) {
1673 output_comment(state
, "%s <- %s", show_pseudo(entry
->pseudo
), show_storage(entry
->storage
));
1674 } END_FOR_EACH_PTR(entry
);
1675 output_comment(state
, "--- spill ---");
1676 FOR_EACH_PTR(state
->internal
, entry
) {
1677 output_comment(state
, "%s <-> %s", show_pseudo(entry
->pseudo
), show_storage(entry
->storage
));
1678 } END_FOR_EACH_PTR(entry
);
1679 output_comment(state
, "--- out ---");
1680 FOR_EACH_PTR(state
->outputs
, entry
) {
1681 output_comment(state
, "%s -> %s", show_pseudo(entry
->pseudo
), show_storage(entry
->storage
));
1682 } END_FOR_EACH_PTR(entry
);
1687 static void generate_list(struct basic_block_list
*list
, unsigned long generation
)
1689 struct basic_block
*bb
;
1690 FOR_EACH_PTR(list
, bb
) {
1691 if (bb
->generation
== generation
)
1693 output_bb(bb
, generation
);
1694 } END_FOR_EACH_PTR(bb
);
1698 * Mark all the output registers of all the parents
1699 * as being "used" - this does not mean that we cannot
1700 * re-use them, but it means that we cannot ask the
1701 * parents to pass in another pseudo in one of those
1702 * registers that it already uses for another child.
1704 static void mark_used_registers(struct basic_block
*bb
, struct bb_state
*state
)
1706 struct basic_block
*parent
;
1708 FOR_EACH_PTR(bb
->parents
, parent
) {
1709 struct storage_hash_list
*outputs
= gather_storage(parent
, STOR_OUT
);
1710 struct storage_hash
*entry
;
1712 FOR_EACH_PTR(outputs
, entry
) {
1713 struct storage
*s
= entry
->storage
;
1714 if (s
->type
== REG_REG
) {
1715 struct hardreg
*reg
= hardregs
+ s
->regno
;
1718 } END_FOR_EACH_PTR(entry
);
1719 } END_FOR_EACH_PTR(parent
);
1722 static void output_bb(struct basic_block
*bb
, unsigned long generation
)
1724 struct bb_state state
;
1726 bb
->generation
= generation
;
1728 /* Make sure all parents have been generated first */
1729 generate_list(bb
->parents
, generation
);
1731 state
.pos
= bb
->pos
;
1732 state
.inputs
= gather_storage(bb
, STOR_IN
);
1733 state
.outputs
= gather_storage(bb
, STOR_OUT
);
1734 state
.internal
= NULL
;
1735 state
.cc_opcode
= 0;
1736 state
.cc_target
= NULL
;
1738 /* Mark incoming registers used */
1739 mark_used_registers(bb
, &state
);
1741 generate(bb
, &state
);
1743 free_ptr_list(&state
.inputs
);
1744 free_ptr_list(&state
.outputs
);
1746 /* Generate all children... */
1747 generate_list(bb
->children
, generation
);
1751 * We should set up argument sources here..
1753 * Things like "first three arguments in registers" etc
1754 * are all for this place.
1756 * On x86, we default to stack, unless it's a static
1757 * function that doesn't have its address taken.
1759 * I should implement the -mregparm=X cmd line option.
1761 static void set_up_arch_entry(struct entrypoint
*ep
, struct instruction
*entry
)
1764 struct symbol
*sym
, *argtype
;
1765 int i
, offset
, regparm
;
1769 if (!(sym
->ctype
.modifiers
& MOD_ADDRESSABLE
))
1771 sym
= sym
->ctype
.base_type
;
1774 PREPARE_PTR_LIST(sym
->arguments
, argtype
);
1775 FOR_EACH_PTR(entry
->arg_list
, arg
) {
1776 struct storage
*in
= lookup_storage(entry
->bb
, arg
, STOR_IN
);
1778 in
= alloc_storage();
1779 add_storage(in
, entry
->bb
, arg
, STOR_IN
);
1785 int bits
= argtype
? argtype
->bit_size
: 0;
1787 if (bits
< bits_in_int
)
1790 in
->type
= REG_FRAME
;
1791 in
->offset
= offset
;
1793 offset
+= bits
>> 3;
1796 NEXT_PTR_LIST(argtype
);
1797 } END_FOR_EACH_PTR(arg
);
1798 FINISH_PTR_LIST(argtype
);
1802 * Set up storage information for "return"
1804 * Not strictly necessary, since the code generator will
1805 * certainly move the return value to the right register,
1806 * but it can help register allocation if the allocator
1807 * sees that the target register is going to return in %eax.
1809 static void set_up_arch_exit(struct basic_block
*bb
, struct instruction
*ret
)
1811 pseudo_t pseudo
= ret
->src
;
1813 if (pseudo
&& pseudo
!= VOID
) {
1814 struct storage
*out
= lookup_storage(bb
, pseudo
, STOR_OUT
);
1816 out
= alloc_storage();
1817 add_storage(out
, bb
, pseudo
, STOR_OUT
);
1819 out
->type
= REG_REG
;
1825 * Set up dummy/silly output storage information for a switch
1826 * instruction. We need to make sure that a register is available
1827 * when we generate code for switch, so force that by creating
1828 * a dummy output rule.
1830 static void set_up_arch_switch(struct basic_block
*bb
, struct instruction
*insn
)
1832 pseudo_t pseudo
= insn
->cond
;
1833 struct storage
*out
= lookup_storage(bb
, pseudo
, STOR_OUT
);
1835 out
= alloc_storage();
1836 add_storage(out
, bb
, pseudo
, STOR_OUT
);
1838 out
->type
= REG_REG
;
1839 out
->regno
= SWITCH_REG
;
1842 static void arch_set_up_storage(struct entrypoint
*ep
)
1844 struct basic_block
*bb
;
1846 /* Argument storage etc.. */
1847 set_up_arch_entry(ep
, ep
->entry
);
1849 FOR_EACH_PTR(ep
->bbs
, bb
) {
1850 struct instruction
*insn
= last_instruction(bb
->insns
);
1853 switch (insn
->opcode
) {
1855 set_up_arch_exit(bb
, insn
);
1858 set_up_arch_switch(bb
, insn
);
1863 } END_FOR_EACH_PTR(bb
);
1866 static void output(struct entrypoint
*ep
)
1868 unsigned long generation
= ++bb_generation
;
1873 /* Set up initial inter-bb storage links */
1876 /* Architecture-specific storage rules.. */
1877 arch_set_up_storage(ep
);
1879 /* Show the results ... */
1880 output_bb(ep
->entry
->bb
, generation
);
1882 /* Clear the storage hashes for the next function.. */
1886 static int compile(struct symbol_list
*list
)
1889 FOR_EACH_PTR(list
, sym
) {
1890 struct entrypoint
*ep
;
1892 ep
= linearize_symbol(sym
);
1895 } END_FOR_EACH_PTR(sym
);
1900 int main(int argc
, char **argv
)
1902 return compile(sparse(argc
, argv
));