Do some kind of signed cast too.
[smatch.git] / example.c
blobc13335fdd629aaf39df1a4aa7148804d650d5efa
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 struct hardreg {
16 const char *name;
17 struct pseudo_list *contains;
18 unsigned busy:16,
19 dead:8,
20 used:1;
23 #define TAG_DEAD 1
24 #define TAG_DIRTY 2
26 /* Our "switch" generation is very very stupid. */
27 #define SWITCH_REG (1)
29 static void output_bb(struct basic_block *bb, unsigned long generation);
32 * We only know about the caller-clobbered registers
33 * right now.
35 static struct hardreg hardregs[] = {
36 { .name = "%eax" },
37 { .name = "%edx" },
38 { .name = "%ecx" },
39 { .name = "%ebx" },
40 { .name = "%esi" },
41 { .name = "%edi" },
43 #define REGNO (sizeof(hardregs)/sizeof(struct hardreg))
45 struct bb_state {
46 struct basic_block *bb;
47 unsigned long stack_offset;
48 struct storage_hash_list *inputs;
49 struct storage_hash_list *outputs;
50 struct storage_hash_list *internal;
53 static struct storage_hash *find_storage_hash(pseudo_t pseudo, struct storage_hash_list *list)
55 struct storage_hash *entry;
56 FOR_EACH_PTR(list, entry) {
57 if (entry->pseudo == pseudo)
58 return entry;
59 } END_FOR_EACH_PTR(entry);
60 return NULL;
63 static struct storage_hash *find_or_create_hash(pseudo_t pseudo, struct storage_hash_list **listp)
65 struct storage_hash *entry;
67 entry = find_storage_hash(pseudo, *listp);
68 if (!entry) {
69 entry = alloc_storage_hash(alloc_storage());
70 entry->pseudo = pseudo;
71 add_ptr_list(listp, entry);
73 return entry;
76 /* Eventually we should just build it up in memory */
77 static void output_line(struct bb_state *state, const char *fmt, ...)
79 va_list args;
81 va_start(args, fmt);
82 vprintf(fmt, args);
83 va_end(args);
86 static void output_label(struct bb_state *state, const char *fmt, ...)
88 static char buffer[512];
89 va_list args;
91 va_start(args, fmt);
92 vsnprintf(buffer, sizeof(buffer), fmt, args);
93 va_end(args);
95 output_line(state, "%s:\n", buffer);
98 static void output_insn(struct bb_state *state, const char *fmt, ...)
100 static char buffer[512];
101 va_list args;
103 va_start(args, fmt);
104 vsnprintf(buffer, sizeof(buffer), fmt, args);
105 va_end(args);
107 output_line(state, "\t%s\n", buffer);
110 static void output_comment(struct bb_state *state, const char *fmt, ...)
112 static char buffer[512];
113 va_list args;
115 if (!verbose)
116 return;
117 va_start(args, fmt);
118 vsnprintf(buffer, sizeof(buffer), fmt, args);
119 va_end(args);
121 output_line(state, "\t# %s\n", buffer);
124 static const char *show_memop(struct storage *storage)
126 static char buffer[1000];
128 if (!storage)
129 return "undef";
130 switch (storage->type) {
131 case REG_FRAME:
132 sprintf(buffer, "%d(FP)", storage->offset);
133 break;
134 case REG_STACK:
135 sprintf(buffer, "%d(SP)", storage->offset);
136 break;
137 case REG_REG:
138 return hardregs[storage->regno].name;
139 default:
140 return show_storage(storage);
142 return buffer;
145 static void alloc_stack(struct bb_state *state, struct storage *storage)
147 storage->type = REG_STACK;
148 storage->offset = state->stack_offset;
149 state->stack_offset += 4;
153 * Can we re-generate the pseudo, so that we don't need to
154 * flush it to memory? We can regenerate:
155 * - immediates and symbol addresses
156 * - pseudos we got as input in non-registers
157 * - pseudos we've already saved off earlier..
159 static int can_regenerate(struct bb_state *state, pseudo_t pseudo)
161 struct storage_hash *in;
163 switch (pseudo->type) {
164 case PSEUDO_VAL:
165 case PSEUDO_SYM:
166 return 1;
168 default:
169 in = find_storage_hash(pseudo, state->inputs);
170 if (in && in->storage->type != REG_REG)
171 return 1;
172 in = find_storage_hash(pseudo, state->internal);
173 if (in)
174 return 1;
176 return 0;
179 static void flush_one_pseudo(struct bb_state *state, struct hardreg *hardreg, pseudo_t pseudo)
181 struct storage_hash *out;
182 struct storage *storage;
184 if (can_regenerate(state, pseudo))
185 return;
187 output_comment(state, "flushing %s from %s", show_pseudo(pseudo), hardreg->name);
188 out = find_storage_hash(pseudo, state->internal);
189 if (!out) {
190 out = find_storage_hash(pseudo, state->outputs);
191 if (!out)
192 out = find_or_create_hash(pseudo, &state->internal);
194 storage = out->storage;
195 switch (storage->type) {
196 default:
198 * Aieee - the next user wants it in a register, but we
199 * need to flush it to memory in between. Which means that
200 * we need to allocate an internal one, dammit..
202 out = find_or_create_hash(pseudo, &state->internal);
203 storage = out->storage;
204 /* Fall through */
205 case REG_UDEF:
206 alloc_stack(state, storage);
207 /* Fall through */
208 case REG_STACK:
209 output_insn(state, "movl %s,%s", hardreg->name, show_memop(storage));
210 break;
214 /* Flush a hardreg out to the storage it has.. */
215 static void flush_reg(struct bb_state *state, struct hardreg *hardreg)
217 pseudo_t pseudo;
219 if (!hardreg->busy)
220 return;
221 hardreg->busy = 0;
222 hardreg->dead = 0;
223 hardreg->used = 1;
224 FOR_EACH_PTR(hardreg->contains, pseudo) {
225 if (CURRENT_TAG(pseudo) & TAG_DEAD)
226 continue;
227 if (!(CURRENT_TAG(pseudo) & TAG_DIRTY))
228 continue;
229 flush_one_pseudo(state, hardreg, pseudo);
230 } END_FOR_EACH_PTR(pseudo);
231 free_ptr_list(&hardreg->contains);
234 static struct storage_hash *find_pseudo_storage(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
236 struct storage_hash *src;
238 src = find_storage_hash(pseudo, state->internal);
239 if (!src) {
240 src = find_storage_hash(pseudo, state->inputs);
241 if (!src) {
242 src = find_storage_hash(pseudo, state->outputs);
243 /* Undefined? Screw it! */
244 if (!src)
245 return NULL;
248 * If we found output storage, it had better be local stack
249 * that we flushed to earlier..
251 if (src->storage->type != REG_STACK)
252 return NULL;
257 * Incoming pseudo with out any pre-set storage allocation?
258 * We can make up our own, and obviously prefer to get it
259 * in the register we already selected (if it hasn't been
260 * used yet).
262 if (src->storage->type == REG_UDEF) {
263 if (reg && !reg->used) {
264 src->storage->type = REG_REG;
265 src->storage->regno = reg - hardregs;
266 } else
267 alloc_stack(state, src->storage);
269 return src;
272 static void mark_reg_dead(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
274 pseudo_t p;
276 FOR_EACH_PTR(reg->contains, p) {
277 if (p != pseudo)
278 continue;
279 if (CURRENT_TAG(p) & TAG_DEAD)
280 continue;
281 output_comment(state, "marking pseudo %s in reg %s dead", show_pseudo(pseudo), reg->name);
282 TAG_CURRENT(p, TAG_DEAD);
283 reg->dead++;
284 } END_FOR_EACH_PTR(p);
287 /* Fill a hardreg with the pseudo it has */
288 static struct hardreg *fill_reg(struct bb_state *state, struct hardreg *hardreg, pseudo_t pseudo)
290 struct storage_hash *src;
291 struct instruction *def;
293 switch (pseudo->type) {
294 case PSEUDO_VAL:
295 output_insn(state, "movl $%lld,%s", pseudo->value, hardreg->name);
296 break;
297 case PSEUDO_SYM:
298 output_insn(state, "movl $<%s>,%s", show_pseudo(pseudo), hardreg->name);
299 break;
300 case PSEUDO_ARG:
301 case PSEUDO_REG:
302 def = pseudo->def;
303 if (def->opcode == OP_SETVAL) {
304 output_insn(state, "movl $<%s>,%s", show_pseudo(def->symbol), hardreg->name);
305 break;
307 src = find_pseudo_storage(state, pseudo, hardreg);
308 if (!src)
309 break;
310 if (src->flags & TAG_DEAD)
311 mark_reg_dead(state, pseudo, hardreg);
312 output_insn(state, "mov.%d %s,%s", 32, show_memop(src->storage), hardreg->name);
313 break;
314 default:
315 output_insn(state, "reload %s from %s", hardreg->name, show_pseudo(pseudo));
316 break;
318 return hardreg;
321 static void add_pseudo_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
323 output_comment(state, "added pseudo %s to reg %s", show_pseudo(pseudo), reg->name);
324 add_ptr_list_tag(&reg->contains, pseudo, TAG_DIRTY);
325 reg->busy++;
328 static int last_reg;
330 static struct hardreg *preferred_reg(struct bb_state *state, pseudo_t target)
332 struct storage_hash *dst;
334 dst = find_storage_hash(target, state->outputs);
335 if (dst) {
336 struct storage *storage = dst->storage;
337 if (storage->type == REG_REG)
338 return hardregs + storage->regno;
340 return NULL;
343 static struct hardreg *empty_reg(struct bb_state *state)
345 int i;
346 struct hardreg *reg = hardregs;
348 for (i = 0; i < REGNO; i++, reg++) {
349 if (!reg->busy)
350 return reg;
352 return NULL;
355 static struct hardreg *target_reg(struct bb_state *state, pseudo_t pseudo, pseudo_t target)
357 int i;
358 struct hardreg *reg;
360 /* First, see if we have a preferred target register.. */
361 reg = preferred_reg(state, target);
362 if (reg && !reg->busy)
363 goto found;
365 reg = empty_reg(state);
366 if (reg)
367 goto found;
369 i = last_reg+1;
370 if (i >= REGNO)
371 i = 0;
372 last_reg = i;
373 reg = hardregs + i;
374 flush_reg(state, reg);
376 found:
377 add_pseudo_reg(state, pseudo, reg);
378 return reg;
381 static struct hardreg *find_in_reg(struct bb_state *state, pseudo_t pseudo)
383 int i;
384 struct hardreg *reg;
386 for (i = 0; i < REGNO; i++) {
387 pseudo_t p;
389 reg = hardregs + i;
390 FOR_EACH_PTR(reg->contains, p) {
391 if (p == pseudo) {
392 last_reg = i;
393 output_comment(state, "found pseudo %s in reg %s", show_pseudo(pseudo), reg->name);
394 return reg;
396 } END_FOR_EACH_PTR(p);
398 return NULL;
401 static struct hardreg *getreg(struct bb_state *state, pseudo_t pseudo, pseudo_t target)
403 struct hardreg *reg;
405 reg = find_in_reg(state, pseudo);
406 if (reg)
407 return reg;
408 reg = target_reg(state, pseudo, target);
409 return fill_reg(state, reg, pseudo);
412 static struct hardreg *copy_reg(struct bb_state *state, struct hardreg *src, pseudo_t target)
414 int i;
415 struct hardreg *reg;
417 if (!src->busy)
418 return src;
420 reg = preferred_reg(state, target);
421 if (reg && !reg->busy) {
422 output_comment(state, "copying %s to preferred target %s", show_pseudo(target), reg->name);
423 output_insn(state, "movl %s,%s", src->name, reg->name);
424 return reg;
427 for (i = 0; i < REGNO; i++) {
428 struct hardreg *reg = hardregs + i;
429 if (!reg->busy) {
430 output_comment(state, "copying %s to %s", show_pseudo(target), reg->name);
431 output_insn(state, "movl %s,%s", src->name, reg->name);
432 return reg;
436 flush_reg(state, src);
437 return src;
440 static const char *generic(struct bb_state *state, pseudo_t pseudo)
442 struct hardreg *reg;
443 struct storage_hash *src;
445 switch (pseudo->type) {
446 case PSEUDO_SYM:
447 case PSEUDO_VAL:
448 return show_pseudo(pseudo);
449 default:
450 reg = find_in_reg(state, pseudo);
451 if (reg)
452 return reg->name;
453 src = find_pseudo_storage(state, pseudo, NULL);
454 if (!src)
455 return "undef";
456 return show_memop(src->storage);
460 static const char *address(struct bb_state *state, struct instruction *memop)
462 struct symbol *sym;
463 struct hardreg *base;
464 static char buffer[100];
465 pseudo_t addr = memop->src;
467 switch(addr->type) {
468 case PSEUDO_SYM:
469 sym = addr->sym;
470 if (sym->ctype.modifiers & MOD_NONLOCAL) {
471 sprintf(buffer, "%s+%d", show_ident(sym->ident), memop->offset);
472 return buffer;
474 sprintf(buffer, "%d+%s(SP)", memop->offset, show_ident(sym->ident));
475 return buffer;
476 default:
477 base = getreg(state, addr, NULL);
478 sprintf(buffer, "%d(%s)", memop->offset, base->name);
479 return buffer;
483 static const char *reg_or_imm(struct bb_state *state, pseudo_t pseudo)
485 switch(pseudo->type) {
486 case PSEUDO_VAL:
487 return show_pseudo(pseudo);
488 default:
489 return getreg(state, pseudo, NULL)->name;
493 static const char* opcodes[] = {
494 [OP_BADOP] = "bad_op",
496 /* Fn entrypoint */
497 [OP_ENTRY] = "<entry-point>",
499 /* Terminator */
500 [OP_RET] = "ret",
501 [OP_BR] = "br",
502 [OP_SWITCH] = "switch",
503 [OP_INVOKE] = "invoke",
504 [OP_COMPUTEDGOTO] = "jmp *",
505 [OP_UNWIND] = "unwind",
507 /* Binary */
508 [OP_ADD] = "add",
509 [OP_SUB] = "sub",
510 [OP_MUL] = "mul",
511 [OP_DIV] = "div",
512 [OP_MOD] = "mod",
513 [OP_SHL] = "shl",
514 [OP_SHR] = "shr",
516 /* Logical */
517 [OP_AND] = "and",
518 [OP_OR] = "or",
519 [OP_XOR] = "xor",
520 [OP_AND_BOOL] = "and-bool",
521 [OP_OR_BOOL] = "or-bool",
523 /* Binary comparison */
524 [OP_SET_EQ] = "seteq",
525 [OP_SET_NE] = "setne",
526 [OP_SET_LE] = "setle",
527 [OP_SET_GE] = "setge",
528 [OP_SET_LT] = "setlt",
529 [OP_SET_GT] = "setgt",
530 [OP_SET_B] = "setb",
531 [OP_SET_A] = "seta",
532 [OP_SET_BE] = "setbe",
533 [OP_SET_AE] = "setae",
535 /* Uni */
536 [OP_NOT] = "not",
537 [OP_NEG] = "neg",
539 /* Special three-input */
540 [OP_SEL] = "select",
542 /* Memory */
543 [OP_MALLOC] = "malloc",
544 [OP_FREE] = "free",
545 [OP_ALLOCA] = "alloca",
546 [OP_LOAD] = "load",
547 [OP_STORE] = "store",
548 [OP_SETVAL] = "set",
549 [OP_GET_ELEMENT_PTR] = "getelem",
551 /* Other */
552 [OP_PHI] = "phi",
553 [OP_PHISOURCE] = "phisrc",
554 [OP_CAST] = "cast",
555 [OP_PTRCAST] = "ptrcast",
556 [OP_CALL] = "call",
557 [OP_VANEXT] = "va_next",
558 [OP_VAARG] = "va_arg",
559 [OP_SLICE] = "slice",
560 [OP_SNOP] = "snop",
561 [OP_LNOP] = "lnop",
562 [OP_NOP] = "nop",
563 [OP_DEATHNOTE] = "dead",
564 [OP_ASM] = "asm",
566 /* Sparse tagging (line numbers, context, whatever) */
567 [OP_CONTEXT] = "context",
570 static void kill_dead_reg(struct hardreg *reg)
572 if (reg->dead) {
573 pseudo_t p;
575 FOR_EACH_PTR(reg->contains, p) {
576 if (CURRENT_TAG(p) & TAG_DEAD) {
577 DELETE_CURRENT_PTR(p);
578 reg->busy--;
579 reg->dead--;
581 } END_FOR_EACH_PTR(p);
582 PACK_PTR_LIST(&reg->contains);
583 assert(!reg->dead);
587 static struct hardreg *target_copy_reg(struct bb_state *state, struct hardreg *src, pseudo_t target)
589 kill_dead_reg(src);
590 return copy_reg(state, src, target);
593 static void do_binop(struct bb_state *state, struct instruction *insn, pseudo_t val1, pseudo_t val2)
595 const char *op = opcodes[insn->opcode];
596 struct hardreg *src = getreg(state, val1, insn->target);
597 const char *src2 = generic(state, val2);
598 struct hardreg *dst;
600 dst = target_copy_reg(state, src, insn->target);
601 output_insn(state, "%s.%d %s,%s", op, insn->size, src2, dst->name);
602 add_pseudo_reg(state, insn->target, dst);
605 static void generate_binop(struct bb_state *state, struct instruction *insn)
607 do_binop(state, insn, insn->src1, insn->src2);
610 static int is_dead_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
612 pseudo_t p;
613 FOR_EACH_PTR(reg->contains, p) {
614 if (p == pseudo)
615 return CURRENT_TAG(p) & TAG_DEAD;
616 } END_FOR_EACH_PTR(p);
617 return 0;
621 * Commutative binops are much more flexible, since we can switch the
622 * sources around to satisfy the target register, or to avoid having
623 * to load one of them into a register..
625 static void generate_commutative_binop(struct bb_state *state, struct instruction *insn)
627 pseudo_t src1 = insn->src1, src2 = insn->src2;
628 struct hardreg *reg1, *reg2 = find_in_reg(state, src2);
630 if (!reg2)
631 goto dont_switch;
632 reg1 = find_in_reg(state, src1);
633 if (!reg1)
634 goto do_switch;
635 if (!is_dead_reg(state, src2, reg2))
636 goto dont_switch;
637 if (!is_dead_reg(state, src1, reg1))
638 goto do_switch;
640 /* Both are dead. Is one preferrable? */
641 if (reg2 != preferred_reg(state, insn->target))
642 goto dont_switch;
644 do_switch:
645 src1 = src2;
646 src2 = insn->src1;
647 dont_switch:
648 do_binop(state, insn, src1, src2);
652 * This marks a pseudo dead. It still stays on the hardreg list (the hardreg
653 * still has its value), but it's scheduled to be killed after the next
654 * "sequence point" when we call "kill_read_pseudos()"
656 static void mark_pseudo_dead(struct bb_state *state, pseudo_t pseudo)
658 int i;
659 struct storage_hash *src;
661 src = find_pseudo_storage(state, pseudo, NULL);
662 if (src)
663 src->flags |= TAG_DEAD;
664 for (i = 0; i < REGNO; i++)
665 mark_reg_dead(state, pseudo, hardregs + i);
668 static void kill_dead_pseudos(struct bb_state *state)
670 int i;
672 for (i = 0; i < REGNO; i++) {
673 kill_dead_reg(hardregs + i);
678 * A PHI source can define a pseudo that we already
679 * have in another register. We need to invalidate the
680 * old register so that we don't end up with the same
681 * pseudo in "two places".
683 static void remove_pseudo_reg(struct bb_state *state, pseudo_t pseudo)
685 int i;
687 output_comment(state, "pseudo %s died", show_pseudo(pseudo));
688 for (i = 0; i < REGNO; i++) {
689 struct hardreg *reg = hardregs + i;
690 pseudo_t p;
691 FOR_EACH_PTR(reg->contains, p) {
692 if (p != pseudo)
693 continue;
694 if (CURRENT_TAG(p) & TAG_DEAD)
695 reg->dead--;
696 reg->busy--;
697 DELETE_CURRENT_PTR(p);
698 output_comment(state, "removed pseudo %s from reg %s", show_pseudo(pseudo), reg->name);
699 } END_FOR_EACH_PTR(p);
700 PACK_PTR_LIST(&reg->contains);
704 static void generate_store(struct instruction *insn, struct bb_state *state)
706 output_insn(state, "mov.%d %s,%s", insn->size, reg_or_imm(state, insn->target), address(state, insn));
709 static void generate_load(struct instruction *insn, struct bb_state *state)
711 const char *input = address(state, insn);
712 struct hardreg *dst;
714 kill_dead_pseudos(state);
715 dst = target_reg(state, insn->target, NULL);
716 output_insn(state, "mov.%d %s,%s", insn->size, input, dst->name);
719 static void generate_phisource(struct instruction *insn, struct bb_state *state)
721 struct instruction *user;
722 struct hardreg *reg;
724 /* Mark all the target pseudos dead first */
725 FOR_EACH_PTR(insn->phi_users, user) {
726 mark_pseudo_dead(state, user->target);
727 } END_FOR_EACH_PTR(user);
729 reg = NULL;
730 FOR_EACH_PTR(insn->phi_users, user) {
731 if (!reg)
732 reg = getreg(state, insn->phi_src, user->target);
733 remove_pseudo_reg(state, user->target);
734 add_pseudo_reg(state, user->target, reg);
735 } END_FOR_EACH_PTR(user);
738 static void generate_cast(struct bb_state *state, struct instruction *insn)
740 struct hardreg *src = getreg(state, insn->src, insn->target);
741 struct hardreg *dst;
742 unsigned int old = insn->orig_type ? insn->orig_type->bit_size : 0;
743 unsigned int new = insn->size;
746 * Cast to smaller type? Ignore the high bits, we
747 * just keep both pseudos in the same register.
749 if (old >= new) {
750 add_pseudo_reg(state, insn->target, src);
751 return;
754 dst = target_copy_reg(state, src, insn->target);
756 if (insn->orig_type && (insn->orig_type->ctype.modifiers & MOD_SIGNED)) {
757 output_insn(state, "sext.%d.%d %s", old, new, dst->name);
758 } else {
759 unsigned long long mask;
760 mask = ~(~0ULL << old);
761 mask &= ~(~0ULL << new);
762 output_insn(state, "andl.%d $%#llx,%s", insn->size, mask, dst->name);
764 add_pseudo_reg(state, insn->target, dst);
767 static void generate_output_storage(struct bb_state *state);
769 static void generate_branch(struct bb_state *state, struct instruction *br)
771 if (br->cond) {
772 struct hardreg *reg = getreg(state, br->cond, NULL);
773 output_insn(state, "testl %s,%s", reg->name, reg->name);
775 generate_output_storage(state);
776 if (br->cond)
777 output_insn(state, "je .L%p", br->bb_false);
778 output_insn(state, "jmp .L%p", br->bb_true);
781 /* We've made sure that there is a dummy reg live for the output */
782 static void generate_switch(struct bb_state *state, struct instruction *insn)
784 struct hardreg *reg = hardregs + SWITCH_REG;
786 generate_output_storage(state);
787 output_insn(state, "switch on %s", reg->name);
788 output_insn(state, "unimplemented: %s", show_instruction(insn));
791 static void generate_ret(struct bb_state *state, struct instruction *ret)
793 if (ret->src && ret->src != VOID) {
794 struct hardreg *wants = hardregs+0;
795 struct hardreg *reg = getreg(state, ret->src, NULL);
796 if (reg != wants)
797 output_insn(state, "movl %s,%s", reg->name, wants->name);
799 output_insn(state, "ret");
803 * Fake "call" linearization just as a taster..
805 static void generate_call(struct bb_state *state, struct instruction *insn)
807 int offset = 0;
808 pseudo_t arg;
810 FOR_EACH_PTR(insn->arguments, arg) {
811 output_insn(state, "pushl %s", generic(state, arg));
812 offset += 4;
813 } END_FOR_EACH_PTR(arg);
814 flush_reg(state, hardregs+0);
815 flush_reg(state, hardregs+1);
816 flush_reg(state, hardregs+2);
817 output_insn(state, "call %s", show_pseudo(insn->func));
818 if (offset)
819 output_insn(state, "addl $%d,%%esp", offset);
820 add_pseudo_reg(state, insn->target, hardregs+0);
823 static void generate_select(struct bb_state *state, struct instruction *insn)
825 struct hardreg *src1, *src2, *cond, *dst;
827 cond = getreg(state, insn->src1, NULL);
828 output_insn(state, "testl %s,%s", cond->name, cond->name);
830 src1 = getreg(state, insn->src2, NULL);
831 dst = copy_reg(state, src1, insn->target);
832 add_pseudo_reg(state, insn->target, dst);
833 src2 = getreg(state, insn->src3, insn->target);
834 output_insn(state, "sele %s,%s", src2->name, dst->name);
837 static void generate_one_insn(struct instruction *insn, struct bb_state *state)
839 if (verbose)
840 output_comment(state, "%s", show_instruction(insn));
842 switch (insn->opcode) {
843 case OP_ENTRY: {
844 struct symbol *sym = insn->bb->ep->name;
845 const char *name = show_ident(sym->ident);
846 if (sym->ctype.modifiers & MOD_STATIC)
847 printf("\n\n%s:\n", name);
848 else
849 printf("\n\n.globl %s\n%s:\n", name, name);
850 break;
854 * OP_PHI doesn't actually generate any code. It has been
855 * done by the storage allocator and the OP_PHISOURCE.
857 case OP_PHI:
858 break;
860 case OP_PHISOURCE:
861 generate_phisource(insn, state);
862 break;
865 * OP_SETVAL likewise doesn't actually generate any
866 * code. On use, the "def" of the pseudo will be
867 * looked up.
869 case OP_SETVAL:
870 break;
872 case OP_STORE:
873 generate_store(insn, state);
874 break;
876 case OP_LOAD:
877 generate_load(insn, state);
878 break;
880 case OP_DEATHNOTE:
881 mark_pseudo_dead(state, insn->target);
882 return;
884 case OP_ADD: case OP_MUL:
885 case OP_AND: case OP_OR: case OP_XOR:
886 case OP_AND_BOOL: case OP_OR_BOOL:
887 case OP_SET_EQ: case OP_SET_NE:
888 generate_commutative_binop(state, insn);
889 break;
891 case OP_SUB: case OP_DIV: case OP_MOD:
892 case OP_SHL: case OP_SHR:
893 case OP_SET_LE: case OP_SET_GE:
894 case OP_SET_LT: case OP_SET_GT:
895 case OP_SET_B: case OP_SET_A:
896 case OP_SET_BE: case OP_SET_AE:
897 generate_binop(state, insn);
898 break;
900 case OP_CAST: case OP_PTRCAST:
901 generate_cast(state, insn);
902 break;
904 case OP_SEL:
905 generate_select(state, insn);
906 break;
908 case OP_BR:
909 generate_branch(state, insn);
910 break;
912 case OP_SWITCH:
913 generate_switch(state, insn);
914 break;
916 case OP_CALL:
917 generate_call(state, insn);
918 break;
920 case OP_RET:
921 generate_ret(state, insn);
922 break;
924 default:
925 output_insn(state, "unimplemented: %s", show_instruction(insn));
926 break;
928 kill_dead_pseudos(state);
931 #define VERY_BUSY 1000
932 #define REG_FIXED 2000
934 static void write_reg_to_storage(struct bb_state *state, struct hardreg *reg, pseudo_t pseudo, struct storage *storage)
936 int i;
937 struct hardreg *out;
939 switch (storage->type) {
940 case REG_REG:
941 out = hardregs + storage->regno;
942 if (reg == out)
943 return;
944 output_insn(state, "movl %s,%s", reg->name, out->name);
945 return;
946 case REG_UDEF:
947 if (reg->busy < VERY_BUSY) {
948 storage->type = REG_REG;
949 storage->regno = reg - hardregs;
950 reg->busy = REG_FIXED;
951 return;
954 /* Try to find a non-busy register.. */
955 for (i = 0; i < REGNO; i++) {
956 out = hardregs + i;
957 if (out->busy)
958 continue;
959 output_insn(state, "movl %s,%s", reg->name, out->name);
960 storage->type = REG_REG;
961 storage->regno = i;
962 reg->busy = REG_FIXED;
963 return;
966 /* Fall back on stack allocation ... */
967 alloc_stack(state, storage);
968 /* Fallthroigh */
969 default:
970 output_insn(state, "movl %s,%s", reg->name, show_memop(storage));
971 return;
975 static void write_val_to_storage(struct bb_state *state, pseudo_t src, struct storage *storage)
977 struct hardreg *out;
979 switch (storage->type) {
980 case REG_UDEF:
981 alloc_stack(state, storage);
982 default:
983 output_insn(state, "movl %s,%s", show_pseudo(src), show_memop(storage));
984 break;
985 case REG_REG:
986 out = hardregs + storage->regno;
987 output_insn(state, "movl %s,%s", show_pseudo(src), out->name);
991 static void fill_output(struct bb_state *state, pseudo_t pseudo, struct storage *out)
993 int i;
994 struct storage_hash *in;
995 struct instruction *def;
997 /* Is that pseudo a constant value? */
998 switch (pseudo->type) {
999 case PSEUDO_VAL:
1000 write_val_to_storage(state, pseudo, out);
1001 return;
1002 case PSEUDO_REG:
1003 def = pseudo->def;
1004 if (def->opcode == OP_SETVAL) {
1005 write_val_to_storage(state, def->symbol, out);
1006 return;
1008 default:
1009 break;
1012 /* See if we have that pseudo in a register.. */
1013 for (i = 0; i < REGNO; i++) {
1014 struct hardreg *reg = hardregs + i;
1015 pseudo_t p;
1017 FOR_EACH_PTR(reg->contains, p) {
1018 if (p == pseudo) {
1019 write_reg_to_storage(state, reg, pseudo, out);
1020 return;
1022 } END_FOR_EACH_PTR(p);
1025 /* Do we have it in another storage? */
1026 in = find_storage_hash(pseudo, state->internal);
1027 if (!in) {
1028 in = find_storage_hash(pseudo, state->inputs);
1029 /* Undefined? */
1030 if (!in)
1031 return;
1033 switch (out->type) {
1034 case REG_UDEF:
1035 *out = *in->storage;
1036 break;
1037 case REG_REG:
1038 output_insn(state, "movl %s,%s", show_memop(in->storage), hardregs[out->regno].name);
1039 break;
1040 default:
1041 if (out == in->storage)
1042 break;
1043 if (out->type == in->storage->type == out->regno == in->storage->regno)
1044 break;
1045 output_insn(state, "movl %s,%s", show_memop(in->storage), show_memop(out));
1046 break;
1048 return;
1051 static int final_pseudo_flush(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
1053 struct storage_hash *hash;
1054 struct storage *out;
1055 struct hardreg *dst;
1058 * Since this pseudo is live at exit, we'd better have output
1059 * storage for it..
1061 hash = find_storage_hash(pseudo, state->outputs);
1062 if (!hash)
1063 return 1;
1064 out = hash->storage;
1066 /* If the output is in a register, try to get it there.. */
1067 if (out->type == REG_REG) {
1068 dst = hardregs + out->regno;
1070 * Two good cases: nobody is using the right register,
1071 * or we've already set it aside for output..
1073 if (!dst->busy || dst->busy > VERY_BUSY)
1074 goto copy_to_dst;
1076 /* Aiee. Try to keep it in a register.. */
1077 dst = empty_reg(state);
1078 if (dst)
1079 goto copy_to_dst;
1081 return 0;
1084 /* If the output is undefined, let's see if we can put it in a register.. */
1085 if (out->type == REG_UDEF) {
1086 dst = empty_reg(state);
1087 if (dst) {
1088 out->type = REG_REG;
1089 out->regno = dst - hardregs;
1090 goto copy_to_dst;
1092 /* Uhhuh. Not so good. No empty registers right now */
1093 return 0;
1096 /* If we know we need to flush it, just do so already .. */
1097 output_insn(state, "movl %s,%s", reg->name, show_memop(out));
1098 return 1;
1100 copy_to_dst:
1101 if (reg == dst)
1102 return 1;
1103 output_insn(state, "movl %s,%s", reg->name, dst->name);
1104 add_pseudo_reg(state, pseudo, dst);
1105 return 1;
1109 * This tries to make sure that we put all the pseudos that are
1110 * live on exit into the proper storage
1112 static void generate_output_storage(struct bb_state *state)
1114 struct storage_hash *entry;
1116 /* Go through the fixed outputs, making sure we have those regs free */
1117 FOR_EACH_PTR(state->outputs, entry) {
1118 struct storage *out = entry->storage;
1119 if (out->type == REG_REG) {
1120 struct hardreg *reg = hardregs + out->regno;
1121 pseudo_t p;
1122 int flushme = 0;
1124 reg->busy = REG_FIXED;
1125 FOR_EACH_PTR(reg->contains, p) {
1126 if (p == entry->pseudo) {
1127 flushme = -100;
1128 continue;
1130 if (CURRENT_TAG(p) & TAG_DEAD)
1131 continue;
1133 /* Try to write back the pseudo to where it should go ... */
1134 if (final_pseudo_flush(state, p, reg)) {
1135 DELETE_CURRENT_PTR(p);
1136 reg->busy--;
1137 continue;
1139 flushme++;
1140 } END_FOR_EACH_PTR(p);
1141 PACK_PTR_LIST(&reg->contains);
1142 if (flushme > 0)
1143 flush_reg(state, reg);
1145 } END_FOR_EACH_PTR(entry);
1147 FOR_EACH_PTR(state->outputs, entry) {
1148 fill_output(state, entry->pseudo, entry->storage);
1149 } END_FOR_EACH_PTR(entry);
1152 static void generate(struct basic_block *bb, struct bb_state *state)
1154 int i;
1155 struct storage_hash *entry;
1156 struct instruction *insn;
1158 for (i = 0; i < REGNO; i++) {
1159 free_ptr_list(&hardregs[i].contains);
1160 hardregs[i].busy = 0;
1161 hardregs[i].dead = 0;
1162 hardregs[i].used = 0;
1165 FOR_EACH_PTR(state->inputs, entry) {
1166 struct storage *storage = entry->storage;
1167 const char *name = show_storage(storage);
1168 output_comment(state, "incoming %s in %s", show_pseudo(entry->pseudo), name);
1169 if (storage->type == REG_REG) {
1170 int regno = storage->regno;
1171 add_pseudo_reg(state, entry->pseudo, hardregs + regno);
1172 name = hardregs[regno].name;
1174 } END_FOR_EACH_PTR(entry);
1176 output_label(state, ".L%p", bb);
1177 FOR_EACH_PTR(bb->insns, insn) {
1178 if (!insn->bb)
1179 continue;
1180 generate_one_insn(insn, state);
1181 } END_FOR_EACH_PTR(insn);
1183 if (verbose) {
1184 output_comment(state, "--- in ---");
1185 FOR_EACH_PTR(state->inputs, entry) {
1186 output_comment(state, "%s <- %s", show_pseudo(entry->pseudo), show_storage(entry->storage));
1187 } END_FOR_EACH_PTR(entry);
1188 output_comment(state, "--- spill ---");
1189 FOR_EACH_PTR(state->internal, entry) {
1190 output_comment(state, "%s <-> %s", show_pseudo(entry->pseudo), show_storage(entry->storage));
1191 } END_FOR_EACH_PTR(entry);
1192 output_comment(state, "--- out ---");
1193 FOR_EACH_PTR(state->outputs, entry) {
1194 output_comment(state, "%s -> %s", show_pseudo(entry->pseudo), show_storage(entry->storage));
1195 } END_FOR_EACH_PTR(entry);
1197 printf("\n");
1200 static void generate_list(struct basic_block_list *list, unsigned long generation)
1202 struct basic_block *bb;
1203 FOR_EACH_PTR(list, bb) {
1204 if (bb->generation == generation)
1205 continue;
1206 output_bb(bb, generation);
1207 } END_FOR_EACH_PTR(bb);
1210 static void output_bb(struct basic_block *bb, unsigned long generation)
1212 struct bb_state state;
1214 bb->generation = generation;
1216 /* Make sure all parents have been generated first */
1217 generate_list(bb->parents, generation);
1219 state.inputs = gather_storage(bb, STOR_IN);
1220 state.outputs = gather_storage(bb, STOR_OUT);
1221 state.internal = NULL;
1222 state.stack_offset = 0;
1224 generate(bb, &state);
1226 free_ptr_list(&state.inputs);
1227 free_ptr_list(&state.outputs);
1229 /* Generate all children... */
1230 generate_list(bb->children, generation);
1233 static void set_up_arch_entry(struct entrypoint *ep, struct instruction *entry)
1235 int i;
1236 pseudo_t arg;
1239 * We should set up argument sources here..
1241 * Things like "first three arguments in registers" etc
1242 * are all for this place.
1244 i = 0;
1245 FOR_EACH_PTR(entry->arg_list, arg) {
1246 struct storage *in = lookup_storage(entry->bb, arg, STOR_IN);
1247 if (!in) {
1248 in = alloc_storage();
1249 add_storage(in, entry->bb, arg, STOR_IN);
1251 if (i < 3) {
1252 in->type = REG_REG;
1253 in->regno = i;
1254 } else {
1255 in->type = REG_FRAME;
1256 in->offset = (i-3)*4;
1258 i++;
1259 } END_FOR_EACH_PTR(arg);
1263 * Set up storage information for "return"
1265 * Not strictly necessary, since the code generator will
1266 * certainly move the return value to the right register,
1267 * but it can help register allocation if the allocator
1268 * sees that the target register is going to return in %eax.
1270 static void set_up_arch_exit(struct basic_block *bb, struct instruction *ret)
1272 pseudo_t pseudo = ret->src;
1274 if (pseudo && pseudo != VOID) {
1275 struct storage *out = lookup_storage(bb, pseudo, STOR_OUT);
1276 if (!out) {
1277 out = alloc_storage();
1278 add_storage(out, bb, pseudo, STOR_OUT);
1280 out->type = REG_REG;
1281 out->regno = 0;
1286 * Set up dummy/silly output storage information for a switch
1287 * instruction. We need to make sure that a register is available
1288 * when we generate code for switch, so force that by creating
1289 * a dummy output rule.
1291 static void set_up_arch_switch(struct basic_block *bb, struct instruction *insn)
1293 pseudo_t pseudo = insn->cond;
1294 struct storage *out = lookup_storage(bb, pseudo, STOR_OUT);
1295 if (!out) {
1296 out = alloc_storage();
1297 add_storage(out, bb, pseudo, STOR_OUT);
1299 out->type = REG_REG;
1300 out->regno = SWITCH_REG;
1303 static void arch_set_up_storage(struct entrypoint *ep)
1305 struct basic_block *bb;
1307 /* Argument storage etc.. */
1308 set_up_arch_entry(ep, ep->entry);
1310 FOR_EACH_PTR(ep->bbs, bb) {
1311 struct instruction *insn = last_instruction(bb->insns);
1312 if (!insn)
1313 continue;
1314 switch (insn->opcode) {
1315 case OP_RET:
1316 set_up_arch_exit(bb, insn);
1317 break;
1318 case OP_SWITCH:
1319 set_up_arch_switch(bb, insn);
1320 break;
1321 default:
1322 /* nothing */;
1324 } END_FOR_EACH_PTR(bb);
1327 static void output(struct entrypoint *ep)
1329 unsigned long generation = ++bb_generation;
1331 last_reg = -1;
1333 /* Set up initial inter-bb storage links */
1334 set_up_storage(ep);
1336 /* Architecture-specific storage rules.. */
1337 arch_set_up_storage(ep);
1339 /* Show the results ... */
1340 output_bb(ep->entry->bb, generation);
1342 /* Clear the storage hashes for the next function.. */
1343 free_storage();
1346 static int compile(struct symbol_list *list)
1348 struct symbol *sym;
1349 FOR_EACH_PTR(list, sym) {
1350 struct entrypoint *ep;
1351 expand_symbol(sym);
1352 ep = linearize_symbol(sym);
1353 if (ep)
1354 output(ep);
1355 } END_FOR_EACH_PTR(sym);
1357 return 0;
1360 int main(int argc, char **argv)
1362 return compile(sparse(argc, argv));