Warn about non-constant case statements.
[smatch.git] / compile-i386.c
bloba48589f21c0044bd421143aefb665e27d7d2abb7
1 /*
2 * sparse/compile-i386.c
4 * Copyright (C) 2003 Transmeta Corp.
5 * 2003 Linus Torvalds
6 * Copyright 2003 Jeff Garzik
8 * Licensed under the Open Software License version 1.1
10 * x86 backend
13 #include <stdarg.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <assert.h>
22 #include "lib.h"
23 #include "token.h"
24 #include "parse.h"
25 #include "symbol.h"
26 #include "scope.h"
27 #include "expression.h"
28 #include "target.h"
31 struct textbuf;
32 struct textbuf {
33 unsigned int len; /* does NOT include terminating null */
34 char *text;
35 struct textbuf *next;
36 struct textbuf *prev;
39 struct function {
40 int pseudo_nr;
41 struct ptr_list *pseudo_list;
42 struct ptr_list *atom_list;
43 struct symbol **argv;
44 unsigned int argc;
45 int ret_target;
48 enum storage_type {
49 STOR_PSEUDO, /* variable stored on the stack */
50 STOR_ARG, /* function argument */
51 STOR_SYM, /* a symbol we can directly ref in the asm */
52 STOR_REG, /* scratch register */
53 STOR_VALUE, /* integer constant */
54 STOR_LABEL, /* label / jump target */
57 struct reg_info {
58 const char *name;
61 struct storage {
62 enum storage_type type;
64 /* STOR_REG */
65 struct reg_info *reg;
67 union {
68 /* STOR_PSEUDO */
69 struct {
70 int pseudo;
72 /* STOR_ARG */
73 struct {
74 int idx;
76 /* STOR_SYM */
77 struct {
78 struct symbol *sym;
80 /* STOR_VALUE */
81 struct {
82 long long value;
84 /* STOR_LABEL */
85 struct {
86 int label;
91 struct symbol_private {
92 struct storage *addr;
95 enum atom_type {
96 ATOM_TEXT,
97 ATOM_INSN,
100 enum {
101 ATOM_FREE_OP1 = (1 << 0),
102 ATOM_FREE_OP2 = (1 << 1),
105 struct atom {
106 enum atom_type type;
107 union {
108 /* stuff for text */
109 struct {
110 char *text;
111 unsigned int text_len; /* w/o terminating null */
114 /* stuff for insns */
115 struct {
116 char insn[32];
117 char comment[40];
118 struct storage *op1;
119 struct storage *op2;
120 unsigned long flags;
126 struct function *current_func = NULL;
127 struct textbuf *unit_post_text = NULL;
128 static const char *current_section;
130 static struct reg_info reg_info_table[] = {
131 { "%eax" },
132 { "%ecx" },
133 { "%edx" },
134 { "%esp" },
137 static struct storage hardreg_storage_table[] = {
139 .type = STOR_REG,
140 .reg = &reg_info_table[0],
143 .type = STOR_REG,
144 .reg = &reg_info_table[1],
147 .type = STOR_REG,
148 .reg = &reg_info_table[2],
151 .type = STOR_REG,
152 .reg = &reg_info_table[3],
156 #define REG_EAX (&hardreg_storage_table[0])
157 #define REG_ECX (&hardreg_storage_table[1])
158 #define REG_EDX (&hardreg_storage_table[2])
159 #define REG_ESP (&hardreg_storage_table[3])
162 static struct storage *x86_address_gen(struct expression *expr);
163 static struct storage *x86_symbol_expr(struct symbol *sym);
164 static void x86_symbol(struct symbol *sym);
165 static struct storage *x86_statement(struct statement *stmt);
166 static struct storage *x86_expression(struct expression *expr);
169 static inline unsigned int pseudo_offset(struct storage *s)
171 if (s->type != STOR_PSEUDO)
172 return 123456; /* intentionally bogus value */
174 return ((s->pseudo - 1) * 4);
177 static inline unsigned int arg_offset(struct storage *s)
179 if (s->type != STOR_ARG)
180 return 123456; /* intentionally bogus value */
182 /* FIXME: this is wrong wrong wrong */
183 return (current_func->pseudo_nr + 1 + s->idx) * 4;
186 static const char *pretty_offset(int ofs)
188 static char esp_buf[64];
190 if (ofs)
191 sprintf(esp_buf, "%d(%%esp)", ofs);
192 else
193 strcpy(esp_buf, "(%esp)");
195 return esp_buf;
198 static void stor_sym_init(struct symbol *sym)
200 struct storage *stor;
201 struct symbol_private *priv;
203 priv = calloc(1, sizeof(*priv) + sizeof(*stor));
204 if (!priv)
205 die("OOM in stor_sym_init");
207 stor = (struct storage *) (priv + 1);
209 priv->addr = stor;
210 stor->type = STOR_SYM;
211 stor->sym = sym;
214 static const char *stor_op_name(struct storage *s)
216 static char name[32];
218 switch (s->type) {
219 case STOR_PSEUDO:
220 strcpy(name, pretty_offset((int) pseudo_offset(s)));
221 break;
222 case STOR_ARG:
223 strcpy(name, pretty_offset((int) arg_offset(s)));
224 break;
225 case STOR_SYM:
226 strcpy(name, show_ident(s->sym->ident));
227 break;
228 case STOR_REG:
229 strcpy(name, s->reg->name);
230 break;
231 case STOR_VALUE:
232 sprintf(name, "$%Ld", s->value);
233 break;
234 case STOR_LABEL:
235 sprintf(name, ".L%d", s->label);
236 break;
239 return name;
242 static struct atom *new_atom(enum atom_type type)
244 struct atom *atom;
246 atom = calloc(1, sizeof(*atom)); /* TODO: chunked alloc */
247 if (!atom)
248 die("nuclear OOM");
250 atom->type = type;
252 return atom;
255 static inline void push_atom(struct function *f, struct atom *atom)
257 add_ptr_list(&f->atom_list, atom);
260 static void push_text_atom(struct function *f, const char *text)
262 struct atom *atom = new_atom(ATOM_TEXT);
264 atom->text = strdup(text);
265 atom->text_len = strlen(text);
267 push_atom(f, atom);
270 static struct storage *new_storage(enum storage_type type)
272 struct storage *stor;
274 stor = calloc(1, sizeof(*stor));
275 if (!stor)
276 die("OOM in new_storage");
278 stor->type = type;
280 return stor;
283 static struct storage *new_pseudo(void)
285 struct function *f = current_func;
286 struct storage *stor;
288 assert(f != NULL);
290 stor = new_storage(STOR_PSEUDO);
291 stor->type = STOR_PSEUDO;
292 stor->pseudo = ++f->pseudo_nr;
294 add_ptr_list(&f->pseudo_list, stor);
296 return stor;
299 static int new_label(void)
301 static int label = 0;
302 return ++label;
305 static void textbuf_push(struct textbuf **buf_p, const char *text)
307 struct textbuf *tmp, *list = *buf_p;
308 unsigned int text_len = strlen(text);
309 unsigned int alloc_len = text_len + 1 + sizeof(*list);
311 tmp = calloc(1, alloc_len);
312 if (!tmp)
313 die("OOM on textbuf alloc");
315 tmp->text = ((void *) tmp) + sizeof(*tmp);
316 memcpy(tmp->text, text, text_len + 1);
317 tmp->len = text_len;
319 /* add to end of list */
320 if (!list) {
321 list = tmp;
322 tmp->prev = tmp;
323 } else {
324 tmp->prev = list->prev;
325 tmp->prev->next = tmp;
326 list->prev = tmp;
328 tmp->next = list;
330 *buf_p = list;
333 static void textbuf_emit(struct textbuf **buf_p)
335 struct textbuf *tmp, *list = *buf_p;
337 while (list) {
338 tmp = list;
339 if (tmp->next == tmp)
340 list = NULL;
341 else {
342 tmp->prev->next = tmp->next;
343 tmp->next->prev = tmp->prev;
344 list = tmp->next;
347 fputs(tmp->text, stdout);
349 free(tmp);
352 *buf_p = list;
355 static void insn(const char *insn, struct storage *op1, struct storage *op2,
356 const char *comment_in, unsigned long flags)
358 struct function *f = current_func;
359 struct atom *atom = new_atom(ATOM_INSN);
361 assert(insn != NULL);
363 strcpy(atom->insn, insn);
364 if (comment_in && (*comment_in))
365 strncpy(atom->comment, comment_in,
366 sizeof(atom->comment) - 1);
368 atom->op1 = op1;
369 atom->op2 = op2;
370 atom->flags = flags;
372 push_atom(f, atom);
375 static void emit_unit_pre(const char *basename)
377 printf("\t.file\t\"%s\"\n", basename);
380 static void emit_unit_post(void)
382 textbuf_emit(&unit_post_text);
383 printf("\t.ident\t\"sparse silly x86 backend (built %s)\"\n", __DATE__);
386 /* conditionally switch sections */
387 static void emit_section(const char *s)
389 if (s == current_section)
390 return;
391 if (current_section && (!strcmp(s, current_section)))
392 return;
394 printf("\t%s\n", s);
395 current_section = s;
398 static void emit_insn_atom(struct function *f, struct atom *atom)
400 char s[128];
401 char comment[64];
403 if (atom->comment[0])
404 sprintf(comment, "\t\t# %s", atom->comment);
405 else
406 comment[0] = 0;
408 if (atom->op2) {
409 char tmp[16];
410 strcpy(tmp, stor_op_name(atom->op1));
411 sprintf(s, "\t%s\t%s, %s%s\n",
412 atom->insn, tmp, stor_op_name(atom->op2), comment);
413 } else if (atom->op1)
414 sprintf(s, "\t%s\t%s%s%s\n",
415 atom->insn, stor_op_name(atom->op1),
416 comment[0] ? "\t" : "", comment);
417 else
418 sprintf(s, "\t%s\t%s%s\n",
419 atom->insn,
420 comment[0] ? "\t\t" : "", comment);
422 write(STDOUT_FILENO, s, strlen(s));
425 static void emit_atom_list(struct function *f)
427 struct atom *atom;
429 FOR_EACH_PTR(f->atom_list, atom) {
430 switch (atom->type) {
431 case ATOM_TEXT: {
432 ssize_t rc = write(STDOUT_FILENO, atom->text,
433 atom->text_len);
434 (void) rc; /* FIXME */
435 break;
437 case ATOM_INSN:
438 emit_insn_atom(f, atom);
439 break;
441 } END_FOR_EACH_PTR;
444 static void func_cleanup(struct function *f)
446 struct storage *stor;
447 struct atom *atom;
449 FOR_EACH_PTR(f->pseudo_list, stor) {
450 free(stor);
451 } END_FOR_EACH_PTR;
453 FOR_EACH_PTR(f->atom_list, atom) {
454 if ((atom->type == ATOM_TEXT) && (atom->text))
455 free(atom->text);
456 if (atom->flags & ATOM_FREE_OP1)
457 free(atom->op1);
458 if (atom->flags & ATOM_FREE_OP2)
459 free(atom->op2);
460 free(atom);
461 } END_FOR_EACH_PTR;
463 free_ptr_list(&f->pseudo_list);
464 free(f);
467 /* function prologue */
468 static void emit_func_pre(struct symbol *sym)
470 const char *name = show_ident(sym->ident);
471 struct function *f;
472 struct symbol *arg;
473 unsigned int i, argc = 0, alloc_len;
474 unsigned char *mem;
475 struct symbol_private *privbase;
476 struct storage *storage_base;
477 struct symbol *base_type = sym->ctype.base_type;
479 FOR_EACH_PTR(base_type->arguments, arg) {
480 argc++;
481 } END_FOR_EACH_PTR;
483 alloc_len =
484 sizeof(*f) +
485 (argc * sizeof(struct symbol *)) +
486 (argc * sizeof(struct symbol_private)) +
487 (argc * sizeof(struct storage));
488 mem = calloc(1, alloc_len);
489 if (!mem)
490 die("OOM on func info");
492 f = (struct function *) mem;
493 mem += sizeof(*f);
494 f->argv = (struct symbol **) mem;
495 mem += (argc * sizeof(struct symbol *));
496 privbase = (struct symbol_private *) mem;
497 mem += (argc * sizeof(struct symbol_private));
498 storage_base = (struct storage *) mem;
500 f->argc = argc;
501 f->ret_target = new_label();
503 i = 0;
504 FOR_EACH_PTR(base_type->arguments, arg) {
505 f->argv[i] = arg;
506 arg->aux = &privbase[i];
507 storage_base[i].type = STOR_ARG;
508 storage_base[i].idx = i;
509 privbase[i].addr = &storage_base[i];
510 i++;
511 } END_FOR_EACH_PTR;
513 assert(current_func == NULL);
514 current_func = f;
516 emit_section(".text");
517 if ((sym->ctype.modifiers & MOD_STATIC) == 0)
518 printf(".globl %s\n", name);
519 printf("\t.type\t%s, @function\n", name);
520 printf("%s:\n", name);
523 /* function epilogue */
524 static void emit_func_post(struct symbol *sym, struct storage *ret_val)
526 const char *name = show_ident(sym->ident);
527 struct function *f = current_func;
528 struct storage *val;
529 int pseudo_nr = f->pseudo_nr;
530 char pseudo_const[16], jump_target[16];
532 /* function epilogue */
533 sprintf(pseudo_const, "$%d", pseudo_nr * 4);
534 printf("\tsubl\t%s, %%esp\n", pseudo_const);
536 /* jump target for 'return' statements */
537 sprintf(jump_target, ".L%d:\n", f->ret_target);
538 push_text_atom(f, jump_target);
540 /* function prologue */
541 if (ret_val)
542 insn("movl", ret_val, REG_EAX, NULL, 0);
544 val = new_storage(STOR_VALUE);
545 val->value = (long long) (pseudo_nr * 4);
547 insn("addl", val, REG_ESP, NULL, ATOM_FREE_OP1);
548 insn("ret", NULL, NULL, NULL, 0);
550 /* output everything to stdout */
551 fflush(stdout); /* paranoia; needed? */
552 emit_atom_list(f);
554 /* function footer */
555 printf("\t.size\t%s, .-%s\n", name, name);
557 func_cleanup(f);
558 current_func = NULL;
561 /* emit object (a.k.a. variable, a.k.a. data) prologue */
562 static void emit_object_pre(const char *name, unsigned long modifiers,
563 unsigned long alignment, unsigned int byte_size)
565 if ((modifiers & MOD_STATIC) == 0)
566 printf(".globl %s\n", name);
567 emit_section(".data");
568 if (alignment)
569 printf("\t.align %lu\n", alignment);
570 printf("\t.type\t%s, @object\n", name);
571 printf("\t.size\t%s, %d\n", name, byte_size);
572 printf("%s:\n", name);
575 /* emit value (only) for an initializer scalar */
576 static void emit_scalar(struct expression *expr, unsigned int bit_size)
578 const char *type;
579 long long ll;
581 assert(expr->type == EXPR_VALUE);
583 if (expr->value == 0ULL) {
584 printf("\t.zero\t%d\n", bit_size / 8);
585 return;
588 ll = (long long) expr->value;
590 switch (bit_size) {
591 case 8: type = "byte"; ll = (char) ll; break;
592 case 16: type = "value"; ll = (short) ll; break;
593 case 32: type = "long"; ll = (int) ll; break;
594 case 64: type = "quad"; break;
595 default: type = NULL; break;
598 assert(type != NULL);
600 printf("\t.%s\t%Ld\n", type, ll);
603 static void emit_global_noinit(const char *name, unsigned long modifiers,
604 unsigned long alignment, unsigned int byte_size)
606 char s[64];
608 if (modifiers & MOD_STATIC) {
609 sprintf(s, "\t.local\t%s\n", name);
610 textbuf_push(&unit_post_text, s);
612 if (alignment)
613 sprintf(s, "\t.comm\t%s,%d,%lu\n", name, byte_size, alignment);
614 else
615 sprintf(s, "\t.comm\t%s,%d\n", name, byte_size);
616 textbuf_push(&unit_post_text, s);
619 static int ea_current, ea_last;
621 static void emit_initializer(struct symbol *sym,
622 struct expression *expr)
624 int distance = ea_current - ea_last - 1;
626 if (distance > 0)
627 printf("\t.zero\t%d\n", (sym->bit_size / 8) * distance);
629 if (expr->type == EXPR_VALUE) {
630 struct symbol *base_type = sym->ctype.base_type;
631 assert(base_type != NULL);
633 emit_scalar(expr, sym->bit_size / base_type->array_size);
634 return;
636 if (expr->type != EXPR_INITIALIZER)
637 return;
639 assert(0); /* FIXME */
642 static int sort_array_cmp(const struct expression *a,
643 const struct expression *b)
645 int a_ofs = 0, b_ofs = 0;
647 if (a->type == EXPR_POS)
648 a_ofs = (int) a->init_offset;
649 if (b->type == EXPR_POS)
650 b_ofs = (int) b->init_offset;
652 return a_ofs - b_ofs;
655 /* move to front-end? */
656 static void sort_array(struct expression *expr)
658 struct expression *entry, **list;
659 unsigned int elem, sorted, i;
661 elem = 0;
662 FOR_EACH_PTR(expr->expr_list, entry) {
663 elem++;
664 } END_FOR_EACH_PTR;
666 if (!elem)
667 return;
669 list = malloc(sizeof(entry) * elem);
670 if (!list)
671 die("OOM in sort_array");
673 /* this code is no doubt evil and ignores EXPR_INDEX possibly
674 * to its detriment and other nasty things. improvements
675 * welcome.
677 i = 0;
678 sorted = 0;
679 FOR_EACH_PTR(expr->expr_list, entry) {
680 if ((entry->type == EXPR_POS) || (entry->type == EXPR_VALUE)) {
681 /* add entry to list[], in sorted order */
682 if (sorted == 0) {
683 list[0] = entry;
684 sorted = 1;
685 } else {
686 unsigned int i;
688 for (i = 0; i < sorted; i++)
689 if (sort_array_cmp(entry, list[i]) <= 0)
690 break;
692 /* If inserting into the middle of list[]
693 * instead of appending, we memmove.
694 * This is ugly, but thankfully
695 * uncommon. Input data with tons of
696 * entries very rarely have explicit
697 * offsets. convert to qsort eventually...
699 if (i != sorted)
700 memmove(&list[i + 1], &list[i],
701 (sorted - i) * sizeof(entry));
702 list[i] = entry;
703 sorted++;
706 } END_FOR_EACH_PTR;
708 i = 0;
709 FOR_EACH_PTR(expr->expr_list, entry) {
710 if ((entry->type == EXPR_POS) || (entry->type == EXPR_VALUE))
711 __list->list[__i] = list[i++];
712 } END_FOR_EACH_PTR;
716 static void emit_array(struct symbol *sym)
718 struct symbol *base_type = sym->ctype.base_type;
719 struct expression *expr = sym->initializer;
720 struct expression *entry;
722 assert(base_type != NULL);
724 stor_sym_init(sym);
726 ea_last = -1;
728 emit_object_pre(show_ident(sym->ident), sym->ctype.modifiers,
729 sym->ctype.alignment,
730 sym->bit_size / 8);
732 sort_array(expr);
734 FOR_EACH_PTR(expr->expr_list, entry) {
735 if (entry->type == EXPR_VALUE) {
736 ea_current = 0;
737 emit_initializer(sym, entry);
738 ea_last = ea_current;
739 } else if (entry->type == EXPR_POS) {
740 ea_current =
741 entry->init_offset / (base_type->bit_size / 8);
742 emit_initializer(sym, entry->init_expr);
743 ea_last = ea_current;
745 } END_FOR_EACH_PTR;
748 static void emit_one_symbol(struct symbol *sym, void *dummy, int flags)
750 x86_symbol(sym);
753 void emit_unit(const char *basename, struct symbol_list *list)
755 emit_unit_pre(basename);
756 symbol_iterate(list, emit_one_symbol, NULL);
757 emit_unit_post();
760 static void emit_move(struct expression *dest_expr, struct storage *dest,
761 struct storage *src, int bits)
763 /* FIXME: Bitfield move! */
765 /* FIXME: pay attention to arg 'bits' */
766 insn("movl", src, REG_EAX, NULL, 0);
768 /* FIXME: pay attention to arg 'bits' */
769 insn("movl", REG_EAX, dest, NULL, 0);
772 static void emit_store(struct expression *dest_expr, struct storage *dest,
773 struct storage *src, int bits)
775 /* FIXME: Bitfield store! */
776 printf("\tst.%d\t\tv%d,[v%d]\n", bits, src->pseudo, dest->pseudo);
779 static void emit_scalar_noinit(struct symbol *sym)
781 emit_global_noinit(show_ident(sym->ident),
782 sym->ctype.modifiers, sym->ctype.alignment,
783 sym->bit_size / 8);
784 stor_sym_init(sym);
787 static void emit_array_noinit(struct symbol *sym)
789 emit_global_noinit(show_ident(sym->ident),
790 sym->ctype.modifiers, sym->ctype.alignment,
791 sym->array_size * (sym->bit_size / 8));
792 stor_sym_init(sym);
795 static struct storage *emit_compare(struct expression *expr)
797 struct storage *left = x86_expression(expr->left);
798 struct storage *right = x86_expression(expr->right);
799 struct storage *new, *val;
800 const char *opname = NULL;
801 static const char *name[] = {
802 ['<'] = "cmovl",
803 ['>'] = "cmovg",
805 unsigned int op = expr->op;
807 if (op < sizeof(name)/sizeof(*name)) {
808 opname = name[op];
809 assert(opname != NULL);
810 } else {
811 const char *tmp = show_special(op);
812 if (!strcmp(tmp, "<="))
813 opname = "cmovle";
814 else if (!strcmp(tmp, ">="))
815 opname = "cmovge";
816 else if (!strcmp(tmp, "=="))
817 opname = "cmove";
818 else if (!strcmp(tmp, "!="))
819 opname = "cmovne";
820 else {
821 assert(0);
825 /* init ECX to 1 */
826 val = new_storage(STOR_VALUE);
827 val->value = 1;
828 insn("movl", val, REG_ECX, "EXPR_COMPARE", ATOM_FREE_OP1);
830 /* init EDX to 0 */
831 insn("xorl", REG_EDX, REG_EDX, NULL, 0);
833 /* FIXME: don't hardcode operand size */
834 /* move op1 into EAX */
835 insn("movl", left, REG_EAX, NULL, 0);
837 /* perform comparison, EAX (op1) and op2 */
838 insn("cmpl", REG_EAX, right, NULL, 0);
840 /* store result of operation, 0 or 1, in EDX using CMOV */
841 /* FIXME: does this need an operand size suffix? */
842 insn(opname, REG_ECX, REG_EDX, NULL, 0);
844 /* finally, store the result (EDX) in a new pseudo / stack slot */
845 new = new_pseudo();
846 insn("movl", REG_EDX, new, "end EXPR_COMPARE", 0);
848 return new;
852 * TODO: use new type STOR_VALUE. This will allow us to store
853 * the constant internally, and avoid assigning stack slots to them.
855 static struct storage *emit_value(struct expression *expr)
857 struct storage *new = new_pseudo();
858 struct storage *val;
860 val = new_storage(STOR_VALUE);
861 val->value = (long long) expr->value;
862 insn("movl", val, new, NULL, ATOM_FREE_OP1);
864 return new;
867 static struct storage *emit_binop(struct expression *expr)
869 struct storage *left = x86_expression(expr->left);
870 struct storage *right = x86_expression(expr->right);
871 struct storage *new;
872 const char *opname;
873 static const char *name[] = {
874 ['+'] = "addl", ['-'] = "subl",
875 ['*'] = "mull", ['/'] = "divl",
876 ['%'] = "modl", ['&'] = "andl",
877 ['|'] = "orl", ['^'] = "xorl"
879 unsigned int op = expr->op;
882 * FIXME FIXME this routine is so wrong it's not even funny.
883 * On x86 both mod/div are handled with the same instruction.
884 * We don't pay attention to signed/unsigned issues,
885 * and like elsewhere we hardcode the operand size at 32 bits.
888 opname = show_special(op);
889 if (op < sizeof(name)/sizeof(*name)) {
890 opname = name[op];
891 assert(opname != NULL);
892 } else
893 assert(0); /* FIXME: no operations other than name[], ATM */
895 /* load op2 into EAX */
896 insn("movl", right, REG_EAX, "EXPR_BINOP/COMMA/LOGICAL", 0);
898 /* perform binop */
899 insn(opname, left, REG_EAX, NULL, 0);
901 /* store result (EAX) in new pseudo / stack slot */
902 new = new_pseudo();
903 insn("movl", REG_EAX, new, "end EXPR_BINOP", 0);
905 return new;
908 static void emit_if_conditional(struct statement *stmt)
910 struct function *f = current_func;
911 struct storage *val, *target_val;
912 int target;
913 struct expression *cond = stmt->if_conditional;
914 char s[16];
916 /* This is only valid if nobody can jump into the "dead" statement */
917 #if 0
918 if (cond->type == EXPR_VALUE) {
919 struct statement *s = stmt->if_true;
920 if (!cond->value)
921 s = stmt->if_false;
922 x86_statement(s);
923 break;
925 #endif
926 val = x86_expression(cond);
928 /* load 'if' test result into EAX */
929 insn("movl", val, REG_EAX, "begin if conditional", 0);
931 /* clear ECX */
932 insn("xorl", REG_ECX, REG_ECX, NULL, 0);
934 /* compare 'if' test result */
935 insn("cmpl", REG_EAX, REG_ECX, NULL, 0);
937 /* create end-of-if label / if-failed labelto jump to,
938 * and jump to it if the expression returned zero.
940 target = new_label();
941 target_val = new_storage(STOR_LABEL);
942 target_val->label = target;
943 insn("je", target_val, NULL, NULL, ATOM_FREE_OP1);
945 x86_statement(stmt->if_true);
946 if (stmt->if_false) {
947 struct storage *last_val;
948 int last;
950 /* finished generating code for if-true statement.
951 * add a jump-to-end jump to avoid falling through
952 * to the if-false statement code.
954 last = new_label();
955 last_val = new_storage(STOR_LABEL);
956 last_val->label = last;
957 insn("jmp", last_val, NULL, NULL, ATOM_FREE_OP1);
959 /* if we have both if-true and if-false statements,
960 * the failed-conditional case will fall through to here
962 sprintf(s, ".L%d:\n", target);
963 push_text_atom(f, s);
965 target = last;
966 x86_statement(stmt->if_false);
969 sprintf(s, ".L%d:\t\t\t\t\t# end if\n", target);
970 push_text_atom(f, s);
973 static struct storage *emit_inc_dec(struct expression *expr, int postop)
975 struct storage *addr = x86_address_gen(expr->unop);
976 struct storage *retval;
977 const char *opname = expr->op == SPECIAL_INCREMENT ? "incl" : "decl";
978 #if 0
979 /* FIXME: don't hardware operand size */
980 int bits = expr->ctype->bit_size;
981 #endif
983 if (postop) {
984 struct storage *new = new_pseudo();
986 emit_move(NULL, new, addr, 1234 /* intentionally bogus */);
988 retval = new;
989 } else
990 retval = addr;
992 insn(opname, addr, NULL, NULL, 0);
994 return retval;
997 static struct storage *emit_postop(struct expression *expr)
999 return emit_inc_dec(expr, 1);
1002 static struct storage *emit_return_stmt(struct statement *stmt)
1004 struct function *f = current_func;
1005 struct expression *expr = stmt->ret_value;
1006 struct storage *val = NULL;
1007 char s[32];
1009 if (expr && expr->ctype)
1010 val = x86_expression(expr);
1012 sprintf(s, "\tjmp\t.L%d\n", f->ret_target);
1013 push_text_atom(f, s);
1015 return val;
1018 static void x86_struct_member(struct symbol *sym, void *data, int flags)
1020 if (flags & ITERATE_FIRST)
1021 printf(" {\n\t");
1022 printf("%s:%d:%ld at offset %ld", show_ident(sym->ident), sym->bit_size, sym->ctype.alignment, sym->offset);
1023 if (sym->fieldwidth)
1024 printf("[%d..%d]", sym->bit_offset, sym->bit_offset+sym->fieldwidth-1);
1025 if (flags & ITERATE_LAST)
1026 printf("\n} ");
1027 else
1028 printf(", ");
1031 static void x86_symbol(struct symbol *sym)
1033 struct symbol *type;
1035 if (!sym)
1036 return;
1038 type = sym->ctype.base_type;
1039 if (!type)
1040 return;
1043 * Show actual implementation information
1045 switch (type->type) {
1047 case SYM_ARRAY:
1048 if (sym->initializer)
1049 emit_array(sym);
1050 else
1051 emit_array_noinit(sym);
1052 break;
1054 case SYM_BASETYPE:
1055 if (sym->initializer) {
1056 emit_object_pre(show_ident(sym->ident),
1057 sym->ctype.modifiers,
1058 sym->ctype.alignment,
1059 sym->bit_size / 8);
1060 emit_scalar(sym->initializer, sym->bit_size);
1061 stor_sym_init(sym);
1062 } else
1063 emit_scalar_noinit(sym);
1064 break;
1066 case SYM_STRUCT:
1067 symbol_iterate(type->symbol_list, x86_struct_member, NULL);
1068 break;
1070 case SYM_UNION:
1071 symbol_iterate(type->symbol_list, x86_struct_member, NULL);
1072 break;
1074 case SYM_FN: {
1075 struct statement *stmt = type->stmt;
1076 if (stmt) {
1077 struct storage *val;
1079 emit_func_pre(sym);
1080 val = x86_statement(stmt);
1081 emit_func_post(sym, val);
1083 break;
1086 default:
1087 break;
1090 if (sym->initializer && (type->type != SYM_BASETYPE) &&
1091 (type->type != SYM_ARRAY)) {
1092 printf(" = \n");
1093 x86_expression(sym->initializer);
1097 static void x86_symbol_init(struct symbol *sym);
1099 static void x86_switch_statement(struct statement *stmt)
1101 struct storage *val = x86_expression(stmt->switch_expression);
1102 struct symbol *sym;
1103 printf("\tswitch v%d\n", val->pseudo);
1106 * Debugging only: Check that the case list is correct
1107 * by printing it out.
1109 * This is where a _real_ back-end would go through the
1110 * cases to decide whether to use a lookup table or a
1111 * series of comparisons etc
1113 printf("# case table:\n");
1114 FOR_EACH_PTR(stmt->switch_case->symbol_list, sym) {
1115 struct statement *case_stmt = sym->stmt;
1116 struct expression *expr = case_stmt->case_expression;
1117 struct expression *to = case_stmt->case_to;
1119 if (!expr) {
1120 printf(" default");
1121 } else {
1122 if (expr->type == EXPR_VALUE) {
1123 printf(" case %lld", expr->value);
1124 if (to) {
1125 if (to->type == EXPR_VALUE) {
1126 printf(" .. %lld", to->value);
1127 } else {
1128 printf(" .. what?");
1131 } else
1132 printf(" what?");
1134 printf(": .L%p\n", sym);
1135 } END_FOR_EACH_PTR;
1136 printf("# end case table\n");
1138 x86_statement(stmt->switch_statement);
1140 if (stmt->switch_break->used)
1141 printf(".L%p:\n", stmt->switch_break);
1144 static void x86_symbol_decl(struct symbol_list *syms)
1146 struct symbol *sym;
1147 FOR_EACH_PTR(syms, sym) {
1148 x86_symbol_init(sym);
1149 } END_FOR_EACH_PTR;
1153 * Print out a statement
1155 static struct storage *x86_statement(struct statement *stmt)
1157 if (!stmt)
1158 return 0;
1159 switch (stmt->type) {
1160 case STMT_RETURN:
1161 return emit_return_stmt(stmt);
1162 case STMT_COMPOUND: {
1163 struct statement *s;
1164 struct storage *last = NULL;
1166 x86_symbol_decl(stmt->syms);
1167 FOR_EACH_PTR(stmt->stmts, s) {
1168 last = x86_statement(s);
1169 } END_FOR_EACH_PTR;
1171 return last;
1174 case STMT_EXPRESSION:
1175 return x86_expression(stmt->expression);
1176 case STMT_IF:
1177 emit_if_conditional(stmt);
1178 return NULL;
1179 case STMT_SWITCH:
1180 x86_switch_statement(stmt);
1181 break;
1183 case STMT_CASE:
1184 printf(".L%p:\n", stmt->case_label);
1185 x86_statement(stmt->case_statement);
1186 break;
1188 case STMT_ITERATOR: {
1189 struct statement *pre_statement = stmt->iterator_pre_statement;
1190 struct expression *pre_condition = stmt->iterator_pre_condition;
1191 struct statement *statement = stmt->iterator_statement;
1192 struct statement *post_statement = stmt->iterator_post_statement;
1193 struct expression *post_condition = stmt->iterator_post_condition;
1194 int loop_top = 0, loop_bottom = 0;
1195 struct storage *val;
1197 x86_symbol_decl(stmt->iterator_syms);
1198 x86_statement(pre_statement);
1199 if (pre_condition) {
1200 if (pre_condition->type == EXPR_VALUE) {
1201 if (!pre_condition->value) {
1202 loop_bottom = new_label();
1203 printf("\tjmp\t\t.L%d\n", loop_bottom);
1205 } else {
1206 loop_bottom = new_label();
1207 val = x86_expression(pre_condition);
1208 printf("\tje\t\tv%d, .L%d\n", val->pseudo, loop_bottom);
1211 if (!post_condition || post_condition->type != EXPR_VALUE || post_condition->value) {
1212 loop_top = new_label();
1213 printf(".L%d:\n", loop_top);
1215 x86_statement(statement);
1216 if (stmt->iterator_continue->used)
1217 printf(".L%p:\n", stmt->iterator_continue);
1218 x86_statement(post_statement);
1219 if (!post_condition) {
1220 printf("\tjmp\t\t.L%d\n", loop_top);
1221 } else if (post_condition->type == EXPR_VALUE) {
1222 if (post_condition->value)
1223 printf("\tjmp\t\t.L%d\n", loop_top);
1224 } else {
1225 val = x86_expression(post_condition);
1226 printf("\tjne\t\tv%d, .L%d\n", val->pseudo, loop_top);
1228 if (stmt->iterator_break->used)
1229 printf(".L%p:\n", stmt->iterator_break);
1230 if (loop_bottom)
1231 printf(".L%d:\n", loop_bottom);
1232 break;
1234 case STMT_NONE:
1235 break;
1237 case STMT_LABEL:
1238 printf(".L%p:\n", stmt->label_identifier);
1239 x86_statement(stmt->label_statement);
1240 break;
1242 case STMT_GOTO:
1243 if (stmt->goto_expression) {
1244 struct storage *val = x86_expression(stmt->goto_expression);
1245 printf("\tgoto *v%d\n", val->pseudo);
1246 } else {
1247 printf("\tgoto .L%p\n", stmt->goto_label);
1249 break;
1250 case STMT_ASM:
1251 printf("\tasm( .... )\n");
1252 break;
1255 return 0;
1258 static struct storage *x86_call_expression(struct expression *expr)
1260 struct function *f = current_func;
1261 struct symbol *direct;
1262 struct expression *arg, *fn;
1263 struct storage *retval, *fncall;
1264 int framesize;
1266 if (!expr->ctype) {
1267 warn(expr->pos, "\tcall with no type!");
1268 return NULL;
1271 framesize = 0;
1272 FOR_EACH_PTR_REVERSE(expr->args, arg) {
1273 struct storage *new = x86_expression(arg);
1274 int size = arg->ctype->bit_size;
1276 /* FIXME: pay attention to 'size' */
1277 insn("pushl", new, NULL,
1278 !framesize ? "begin function call" : NULL, 0);
1280 framesize += size >> 3;
1281 } END_FOR_EACH_PTR_REVERSE;
1283 fn = expr->fn;
1285 /* Remove dereference, if any */
1286 direct = NULL;
1287 if (fn->type == EXPR_PREOP) {
1288 if (fn->unop->type == EXPR_SYMBOL) {
1289 struct symbol *sym = fn->unop->symbol;
1290 if (sym->ctype.base_type->type == SYM_FN)
1291 direct = sym;
1294 if (direct) {
1295 char s[64];
1296 sprintf(s, "\tcall\t%s\n", show_ident(direct->ident));
1297 push_text_atom(f, s);
1298 } else {
1299 fncall = x86_expression(fn);
1300 printf("\tcall\t*v%d\n", fncall->pseudo);
1303 /* FIXME: pay attention to BITS_IN_POINTER */
1304 if (framesize) {
1305 struct storage *val = new_storage(STOR_VALUE);
1306 val->value = (long long) framesize;
1307 insn("addl", val, REG_ESP, "end function call", ATOM_FREE_OP1);
1310 retval = new_pseudo();
1311 printf("\tmov.%d\t\tv%d,retval\n", expr->ctype->bit_size, retval->pseudo);
1312 return retval;
1315 static struct storage *x86_regular_preop(struct expression *expr)
1317 struct storage *target = x86_expression(expr->unop);
1318 struct storage *new = new_pseudo();
1319 static const char *name[] = {
1320 ['!'] = "nonzero", ['-'] = "neg",
1321 ['~'] = "not",
1323 unsigned int op = expr->op;
1324 const char *opname;
1326 opname = show_special(op);
1327 if (op < sizeof(name)/sizeof(*name))
1328 opname = name[op];
1329 printf("\t%s.%d\t\tv%d,v%d\n", opname, expr->ctype->bit_size, new->pseudo, target->pseudo);
1330 return new;
1334 * FIXME! Not all accesses are memory loads. We should
1335 * check what kind of symbol is behind the dereference.
1337 static struct storage *x86_address_gen(struct expression *expr)
1339 if (expr->type == EXPR_PREOP)
1340 return x86_expression(expr->unop);
1341 return x86_expression(expr->address);
1344 static struct storage *x86_assignment(struct expression *expr)
1346 struct expression *target = expr->left;
1347 struct storage *val, *addr;
1348 int bits;
1350 if (!expr->ctype)
1351 return NULL;
1353 bits = expr->ctype->bit_size;
1354 val = x86_expression(expr->right);
1355 addr = x86_address_gen(target);
1356 emit_move(target, addr, val, bits);
1357 return val;
1360 static int x86_initialization(struct symbol *sym, struct expression *expr)
1362 struct storage *val, *addr;
1363 int bits;
1365 if (!expr->ctype)
1366 return 0;
1368 bits = expr->ctype->bit_size;
1369 val = x86_expression(expr);
1370 addr = x86_symbol_expr(sym);
1371 // FIXME! The "target" expression is for bitfield store information.
1372 // Leave it NULL, which works fine.
1373 emit_store(NULL, addr, val, bits);
1374 return 0;
1377 static struct storage *x86_access(struct expression *expr)
1379 return x86_address_gen(expr);
1382 static struct storage *x86_preop(struct expression *expr)
1385 * '*' is an lvalue access, and is fundamentally different
1386 * from an arithmetic operation. Maybe it should have an
1387 * expression type of its own..
1389 if (expr->op == '*')
1390 return x86_access(expr);
1391 if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT)
1392 return emit_inc_dec(expr, 0);
1393 return x86_regular_preop(expr);
1396 static struct storage *x86_symbol_expr(struct symbol *sym)
1398 struct storage *new = new_pseudo();
1400 if (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_EXTERN | MOD_STATIC)) {
1401 printf("\tmovi.%d\t\tv%d,$%s\n", BITS_IN_POINTER, new->pseudo, show_ident(sym->ident));
1402 return new;
1404 if (sym->ctype.modifiers & MOD_ADDRESSABLE) {
1405 printf("\taddi.%d\t\tv%d,vFP,$%lld\n", BITS_IN_POINTER, new->pseudo, sym->value);
1406 return new;
1408 printf("\taddi.%d\t\tv%d,vFP,$offsetof(%s:%p)\n", BITS_IN_POINTER, new->pseudo, show_ident(sym->ident), sym);
1409 return new;
1412 static void x86_symbol_init(struct symbol *sym)
1414 struct symbol_private *priv = sym->aux;
1415 struct expression *expr = sym->initializer;
1416 struct storage *new;
1418 if (expr)
1419 new = x86_expression(expr);
1420 else
1421 new = new_pseudo();
1423 if (!priv) {
1424 priv = calloc(1, sizeof(*priv));
1425 sym->aux = priv;
1426 /* FIXME: leak! we don't free... */
1427 /* (well, we don't free symbols either) */
1430 priv->addr = new;
1433 static int type_is_signed(struct symbol *sym)
1435 if (sym->type == SYM_NODE)
1436 sym = sym->ctype.base_type;
1437 if (sym->type == SYM_PTR)
1438 return 0;
1439 return !(sym->ctype.modifiers & MOD_UNSIGNED);
1442 static struct storage *x86_cast_expr(struct expression *expr)
1444 struct symbol *old_type, *new_type;
1445 struct storage *op = x86_expression(expr->cast_expression);
1446 int oldbits, newbits;
1447 int is_signed;
1448 struct storage *new;
1450 old_type = expr->cast_expression->ctype;
1451 new_type = expr->cast_type;
1453 oldbits = old_type->bit_size;
1454 newbits = new_type->bit_size;
1455 if (oldbits >= newbits)
1456 return op;
1457 new = new_pseudo();
1458 is_signed = type_is_signed(old_type);
1459 if (is_signed) {
1460 printf("\tsext%d.%d\tv%d,v%d\n", oldbits, newbits, new->pseudo, op->pseudo);
1461 } else {
1462 printf("\tandl.%d\t\tv%d,v%d,$%lu\n", newbits, new->pseudo, op->pseudo, (1UL << oldbits)-1);
1464 return new;
1467 static struct storage *show_string_expr(struct expression *expr)
1469 struct storage *new = new_pseudo();
1471 printf("\tmovi.%d\t\tv%d,&%s\n", BITS_IN_POINTER, new->pseudo,
1472 show_string(expr->string));
1473 return new;
1476 static struct storage *x86_bitfield_expr(struct expression *expr)
1478 return x86_access(expr);
1481 static struct storage *x86_label_expr(struct expression *expr)
1483 struct storage *new = new_pseudo();
1484 printf("\tmovi.%d\t\tv%d,.L%p\n",BITS_IN_POINTER, new->pseudo, expr->label_symbol);
1485 return new;
1488 static struct storage *x86_conditional_expr(struct expression *expr)
1490 struct storage *cond = x86_expression(expr->conditional);
1491 struct storage *true = x86_expression(expr->cond_true);
1492 struct storage *false = x86_expression(expr->cond_false);
1493 struct storage *new = new_pseudo();
1495 if (!true)
1496 true = cond;
1497 printf("[v%d]\tcmov.%d\t\tv%d,v%d,v%d\n",
1498 cond->pseudo, expr->ctype->bit_size, new->pseudo,
1499 true->pseudo, false->pseudo);
1500 return new;
1503 static struct storage *x86_statement_expr(struct expression *expr)
1505 return x86_statement(expr->statement);
1508 static int x86_position_expr(struct expression *expr, struct symbol *base)
1510 struct storage *new = x86_expression(expr->init_expr);
1511 struct symbol *ctype = expr->init_sym;
1513 printf("\tinsert v%d at [%d:%d] of %s\n", new->pseudo,
1514 expr->init_offset, ctype->bit_offset,
1515 show_ident(base->ident));
1516 return 0;
1519 static void x86_initializer_expr(struct expression *expr, struct symbol *ctype)
1521 struct expression *entry;
1523 FOR_EACH_PTR(expr->expr_list, entry) {
1524 // Nested initializers have their positions already
1525 // recursively calculated - just output them too
1526 if (entry->type == EXPR_INITIALIZER) {
1527 x86_initializer_expr(entry, ctype);
1528 continue;
1531 // Ignore initializer indexes and identifiers - the
1532 // evaluator has taken them into account
1533 if (entry->type == EXPR_IDENTIFIER || entry->type == EXPR_INDEX)
1534 continue;
1535 if (entry->type == EXPR_POS) {
1536 x86_position_expr(entry, ctype);
1537 continue;
1539 x86_initialization(ctype, entry);
1540 } END_FOR_EACH_PTR;
1543 static struct storage *x86_symbol_expr_init(struct symbol *sym)
1545 struct expression *expr = sym->initializer;
1546 struct symbol_private *priv = sym->aux;
1548 if (expr)
1549 x86_initializer_expr(expr, expr->ctype);
1551 if (priv == NULL) {
1552 fprintf(stderr, "WARNING! priv == NULL\n");
1553 priv = calloc(1, sizeof(*priv));
1554 sym->aux = priv;
1555 priv->addr = new_pseudo(); /* this is wrong! */
1558 return priv->addr;
1562 * Print out an expression. Return the pseudo that contains the
1563 * variable.
1565 static struct storage *x86_expression(struct expression *expr)
1567 if (!expr)
1568 return 0;
1570 if (!expr->ctype) {
1571 struct position *pos = &expr->pos;
1572 printf("\tno type at %s:%d:%d\n",
1573 input_streams[pos->stream].name,
1574 pos->line, pos->pos);
1575 return 0;
1578 switch (expr->type) {
1579 case EXPR_CALL:
1580 return x86_call_expression(expr);
1582 case EXPR_ASSIGNMENT:
1583 return x86_assignment(expr);
1585 case EXPR_COMPARE:
1586 return emit_compare(expr);
1587 case EXPR_BINOP:
1588 case EXPR_COMMA:
1589 case EXPR_LOGICAL:
1590 return emit_binop(expr);
1591 case EXPR_PREOP:
1592 return x86_preop(expr);
1593 case EXPR_POSTOP:
1594 return emit_postop(expr);
1595 case EXPR_SYMBOL:
1596 return x86_symbol_expr_init(expr->symbol);
1597 case EXPR_DEREF:
1598 case EXPR_SIZEOF:
1599 warn(expr->pos, "invalid expression after evaluation");
1600 return 0;
1601 case EXPR_CAST:
1602 return x86_cast_expr(expr);
1603 case EXPR_VALUE:
1604 return emit_value(expr);
1605 case EXPR_STRING:
1606 return show_string_expr(expr);
1607 case EXPR_BITFIELD:
1608 return x86_bitfield_expr(expr);
1609 case EXPR_INITIALIZER:
1610 x86_initializer_expr(expr, expr->ctype);
1611 return NULL;
1612 case EXPR_CONDITIONAL:
1613 return x86_conditional_expr(expr);
1614 case EXPR_STATEMENT:
1615 return x86_statement_expr(expr);
1616 case EXPR_LABEL:
1617 return x86_label_expr(expr);
1619 // None of these should exist as direct expressions: they are only
1620 // valid as sub-expressions of initializers.
1621 case EXPR_POS:
1622 warn(expr->pos, "unable to show plain initializer position expression");
1623 return 0;
1624 case EXPR_IDENTIFIER:
1625 warn(expr->pos, "unable to show identifier expression");
1626 return 0;
1627 case EXPR_INDEX:
1628 warn(expr->pos, "unable to show index expression");
1629 return 0;
1631 return 0;