If we decide to mark a register as being its own storage,
[smatch.git] / example.c
blob3c1fec3f02b23144bdee6bd7290b4bb92c0a9b34
1 /*
2 * Example of how to write a compiler with sparse
3 */
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <stdarg.h>
7 #include <assert.h>
9 #include "symbol.h"
10 #include "expression.h"
11 #include "linearize.h"
12 #include "flow.h"
13 #include "storage.h"
15 static const char* opcodes[] = {
16 [OP_BADOP] = "bad_op",
18 /* Fn entrypoint */
19 [OP_ENTRY] = "<entry-point>",
21 /* Terminator */
22 [OP_RET] = "ret",
23 [OP_BR] = "br",
24 [OP_SWITCH] = "switch",
25 [OP_INVOKE] = "invoke",
26 [OP_COMPUTEDGOTO] = "jmp *",
27 [OP_UNWIND] = "unwind",
29 /* Binary */
30 [OP_ADD] = "add",
31 [OP_SUB] = "sub",
32 [OP_MUL] = "mul",
33 [OP_DIV] = "div",
34 [OP_MOD] = "mod",
35 [OP_SHL] = "shl",
36 [OP_SHR] = "shr",
38 /* Logical */
39 [OP_AND] = "and",
40 [OP_OR] = "or",
41 [OP_XOR] = "xor",
42 [OP_AND_BOOL] = "and-bool",
43 [OP_OR_BOOL] = "or-bool",
45 /* Binary comparison */
46 [OP_SET_EQ] = "seteq",
47 [OP_SET_NE] = "setne",
48 [OP_SET_LE] = "setle",
49 [OP_SET_GE] = "setge",
50 [OP_SET_LT] = "setlt",
51 [OP_SET_GT] = "setgt",
52 [OP_SET_B] = "setb",
53 [OP_SET_A] = "seta",
54 [OP_SET_BE] = "setbe",
55 [OP_SET_AE] = "setae",
57 /* Uni */
58 [OP_NOT] = "not",
59 [OP_NEG] = "neg",
61 /* Special three-input */
62 [OP_SEL] = "select",
64 /* Memory */
65 [OP_MALLOC] = "malloc",
66 [OP_FREE] = "free",
67 [OP_ALLOCA] = "alloca",
68 [OP_LOAD] = "load",
69 [OP_STORE] = "store",
70 [OP_SETVAL] = "set",
71 [OP_GET_ELEMENT_PTR] = "getelem",
73 /* Other */
74 [OP_PHI] = "phi",
75 [OP_PHISOURCE] = "phisrc",
76 [OP_CAST] = "cast",
77 [OP_PTRCAST] = "ptrcast",
78 [OP_CALL] = "call",
79 [OP_VANEXT] = "va_next",
80 [OP_VAARG] = "va_arg",
81 [OP_SLICE] = "slice",
82 [OP_SNOP] = "snop",
83 [OP_LNOP] = "lnop",
84 [OP_NOP] = "nop",
85 [OP_DEATHNOTE] = "dead",
86 [OP_ASM] = "asm",
88 /* Sparse tagging (line numbers, context, whatever) */
89 [OP_CONTEXT] = "context",
92 struct hardreg {
93 const char *name;
94 struct pseudo_list *contains;
95 unsigned busy:16,
96 dead:8,
97 used:1;
100 #define TAG_DEAD 1
101 #define TAG_DIRTY 2
103 /* Our "switch" generation is very very stupid. */
104 #define SWITCH_REG (1)
106 static void output_bb(struct basic_block *bb, unsigned long generation);
109 * We only know about the caller-clobbered registers
110 * right now.
112 static struct hardreg hardregs[] = {
113 { .name = "%eax" },
114 { .name = "%edx" },
115 { .name = "%ecx" },
116 { .name = "%ebx" },
117 { .name = "%esi" },
118 { .name = "%edi" },
120 #define REGNO (sizeof(hardregs)/sizeof(struct hardreg))
122 struct bb_state {
123 struct position pos;
124 unsigned long stack_offset;
125 struct storage_hash_list *inputs;
126 struct storage_hash_list *outputs;
127 struct storage_hash_list *internal;
129 /* CC cache.. */
130 int cc_opcode, cc_dead;
131 pseudo_t cc_target;
134 static struct storage_hash *find_storage_hash(pseudo_t pseudo, struct storage_hash_list *list)
136 struct storage_hash *entry;
137 FOR_EACH_PTR(list, entry) {
138 if (entry->pseudo == pseudo)
139 return entry;
140 } END_FOR_EACH_PTR(entry);
141 return NULL;
144 static struct storage_hash *find_or_create_hash(pseudo_t pseudo, struct storage_hash_list **listp)
146 struct storage_hash *entry;
148 entry = find_storage_hash(pseudo, *listp);
149 if (!entry) {
150 entry = alloc_storage_hash(alloc_storage());
151 entry->pseudo = pseudo;
152 add_ptr_list(listp, entry);
154 return entry;
157 /* Eventually we should just build it up in memory */
158 static void output_line(struct bb_state *state, const char *fmt, ...)
160 va_list args;
162 va_start(args, fmt);
163 vprintf(fmt, args);
164 va_end(args);
167 static void output_label(struct bb_state *state, const char *fmt, ...)
169 static char buffer[512];
170 va_list args;
172 va_start(args, fmt);
173 vsnprintf(buffer, sizeof(buffer), fmt, args);
174 va_end(args);
176 output_line(state, "%s:\n", buffer);
179 static void output_insn(struct bb_state *state, const char *fmt, ...)
181 static char buffer[512];
182 va_list args;
184 va_start(args, fmt);
185 vsnprintf(buffer, sizeof(buffer), fmt, args);
186 va_end(args);
188 output_line(state, "\t%s\n", buffer);
191 static void output_comment(struct bb_state *state, const char *fmt, ...)
193 static char buffer[512];
194 va_list args;
196 if (!verbose)
197 return;
198 va_start(args, fmt);
199 vsnprintf(buffer, sizeof(buffer), fmt, args);
200 va_end(args);
202 output_line(state, "\t# %s\n", buffer);
205 static const char *show_memop(struct storage *storage)
207 static char buffer[1000];
209 if (!storage)
210 return "undef";
211 switch (storage->type) {
212 case REG_FRAME:
213 sprintf(buffer, "%d(FP)", storage->offset);
214 break;
215 case REG_STACK:
216 sprintf(buffer, "%d(SP)", storage->offset);
217 break;
218 case REG_REG:
219 return hardregs[storage->regno].name;
220 default:
221 return show_storage(storage);
223 return buffer;
226 static void alloc_stack(struct bb_state *state, struct storage *storage)
228 storage->type = REG_STACK;
229 storage->offset = state->stack_offset;
230 state->stack_offset += 4;
234 * Can we re-generate the pseudo, so that we don't need to
235 * flush it to memory? We can regenerate:
236 * - immediates and symbol addresses
237 * - pseudos we got as input in non-registers
238 * - pseudos we've already saved off earlier..
240 static int can_regenerate(struct bb_state *state, pseudo_t pseudo)
242 struct storage_hash *in;
244 switch (pseudo->type) {
245 case PSEUDO_VAL:
246 case PSEUDO_SYM:
247 return 1;
249 default:
250 in = find_storage_hash(pseudo, state->inputs);
251 if (in && in->storage->type != REG_REG)
252 return 1;
253 in = find_storage_hash(pseudo, state->internal);
254 if (in)
255 return 1;
257 return 0;
260 static void flush_one_pseudo(struct bb_state *state, struct hardreg *hardreg, pseudo_t pseudo)
262 struct storage_hash *out;
263 struct storage *storage;
265 if (can_regenerate(state, pseudo))
266 return;
268 output_comment(state, "flushing %s from %s", show_pseudo(pseudo), hardreg->name);
269 out = find_storage_hash(pseudo, state->internal);
270 if (!out) {
271 out = find_storage_hash(pseudo, state->outputs);
272 if (!out)
273 out = find_or_create_hash(pseudo, &state->internal);
275 storage = out->storage;
276 switch (storage->type) {
277 default:
279 * Aieee - the next user wants it in a register, but we
280 * need to flush it to memory in between. Which means that
281 * we need to allocate an internal one, dammit..
283 out = find_or_create_hash(pseudo, &state->internal);
284 storage = out->storage;
285 /* Fall through */
286 case REG_UDEF:
287 alloc_stack(state, storage);
288 /* Fall through */
289 case REG_STACK:
290 output_insn(state, "movl %s,%s", hardreg->name, show_memop(storage));
291 break;
295 /* Flush a hardreg out to the storage it has.. */
296 static void flush_reg(struct bb_state *state, struct hardreg *hardreg)
298 pseudo_t pseudo;
300 if (!hardreg->busy)
301 return;
302 hardreg->busy = 0;
303 hardreg->dead = 0;
304 hardreg->used = 1;
305 FOR_EACH_PTR(hardreg->contains, pseudo) {
306 if (CURRENT_TAG(pseudo) & TAG_DEAD)
307 continue;
308 if (!(CURRENT_TAG(pseudo) & TAG_DIRTY))
309 continue;
310 flush_one_pseudo(state, hardreg, pseudo);
311 } END_FOR_EACH_PTR(pseudo);
312 free_ptr_list(&hardreg->contains);
315 static struct storage_hash *find_pseudo_storage(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
317 struct storage_hash *src;
319 src = find_storage_hash(pseudo, state->internal);
320 if (!src) {
321 src = find_storage_hash(pseudo, state->inputs);
322 if (!src) {
323 src = find_storage_hash(pseudo, state->outputs);
324 /* Undefined? Screw it! */
325 if (!src)
326 return NULL;
329 * If we found output storage, it had better be local stack
330 * that we flushed to earlier..
332 if (src->storage->type != REG_STACK)
333 return NULL;
338 * Incoming pseudo with out any pre-set storage allocation?
339 * We can make up our own, and obviously prefer to get it
340 * in the register we already selected (if it hasn't been
341 * used yet).
343 if (src->storage->type == REG_UDEF) {
344 if (reg && !reg->used) {
345 src->storage->type = REG_REG;
346 src->storage->regno = reg - hardregs;
347 return NULL;
349 alloc_stack(state, src->storage);
351 return src;
354 static void mark_reg_dead(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
356 pseudo_t p;
358 FOR_EACH_PTR(reg->contains, p) {
359 if (p != pseudo)
360 continue;
361 if (CURRENT_TAG(p) & TAG_DEAD)
362 continue;
363 output_comment(state, "marking pseudo %s in reg %s dead", show_pseudo(pseudo), reg->name);
364 TAG_CURRENT(p, TAG_DEAD);
365 reg->dead++;
366 } END_FOR_EACH_PTR(p);
369 static void add_pseudo_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
371 output_comment(state, "added pseudo %s to reg %s", show_pseudo(pseudo), reg->name);
372 add_ptr_list_tag(&reg->contains, pseudo, TAG_DIRTY);
373 reg->busy++;
376 static int last_reg;
378 static struct hardreg *preferred_reg(struct bb_state *state, pseudo_t target)
380 struct storage_hash *dst;
382 dst = find_storage_hash(target, state->outputs);
383 if (dst) {
384 struct storage *storage = dst->storage;
385 if (storage->type == REG_REG)
386 return hardregs + storage->regno;
388 return NULL;
391 static struct hardreg *empty_reg(struct bb_state *state)
393 int i;
394 struct hardreg *reg = hardregs;
396 for (i = 0; i < REGNO; i++, reg++) {
397 if (!reg->busy)
398 return reg;
400 return NULL;
403 static struct hardreg *target_reg(struct bb_state *state, pseudo_t pseudo, pseudo_t target)
405 int i;
406 struct hardreg *reg;
408 /* First, see if we have a preferred target register.. */
409 reg = preferred_reg(state, target);
410 if (reg && !reg->busy)
411 goto found;
413 reg = empty_reg(state);
414 if (reg)
415 goto found;
417 i = last_reg+1;
418 if (i >= REGNO)
419 i = 0;
420 last_reg = i;
421 reg = hardregs + i;
422 flush_reg(state, reg);
424 found:
425 add_pseudo_reg(state, pseudo, reg);
426 return reg;
429 static struct hardreg *find_in_reg(struct bb_state *state, pseudo_t pseudo)
431 int i;
432 struct hardreg *reg;
434 for (i = 0; i < REGNO; i++) {
435 pseudo_t p;
437 reg = hardregs + i;
438 FOR_EACH_PTR(reg->contains, p) {
439 if (p == pseudo) {
440 last_reg = i;
441 output_comment(state, "found pseudo %s in reg %s", show_pseudo(pseudo), reg->name);
442 return reg;
444 } END_FOR_EACH_PTR(p);
446 return NULL;
449 static void flush_cc_cache_to_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
451 int opcode = state->cc_opcode;
453 state->cc_opcode = 0;
454 state->cc_target = NULL;
455 output_insn(state, "%s %s", opcodes[opcode], reg->name);
458 static void flush_cc_cache(struct bb_state *state)
460 pseudo_t pseudo = state->cc_target;
462 if (pseudo) {
463 struct hardreg *dst;
465 state->cc_target = NULL;
467 if (!state->cc_dead) {
468 dst = target_reg(state, pseudo, pseudo);
469 flush_cc_cache_to_reg(state, pseudo, dst);
474 static void add_cc_cache(struct bb_state *state, int opcode, pseudo_t pseudo)
476 assert(!state->cc_target);
477 state->cc_target = pseudo;
478 state->cc_opcode = opcode;
479 state->cc_dead = 0;
480 output_comment(state, "caching %s", opcodes[opcode]);
483 /* Fill a hardreg with the pseudo it has */
484 static struct hardreg *fill_reg(struct bb_state *state, struct hardreg *hardreg, pseudo_t pseudo)
486 struct storage_hash *src;
487 struct instruction *def;
489 if (state->cc_target == pseudo) {
490 flush_cc_cache_to_reg(state, pseudo, hardreg);
491 return hardreg;
494 switch (pseudo->type) {
495 case PSEUDO_VAL:
496 output_insn(state, "movl $%lld,%s", pseudo->value, hardreg->name);
497 break;
498 case PSEUDO_SYM:
499 output_insn(state, "movl $<%s>,%s", show_pseudo(pseudo), hardreg->name);
500 break;
501 case PSEUDO_ARG:
502 case PSEUDO_REG:
503 def = pseudo->def;
504 if (def->opcode == OP_SETVAL) {
505 output_insn(state, "movl $<%s>,%s", show_pseudo(def->symbol), hardreg->name);
506 break;
508 src = find_pseudo_storage(state, pseudo, hardreg);
509 if (!src)
510 break;
511 if (src->flags & TAG_DEAD)
512 mark_reg_dead(state, pseudo, hardreg);
513 output_insn(state, "mov.%d %s,%s", 32, show_memop(src->storage), hardreg->name);
514 break;
515 default:
516 output_insn(state, "reload %s from %s", hardreg->name, show_pseudo(pseudo));
517 break;
519 return hardreg;
522 static struct hardreg *getreg(struct bb_state *state, pseudo_t pseudo, pseudo_t target)
524 struct hardreg *reg;
526 reg = find_in_reg(state, pseudo);
527 if (reg)
528 return reg;
529 reg = target_reg(state, pseudo, target);
530 return fill_reg(state, reg, pseudo);
533 static struct hardreg *copy_reg(struct bb_state *state, struct hardreg *src, pseudo_t target)
535 int i;
536 struct hardreg *reg;
538 if (!src->busy)
539 return src;
541 reg = preferred_reg(state, target);
542 if (reg && !reg->busy) {
543 output_comment(state, "copying %s to preferred target %s", show_pseudo(target), reg->name);
544 output_insn(state, "movl %s,%s", src->name, reg->name);
545 return reg;
548 for (i = 0; i < REGNO; i++) {
549 struct hardreg *reg = hardregs + i;
550 if (!reg->busy) {
551 output_comment(state, "copying %s to %s", show_pseudo(target), reg->name);
552 output_insn(state, "movl %s,%s", src->name, reg->name);
553 return reg;
557 flush_reg(state, src);
558 return src;
561 static const char *generic(struct bb_state *state, pseudo_t pseudo)
563 struct hardreg *reg;
564 struct storage_hash *src;
566 switch (pseudo->type) {
567 case PSEUDO_SYM:
568 case PSEUDO_VAL:
569 return show_pseudo(pseudo);
570 default:
571 reg = find_in_reg(state, pseudo);
572 if (reg)
573 return reg->name;
574 src = find_pseudo_storage(state, pseudo, NULL);
575 if (!src)
576 return "undef";
577 return show_memop(src->storage);
581 static const char *address(struct bb_state *state, struct instruction *memop)
583 struct symbol *sym;
584 struct hardreg *base;
585 static char buffer[100];
586 pseudo_t addr = memop->src;
588 switch(addr->type) {
589 case PSEUDO_SYM:
590 sym = addr->sym;
591 if (sym->ctype.modifiers & MOD_NONLOCAL) {
592 sprintf(buffer, "%s+%d", show_ident(sym->ident), memop->offset);
593 return buffer;
595 sprintf(buffer, "%d+%s(SP)", memop->offset, show_ident(sym->ident));
596 return buffer;
597 default:
598 base = getreg(state, addr, NULL);
599 sprintf(buffer, "%d(%s)", memop->offset, base->name);
600 return buffer;
604 static const char *reg_or_imm(struct bb_state *state, pseudo_t pseudo)
606 switch(pseudo->type) {
607 case PSEUDO_VAL:
608 return show_pseudo(pseudo);
609 default:
610 return getreg(state, pseudo, NULL)->name;
614 static void kill_dead_reg(struct hardreg *reg)
616 if (reg->dead) {
617 pseudo_t p;
619 FOR_EACH_PTR(reg->contains, p) {
620 if (CURRENT_TAG(p) & TAG_DEAD) {
621 DELETE_CURRENT_PTR(p);
622 reg->busy--;
623 reg->dead--;
625 } END_FOR_EACH_PTR(p);
626 PACK_PTR_LIST(&reg->contains);
627 assert(!reg->dead);
631 static struct hardreg *target_copy_reg(struct bb_state *state, struct hardreg *src, pseudo_t target)
633 kill_dead_reg(src);
634 return copy_reg(state, src, target);
637 static void do_binop(struct bb_state *state, struct instruction *insn, pseudo_t val1, pseudo_t val2)
639 const char *op = opcodes[insn->opcode];
640 struct hardreg *src = getreg(state, val1, insn->target);
641 const char *src2 = generic(state, val2);
642 struct hardreg *dst;
644 dst = target_copy_reg(state, src, insn->target);
645 output_insn(state, "%s.%d %s,%s", op, insn->size, src2, dst->name);
646 add_pseudo_reg(state, insn->target, dst);
649 static void generate_binop(struct bb_state *state, struct instruction *insn)
651 flush_cc_cache(state);
652 do_binop(state, insn, insn->src1, insn->src2);
655 static int is_dead_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
657 pseudo_t p;
658 FOR_EACH_PTR(reg->contains, p) {
659 if (p == pseudo)
660 return CURRENT_TAG(p) & TAG_DEAD;
661 } END_FOR_EACH_PTR(p);
662 return 0;
666 * Commutative binops are much more flexible, since we can switch the
667 * sources around to satisfy the target register, or to avoid having
668 * to load one of them into a register..
670 static void generate_commutative_binop(struct bb_state *state, struct instruction *insn)
672 pseudo_t src1, src2;
673 struct hardreg *reg1, *reg2;
675 flush_cc_cache(state);
676 src1 = insn->src1;
677 src2 = insn->src2;
678 reg2 = find_in_reg(state, src2);
679 if (!reg2)
680 goto dont_switch;
681 reg1 = find_in_reg(state, src1);
682 if (!reg1)
683 goto do_switch;
684 if (!is_dead_reg(state, src2, reg2))
685 goto dont_switch;
686 if (!is_dead_reg(state, src1, reg1))
687 goto do_switch;
689 /* Both are dead. Is one preferrable? */
690 if (reg2 != preferred_reg(state, insn->target))
691 goto dont_switch;
693 do_switch:
694 src1 = src2;
695 src2 = insn->src1;
696 dont_switch:
697 do_binop(state, insn, src1, src2);
701 * This marks a pseudo dead. It still stays on the hardreg list (the hardreg
702 * still has its value), but it's scheduled to be killed after the next
703 * "sequence point" when we call "kill_read_pseudos()"
705 static void mark_pseudo_dead(struct bb_state *state, pseudo_t pseudo)
707 int i;
708 struct storage_hash *src;
710 if (state->cc_target == pseudo)
711 state->cc_dead = 1;
712 src = find_pseudo_storage(state, pseudo, NULL);
713 if (src)
714 src->flags |= TAG_DEAD;
715 for (i = 0; i < REGNO; i++)
716 mark_reg_dead(state, pseudo, hardregs + i);
719 static void kill_dead_pseudos(struct bb_state *state)
721 int i;
723 for (i = 0; i < REGNO; i++) {
724 kill_dead_reg(hardregs + i);
729 * A PHI source can define a pseudo that we already
730 * have in another register. We need to invalidate the
731 * old register so that we don't end up with the same
732 * pseudo in "two places".
734 static void remove_pseudo_reg(struct bb_state *state, pseudo_t pseudo)
736 int i;
738 output_comment(state, "pseudo %s died", show_pseudo(pseudo));
739 for (i = 0; i < REGNO; i++) {
740 struct hardreg *reg = hardregs + i;
741 pseudo_t p;
742 FOR_EACH_PTR(reg->contains, p) {
743 if (p != pseudo)
744 continue;
745 if (CURRENT_TAG(p) & TAG_DEAD)
746 reg->dead--;
747 reg->busy--;
748 DELETE_CURRENT_PTR(p);
749 output_comment(state, "removed pseudo %s from reg %s", show_pseudo(pseudo), reg->name);
750 } END_FOR_EACH_PTR(p);
751 PACK_PTR_LIST(&reg->contains);
755 static void generate_store(struct instruction *insn, struct bb_state *state)
757 output_insn(state, "mov.%d %s,%s", insn->size, reg_or_imm(state, insn->target), address(state, insn));
760 static void generate_load(struct instruction *insn, struct bb_state *state)
762 const char *input = address(state, insn);
763 struct hardreg *dst;
765 kill_dead_pseudos(state);
766 dst = target_reg(state, insn->target, NULL);
767 output_insn(state, "mov.%d %s,%s", insn->size, input, dst->name);
770 static void generate_phisource(struct instruction *insn, struct bb_state *state)
772 struct instruction *user;
773 struct hardreg *reg;
775 /* Mark all the target pseudos dead first */
776 FOR_EACH_PTR(insn->phi_users, user) {
777 mark_pseudo_dead(state, user->target);
778 } END_FOR_EACH_PTR(user);
780 reg = NULL;
781 FOR_EACH_PTR(insn->phi_users, user) {
782 if (!reg)
783 reg = getreg(state, insn->phi_src, user->target);
784 remove_pseudo_reg(state, user->target);
785 add_pseudo_reg(state, user->target, reg);
786 } END_FOR_EACH_PTR(user);
789 static void generate_cast(struct bb_state *state, struct instruction *insn)
791 struct hardreg *src = getreg(state, insn->src, insn->target);
792 struct hardreg *dst;
793 unsigned int old = insn->orig_type ? insn->orig_type->bit_size : 0;
794 unsigned int new = insn->size;
797 * Cast to smaller type? Ignore the high bits, we
798 * just keep both pseudos in the same register.
800 if (old >= new) {
801 add_pseudo_reg(state, insn->target, src);
802 return;
805 dst = target_copy_reg(state, src, insn->target);
807 if (insn->orig_type && (insn->orig_type->ctype.modifiers & MOD_SIGNED)) {
808 output_insn(state, "sext.%d.%d %s", old, new, dst->name);
809 } else {
810 unsigned long long mask;
811 mask = ~(~0ULL << old);
812 mask &= ~(~0ULL << new);
813 output_insn(state, "andl.%d $%#llx,%s", insn->size, mask, dst->name);
815 add_pseudo_reg(state, insn->target, dst);
818 static void generate_output_storage(struct bb_state *state);
820 static void generate_branch(struct bb_state *state, struct instruction *br)
822 const char *branch = "jXXX";
823 struct basic_block *target;
825 if (br->cond) {
826 if (state->cc_target == br->cond) {
827 static const char *branches[] = {
828 [OP_SET_EQ] = "je",
829 [OP_SET_NE] = "jne",
830 [OP_SET_LE] = "jle",
831 [OP_SET_GE] = "jge",
832 [OP_SET_LT] = "jlt",
833 [OP_SET_GT] = "jgt",
834 [OP_SET_B] = "jb",
835 [OP_SET_A] = "ja",
836 [OP_SET_BE] = "jbe",
837 [OP_SET_AE] = "jae"
839 branch = branches[state->cc_opcode];
840 } else {
841 struct hardreg *reg = getreg(state, br->cond, NULL);
842 output_insn(state, "testl %s,%s", reg->name, reg->name);
843 branch = "jne";
846 generate_output_storage(state);
847 target = br->bb_true;
848 if (br->cond) {
849 output_insn(state, "%s .L%p", branch, target);
850 target = br->bb_false;
852 output_insn(state, "jmp .L%p", target);
855 /* We've made sure that there is a dummy reg live for the output */
856 static void generate_switch(struct bb_state *state, struct instruction *insn)
858 struct hardreg *reg = hardregs + SWITCH_REG;
860 generate_output_storage(state);
861 output_insn(state, "switch on %s", reg->name);
862 output_insn(state, "unimplemented: %s", show_instruction(insn));
865 static void generate_ret(struct bb_state *state, struct instruction *ret)
867 if (ret->src && ret->src != VOID) {
868 struct hardreg *wants = hardregs+0;
869 struct hardreg *reg = getreg(state, ret->src, NULL);
870 if (reg != wants)
871 output_insn(state, "movl %s,%s", reg->name, wants->name);
873 output_insn(state, "ret");
877 * Fake "call" linearization just as a taster..
879 static void generate_call(struct bb_state *state, struct instruction *insn)
881 int offset = 0;
882 pseudo_t arg;
884 FOR_EACH_PTR(insn->arguments, arg) {
885 output_insn(state, "pushl %s", generic(state, arg));
886 offset += 4;
887 } END_FOR_EACH_PTR(arg);
888 flush_reg(state, hardregs+0);
889 flush_reg(state, hardregs+1);
890 flush_reg(state, hardregs+2);
891 output_insn(state, "call %s", show_pseudo(insn->func));
892 if (offset)
893 output_insn(state, "addl $%d,%%esp", offset);
894 add_pseudo_reg(state, insn->target, hardregs+0);
897 static void generate_select(struct bb_state *state, struct instruction *insn)
899 struct hardreg *src1, *src2, *cond, *dst;
901 cond = getreg(state, insn->src1, NULL);
902 output_insn(state, "testl %s,%s", cond->name, cond->name);
904 src1 = getreg(state, insn->src2, NULL);
905 dst = copy_reg(state, src1, insn->target);
906 add_pseudo_reg(state, insn->target, dst);
907 src2 = getreg(state, insn->src3, insn->target);
908 output_insn(state, "sele %s,%s", src2->name, dst->name);
911 static void generate_asm_inputs(struct bb_state *state, struct asm_constraint_list *list)
913 struct asm_constraint *entry;
915 FOR_EACH_PTR(list, entry) {
916 const char *constraint = entry->constraint;
917 pseudo_t pseudo = entry->pseudo;
919 output_insn(state, "# asm input \"%s\": %s", constraint, show_pseudo(pseudo));
920 } END_FOR_EACH_PTR(entry);
923 static void generate_asm_outputs(struct bb_state *state, struct asm_constraint_list *list)
925 struct asm_constraint *entry;
927 FOR_EACH_PTR(list, entry) {
928 const char *constraint = entry->constraint;
929 pseudo_t pseudo = entry->pseudo;
931 while (*constraint == '=' || *constraint == '+')
932 constraint++;
934 output_insn(state, "# asm output \"%s\": %s", constraint, show_pseudo(pseudo));
935 } END_FOR_EACH_PTR(entry);
938 static void generate_asm(struct bb_state *state, struct instruction *insn)
940 generate_asm_inputs(state, insn->asm_rules->inputs);
941 output_insn(state, "ASM: %s", insn->string);
942 generate_asm_outputs(state, insn->asm_rules->outputs);
945 static void generate_compare(struct bb_state *state, struct instruction *insn)
947 struct hardreg *src;
948 const char *src2;
949 int opcode;
951 flush_cc_cache(state);
952 opcode = insn->opcode;
955 * We should try to switch these around if necessary,
956 * and update the opcode to match..
958 src = getreg(state, insn->src1, insn->target);
959 src2 = generic(state, insn->src2);
961 output_insn(state, "cmp.%d %s,%s", insn->size, src2, src->name);
963 add_cc_cache(state, opcode, insn->target);
966 static void generate_one_insn(struct instruction *insn, struct bb_state *state)
968 if (verbose)
969 output_comment(state, "%s", show_instruction(insn));
971 switch (insn->opcode) {
972 case OP_ENTRY: {
973 struct symbol *sym = insn->bb->ep->name;
974 const char *name = show_ident(sym->ident);
975 if (sym->ctype.modifiers & MOD_STATIC)
976 printf("\n\n%s:\n", name);
977 else
978 printf("\n\n.globl %s\n%s:\n", name, name);
979 break;
983 * OP_PHI doesn't actually generate any code. It has been
984 * done by the storage allocator and the OP_PHISOURCE.
986 case OP_PHI:
987 break;
989 case OP_PHISOURCE:
990 generate_phisource(insn, state);
991 break;
994 * OP_SETVAL likewise doesn't actually generate any
995 * code. On use, the "def" of the pseudo will be
996 * looked up.
998 case OP_SETVAL:
999 break;
1001 case OP_STORE:
1002 generate_store(insn, state);
1003 break;
1005 case OP_LOAD:
1006 generate_load(insn, state);
1007 break;
1009 case OP_DEATHNOTE:
1010 mark_pseudo_dead(state, insn->target);
1011 return;
1013 case OP_ADD: case OP_MUL:
1014 case OP_AND: case OP_OR: case OP_XOR:
1015 case OP_AND_BOOL: case OP_OR_BOOL:
1016 generate_commutative_binop(state, insn);
1017 break;
1019 case OP_SUB: case OP_DIV: case OP_MOD:
1020 case OP_SHL: case OP_SHR:
1021 generate_binop(state, insn);
1022 break;
1024 case OP_BINCMP ... OP_BINCMP_END:
1025 generate_compare(state, insn);
1026 break;
1028 case OP_CAST: case OP_PTRCAST:
1029 generate_cast(state, insn);
1030 break;
1032 case OP_SEL:
1033 generate_select(state, insn);
1034 break;
1036 case OP_BR:
1037 generate_branch(state, insn);
1038 break;
1040 case OP_SWITCH:
1041 generate_switch(state, insn);
1042 break;
1044 case OP_CALL:
1045 generate_call(state, insn);
1046 break;
1048 case OP_RET:
1049 generate_ret(state, insn);
1050 break;
1052 case OP_ASM:
1053 generate_asm(state, insn);
1054 break;
1056 default:
1057 output_insn(state, "unimplemented: %s", show_instruction(insn));
1058 break;
1060 kill_dead_pseudos(state);
1063 #define VERY_BUSY 1000
1064 #define REG_FIXED 2000
1066 static void write_reg_to_storage(struct bb_state *state, struct hardreg *reg, pseudo_t pseudo, struct storage *storage)
1068 int i;
1069 struct hardreg *out;
1071 switch (storage->type) {
1072 case REG_REG:
1073 out = hardregs + storage->regno;
1074 if (reg == out)
1075 return;
1076 output_insn(state, "movl %s,%s", reg->name, out->name);
1077 return;
1078 case REG_UDEF:
1079 if (reg->busy < VERY_BUSY) {
1080 storage->type = REG_REG;
1081 storage->regno = reg - hardregs;
1082 reg->busy = REG_FIXED;
1083 return;
1086 /* Try to find a non-busy register.. */
1087 for (i = 0; i < REGNO; i++) {
1088 out = hardregs + i;
1089 if (out->busy)
1090 continue;
1091 output_insn(state, "movl %s,%s", reg->name, out->name);
1092 storage->type = REG_REG;
1093 storage->regno = i;
1094 reg->busy = REG_FIXED;
1095 return;
1098 /* Fall back on stack allocation ... */
1099 alloc_stack(state, storage);
1100 /* Fallthroigh */
1101 default:
1102 output_insn(state, "movl %s,%s", reg->name, show_memop(storage));
1103 return;
1107 static void write_val_to_storage(struct bb_state *state, pseudo_t src, struct storage *storage)
1109 struct hardreg *out;
1111 switch (storage->type) {
1112 case REG_UDEF:
1113 alloc_stack(state, storage);
1114 default:
1115 output_insn(state, "movl %s,%s", show_pseudo(src), show_memop(storage));
1116 break;
1117 case REG_REG:
1118 out = hardregs + storage->regno;
1119 output_insn(state, "movl %s,%s", show_pseudo(src), out->name);
1123 static void fill_output(struct bb_state *state, pseudo_t pseudo, struct storage *out)
1125 int i;
1126 struct storage_hash *in;
1127 struct instruction *def;
1129 /* Is that pseudo a constant value? */
1130 switch (pseudo->type) {
1131 case PSEUDO_VAL:
1132 write_val_to_storage(state, pseudo, out);
1133 return;
1134 case PSEUDO_REG:
1135 def = pseudo->def;
1136 if (def->opcode == OP_SETVAL) {
1137 write_val_to_storage(state, def->symbol, out);
1138 return;
1140 default:
1141 break;
1144 /* See if we have that pseudo in a register.. */
1145 for (i = 0; i < REGNO; i++) {
1146 struct hardreg *reg = hardregs + i;
1147 pseudo_t p;
1149 FOR_EACH_PTR(reg->contains, p) {
1150 if (p == pseudo) {
1151 write_reg_to_storage(state, reg, pseudo, out);
1152 return;
1154 } END_FOR_EACH_PTR(p);
1157 /* Do we have it in another storage? */
1158 in = find_storage_hash(pseudo, state->internal);
1159 if (!in) {
1160 in = find_storage_hash(pseudo, state->inputs);
1161 /* Undefined? */
1162 if (!in)
1163 return;
1165 switch (out->type) {
1166 case REG_UDEF:
1167 *out = *in->storage;
1168 break;
1169 case REG_REG:
1170 output_insn(state, "movl %s,%s", show_memop(in->storage), hardregs[out->regno].name);
1171 break;
1172 default:
1173 if (out == in->storage)
1174 break;
1175 if (out->type == in->storage->type == out->regno == in->storage->regno)
1176 break;
1177 output_insn(state, "movl %s,%s", show_memop(in->storage), show_memop(out));
1178 break;
1180 return;
1183 static int final_pseudo_flush(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
1185 struct storage_hash *hash;
1186 struct storage *out;
1187 struct hardreg *dst;
1190 * Since this pseudo is live at exit, we'd better have output
1191 * storage for it..
1193 hash = find_storage_hash(pseudo, state->outputs);
1194 if (!hash)
1195 return 1;
1196 out = hash->storage;
1198 /* If the output is in a register, try to get it there.. */
1199 if (out->type == REG_REG) {
1200 dst = hardregs + out->regno;
1202 * Two good cases: nobody is using the right register,
1203 * or we've already set it aside for output..
1205 if (!dst->busy || dst->busy > VERY_BUSY)
1206 goto copy_to_dst;
1208 /* Aiee. Try to keep it in a register.. */
1209 dst = empty_reg(state);
1210 if (dst)
1211 goto copy_to_dst;
1213 return 0;
1216 /* If the output is undefined, let's see if we can put it in a register.. */
1217 if (out->type == REG_UDEF) {
1218 dst = empty_reg(state);
1219 if (dst) {
1220 out->type = REG_REG;
1221 out->regno = dst - hardregs;
1222 goto copy_to_dst;
1224 /* Uhhuh. Not so good. No empty registers right now */
1225 return 0;
1228 /* If we know we need to flush it, just do so already .. */
1229 output_insn(state, "movl %s,%s", reg->name, show_memop(out));
1230 return 1;
1232 copy_to_dst:
1233 if (reg == dst)
1234 return 1;
1235 output_insn(state, "movl %s,%s", reg->name, dst->name);
1236 add_pseudo_reg(state, pseudo, dst);
1237 return 1;
1241 * This tries to make sure that we put all the pseudos that are
1242 * live on exit into the proper storage
1244 static void generate_output_storage(struct bb_state *state)
1246 struct storage_hash *entry;
1248 /* Go through the fixed outputs, making sure we have those regs free */
1249 FOR_EACH_PTR(state->outputs, entry) {
1250 struct storage *out = entry->storage;
1251 if (out->type == REG_REG) {
1252 struct hardreg *reg = hardregs + out->regno;
1253 pseudo_t p;
1254 int flushme = 0;
1256 reg->busy = REG_FIXED;
1257 FOR_EACH_PTR(reg->contains, p) {
1258 if (p == entry->pseudo) {
1259 flushme = -100;
1260 continue;
1262 if (CURRENT_TAG(p) & TAG_DEAD)
1263 continue;
1265 /* Try to write back the pseudo to where it should go ... */
1266 if (final_pseudo_flush(state, p, reg)) {
1267 DELETE_CURRENT_PTR(p);
1268 reg->busy--;
1269 continue;
1271 flushme++;
1272 } END_FOR_EACH_PTR(p);
1273 PACK_PTR_LIST(&reg->contains);
1274 if (flushme > 0)
1275 flush_reg(state, reg);
1277 } END_FOR_EACH_PTR(entry);
1279 FOR_EACH_PTR(state->outputs, entry) {
1280 fill_output(state, entry->pseudo, entry->storage);
1281 } END_FOR_EACH_PTR(entry);
1284 static void generate(struct basic_block *bb, struct bb_state *state)
1286 int i;
1287 struct storage_hash *entry;
1288 struct instruction *insn;
1290 for (i = 0; i < REGNO; i++) {
1291 free_ptr_list(&hardregs[i].contains);
1292 hardregs[i].busy = 0;
1293 hardregs[i].dead = 0;
1294 hardregs[i].used = 0;
1297 FOR_EACH_PTR(state->inputs, entry) {
1298 struct storage *storage = entry->storage;
1299 const char *name = show_storage(storage);
1300 output_comment(state, "incoming %s in %s", show_pseudo(entry->pseudo), name);
1301 if (storage->type == REG_REG) {
1302 int regno = storage->regno;
1303 add_pseudo_reg(state, entry->pseudo, hardregs + regno);
1304 name = hardregs[regno].name;
1306 } END_FOR_EACH_PTR(entry);
1308 output_label(state, ".L%p", bb);
1309 FOR_EACH_PTR(bb->insns, insn) {
1310 if (!insn->bb)
1311 continue;
1312 generate_one_insn(insn, state);
1313 } END_FOR_EACH_PTR(insn);
1315 if (verbose) {
1316 output_comment(state, "--- in ---");
1317 FOR_EACH_PTR(state->inputs, entry) {
1318 output_comment(state, "%s <- %s", show_pseudo(entry->pseudo), show_storage(entry->storage));
1319 } END_FOR_EACH_PTR(entry);
1320 output_comment(state, "--- spill ---");
1321 FOR_EACH_PTR(state->internal, entry) {
1322 output_comment(state, "%s <-> %s", show_pseudo(entry->pseudo), show_storage(entry->storage));
1323 } END_FOR_EACH_PTR(entry);
1324 output_comment(state, "--- out ---");
1325 FOR_EACH_PTR(state->outputs, entry) {
1326 output_comment(state, "%s -> %s", show_pseudo(entry->pseudo), show_storage(entry->storage));
1327 } END_FOR_EACH_PTR(entry);
1329 printf("\n");
1332 static void generate_list(struct basic_block_list *list, unsigned long generation)
1334 struct basic_block *bb;
1335 FOR_EACH_PTR(list, bb) {
1336 if (bb->generation == generation)
1337 continue;
1338 output_bb(bb, generation);
1339 } END_FOR_EACH_PTR(bb);
1342 static void output_bb(struct basic_block *bb, unsigned long generation)
1344 struct bb_state state;
1346 bb->generation = generation;
1348 /* Make sure all parents have been generated first */
1349 generate_list(bb->parents, generation);
1351 state.pos = bb->pos;
1352 state.inputs = gather_storage(bb, STOR_IN);
1353 state.outputs = gather_storage(bb, STOR_OUT);
1354 state.internal = NULL;
1355 state.stack_offset = 0;
1356 state.cc_opcode = 0;
1357 state.cc_target = NULL;
1359 generate(bb, &state);
1361 free_ptr_list(&state.inputs);
1362 free_ptr_list(&state.outputs);
1364 /* Generate all children... */
1365 generate_list(bb->children, generation);
1368 static void set_up_arch_entry(struct entrypoint *ep, struct instruction *entry)
1370 int i;
1371 pseudo_t arg;
1374 * We should set up argument sources here..
1376 * Things like "first three arguments in registers" etc
1377 * are all for this place.
1379 i = 0;
1380 FOR_EACH_PTR(entry->arg_list, arg) {
1381 struct storage *in = lookup_storage(entry->bb, arg, STOR_IN);
1382 if (!in) {
1383 in = alloc_storage();
1384 add_storage(in, entry->bb, arg, STOR_IN);
1386 if (i < 3) {
1387 in->type = REG_REG;
1388 in->regno = i;
1389 } else {
1390 in->type = REG_FRAME;
1391 in->offset = (i-3)*4;
1393 i++;
1394 } END_FOR_EACH_PTR(arg);
1398 * Set up storage information for "return"
1400 * Not strictly necessary, since the code generator will
1401 * certainly move the return value to the right register,
1402 * but it can help register allocation if the allocator
1403 * sees that the target register is going to return in %eax.
1405 static void set_up_arch_exit(struct basic_block *bb, struct instruction *ret)
1407 pseudo_t pseudo = ret->src;
1409 if (pseudo && pseudo != VOID) {
1410 struct storage *out = lookup_storage(bb, pseudo, STOR_OUT);
1411 if (!out) {
1412 out = alloc_storage();
1413 add_storage(out, bb, pseudo, STOR_OUT);
1415 out->type = REG_REG;
1416 out->regno = 0;
1421 * Set up dummy/silly output storage information for a switch
1422 * instruction. We need to make sure that a register is available
1423 * when we generate code for switch, so force that by creating
1424 * a dummy output rule.
1426 static void set_up_arch_switch(struct basic_block *bb, struct instruction *insn)
1428 pseudo_t pseudo = insn->cond;
1429 struct storage *out = lookup_storage(bb, pseudo, STOR_OUT);
1430 if (!out) {
1431 out = alloc_storage();
1432 add_storage(out, bb, pseudo, STOR_OUT);
1434 out->type = REG_REG;
1435 out->regno = SWITCH_REG;
1438 static void arch_set_up_storage(struct entrypoint *ep)
1440 struct basic_block *bb;
1442 /* Argument storage etc.. */
1443 set_up_arch_entry(ep, ep->entry);
1445 FOR_EACH_PTR(ep->bbs, bb) {
1446 struct instruction *insn = last_instruction(bb->insns);
1447 if (!insn)
1448 continue;
1449 switch (insn->opcode) {
1450 case OP_RET:
1451 set_up_arch_exit(bb, insn);
1452 break;
1453 case OP_SWITCH:
1454 set_up_arch_switch(bb, insn);
1455 break;
1456 default:
1457 /* nothing */;
1459 } END_FOR_EACH_PTR(bb);
1462 static void output(struct entrypoint *ep)
1464 unsigned long generation = ++bb_generation;
1466 last_reg = -1;
1468 /* Set up initial inter-bb storage links */
1469 set_up_storage(ep);
1471 /* Architecture-specific storage rules.. */
1472 arch_set_up_storage(ep);
1474 /* Show the results ... */
1475 output_bb(ep->entry->bb, generation);
1477 /* Clear the storage hashes for the next function.. */
1478 free_storage();
1481 static int compile(struct symbol_list *list)
1483 struct symbol *sym;
1484 FOR_EACH_PTR(list, sym) {
1485 struct entrypoint *ep;
1486 expand_symbol(sym);
1487 ep = linearize_symbol(sym);
1488 if (ep)
1489 output(ep);
1490 } END_FOR_EACH_PTR(sym);
1492 return 0;
1495 int main(int argc, char **argv)
1497 return compile(sparse(argc, argv));