modified smatch to catch msync and similar funcs
[smatch.git] / example.c
blob691e0f97cb4328812fd8f93d57538815ddd0d1b2
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 <string.h>
8 #include <assert.h>
10 #include "symbol.h"
11 #include "expression.h"
12 #include "linearize.h"
13 #include "flow.h"
14 #include "storage.h"
15 #include "target.h"
17 static const char *opcodes[] = {
18 [OP_BADOP] = "bad_op",
20 /* Fn entrypoint */
21 [OP_ENTRY] = "<entry-point>",
23 /* Terminator */
24 [OP_RET] = "ret",
25 [OP_BR] = "br",
26 [OP_CBR] = "cbr",
27 [OP_SWITCH] = "switch",
28 [OP_INVOKE] = "invoke",
29 [OP_COMPUTEDGOTO] = "jmp *",
30 [OP_UNWIND] = "unwind",
32 /* Binary */
33 [OP_ADD] = "add",
34 [OP_SUB] = "sub",
35 [OP_MULU] = "mulu",
36 [OP_MULS] = "muls",
37 [OP_DIVU] = "divu",
38 [OP_DIVS] = "divs",
39 [OP_MODU] = "modu",
40 [OP_MODS] = "mods",
41 [OP_SHL] = "shl",
42 [OP_LSR] = "lsr",
43 [OP_ASR] = "asr",
45 /* Logical */
46 [OP_AND] = "and",
47 [OP_OR] = "or",
48 [OP_XOR] = "xor",
49 [OP_AND_BOOL] = "and-bool",
50 [OP_OR_BOOL] = "or-bool",
52 /* Binary comparison */
53 [OP_SET_EQ] = "seteq",
54 [OP_SET_NE] = "setne",
55 [OP_SET_LE] = "setle",
56 [OP_SET_GE] = "setge",
57 [OP_SET_LT] = "setlt",
58 [OP_SET_GT] = "setgt",
59 [OP_SET_B] = "setb",
60 [OP_SET_A] = "seta",
61 [OP_SET_BE] = "setbe",
62 [OP_SET_AE] = "setae",
64 /* Uni */
65 [OP_NOT] = "not",
66 [OP_NEG] = "neg",
68 /* Special three-input */
69 [OP_SEL] = "select",
71 /* Memory */
72 [OP_MALLOC] = "malloc",
73 [OP_FREE] = "free",
74 [OP_ALLOCA] = "alloca",
75 [OP_LOAD] = "load",
76 [OP_STORE] = "store",
77 [OP_SETVAL] = "set",
78 [OP_GET_ELEMENT_PTR] = "getelem",
80 /* Other */
81 [OP_PHI] = "phi",
82 [OP_PHISOURCE] = "phisrc",
83 [OP_COPY] = "copy",
84 [OP_CAST] = "cast",
85 [OP_SCAST] = "scast",
86 [OP_FPCAST] = "fpcast",
87 [OP_PTRCAST] = "ptrcast",
88 [OP_CALL] = "call",
89 [OP_VANEXT] = "va_next",
90 [OP_VAARG] = "va_arg",
91 [OP_SLICE] = "slice",
92 [OP_SNOP] = "snop",
93 [OP_LNOP] = "lnop",
94 [OP_NOP] = "nop",
95 [OP_DEATHNOTE] = "dead",
96 [OP_ASM] = "asm",
98 /* Sparse tagging (line numbers, context, whatever) */
99 [OP_CONTEXT] = "context",
102 static int last_reg, stack_offset;
104 struct hardreg {
105 const char *name;
106 struct pseudo_list *contains;
107 unsigned busy:16,
108 dead:8,
109 used:1;
112 #define TAG_DEAD 1
113 #define TAG_DIRTY 2
115 /* Our "switch" generation is very very stupid. */
116 #define SWITCH_REG (1)
118 static void output_bb(struct basic_block *bb, unsigned long generation);
121 * We only know about the caller-clobbered registers
122 * right now.
124 static struct hardreg hardregs[] = {
125 { .name = "%eax" },
126 { .name = "%edx" },
127 { .name = "%ecx" },
128 { .name = "%ebx" },
129 { .name = "%esi" },
130 { .name = "%edi" },
132 { .name = "%ebp" },
133 { .name = "%esp" },
135 #define REGNO 6
136 #define REG_EBP 6
137 #define REG_ESP 7
139 struct bb_state {
140 struct position pos;
141 struct storage_hash_list *inputs;
142 struct storage_hash_list *outputs;
143 struct storage_hash_list *internal;
145 /* CC cache.. */
146 int cc_opcode, cc_dead;
147 pseudo_t cc_target;
150 enum optype {
151 OP_UNDEF,
152 OP_REG,
153 OP_VAL,
154 OP_MEM,
155 OP_ADDR,
158 struct operand {
159 enum optype type;
160 int size;
161 union {
162 struct hardreg *reg;
163 long long value;
164 struct /* OP_MEM and OP_ADDR */ {
165 unsigned int offset;
166 unsigned int scale;
167 struct symbol *sym;
168 struct hardreg *base;
169 struct hardreg *index;
174 static const char *show_op(struct bb_state *state, struct operand *op)
176 static char buf[256][4];
177 static int bufnr;
178 char *p, *ret;
179 int nr;
181 nr = (bufnr + 1) & 3;
182 bufnr = nr;
183 ret = p = buf[nr];
185 switch (op->type) {
186 case OP_UNDEF:
187 return "undef";
188 case OP_REG:
189 return op->reg->name;
190 case OP_VAL:
191 sprintf(p, "$%lld", op->value);
192 break;
193 case OP_MEM:
194 case OP_ADDR:
195 if (op->offset)
196 p += sprintf(p, "%d", op->offset);
197 if (op->sym)
198 p += sprintf(p, "%s%s",
199 op->offset ? "+" : "",
200 show_ident(op->sym->ident));
201 if (op->base || op->index) {
202 p += sprintf(p, "(%s%s%s",
203 op->base ? op->base->name : "",
204 (op->base && op->index) ? "," : "",
205 op->index ? op->index->name : "");
206 if (op->scale > 1)
207 p += sprintf(p, ",%d", op->scale);
208 *p++ = ')';
209 *p = '\0';
211 break;
213 return ret;
216 static struct storage_hash *find_storage_hash(pseudo_t pseudo, struct storage_hash_list *list)
218 struct storage_hash *entry;
219 FOR_EACH_PTR(list, entry) {
220 if (entry->pseudo == pseudo)
221 return entry;
222 } END_FOR_EACH_PTR(entry);
223 return NULL;
226 static struct storage_hash *find_or_create_hash(pseudo_t pseudo, struct storage_hash_list **listp)
228 struct storage_hash *entry;
230 entry = find_storage_hash(pseudo, *listp);
231 if (!entry) {
232 entry = alloc_storage_hash(alloc_storage());
233 entry->pseudo = pseudo;
234 add_ptr_list(listp, entry);
236 return entry;
239 /* Eventually we should just build it up in memory */
240 static void FORMAT_ATTR(2) output_line(struct bb_state *state, const char *fmt, ...)
242 va_list args;
244 va_start(args, fmt);
245 vprintf(fmt, args);
246 va_end(args);
249 static void FORMAT_ATTR(2) output_label(struct bb_state *state, const char *fmt, ...)
251 static char buffer[512];
252 va_list args;
254 va_start(args, fmt);
255 vsnprintf(buffer, sizeof(buffer), fmt, args);
256 va_end(args);
258 output_line(state, "%s:\n", buffer);
261 static void FORMAT_ATTR(2) output_insn(struct bb_state *state, const char *fmt, ...)
263 static char buffer[512];
264 va_list args;
266 va_start(args, fmt);
267 vsnprintf(buffer, sizeof(buffer), fmt, args);
268 va_end(args);
270 output_line(state, "\t%s\n", buffer);
273 #define output_insn(state, fmt, arg...) \
274 output_insn(state, fmt "\t\t# %s" , ## arg , __FUNCTION__)
276 static void FORMAT_ATTR(2) output_comment(struct bb_state *state, const char *fmt, ...)
278 static char buffer[512];
279 va_list args;
281 if (!verbose)
282 return;
283 va_start(args, fmt);
284 vsnprintf(buffer, sizeof(buffer), fmt, args);
285 va_end(args);
287 output_line(state, "\t# %s\n", buffer);
290 static const char *show_memop(struct storage *storage)
292 static char buffer[1000];
294 if (!storage)
295 return "undef";
296 switch (storage->type) {
297 case REG_FRAME:
298 sprintf(buffer, "%d(FP)", storage->offset);
299 break;
300 case REG_STACK:
301 sprintf(buffer, "%d(SP)", storage->offset);
302 break;
303 case REG_REG:
304 return hardregs[storage->regno].name;
305 default:
306 return show_storage(storage);
308 return buffer;
311 static int alloc_stack_offset(int size)
313 int ret = stack_offset;
314 stack_offset = ret + size;
315 return ret;
318 static void alloc_stack(struct bb_state *state, struct storage *storage)
320 storage->type = REG_STACK;
321 storage->offset = alloc_stack_offset(4);
325 * Can we re-generate the pseudo, so that we don't need to
326 * flush it to memory? We can regenerate:
327 * - immediates and symbol addresses
328 * - pseudos we got as input in non-registers
329 * - pseudos we've already saved off earlier..
331 static int can_regenerate(struct bb_state *state, pseudo_t pseudo)
333 struct storage_hash *in;
335 switch (pseudo->type) {
336 case PSEUDO_VAL:
337 case PSEUDO_SYM:
338 return 1;
340 default:
341 in = find_storage_hash(pseudo, state->inputs);
342 if (in && in->storage->type != REG_REG)
343 return 1;
344 in = find_storage_hash(pseudo, state->internal);
345 if (in)
346 return 1;
348 return 0;
351 static void flush_one_pseudo(struct bb_state *state, struct hardreg *hardreg, pseudo_t pseudo)
353 struct storage_hash *out;
354 struct storage *storage;
356 if (can_regenerate(state, pseudo))
357 return;
359 output_comment(state, "flushing %s from %s", show_pseudo(pseudo), hardreg->name);
360 out = find_storage_hash(pseudo, state->internal);
361 if (!out) {
362 out = find_storage_hash(pseudo, state->outputs);
363 if (!out)
364 out = find_or_create_hash(pseudo, &state->internal);
366 storage = out->storage;
367 switch (storage->type) {
368 default:
370 * Aieee - the next user wants it in a register, but we
371 * need to flush it to memory in between. Which means that
372 * we need to allocate an internal one, dammit..
374 out = find_or_create_hash(pseudo, &state->internal);
375 storage = out->storage;
376 /* Fall through */
377 case REG_UDEF:
378 alloc_stack(state, storage);
379 /* Fall through */
380 case REG_STACK:
381 output_insn(state, "movl %s,%s", hardreg->name, show_memop(storage));
382 break;
386 /* Flush a hardreg out to the storage it has.. */
387 static void flush_reg(struct bb_state *state, struct hardreg *reg)
389 pseudo_t pseudo;
391 if (reg->busy)
392 output_comment(state, "reg %s flushed while busy is %d!", reg->name, reg->busy);
393 if (!reg->contains)
394 return;
395 reg->dead = 0;
396 reg->used = 1;
397 FOR_EACH_PTR(reg->contains, pseudo) {
398 if (CURRENT_TAG(pseudo) & TAG_DEAD)
399 continue;
400 if (!(CURRENT_TAG(pseudo) & TAG_DIRTY))
401 continue;
402 flush_one_pseudo(state, reg, pseudo);
403 } END_FOR_EACH_PTR(pseudo);
404 free_ptr_list(&reg->contains);
407 static struct storage_hash *find_pseudo_storage(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
409 struct storage_hash *src;
411 src = find_storage_hash(pseudo, state->internal);
412 if (!src) {
413 src = find_storage_hash(pseudo, state->inputs);
414 if (!src) {
415 src = find_storage_hash(pseudo, state->outputs);
416 /* Undefined? Screw it! */
417 if (!src)
418 return NULL;
421 * If we found output storage, it had better be local stack
422 * that we flushed to earlier..
424 if (src->storage->type != REG_STACK)
425 return NULL;
430 * Incoming pseudo with out any pre-set storage allocation?
431 * We can make up our own, and obviously prefer to get it
432 * in the register we already selected (if it hasn't been
433 * used yet).
435 if (src->storage->type == REG_UDEF) {
436 if (reg && !reg->used) {
437 src->storage->type = REG_REG;
438 src->storage->regno = reg - hardregs;
439 return NULL;
441 alloc_stack(state, src->storage);
443 return src;
446 static void mark_reg_dead(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
448 pseudo_t p;
450 FOR_EACH_PTR(reg->contains, p) {
451 if (p != pseudo)
452 continue;
453 if (CURRENT_TAG(p) & TAG_DEAD)
454 continue;
455 output_comment(state, "marking pseudo %s in reg %s dead", show_pseudo(pseudo), reg->name);
456 TAG_CURRENT(p, TAG_DEAD);
457 reg->dead++;
458 } END_FOR_EACH_PTR(p);
461 static void add_pseudo_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
463 output_comment(state, "added pseudo %s to reg %s", show_pseudo(pseudo), reg->name);
464 add_ptr_list_tag(&reg->contains, pseudo, TAG_DIRTY);
467 static struct hardreg *preferred_reg(struct bb_state *state, pseudo_t target)
469 struct storage_hash *dst;
471 dst = find_storage_hash(target, state->outputs);
472 if (dst) {
473 struct storage *storage = dst->storage;
474 if (storage->type == REG_REG)
475 return hardregs + storage->regno;
477 return NULL;
480 static struct hardreg *empty_reg(struct bb_state *state)
482 int i;
483 struct hardreg *reg = hardregs;
485 for (i = 0; i < REGNO; i++, reg++) {
486 if (!reg->contains)
487 return reg;
489 return NULL;
492 static struct hardreg *target_reg(struct bb_state *state, pseudo_t pseudo, pseudo_t target)
494 int i;
495 int unable_to_find_reg = 0;
496 struct hardreg *reg;
498 /* First, see if we have a preferred target register.. */
499 reg = preferred_reg(state, target);
500 if (reg && !reg->contains)
501 goto found;
503 reg = empty_reg(state);
504 if (reg)
505 goto found;
507 i = last_reg;
508 do {
509 i++;
510 if (i >= REGNO)
511 i = 0;
512 reg = hardregs + i;
513 if (!reg->busy) {
514 flush_reg(state, reg);
515 last_reg = i;
516 goto found;
518 } while (i != last_reg);
519 assert(unable_to_find_reg);
521 found:
522 add_pseudo_reg(state, pseudo, reg);
523 return reg;
526 static struct hardreg *find_in_reg(struct bb_state *state, pseudo_t pseudo)
528 int i;
529 struct hardreg *reg;
531 for (i = 0; i < REGNO; i++) {
532 pseudo_t p;
534 reg = hardregs + i;
535 FOR_EACH_PTR(reg->contains, p) {
536 if (p == pseudo) {
537 last_reg = i;
538 output_comment(state, "found pseudo %s in reg %s (busy=%d)", show_pseudo(pseudo), reg->name, reg->busy);
539 return reg;
541 } END_FOR_EACH_PTR(p);
543 return NULL;
546 static void flush_pseudo(struct bb_state *state, pseudo_t pseudo, struct storage *storage)
548 struct hardreg *reg = find_in_reg(state, pseudo);
550 if (reg)
551 flush_reg(state, reg);
554 static void flush_cc_cache_to_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
556 int opcode = state->cc_opcode;
558 state->cc_opcode = 0;
559 state->cc_target = NULL;
560 output_insn(state, "%s %s", opcodes[opcode], reg->name);
563 static void flush_cc_cache(struct bb_state *state)
565 pseudo_t pseudo = state->cc_target;
567 if (pseudo) {
568 struct hardreg *dst;
570 state->cc_target = NULL;
572 if (!state->cc_dead) {
573 dst = target_reg(state, pseudo, pseudo);
574 flush_cc_cache_to_reg(state, pseudo, dst);
579 static void add_cc_cache(struct bb_state *state, int opcode, pseudo_t pseudo)
581 assert(!state->cc_target);
582 state->cc_target = pseudo;
583 state->cc_opcode = opcode;
584 state->cc_dead = 0;
585 output_comment(state, "caching %s", opcodes[opcode]);
588 /* Fill a hardreg with the pseudo it has */
589 static struct hardreg *fill_reg(struct bb_state *state, struct hardreg *hardreg, pseudo_t pseudo)
591 struct storage_hash *src;
592 struct instruction *def;
594 if (state->cc_target == pseudo) {
595 flush_cc_cache_to_reg(state, pseudo, hardreg);
596 return hardreg;
599 switch (pseudo->type) {
600 case PSEUDO_VAL:
601 output_insn(state, "movl $%lld,%s", pseudo->value, hardreg->name);
602 break;
603 case PSEUDO_SYM:
604 src = find_pseudo_storage(state, pseudo, NULL);
605 /* Static thing? */
606 if (!src) {
607 output_insn(state, "movl $<%s>,%s", show_pseudo(pseudo), hardreg->name);
608 break;
610 switch (src->storage->type) {
611 case REG_REG:
612 /* Aiaiaiaiaii! Need to flush it to temporary memory */
613 src = find_or_create_hash(pseudo, &state->internal);
614 /* Fall through */
615 default:
616 alloc_stack(state, src->storage);
617 /* Fall through */
618 case REG_STACK:
619 case REG_FRAME:
620 flush_pseudo(state, pseudo, src->storage);
621 output_insn(state, "leal %s,%s", show_memop(src->storage), hardreg->name);
622 break;
624 break;
625 case PSEUDO_ARG:
626 case PSEUDO_REG:
627 def = pseudo->def;
628 if (def && def->opcode == OP_SETVAL) {
629 output_insn(state, "movl $<%s>,%s", show_pseudo(def->target), hardreg->name);
630 break;
632 src = find_pseudo_storage(state, pseudo, hardreg);
633 if (!src)
634 break;
635 if (src->flags & TAG_DEAD)
636 mark_reg_dead(state, pseudo, hardreg);
637 output_insn(state, "mov.%d %s,%s", 32, show_memop(src->storage), hardreg->name);
638 break;
639 default:
640 output_insn(state, "reload %s from %s", hardreg->name, show_pseudo(pseudo));
641 break;
643 return hardreg;
646 static struct hardreg *getreg(struct bb_state *state, pseudo_t pseudo, pseudo_t target)
648 struct hardreg *reg;
650 reg = find_in_reg(state, pseudo);
651 if (reg)
652 return reg;
653 reg = target_reg(state, pseudo, target);
654 return fill_reg(state, reg, pseudo);
657 static void move_reg(struct bb_state *state, struct hardreg *src, struct hardreg *dst)
659 output_insn(state, "movl %s,%s", src->name, dst->name);
662 static struct hardreg *copy_reg(struct bb_state *state, struct hardreg *src, pseudo_t target)
664 int i;
665 struct hardreg *reg;
667 /* If the container has been killed off, just re-use it */
668 if (!src->contains)
669 return src;
671 /* If "src" only has one user, and the contents are dead, we can re-use it */
672 if (src->busy == 1 && src->dead == 1)
673 return src;
675 reg = preferred_reg(state, target);
676 if (reg && !reg->contains) {
677 output_comment(state, "copying %s to preferred target %s", show_pseudo(target), reg->name);
678 move_reg(state, src, reg);
679 return reg;
682 for (i = 0; i < REGNO; i++) {
683 reg = hardregs + i;
684 if (!reg->contains) {
685 output_comment(state, "copying %s to %s", show_pseudo(target), reg->name);
686 output_insn(state, "movl %s,%s", src->name, reg->name);
687 return reg;
691 flush_reg(state, src);
692 return src;
695 static void put_operand(struct bb_state *state, struct operand *op)
697 switch (op->type) {
698 case OP_REG:
699 op->reg->busy--;
700 break;
701 case OP_ADDR:
702 case OP_MEM:
703 if (op->base)
704 op->base->busy--;
705 if (op->index)
706 op->index->busy--;
707 break;
708 default:
709 break;
713 static struct operand *alloc_op(void)
715 struct operand *op = malloc(sizeof(*op));
716 memset(op, 0, sizeof(*op));
717 return op;
720 static struct operand *get_register_operand(struct bb_state *state, pseudo_t pseudo, pseudo_t target)
722 struct operand *op = alloc_op();
723 op->type = OP_REG;
724 op->reg = getreg(state, pseudo, target);
725 op->reg->busy++;
726 return op;
729 static int get_sym_frame_offset(struct bb_state *state, pseudo_t pseudo)
731 int offset = pseudo->nr;
732 if (offset < 0) {
733 offset = alloc_stack_offset(4);
734 pseudo->nr = offset;
736 return offset;
739 static struct operand *get_generic_operand(struct bb_state *state, pseudo_t pseudo)
741 struct hardreg *reg;
742 struct storage *src;
743 struct storage_hash *hash;
744 struct operand *op = malloc(sizeof(*op));
746 memset(op, 0, sizeof(*op));
747 switch (pseudo->type) {
748 case PSEUDO_VAL:
749 op->type = OP_VAL;
750 op->value = pseudo->value;
751 break;
753 case PSEUDO_SYM: {
754 struct symbol *sym = pseudo->sym;
755 op->type = OP_ADDR;
756 if (sym->ctype.modifiers & MOD_NONLOCAL) {
757 op->sym = sym;
758 break;
760 op->base = hardregs + REG_EBP;
761 op->offset = get_sym_frame_offset(state, pseudo);
762 break;
765 default:
766 reg = find_in_reg(state, pseudo);
767 if (reg) {
768 op->type = OP_REG;
769 op->reg = reg;
770 reg->busy++;
771 break;
773 hash = find_pseudo_storage(state, pseudo, NULL);
774 if (!hash)
775 break;
776 src = hash->storage;
777 switch (src->type) {
778 case REG_REG:
779 op->type = OP_REG;
780 op->reg = hardregs + src->regno;
781 op->reg->busy++;
782 break;
783 case REG_FRAME:
784 op->type = OP_MEM;
785 op->offset = src->offset;
786 op->base = hardregs + REG_EBP;
787 break;
788 case REG_STACK:
789 op->type = OP_MEM;
790 op->offset = src->offset;
791 op->base = hardregs + REG_ESP;
792 break;
793 default:
794 break;
797 return op;
800 /* Callers should be made to use the proper "operand" formats */
801 static const char *generic(struct bb_state *state, pseudo_t pseudo)
803 struct hardreg *reg;
804 struct operand *op = get_generic_operand(state, pseudo);
805 static char buf[100];
806 const char *str;
808 switch (op->type) {
809 case OP_ADDR:
810 if (!op->offset && op->base && !op->sym)
811 return op->base->name;
812 if (op->sym && !op->base) {
813 int len = sprintf(buf, "$ %s", show_op(state, op));
814 if (op->offset)
815 sprintf(buf + len, " + %d", op->offset);
816 return buf;
818 str = show_op(state, op);
819 put_operand(state, op);
820 reg = target_reg(state, pseudo, NULL);
821 output_insn(state, "lea %s,%s", show_op(state, op), reg->name);
822 return reg->name;
824 default:
825 str = show_op(state, op);
827 put_operand(state, op);
828 return str;
831 static struct operand *get_address_operand(struct bb_state *state, struct instruction *memop)
833 struct hardreg *base;
834 struct operand *op = get_generic_operand(state, memop->src);
836 switch (op->type) {
837 case OP_ADDR:
838 op->offset += memop->offset;
839 break;
840 default:
841 put_operand(state, op);
842 base = getreg(state, memop->src, NULL);
843 op->type = OP_ADDR;
844 op->base = base;
845 base->busy++;
846 op->offset = memop->offset;
847 op->sym = NULL;
849 return op;
852 static const char *address(struct bb_state *state, struct instruction *memop)
854 struct operand *op = get_address_operand(state, memop);
855 const char *str = show_op(state, op);
856 put_operand(state, op);
857 return str;
860 static const char *reg_or_imm(struct bb_state *state, pseudo_t pseudo)
862 switch(pseudo->type) {
863 case PSEUDO_VAL:
864 return show_pseudo(pseudo);
865 default:
866 return getreg(state, pseudo, NULL)->name;
870 static void kill_dead_reg(struct hardreg *reg)
872 if (reg->dead) {
873 pseudo_t p;
875 FOR_EACH_PTR(reg->contains, p) {
876 if (CURRENT_TAG(p) & TAG_DEAD) {
877 DELETE_CURRENT_PTR(p);
878 reg->dead--;
880 } END_FOR_EACH_PTR(p);
881 PACK_PTR_LIST(&reg->contains);
882 assert(!reg->dead);
886 static struct hardreg *target_copy_reg(struct bb_state *state, struct hardreg *src, pseudo_t target)
888 kill_dead_reg(src);
889 return copy_reg(state, src, target);
892 static void do_binop(struct bb_state *state, struct instruction *insn, pseudo_t val1, pseudo_t val2)
894 const char *op = opcodes[insn->opcode];
895 struct operand *src = get_register_operand(state, val1, insn->target);
896 struct operand *src2 = get_generic_operand(state, val2);
897 struct hardreg *dst;
899 dst = target_copy_reg(state, src->reg, insn->target);
900 output_insn(state, "%s.%d %s,%s", op, insn->size, show_op(state, src2), dst->name);
901 put_operand(state, src);
902 put_operand(state, src2);
903 add_pseudo_reg(state, insn->target, dst);
906 static void generate_binop(struct bb_state *state, struct instruction *insn)
908 flush_cc_cache(state);
909 do_binop(state, insn, insn->src1, insn->src2);
912 static int is_dead_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
914 pseudo_t p;
915 FOR_EACH_PTR(reg->contains, p) {
916 if (p == pseudo)
917 return CURRENT_TAG(p) & TAG_DEAD;
918 } END_FOR_EACH_PTR(p);
919 return 0;
923 * Commutative binops are much more flexible, since we can switch the
924 * sources around to satisfy the target register, or to avoid having
925 * to load one of them into a register..
927 static void generate_commutative_binop(struct bb_state *state, struct instruction *insn)
929 pseudo_t src1, src2;
930 struct hardreg *reg1, *reg2;
932 flush_cc_cache(state);
933 src1 = insn->src1;
934 src2 = insn->src2;
935 reg2 = find_in_reg(state, src2);
936 if (!reg2)
937 goto dont_switch;
938 reg1 = find_in_reg(state, src1);
939 if (!reg1)
940 goto do_switch;
941 if (!is_dead_reg(state, src2, reg2))
942 goto dont_switch;
943 if (!is_dead_reg(state, src1, reg1))
944 goto do_switch;
946 /* Both are dead. Is one preferable? */
947 if (reg2 != preferred_reg(state, insn->target))
948 goto dont_switch;
950 do_switch:
951 src1 = src2;
952 src2 = insn->src1;
953 dont_switch:
954 do_binop(state, insn, src1, src2);
958 * This marks a pseudo dead. It still stays on the hardreg list (the hardreg
959 * still has its value), but it's scheduled to be killed after the next
960 * "sequence point" when we call "kill_read_pseudos()"
962 static void mark_pseudo_dead(struct bb_state *state, pseudo_t pseudo)
964 int i;
965 struct storage_hash *src;
967 if (state->cc_target == pseudo)
968 state->cc_dead = 1;
969 src = find_pseudo_storage(state, pseudo, NULL);
970 if (src)
971 src->flags |= TAG_DEAD;
972 for (i = 0; i < REGNO; i++)
973 mark_reg_dead(state, pseudo, hardregs + i);
976 static void kill_dead_pseudos(struct bb_state *state)
978 int i;
980 for (i = 0; i < REGNO; i++) {
981 kill_dead_reg(hardregs + i);
985 static void generate_store(struct instruction *insn, struct bb_state *state)
987 output_insn(state, "mov.%d %s,%s", insn->size, reg_or_imm(state, insn->target), address(state, insn));
990 static void generate_load(struct instruction *insn, struct bb_state *state)
992 const char *input = address(state, insn);
993 struct hardreg *dst;
995 kill_dead_pseudos(state);
996 dst = target_reg(state, insn->target, NULL);
997 output_insn(state, "mov.%d %s,%s", insn->size, input, dst->name);
1000 static void kill_pseudo(struct bb_state *state, pseudo_t pseudo)
1002 int i;
1003 struct hardreg *reg;
1005 output_comment(state, "killing pseudo %s", show_pseudo(pseudo));
1006 for (i = 0; i < REGNO; i++) {
1007 pseudo_t p;
1009 reg = hardregs + i;
1010 FOR_EACH_PTR(reg->contains, p) {
1011 if (p != pseudo)
1012 continue;
1013 if (CURRENT_TAG(p) & TAG_DEAD)
1014 reg->dead--;
1015 output_comment(state, "removing pseudo %s from reg %s",
1016 show_pseudo(pseudo), reg->name);
1017 DELETE_CURRENT_PTR(p);
1018 } END_FOR_EACH_PTR(p);
1019 PACK_PTR_LIST(&reg->contains);
1023 static void generate_copy(struct bb_state *state, struct instruction *insn)
1025 struct hardreg *src = getreg(state, insn->src, insn->target);
1026 kill_pseudo(state, insn->target);
1027 add_pseudo_reg(state, insn->target, src);
1030 static void generate_cast(struct bb_state *state, struct instruction *insn)
1032 struct hardreg *src = getreg(state, insn->src, insn->target);
1033 struct hardreg *dst;
1034 unsigned int old = insn->orig_type ? insn->orig_type->bit_size : 0;
1035 unsigned int new = insn->size;
1038 * Cast to smaller type? Ignore the high bits, we
1039 * just keep both pseudos in the same register.
1041 if (old >= new) {
1042 add_pseudo_reg(state, insn->target, src);
1043 return;
1046 dst = target_copy_reg(state, src, insn->target);
1048 if (insn->orig_type && (insn->orig_type->ctype.modifiers & MOD_SIGNED)) {
1049 output_insn(state, "sext.%d.%d %s", old, new, dst->name);
1050 } else {
1051 unsigned long long mask;
1052 mask = ~(~0ULL << old);
1053 mask &= ~(~0ULL << new);
1054 output_insn(state, "andl.%d $%#llx,%s", insn->size, mask, dst->name);
1056 add_pseudo_reg(state, insn->target, dst);
1059 static void generate_output_storage(struct bb_state *state);
1061 static const char *conditional[] = {
1062 [OP_SET_EQ] = "e",
1063 [OP_SET_NE] = "ne",
1064 [OP_SET_LE] = "le",
1065 [OP_SET_GE] = "ge",
1066 [OP_SET_LT] = "lt",
1067 [OP_SET_GT] = "gt",
1068 [OP_SET_B] = "b",
1069 [OP_SET_A] = "a",
1070 [OP_SET_BE] = "be",
1071 [OP_SET_AE] = "ae"
1075 static void generate_branch(struct bb_state *state, struct instruction *br)
1077 const char *cond = "XXX";
1078 struct basic_block *target;
1080 if (br->cond) {
1081 if (state->cc_target == br->cond) {
1082 cond = conditional[state->cc_opcode];
1083 } else {
1084 struct hardreg *reg = getreg(state, br->cond, NULL);
1085 output_insn(state, "testl %s,%s", reg->name, reg->name);
1086 cond = "ne";
1089 generate_output_storage(state);
1090 target = br->bb_true;
1091 if (br->cond) {
1092 output_insn(state, "j%s .L%p", cond, target);
1093 target = br->bb_false;
1095 output_insn(state, "jmp .L%p", target);
1098 /* We've made sure that there is a dummy reg live for the output */
1099 static void generate_switch(struct bb_state *state, struct instruction *insn)
1101 struct hardreg *reg = hardregs + SWITCH_REG;
1103 generate_output_storage(state);
1104 output_insn(state, "switch on %s", reg->name);
1105 output_insn(state, "unimplemented: %s", show_instruction(insn));
1108 static void generate_ret(struct bb_state *state, struct instruction *ret)
1110 if (ret->src && ret->src != VOID) {
1111 struct hardreg *wants = hardregs+0;
1112 struct hardreg *reg = getreg(state, ret->src, NULL);
1113 if (reg != wants)
1114 output_insn(state, "movl %s,%s", reg->name, wants->name);
1116 output_insn(state, "ret");
1120 * Fake "call" linearization just as a taster..
1122 static void generate_call(struct bb_state *state, struct instruction *insn)
1124 int offset = 0;
1125 pseudo_t arg;
1127 FOR_EACH_PTR(insn->arguments, arg) {
1128 output_insn(state, "pushl %s", generic(state, arg));
1129 offset += 4;
1130 } END_FOR_EACH_PTR(arg);
1131 flush_reg(state, hardregs+0);
1132 flush_reg(state, hardregs+1);
1133 flush_reg(state, hardregs+2);
1134 output_insn(state, "call %s", show_pseudo(insn->func));
1135 if (offset)
1136 output_insn(state, "addl $%d,%%esp", offset);
1137 if (insn->target && insn->target != VOID)
1138 add_pseudo_reg(state, insn->target, hardregs+0);
1141 static void generate_select(struct bb_state *state, struct instruction *insn)
1143 const char *cond;
1144 struct hardreg *src1, *src2, *dst;
1146 src1 = getreg(state, insn->src2, NULL);
1147 dst = copy_reg(state, src1, insn->target);
1148 add_pseudo_reg(state, insn->target, dst);
1149 src2 = getreg(state, insn->src3, insn->target);
1151 if (state->cc_target == insn->src1) {
1152 cond = conditional[state->cc_opcode];
1153 } else {
1154 struct hardreg *reg = getreg(state, insn->src1, NULL);
1155 output_insn(state, "testl %s,%s", reg->name, reg->name);
1156 cond = "ne";
1159 output_insn(state, "sel%s %s,%s", cond, src2->name, dst->name);
1162 struct asm_arg {
1163 const struct ident *name;
1164 const char *value;
1165 pseudo_t pseudo;
1166 struct hardreg *reg;
1169 static void replace_asm_arg(char **dst_p, struct asm_arg *arg)
1171 char *dst = *dst_p;
1172 int len = strlen(arg->value);
1174 memcpy(dst, arg->value, len);
1175 *dst_p = dst + len;
1178 static void replace_asm_percent(const char **src_p, char **dst_p, struct asm_arg *args, int nr)
1180 const char *src = *src_p;
1181 char c;
1182 int index;
1184 c = *src++;
1185 switch (c) {
1186 case '0' ... '9':
1187 index = c - '0';
1188 if (index < nr)
1189 replace_asm_arg(dst_p, args+index);
1190 break;
1192 *src_p = src;
1193 return;
1196 static void replace_asm_named(const char **src_p, char **dst_p, struct asm_arg *args, int nr)
1198 const char *src = *src_p;
1199 const char *end = src;
1201 for(;;) {
1202 char c = *end++;
1203 if (!c)
1204 return;
1205 if (c == ']') {
1206 int i;
1208 *src_p = end;
1209 for (i = 0; i < nr; i++) {
1210 const struct ident *ident = args[i].name;
1211 int len;
1212 if (!ident)
1213 continue;
1214 len = ident->len;
1215 if (memcmp(src, ident->name, len))
1216 continue;
1217 replace_asm_arg(dst_p, args+i);
1218 return;
1224 static const char *replace_asm_args(const char *str, struct asm_arg *args, int nr)
1226 static char buffer[1000];
1227 char *p = buffer;
1229 for (;;) {
1230 char c = *str;
1231 *p = c;
1232 if (!c)
1233 return buffer;
1234 str++;
1235 switch (c) {
1236 case '%':
1237 if (*str == '%') {
1238 str++;
1239 p++;
1240 continue;
1242 replace_asm_percent(&str, &p, args, nr);
1243 continue;
1244 case '[':
1245 replace_asm_named(&str, &p, args, nr);
1246 continue;
1247 default:
1248 break;
1250 p++;
1254 #define MAX_ASM_ARG (50)
1255 static struct asm_arg asm_arguments[MAX_ASM_ARG];
1257 static struct asm_arg *generate_asm_inputs(struct bb_state *state, struct asm_constraint_list *list, struct asm_arg *arg)
1259 struct asm_constraint *entry;
1261 FOR_EACH_PTR(list, entry) {
1262 const char *constraint = entry->constraint;
1263 pseudo_t pseudo = entry->pseudo;
1264 struct hardreg *reg, *orig;
1265 const char *string;
1266 int index;
1268 string = "undef";
1269 switch (*constraint) {
1270 case 'r':
1271 string = getreg(state, pseudo, NULL)->name;
1272 break;
1273 case '0' ... '9':
1274 index = *constraint - '0';
1275 reg = asm_arguments[index].reg;
1276 orig = find_in_reg(state, pseudo);
1277 if (orig)
1278 move_reg(state, orig, reg);
1279 else
1280 fill_reg(state, reg, pseudo);
1281 string = reg->name;
1282 break;
1283 default:
1284 string = generic(state, pseudo);
1285 break;
1288 output_insn(state, "# asm input \"%s\": %s : %s", constraint, show_pseudo(pseudo), string);
1290 arg->name = entry->ident;
1291 arg->value = string;
1292 arg->pseudo = NULL;
1293 arg->reg = NULL;
1294 arg++;
1295 } END_FOR_EACH_PTR(entry);
1296 return arg;
1299 static struct asm_arg *generate_asm_outputs(struct bb_state *state, struct asm_constraint_list *list, struct asm_arg *arg)
1301 struct asm_constraint *entry;
1303 FOR_EACH_PTR(list, entry) {
1304 const char *constraint = entry->constraint;
1305 pseudo_t pseudo = entry->pseudo;
1306 struct hardreg *reg;
1307 const char *string;
1309 while (*constraint == '=' || *constraint == '+')
1310 constraint++;
1312 string = "undef";
1313 switch (*constraint) {
1314 case 'r':
1315 default:
1316 reg = target_reg(state, pseudo, NULL);
1317 arg->pseudo = pseudo;
1318 arg->reg = reg;
1319 string = reg->name;
1320 break;
1323 output_insn(state, "# asm output \"%s\": %s : %s", constraint, show_pseudo(pseudo), string);
1325 arg->name = entry->ident;
1326 arg->value = string;
1327 arg++;
1328 } END_FOR_EACH_PTR(entry);
1329 return arg;
1332 static void generate_asm(struct bb_state *state, struct instruction *insn)
1334 const char *str = insn->string;
1336 if (insn->asm_rules->outputs || insn->asm_rules->inputs) {
1337 struct asm_arg *arg;
1339 arg = generate_asm_outputs(state, insn->asm_rules->outputs, asm_arguments);
1340 arg = generate_asm_inputs(state, insn->asm_rules->inputs, arg);
1341 str = replace_asm_args(str, asm_arguments, arg - asm_arguments);
1343 output_insn(state, "%s", str);
1346 static void generate_compare(struct bb_state *state, struct instruction *insn)
1348 struct hardreg *src;
1349 const char *src2;
1350 int opcode;
1352 flush_cc_cache(state);
1353 opcode = insn->opcode;
1356 * We should try to switch these around if necessary,
1357 * and update the opcode to match..
1359 src = getreg(state, insn->src1, insn->target);
1360 src2 = generic(state, insn->src2);
1362 output_insn(state, "cmp.%d %s,%s", insn->size, src2, src->name);
1364 add_cc_cache(state, opcode, insn->target);
1367 static void generate_one_insn(struct instruction *insn, struct bb_state *state)
1369 if (verbose)
1370 output_comment(state, "%s", show_instruction(insn));
1372 switch (insn->opcode) {
1373 case OP_ENTRY: {
1374 struct symbol *sym = insn->bb->ep->name;
1375 const char *name = show_ident(sym->ident);
1376 if (sym->ctype.modifiers & MOD_STATIC)
1377 printf("\n\n%s:\n", name);
1378 else
1379 printf("\n\n.globl %s\n%s:\n", name, name);
1380 break;
1384 * OP_SETVAL likewise doesn't actually generate any
1385 * code. On use, the "def" of the pseudo will be
1386 * looked up.
1388 case OP_SETVAL:
1389 break;
1391 case OP_STORE:
1392 generate_store(insn, state);
1393 break;
1395 case OP_LOAD:
1396 generate_load(insn, state);
1397 break;
1399 case OP_DEATHNOTE:
1400 mark_pseudo_dead(state, insn->target);
1401 return;
1403 case OP_COPY:
1404 generate_copy(state, insn);
1405 break;
1407 case OP_ADD: case OP_MULU: case OP_MULS:
1408 case OP_AND: case OP_OR: case OP_XOR:
1409 case OP_AND_BOOL: case OP_OR_BOOL:
1410 generate_commutative_binop(state, insn);
1411 break;
1413 case OP_SUB: case OP_DIVU: case OP_DIVS:
1414 case OP_MODU: case OP_MODS:
1415 case OP_SHL: case OP_LSR: case OP_ASR:
1416 generate_binop(state, insn);
1417 break;
1419 case OP_BINCMP ... OP_BINCMP_END:
1420 generate_compare(state, insn);
1421 break;
1423 case OP_CAST: case OP_SCAST: case OP_FPCAST: case OP_PTRCAST:
1424 generate_cast(state, insn);
1425 break;
1427 case OP_SEL:
1428 generate_select(state, insn);
1429 break;
1431 case OP_BR:
1432 case OP_CBR:
1433 generate_branch(state, insn);
1434 break;
1436 case OP_SWITCH:
1437 generate_switch(state, insn);
1438 break;
1440 case OP_CALL:
1441 generate_call(state, insn);
1442 break;
1444 case OP_RET:
1445 generate_ret(state, insn);
1446 break;
1448 case OP_ASM:
1449 generate_asm(state, insn);
1450 break;
1452 case OP_PHI:
1453 case OP_PHISOURCE:
1454 default:
1455 output_insn(state, "unimplemented: %s", show_instruction(insn));
1456 break;
1458 kill_dead_pseudos(state);
1461 #define VERY_BUSY 1000
1462 #define REG_FIXED 2000
1464 static void write_reg_to_storage(struct bb_state *state, struct hardreg *reg, pseudo_t pseudo, struct storage *storage)
1466 int i;
1467 struct hardreg *out;
1469 switch (storage->type) {
1470 case REG_REG:
1471 out = hardregs + storage->regno;
1472 if (reg == out)
1473 return;
1474 output_insn(state, "movl %s,%s", reg->name, out->name);
1475 return;
1476 case REG_UDEF:
1477 if (reg->busy < VERY_BUSY) {
1478 storage->type = REG_REG;
1479 storage->regno = reg - hardregs;
1480 reg->busy = REG_FIXED;
1481 return;
1484 /* Try to find a non-busy register.. */
1485 for (i = 0; i < REGNO; i++) {
1486 out = hardregs + i;
1487 if (out->contains)
1488 continue;
1489 output_insn(state, "movl %s,%s", reg->name, out->name);
1490 storage->type = REG_REG;
1491 storage->regno = i;
1492 out->busy = REG_FIXED;
1493 return;
1496 /* Fall back on stack allocation ... */
1497 alloc_stack(state, storage);
1498 /* Fall through */
1499 default:
1500 output_insn(state, "movl %s,%s", reg->name, show_memop(storage));
1501 return;
1505 static void write_val_to_storage(struct bb_state *state, pseudo_t src, struct storage *storage)
1507 struct hardreg *out;
1509 switch (storage->type) {
1510 case REG_UDEF:
1511 alloc_stack(state, storage);
1512 default:
1513 output_insn(state, "movl %s,%s", show_pseudo(src), show_memop(storage));
1514 break;
1515 case REG_REG:
1516 out = hardregs + storage->regno;
1517 output_insn(state, "movl %s,%s", show_pseudo(src), out->name);
1521 static void fill_output(struct bb_state *state, pseudo_t pseudo, struct storage *out)
1523 int i;
1524 struct storage_hash *in;
1525 struct instruction *def;
1527 /* Is that pseudo a constant value? */
1528 switch (pseudo->type) {
1529 case PSEUDO_VAL:
1530 write_val_to_storage(state, pseudo, out);
1531 return;
1532 case PSEUDO_REG:
1533 def = pseudo->def;
1534 if (def && def->opcode == OP_SETVAL) {
1535 write_val_to_storage(state, pseudo, out);
1536 return;
1538 default:
1539 break;
1542 /* See if we have that pseudo in a register.. */
1543 for (i = 0; i < REGNO; i++) {
1544 struct hardreg *reg = hardregs + i;
1545 pseudo_t p;
1547 FOR_EACH_PTR(reg->contains, p) {
1548 if (p == pseudo) {
1549 write_reg_to_storage(state, reg, pseudo, out);
1550 return;
1552 } END_FOR_EACH_PTR(p);
1555 /* Do we have it in another storage? */
1556 in = find_storage_hash(pseudo, state->internal);
1557 if (!in) {
1558 in = find_storage_hash(pseudo, state->inputs);
1559 /* Undefined? */
1560 if (!in)
1561 return;
1563 switch (out->type) {
1564 case REG_UDEF:
1565 *out = *in->storage;
1566 break;
1567 case REG_REG:
1568 output_insn(state, "movl %s,%s", show_memop(in->storage), hardregs[out->regno].name);
1569 break;
1570 default:
1571 if (out == in->storage)
1572 break;
1573 if ((out->type == in->storage->type) && (out->regno == in->storage->regno))
1574 break;
1575 output_insn(state, "movl %s,%s", show_memop(in->storage), show_memop(out));
1576 break;
1578 return;
1581 static int final_pseudo_flush(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
1583 struct storage_hash *hash;
1584 struct storage *out;
1585 struct hardreg *dst;
1588 * Since this pseudo is live at exit, we'd better have output
1589 * storage for it..
1591 hash = find_storage_hash(pseudo, state->outputs);
1592 if (!hash)
1593 return 1;
1594 out = hash->storage;
1596 /* If the output is in a register, try to get it there.. */
1597 if (out->type == REG_REG) {
1598 dst = hardregs + out->regno;
1600 * Two good cases: nobody is using the right register,
1601 * or we've already set it aside for output..
1603 if (!dst->contains || dst->busy > VERY_BUSY)
1604 goto copy_to_dst;
1606 /* Aiee. Try to keep it in a register.. */
1607 dst = empty_reg(state);
1608 if (dst)
1609 goto copy_to_dst;
1611 return 0;
1614 /* If the output is undefined, let's see if we can put it in a register.. */
1615 if (out->type == REG_UDEF) {
1616 dst = empty_reg(state);
1617 if (dst) {
1618 out->type = REG_REG;
1619 out->regno = dst - hardregs;
1620 goto copy_to_dst;
1622 /* Uhhuh. Not so good. No empty registers right now */
1623 return 0;
1626 /* If we know we need to flush it, just do so already .. */
1627 output_insn(state, "movl %s,%s", reg->name, show_memop(out));
1628 return 1;
1630 copy_to_dst:
1631 if (reg == dst)
1632 return 1;
1633 output_insn(state, "movl %s,%s", reg->name, dst->name);
1634 add_pseudo_reg(state, pseudo, dst);
1635 return 1;
1639 * This tries to make sure that we put all the pseudos that are
1640 * live on exit into the proper storage
1642 static void generate_output_storage(struct bb_state *state)
1644 struct storage_hash *entry;
1646 /* Go through the fixed outputs, making sure we have those regs free */
1647 FOR_EACH_PTR(state->outputs, entry) {
1648 struct storage *out = entry->storage;
1649 if (out->type == REG_REG) {
1650 struct hardreg *reg = hardregs + out->regno;
1651 pseudo_t p;
1652 int flushme = 0;
1654 reg->busy = REG_FIXED;
1655 FOR_EACH_PTR(reg->contains, p) {
1656 if (p == entry->pseudo) {
1657 flushme = -100;
1658 continue;
1660 if (CURRENT_TAG(p) & TAG_DEAD)
1661 continue;
1663 /* Try to write back the pseudo to where it should go ... */
1664 if (final_pseudo_flush(state, p, reg)) {
1665 DELETE_CURRENT_PTR(p);
1666 continue;
1668 flushme++;
1669 } END_FOR_EACH_PTR(p);
1670 PACK_PTR_LIST(&reg->contains);
1671 if (flushme > 0)
1672 flush_reg(state, reg);
1674 } END_FOR_EACH_PTR(entry);
1676 FOR_EACH_PTR(state->outputs, entry) {
1677 fill_output(state, entry->pseudo, entry->storage);
1678 } END_FOR_EACH_PTR(entry);
1681 static void generate(struct basic_block *bb, struct bb_state *state)
1683 int i;
1684 struct storage_hash *entry;
1685 struct instruction *insn;
1687 for (i = 0; i < REGNO; i++) {
1688 free_ptr_list(&hardregs[i].contains);
1689 hardregs[i].busy = 0;
1690 hardregs[i].dead = 0;
1691 hardregs[i].used = 0;
1694 FOR_EACH_PTR(state->inputs, entry) {
1695 struct storage *storage = entry->storage;
1696 const char *name = show_storage(storage);
1697 output_comment(state, "incoming %s in %s", show_pseudo(entry->pseudo), name);
1698 if (storage->type == REG_REG) {
1699 int regno = storage->regno;
1700 add_pseudo_reg(state, entry->pseudo, hardregs + regno);
1701 name = hardregs[regno].name;
1703 } END_FOR_EACH_PTR(entry);
1705 output_label(state, ".L%p", bb);
1706 FOR_EACH_PTR(bb->insns, insn) {
1707 if (!insn->bb)
1708 continue;
1709 generate_one_insn(insn, state);
1710 } END_FOR_EACH_PTR(insn);
1712 if (verbose) {
1713 output_comment(state, "--- in ---");
1714 FOR_EACH_PTR(state->inputs, entry) {
1715 output_comment(state, "%s <- %s", show_pseudo(entry->pseudo), show_storage(entry->storage));
1716 } END_FOR_EACH_PTR(entry);
1717 output_comment(state, "--- spill ---");
1718 FOR_EACH_PTR(state->internal, entry) {
1719 output_comment(state, "%s <-> %s", show_pseudo(entry->pseudo), show_storage(entry->storage));
1720 } END_FOR_EACH_PTR(entry);
1721 output_comment(state, "--- out ---");
1722 FOR_EACH_PTR(state->outputs, entry) {
1723 output_comment(state, "%s -> %s", show_pseudo(entry->pseudo), show_storage(entry->storage));
1724 } END_FOR_EACH_PTR(entry);
1726 printf("\n");
1729 static void generate_list(struct basic_block_list *list, unsigned long generation)
1731 struct basic_block *bb;
1732 FOR_EACH_PTR(list, bb) {
1733 if (bb->generation == generation)
1734 continue;
1735 output_bb(bb, generation);
1736 } END_FOR_EACH_PTR(bb);
1740 * Mark all the output registers of all the parents
1741 * as being "used" - this does not mean that we cannot
1742 * re-use them, but it means that we cannot ask the
1743 * parents to pass in another pseudo in one of those
1744 * registers that it already uses for another child.
1746 static void mark_used_registers(struct basic_block *bb, struct bb_state *state)
1748 struct basic_block *parent;
1750 FOR_EACH_PTR(bb->parents, parent) {
1751 struct storage_hash_list *outputs = gather_storage(parent, STOR_OUT);
1752 struct storage_hash *entry;
1754 FOR_EACH_PTR(outputs, entry) {
1755 struct storage *s = entry->storage;
1756 if (s->type == REG_REG) {
1757 struct hardreg *reg = hardregs + s->regno;
1758 reg->used = 1;
1760 } END_FOR_EACH_PTR(entry);
1761 } END_FOR_EACH_PTR(parent);
1764 static void output_bb(struct basic_block *bb, unsigned long generation)
1766 struct bb_state state;
1768 bb->generation = generation;
1770 /* Make sure all parents have been generated first */
1771 generate_list(bb->parents, generation);
1773 state.pos = bb->pos;
1774 state.inputs = gather_storage(bb, STOR_IN);
1775 state.outputs = gather_storage(bb, STOR_OUT);
1776 state.internal = NULL;
1777 state.cc_opcode = 0;
1778 state.cc_target = NULL;
1780 /* Mark incoming registers used */
1781 mark_used_registers(bb, &state);
1783 generate(bb, &state);
1785 free_ptr_list(&state.inputs);
1786 free_ptr_list(&state.outputs);
1788 /* Generate all children... */
1789 generate_list(bb->children, generation);
1793 * We should set up argument sources here..
1795 * Things like "first three arguments in registers" etc
1796 * are all for this place.
1798 * On x86, we default to stack, unless it's a static
1799 * function that doesn't have its address taken.
1801 * I should implement the -mregparm=X cmd line option.
1803 static void set_up_arch_entry(struct entrypoint *ep, struct instruction *entry)
1805 pseudo_t arg;
1806 struct symbol *sym, *argtype;
1807 int i, offset, regparm;
1809 sym = ep->name;
1810 regparm = 0;
1811 if (!(sym->ctype.modifiers & MOD_ADDRESSABLE))
1812 regparm = 3;
1813 sym = sym->ctype.base_type;
1814 i = 0;
1815 offset = 0;
1816 PREPARE_PTR_LIST(sym->arguments, argtype);
1817 FOR_EACH_PTR(entry->arg_list, arg) {
1818 struct storage *in = lookup_storage(entry->bb, arg, STOR_IN);
1819 if (!in) {
1820 in = alloc_storage();
1821 add_storage(in, entry->bb, arg, STOR_IN);
1823 if (i < regparm) {
1824 in->type = REG_REG;
1825 in->regno = i;
1826 } else {
1827 int bits = argtype ? argtype->bit_size : 0;
1829 if (bits < bits_in_int)
1830 bits = bits_in_int;
1832 in->type = REG_FRAME;
1833 in->offset = offset;
1835 offset += bits_to_bytes(bits);
1837 i++;
1838 NEXT_PTR_LIST(argtype);
1839 } END_FOR_EACH_PTR(arg);
1840 FINISH_PTR_LIST(argtype);
1844 * Set up storage information for "return"
1846 * Not strictly necessary, since the code generator will
1847 * certainly move the return value to the right register,
1848 * but it can help register allocation if the allocator
1849 * sees that the target register is going to return in %eax.
1851 static void set_up_arch_exit(struct basic_block *bb, struct instruction *ret)
1853 pseudo_t pseudo = ret->src;
1855 if (pseudo && pseudo != VOID) {
1856 struct storage *out = lookup_storage(bb, pseudo, STOR_OUT);
1857 if (!out) {
1858 out = alloc_storage();
1859 add_storage(out, bb, pseudo, STOR_OUT);
1861 out->type = REG_REG;
1862 out->regno = 0;
1867 * Set up dummy/silly output storage information for a switch
1868 * instruction. We need to make sure that a register is available
1869 * when we generate code for switch, so force that by creating
1870 * a dummy output rule.
1872 static void set_up_arch_switch(struct basic_block *bb, struct instruction *insn)
1874 pseudo_t pseudo = insn->cond;
1875 struct storage *out = lookup_storage(bb, pseudo, STOR_OUT);
1876 if (!out) {
1877 out = alloc_storage();
1878 add_storage(out, bb, pseudo, STOR_OUT);
1880 out->type = REG_REG;
1881 out->regno = SWITCH_REG;
1884 static void arch_set_up_storage(struct entrypoint *ep)
1886 struct basic_block *bb;
1888 /* Argument storage etc.. */
1889 set_up_arch_entry(ep, ep->entry);
1891 FOR_EACH_PTR(ep->bbs, bb) {
1892 struct instruction *insn = last_instruction(bb->insns);
1893 if (!insn)
1894 continue;
1895 switch (insn->opcode) {
1896 case OP_RET:
1897 set_up_arch_exit(bb, insn);
1898 break;
1899 case OP_SWITCH:
1900 set_up_arch_switch(bb, insn);
1901 break;
1902 default:
1903 /* nothing */;
1905 } END_FOR_EACH_PTR(bb);
1908 static void output(struct entrypoint *ep)
1910 unsigned long generation = ++bb_generation;
1912 last_reg = -1;
1913 stack_offset = 0;
1915 /* Get rid of SSA form (phinodes etc) */
1916 unssa(ep);
1918 /* Set up initial inter-bb storage links */
1919 set_up_storage(ep);
1921 /* Architecture-specific storage rules.. */
1922 arch_set_up_storage(ep);
1924 /* Show the results ... */
1925 output_bb(ep->entry->bb, generation);
1927 /* Clear the storage hashes for the next function.. */
1928 free_storage();
1931 static int compile(struct symbol_list *list)
1933 struct symbol *sym;
1934 FOR_EACH_PTR(list, sym) {
1935 struct entrypoint *ep;
1936 expand_symbol(sym);
1937 ep = linearize_symbol(sym);
1938 if (ep)
1939 output(ep);
1940 } END_FOR_EACH_PTR(sym);
1942 return 0;
1945 int main(int argc, char **argv)
1947 struct string_list *filelist = NULL;
1948 char *file;
1950 compile(sparse_initialize(argc, argv, &filelist));
1951 dbg_dead = 1;
1952 FOR_EACH_PTR_NOTAG(filelist, file) {
1953 compile(sparse(file));
1954 } END_FOR_EACH_PTR_NOTAG(file);
1955 return 0;