[be] comparison, signedness, and operand size update
[smatch.git] / compile-i386.c
blob4e1a2852b5124d0649de312f0b52ed4e82aafed9
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" },
135 { "%dl" },
138 static struct storage hardreg_storage_table[] = {
139 { /* eax */
140 .type = STOR_REG,
141 .reg = &reg_info_table[0],
144 { /* ecx */
145 .type = STOR_REG,
146 .reg = &reg_info_table[1],
149 { /* edx */
150 .type = STOR_REG,
151 .reg = &reg_info_table[2],
154 { /* esp */
155 .type = STOR_REG,
156 .reg = &reg_info_table[3],
159 { /* dl */
160 .type = STOR_REG,
161 .reg = &reg_info_table[4],
165 #define REG_EAX (&hardreg_storage_table[0])
166 #define REG_ECX (&hardreg_storage_table[1])
167 #define REG_EDX (&hardreg_storage_table[2])
168 #define REG_ESP (&hardreg_storage_table[3])
169 #define REG_DL (&hardreg_storage_table[4])
172 static void emit_move(struct storage *src, struct storage *dest,
173 struct symbol *ctype, const char *comment,
174 unsigned long flags);
175 static int type_is_signed(struct symbol *sym);
176 static struct storage *x86_address_gen(struct expression *expr);
177 static struct storage *x86_symbol_expr(struct symbol *sym);
178 static void x86_symbol(struct symbol *sym);
179 static struct storage *x86_statement(struct statement *stmt);
180 static struct storage *x86_expression(struct expression *expr);
183 static inline unsigned int pseudo_offset(struct storage *s)
185 if (s->type != STOR_PSEUDO)
186 return 123456; /* intentionally bogus value */
188 return ((s->pseudo - 1) * 4);
191 static inline unsigned int arg_offset(struct storage *s)
193 if (s->type != STOR_ARG)
194 return 123456; /* intentionally bogus value */
196 /* FIXME: this is wrong wrong wrong */
197 return (current_func->pseudo_nr + 1 + s->idx) * 4;
200 static const char *pretty_offset(int ofs)
202 static char esp_buf[64];
204 if (ofs)
205 sprintf(esp_buf, "%d(%%esp)", ofs);
206 else
207 strcpy(esp_buf, "(%esp)");
209 return esp_buf;
212 static void stor_sym_init(struct symbol *sym)
214 struct storage *stor;
215 struct symbol_private *priv;
217 priv = calloc(1, sizeof(*priv) + sizeof(*stor));
218 if (!priv)
219 die("OOM in stor_sym_init");
221 stor = (struct storage *) (priv + 1);
223 priv->addr = stor;
224 stor->type = STOR_SYM;
225 stor->sym = sym;
228 static const char *stor_op_name(struct storage *s)
230 static char name[32];
232 switch (s->type) {
233 case STOR_PSEUDO:
234 strcpy(name, pretty_offset((int) pseudo_offset(s)));
235 break;
236 case STOR_ARG:
237 strcpy(name, pretty_offset((int) arg_offset(s)));
238 break;
239 case STOR_SYM:
240 strcpy(name, show_ident(s->sym->ident));
241 break;
242 case STOR_REG:
243 strcpy(name, s->reg->name);
244 break;
245 case STOR_VALUE:
246 sprintf(name, "$%Ld", s->value);
247 break;
248 case STOR_LABEL:
249 sprintf(name, ".L%d", s->label);
250 break;
253 return name;
256 static struct atom *new_atom(enum atom_type type)
258 struct atom *atom;
260 atom = calloc(1, sizeof(*atom)); /* TODO: chunked alloc */
261 if (!atom)
262 die("nuclear OOM");
264 atom->type = type;
266 return atom;
269 static inline void push_atom(struct function *f, struct atom *atom)
271 add_ptr_list(&f->atom_list, atom);
274 static void push_text_atom(struct function *f, const char *text)
276 struct atom *atom = new_atom(ATOM_TEXT);
278 atom->text = strdup(text);
279 atom->text_len = strlen(text);
281 push_atom(f, atom);
284 static struct storage *new_storage(enum storage_type type)
286 struct storage *stor;
288 stor = calloc(1, sizeof(*stor));
289 if (!stor)
290 die("OOM in new_storage");
292 stor->type = type;
294 return stor;
297 static struct storage *new_pseudo(void)
299 struct function *f = current_func;
300 struct storage *stor;
302 assert(f != NULL);
304 stor = new_storage(STOR_PSEUDO);
305 stor->type = STOR_PSEUDO;
306 stor->pseudo = ++f->pseudo_nr;
308 add_ptr_list(&f->pseudo_list, stor);
310 return stor;
313 static int new_label(void)
315 static int label = 0;
316 return ++label;
319 static void textbuf_push(struct textbuf **buf_p, const char *text)
321 struct textbuf *tmp, *list = *buf_p;
322 unsigned int text_len = strlen(text);
323 unsigned int alloc_len = text_len + 1 + sizeof(*list);
325 tmp = calloc(1, alloc_len);
326 if (!tmp)
327 die("OOM on textbuf alloc");
329 tmp->text = ((void *) tmp) + sizeof(*tmp);
330 memcpy(tmp->text, text, text_len + 1);
331 tmp->len = text_len;
333 /* add to end of list */
334 if (!list) {
335 list = tmp;
336 tmp->prev = tmp;
337 } else {
338 tmp->prev = list->prev;
339 tmp->prev->next = tmp;
340 list->prev = tmp;
342 tmp->next = list;
344 *buf_p = list;
347 static void textbuf_emit(struct textbuf **buf_p)
349 struct textbuf *tmp, *list = *buf_p;
351 while (list) {
352 tmp = list;
353 if (tmp->next == tmp)
354 list = NULL;
355 else {
356 tmp->prev->next = tmp->next;
357 tmp->next->prev = tmp->prev;
358 list = tmp->next;
361 fputs(tmp->text, stdout);
363 free(tmp);
366 *buf_p = list;
369 static void insn(const char *insn, struct storage *op1, struct storage *op2,
370 const char *comment_in, unsigned long flags)
372 struct function *f = current_func;
373 struct atom *atom = new_atom(ATOM_INSN);
375 assert(insn != NULL);
377 strcpy(atom->insn, insn);
378 if (comment_in && (*comment_in))
379 strncpy(atom->comment, comment_in,
380 sizeof(atom->comment) - 1);
382 atom->op1 = op1;
383 atom->op2 = op2;
384 atom->flags = flags;
386 push_atom(f, atom);
389 static void emit_unit_pre(const char *basename)
391 printf("\t.file\t\"%s\"\n", basename);
394 static void emit_unit_post(void)
396 textbuf_emit(&unit_post_text);
397 printf("\t.ident\t\"sparse silly x86 backend (built %s)\"\n", __DATE__);
400 /* conditionally switch sections */
401 static void emit_section(const char *s)
403 if (s == current_section)
404 return;
405 if (current_section && (!strcmp(s, current_section)))
406 return;
408 printf("\t%s\n", s);
409 current_section = s;
412 static void emit_insn_atom(struct function *f, struct atom *atom)
414 char s[128];
415 char comment[64];
417 if (atom->comment[0])
418 sprintf(comment, "\t\t# %s", atom->comment);
419 else
420 comment[0] = 0;
422 if (atom->op2) {
423 char tmp[16];
424 strcpy(tmp, stor_op_name(atom->op1));
425 sprintf(s, "\t%s\t%s, %s%s\n",
426 atom->insn, tmp, stor_op_name(atom->op2), comment);
427 } else if (atom->op1)
428 sprintf(s, "\t%s\t%s%s%s\n",
429 atom->insn, stor_op_name(atom->op1),
430 comment[0] ? "\t" : "", comment);
431 else
432 sprintf(s, "\t%s\t%s%s\n",
433 atom->insn,
434 comment[0] ? "\t\t" : "", comment);
436 write(STDOUT_FILENO, s, strlen(s));
439 static void emit_atom_list(struct function *f)
441 struct atom *atom;
443 FOR_EACH_PTR(f->atom_list, atom) {
444 switch (atom->type) {
445 case ATOM_TEXT: {
446 ssize_t rc = write(STDOUT_FILENO, atom->text,
447 atom->text_len);
448 (void) rc; /* FIXME */
449 break;
451 case ATOM_INSN:
452 emit_insn_atom(f, atom);
453 break;
455 } END_FOR_EACH_PTR;
458 static void func_cleanup(struct function *f)
460 struct storage *stor;
461 struct atom *atom;
463 FOR_EACH_PTR(f->pseudo_list, stor) {
464 free(stor);
465 } END_FOR_EACH_PTR;
467 FOR_EACH_PTR(f->atom_list, atom) {
468 if ((atom->type == ATOM_TEXT) && (atom->text))
469 free(atom->text);
470 if (atom->flags & ATOM_FREE_OP1)
471 free(atom->op1);
472 if (atom->flags & ATOM_FREE_OP2)
473 free(atom->op2);
474 free(atom);
475 } END_FOR_EACH_PTR;
477 free_ptr_list(&f->pseudo_list);
478 free(f);
481 /* function prologue */
482 static void emit_func_pre(struct symbol *sym)
484 const char *name = show_ident(sym->ident);
485 struct function *f;
486 struct symbol *arg;
487 unsigned int i, argc = 0, alloc_len;
488 unsigned char *mem;
489 struct symbol_private *privbase;
490 struct storage *storage_base;
491 struct symbol *base_type = sym->ctype.base_type;
493 FOR_EACH_PTR(base_type->arguments, arg) {
494 argc++;
495 } END_FOR_EACH_PTR;
497 alloc_len =
498 sizeof(*f) +
499 (argc * sizeof(struct symbol *)) +
500 (argc * sizeof(struct symbol_private)) +
501 (argc * sizeof(struct storage));
502 mem = calloc(1, alloc_len);
503 if (!mem)
504 die("OOM on func info");
506 f = (struct function *) mem;
507 mem += sizeof(*f);
508 f->argv = (struct symbol **) mem;
509 mem += (argc * sizeof(struct symbol *));
510 privbase = (struct symbol_private *) mem;
511 mem += (argc * sizeof(struct symbol_private));
512 storage_base = (struct storage *) mem;
514 f->argc = argc;
515 f->ret_target = new_label();
517 i = 0;
518 FOR_EACH_PTR(base_type->arguments, arg) {
519 f->argv[i] = arg;
520 arg->aux = &privbase[i];
521 storage_base[i].type = STOR_ARG;
522 storage_base[i].idx = i;
523 privbase[i].addr = &storage_base[i];
524 i++;
525 } END_FOR_EACH_PTR;
527 assert(current_func == NULL);
528 current_func = f;
530 emit_section(".text");
531 if ((sym->ctype.modifiers & MOD_STATIC) == 0)
532 printf(".globl %s\n", name);
533 printf("\t.type\t%s, @function\n", name);
534 printf("%s:\n", name);
537 /* function epilogue */
538 static void emit_func_post(struct symbol *sym, struct storage *ret_val)
540 const char *name = show_ident(sym->ident);
541 struct function *f = current_func;
542 struct storage *val;
543 int pseudo_nr = f->pseudo_nr;
544 char pseudo_const[16], jump_target[16];
546 /* function epilogue */
547 sprintf(pseudo_const, "$%d", pseudo_nr * 4);
548 printf("\tsubl\t%s, %%esp\n", pseudo_const);
550 /* jump target for 'return' statements */
551 sprintf(jump_target, ".L%d:\n", f->ret_target);
552 push_text_atom(f, jump_target);
554 /* function prologue */
555 if (ret_val) {
556 /* FIXME: mem operand hardcoded at 32 bits */
557 emit_move(ret_val, REG_EAX, NULL, NULL, 0);
560 val = new_storage(STOR_VALUE);
561 val->value = (long long) (pseudo_nr * 4);
563 insn("addl", val, REG_ESP, NULL, ATOM_FREE_OP1);
564 insn("ret", NULL, NULL, NULL, 0);
566 /* output everything to stdout */
567 fflush(stdout); /* paranoia; needed? */
568 emit_atom_list(f);
570 /* function footer */
571 printf("\t.size\t%s, .-%s\n", name, name);
573 func_cleanup(f);
574 current_func = NULL;
577 /* emit object (a.k.a. variable, a.k.a. data) prologue */
578 static void emit_object_pre(const char *name, unsigned long modifiers,
579 unsigned long alignment, unsigned int byte_size)
581 if ((modifiers & MOD_STATIC) == 0)
582 printf(".globl %s\n", name);
583 emit_section(".data");
584 if (alignment)
585 printf("\t.align %lu\n", alignment);
586 printf("\t.type\t%s, @object\n", name);
587 printf("\t.size\t%s, %d\n", name, byte_size);
588 printf("%s:\n", name);
591 /* emit value (only) for an initializer scalar */
592 static void emit_scalar(struct expression *expr, unsigned int bit_size)
594 const char *type;
595 long long ll;
597 assert(expr->type == EXPR_VALUE);
599 if (expr->value == 0ULL) {
600 printf("\t.zero\t%d\n", bit_size / 8);
601 return;
604 ll = (long long) expr->value;
606 switch (bit_size) {
607 case 8: type = "byte"; ll = (char) ll; break;
608 case 16: type = "value"; ll = (short) ll; break;
609 case 32: type = "long"; ll = (int) ll; break;
610 case 64: type = "quad"; break;
611 default: type = NULL; break;
614 assert(type != NULL);
616 printf("\t.%s\t%Ld\n", type, ll);
619 static void emit_global_noinit(const char *name, unsigned long modifiers,
620 unsigned long alignment, unsigned int byte_size)
622 char s[64];
624 if (modifiers & MOD_STATIC) {
625 sprintf(s, "\t.local\t%s\n", name);
626 textbuf_push(&unit_post_text, s);
628 if (alignment)
629 sprintf(s, "\t.comm\t%s,%d,%lu\n", name, byte_size, alignment);
630 else
631 sprintf(s, "\t.comm\t%s,%d\n", name, byte_size);
632 textbuf_push(&unit_post_text, s);
635 static int ea_current, ea_last;
637 static void emit_initializer(struct symbol *sym,
638 struct expression *expr)
640 int distance = ea_current - ea_last - 1;
642 if (distance > 0)
643 printf("\t.zero\t%d\n", (sym->bit_size / 8) * distance);
645 if (expr->type == EXPR_VALUE) {
646 struct symbol *base_type = sym->ctype.base_type;
647 assert(base_type != NULL);
649 emit_scalar(expr, sym->bit_size / base_type->array_size);
650 return;
652 if (expr->type != EXPR_INITIALIZER)
653 return;
655 assert(0); /* FIXME */
658 static int sort_array_cmp(const struct expression *a,
659 const struct expression *b)
661 int a_ofs = 0, b_ofs = 0;
663 if (a->type == EXPR_POS)
664 a_ofs = (int) a->init_offset;
665 if (b->type == EXPR_POS)
666 b_ofs = (int) b->init_offset;
668 return a_ofs - b_ofs;
671 /* move to front-end? */
672 static void sort_array(struct expression *expr)
674 struct expression *entry, **list;
675 unsigned int elem, sorted, i;
677 elem = 0;
678 FOR_EACH_PTR(expr->expr_list, entry) {
679 elem++;
680 } END_FOR_EACH_PTR;
682 if (!elem)
683 return;
685 list = malloc(sizeof(entry) * elem);
686 if (!list)
687 die("OOM in sort_array");
689 /* this code is no doubt evil and ignores EXPR_INDEX possibly
690 * to its detriment and other nasty things. improvements
691 * welcome.
693 i = 0;
694 sorted = 0;
695 FOR_EACH_PTR(expr->expr_list, entry) {
696 if ((entry->type == EXPR_POS) || (entry->type == EXPR_VALUE)) {
697 /* add entry to list[], in sorted order */
698 if (sorted == 0) {
699 list[0] = entry;
700 sorted = 1;
701 } else {
702 unsigned int i;
704 for (i = 0; i < sorted; i++)
705 if (sort_array_cmp(entry, list[i]) <= 0)
706 break;
708 /* If inserting into the middle of list[]
709 * instead of appending, we memmove.
710 * This is ugly, but thankfully
711 * uncommon. Input data with tons of
712 * entries very rarely have explicit
713 * offsets. convert to qsort eventually...
715 if (i != sorted)
716 memmove(&list[i + 1], &list[i],
717 (sorted - i) * sizeof(entry));
718 list[i] = entry;
719 sorted++;
722 } END_FOR_EACH_PTR;
724 i = 0;
725 FOR_EACH_PTR(expr->expr_list, entry) {
726 if ((entry->type == EXPR_POS) || (entry->type == EXPR_VALUE))
727 __list->list[__i] = list[i++];
728 } END_FOR_EACH_PTR;
732 static void emit_array(struct symbol *sym)
734 struct symbol *base_type = sym->ctype.base_type;
735 struct expression *expr = sym->initializer;
736 struct expression *entry;
738 assert(base_type != NULL);
740 stor_sym_init(sym);
742 ea_last = -1;
744 emit_object_pre(show_ident(sym->ident), sym->ctype.modifiers,
745 sym->ctype.alignment,
746 sym->bit_size / 8);
748 sort_array(expr);
750 FOR_EACH_PTR(expr->expr_list, entry) {
751 if (entry->type == EXPR_VALUE) {
752 ea_current = 0;
753 emit_initializer(sym, entry);
754 ea_last = ea_current;
755 } else if (entry->type == EXPR_POS) {
756 ea_current =
757 entry->init_offset / (base_type->bit_size / 8);
758 emit_initializer(sym, entry->init_expr);
759 ea_last = ea_current;
761 } END_FOR_EACH_PTR;
764 static void emit_one_symbol(struct symbol *sym, void *dummy, int flags)
766 x86_symbol(sym);
769 void emit_unit(const char *basename, struct symbol_list *list)
771 emit_unit_pre(basename);
772 symbol_iterate(list, emit_one_symbol, NULL);
773 emit_unit_post();
776 static void emit_copy(struct storage *src, struct symbol *src_ctype,
777 struct storage *dest, struct symbol *dest_ctype)
779 /* FIXME: Bitfield move! */
781 emit_move(src, REG_EAX, src_ctype, "begin copy ...", 0);
782 emit_move(REG_EAX, dest, dest_ctype, "... end copy", 0);
785 static void emit_store(struct expression *dest_expr, struct storage *dest,
786 struct storage *src, int bits)
788 /* FIXME: Bitfield store! */
789 printf("\tst.%d\t\tv%d,[v%d]\n", bits, src->pseudo, dest->pseudo);
792 static void emit_scalar_noinit(struct symbol *sym)
794 emit_global_noinit(show_ident(sym->ident),
795 sym->ctype.modifiers, sym->ctype.alignment,
796 sym->bit_size / 8);
797 stor_sym_init(sym);
800 static void emit_array_noinit(struct symbol *sym)
802 emit_global_noinit(show_ident(sym->ident),
803 sym->ctype.modifiers, sym->ctype.alignment,
804 sym->array_size * (sym->bit_size / 8));
805 stor_sym_init(sym);
808 static const char *opbits(const char *insn, unsigned int bits)
810 static char opbits_str[32];
811 char c;
813 switch (bits) {
814 case 8: c = 'b'; break;
815 case 16: c = 'w'; break;
816 case 32: c = 'l'; break;
817 case 64: c = 'q'; break;
818 default: assert(0); break;
821 sprintf(opbits_str, "%s%c", insn, bits);
823 return opbits_str;
826 static void emit_move(struct storage *src, struct storage *dest,
827 struct symbol *ctype, const char *comment,
828 unsigned long flags)
830 unsigned int bits;
831 unsigned int is_signed;
832 unsigned int is_dest = (src->type == STOR_REG);
833 const char *opname;
835 if (ctype) {
836 bits = ctype->bit_size;
837 is_signed = type_is_signed(ctype);
838 } else {
839 bits = 32;
840 is_signed = 0;
843 if ((dest->type == STOR_REG) && (src->type == STOR_REG)) {
844 insn("mov", src, dest, NULL, 0);
845 return;
848 switch (bits) {
849 case 8:
850 if (is_dest)
851 opname = "movb";
852 else {
853 if (is_signed) opname = "movsxb";
854 else opname = "movzxb";
856 break;
857 case 16:
858 if (is_dest)
859 opname = "movw";
860 else {
861 if (is_signed) opname = "movsxw";
862 else opname = "movzxw";
864 break;
866 case 32: opname = "movl"; break;
867 case 64: opname = "movq"; break;
869 default: assert(0); break;
872 insn(opname, src, dest, comment, flags);
875 static struct storage *emit_compare(struct expression *expr)
877 struct storage *left = x86_expression(expr->left);
878 struct storage *right = x86_expression(expr->right);
879 struct storage *new;
880 const char *opname = NULL;
881 unsigned int is_signed = type_is_signed(expr->left->ctype); /* FIXME */
882 unsigned int right_bits = expr->right->ctype->bit_size;
884 switch(expr->op) {
885 case '<':
886 if (is_signed) opname = "setl";
887 else opname = "setb";
888 break;
889 case '>':
890 if (is_signed) opname = "setg";
891 else opname = "seta";
892 break;
893 case SPECIAL_LTE:
894 if (is_signed) opname = "setle";
895 else opname = "setbe";
896 break;
897 case SPECIAL_GTE:
898 if (is_signed) opname = "setge";
899 else opname = "setae";
900 break;
902 case SPECIAL_EQUAL: opname = "sete"; break;
903 case SPECIAL_NOTEQUAL: opname = "setne"; break;
905 default:
906 assert(0);
907 break;
910 /* init EDX to 0 */
911 insn("xor", REG_EDX, REG_EDX, "begin EXPR_COMPARE", 0);
913 /* move op1 into EAX */
914 emit_move(left, REG_EAX, expr->left->ctype, NULL, 0);
916 /* perform comparison, RHS (op1, right) and LHS (op2, EAX) */
917 insn(opbits("cmp", right_bits), right, REG_EAX, NULL, 0);
919 /* store result of operation, 0 or 1, in DL using SETcc */
920 insn(opname, REG_DL, NULL, NULL, 0);
922 /* finally, store the result (DL) in a new pseudo / stack slot */
923 new = new_pseudo();
924 emit_move(REG_EDX, new, NULL, "end EXPR_COMPARE", 0);
926 return new;
930 * TODO: use new type STOR_VALUE. This will allow us to store
931 * the constant internally, and avoid assigning stack slots to them.
933 static struct storage *emit_value(struct expression *expr)
935 struct storage *new = new_pseudo();
936 struct storage *val;
938 val = new_storage(STOR_VALUE);
939 val->value = (long long) expr->value;
940 insn("movl", val, new, NULL, ATOM_FREE_OP1);
942 return new;
945 static struct storage *emit_binop(struct expression *expr)
947 struct storage *left = x86_expression(expr->left);
948 struct storage *right = x86_expression(expr->right);
949 struct storage *new;
950 const char *opname;
951 static const char *name[] = {
952 ['+'] = "addl", ['-'] = "subl",
953 ['*'] = "mull", ['/'] = "divl",
954 ['%'] = "modl", ['&'] = "andl",
955 ['|'] = "orl", ['^'] = "xorl"
957 unsigned int op = expr->op;
960 * FIXME FIXME this routine is so wrong it's not even funny.
961 * On x86 both mod/div are handled with the same instruction.
962 * We don't pay attention to signed/unsigned issues,
963 * and like elsewhere we hardcode the operand size at 32 bits.
966 opname = show_special(op);
967 if (op < sizeof(name)/sizeof(*name)) {
968 opname = name[op];
969 assert(opname != NULL);
970 } else
971 assert(0); /* FIXME: no operations other than name[], ATM */
973 /* load op2 into EAX */
974 insn("movl", right, REG_EAX, "EXPR_BINOP/COMMA/LOGICAL", 0);
976 /* perform binop */
977 insn(opname, left, REG_EAX, NULL, 0);
979 /* store result (EAX) in new pseudo / stack slot */
980 new = new_pseudo();
981 insn("movl", REG_EAX, new, "end EXPR_BINOP", 0);
983 return new;
986 static void emit_if_conditional(struct statement *stmt)
988 struct function *f = current_func;
989 struct storage *val, *target_val;
990 int target;
991 struct expression *cond = stmt->if_conditional;
992 char s[16];
994 /* This is only valid if nobody can jump into the "dead" statement */
995 #if 0
996 if (cond->type == EXPR_VALUE) {
997 struct statement *s = stmt->if_true;
998 if (!cond->value)
999 s = stmt->if_false;
1000 x86_statement(s);
1001 break;
1003 #endif
1004 val = x86_expression(cond);
1006 /* load 'if' test result into EAX */
1007 insn("movl", val, REG_EAX, "begin if conditional", 0);
1009 /* clear ECX */
1010 insn("xorl", REG_ECX, REG_ECX, NULL, 0);
1012 /* compare 'if' test result */
1013 insn("cmpl", REG_EAX, REG_ECX, NULL, 0);
1015 /* create end-of-if label / if-failed labelto jump to,
1016 * and jump to it if the expression returned zero.
1018 target = new_label();
1019 target_val = new_storage(STOR_LABEL);
1020 target_val->label = target;
1021 insn("je", target_val, NULL, NULL, ATOM_FREE_OP1);
1023 x86_statement(stmt->if_true);
1024 if (stmt->if_false) {
1025 struct storage *last_val;
1026 int last;
1028 /* finished generating code for if-true statement.
1029 * add a jump-to-end jump to avoid falling through
1030 * to the if-false statement code.
1032 last = new_label();
1033 last_val = new_storage(STOR_LABEL);
1034 last_val->label = last;
1035 insn("jmp", last_val, NULL, NULL, ATOM_FREE_OP1);
1037 /* if we have both if-true and if-false statements,
1038 * the failed-conditional case will fall through to here
1040 sprintf(s, ".L%d:\n", target);
1041 push_text_atom(f, s);
1043 target = last;
1044 x86_statement(stmt->if_false);
1047 sprintf(s, ".L%d:\t\t\t\t\t# end if\n", target);
1048 push_text_atom(f, s);
1051 static struct storage *emit_inc_dec(struct expression *expr, int postop)
1053 struct storage *addr = x86_address_gen(expr->unop);
1054 struct storage *retval;
1055 const char *opname = expr->op == SPECIAL_INCREMENT ? "incl" : "decl";
1056 #if 0
1057 /* FIXME: don't hardware operand size */
1058 int bits = expr->ctype->bit_size;
1059 #endif
1061 if (postop) {
1062 struct storage *new = new_pseudo();
1064 emit_copy(addr, expr->unop->ctype, new, NULL);
1066 retval = new;
1067 } else
1068 retval = addr;
1070 insn(opname, addr, NULL, NULL, 0);
1072 return retval;
1075 static struct storage *emit_postop(struct expression *expr)
1077 return emit_inc_dec(expr, 1);
1080 static struct storage *emit_return_stmt(struct statement *stmt)
1082 struct function *f = current_func;
1083 struct expression *expr = stmt->ret_value;
1084 struct storage *val = NULL;
1085 char s[32];
1087 if (expr && expr->ctype)
1088 val = x86_expression(expr);
1090 sprintf(s, "\tjmp\t.L%d\n", f->ret_target);
1091 push_text_atom(f, s);
1093 return val;
1096 static void x86_struct_member(struct symbol *sym, void *data, int flags)
1098 if (flags & ITERATE_FIRST)
1099 printf(" {\n\t");
1100 printf("%s:%d:%ld at offset %ld", show_ident(sym->ident), sym->bit_size, sym->ctype.alignment, sym->offset);
1101 if (sym->fieldwidth)
1102 printf("[%d..%d]", sym->bit_offset, sym->bit_offset+sym->fieldwidth-1);
1103 if (flags & ITERATE_LAST)
1104 printf("\n} ");
1105 else
1106 printf(", ");
1109 static void x86_symbol(struct symbol *sym)
1111 struct symbol *type;
1113 if (!sym)
1114 return;
1116 type = sym->ctype.base_type;
1117 if (!type)
1118 return;
1121 * Show actual implementation information
1123 switch (type->type) {
1125 case SYM_ARRAY:
1126 if (sym->initializer)
1127 emit_array(sym);
1128 else
1129 emit_array_noinit(sym);
1130 break;
1132 case SYM_BASETYPE:
1133 if (sym->initializer) {
1134 emit_object_pre(show_ident(sym->ident),
1135 sym->ctype.modifiers,
1136 sym->ctype.alignment,
1137 sym->bit_size / 8);
1138 emit_scalar(sym->initializer, sym->bit_size);
1139 stor_sym_init(sym);
1140 } else
1141 emit_scalar_noinit(sym);
1142 break;
1144 case SYM_STRUCT:
1145 symbol_iterate(type->symbol_list, x86_struct_member, NULL);
1146 break;
1148 case SYM_UNION:
1149 symbol_iterate(type->symbol_list, x86_struct_member, NULL);
1150 break;
1152 case SYM_FN: {
1153 struct statement *stmt = type->stmt;
1154 if (stmt) {
1155 struct storage *val;
1157 emit_func_pre(sym);
1158 val = x86_statement(stmt);
1159 emit_func_post(sym, val);
1161 break;
1164 default:
1165 break;
1168 if (sym->initializer && (type->type != SYM_BASETYPE) &&
1169 (type->type != SYM_ARRAY)) {
1170 printf(" = \n");
1171 x86_expression(sym->initializer);
1175 static void x86_symbol_init(struct symbol *sym);
1177 static void x86_switch_statement(struct statement *stmt)
1179 struct storage *val = x86_expression(stmt->switch_expression);
1180 struct symbol *sym;
1181 printf("\tswitch v%d\n", val->pseudo);
1184 * Debugging only: Check that the case list is correct
1185 * by printing it out.
1187 * This is where a _real_ back-end would go through the
1188 * cases to decide whether to use a lookup table or a
1189 * series of comparisons etc
1191 printf("# case table:\n");
1192 FOR_EACH_PTR(stmt->switch_case->symbol_list, sym) {
1193 struct statement *case_stmt = sym->stmt;
1194 struct expression *expr = case_stmt->case_expression;
1195 struct expression *to = case_stmt->case_to;
1197 if (!expr) {
1198 printf(" default");
1199 } else {
1200 if (expr->type == EXPR_VALUE) {
1201 printf(" case %lld", expr->value);
1202 if (to) {
1203 if (to->type == EXPR_VALUE) {
1204 printf(" .. %lld", to->value);
1205 } else {
1206 printf(" .. what?");
1209 } else
1210 printf(" what?");
1212 printf(": .L%p\n", sym);
1213 } END_FOR_EACH_PTR;
1214 printf("# end case table\n");
1216 x86_statement(stmt->switch_statement);
1218 if (stmt->switch_break->used)
1219 printf(".L%p:\n", stmt->switch_break);
1222 static void x86_symbol_decl(struct symbol_list *syms)
1224 struct symbol *sym;
1225 FOR_EACH_PTR(syms, sym) {
1226 x86_symbol_init(sym);
1227 } END_FOR_EACH_PTR;
1231 * Print out a statement
1233 static struct storage *x86_statement(struct statement *stmt)
1235 if (!stmt)
1236 return 0;
1237 switch (stmt->type) {
1238 case STMT_RETURN:
1239 return emit_return_stmt(stmt);
1240 case STMT_COMPOUND: {
1241 struct statement *s;
1242 struct storage *last = NULL;
1244 x86_symbol_decl(stmt->syms);
1245 FOR_EACH_PTR(stmt->stmts, s) {
1246 last = x86_statement(s);
1247 } END_FOR_EACH_PTR;
1249 return last;
1252 case STMT_EXPRESSION:
1253 return x86_expression(stmt->expression);
1254 case STMT_IF:
1255 emit_if_conditional(stmt);
1256 return NULL;
1257 case STMT_SWITCH:
1258 x86_switch_statement(stmt);
1259 break;
1261 case STMT_CASE:
1262 printf(".L%p:\n", stmt->case_label);
1263 x86_statement(stmt->case_statement);
1264 break;
1266 case STMT_ITERATOR: {
1267 struct statement *pre_statement = stmt->iterator_pre_statement;
1268 struct expression *pre_condition = stmt->iterator_pre_condition;
1269 struct statement *statement = stmt->iterator_statement;
1270 struct statement *post_statement = stmt->iterator_post_statement;
1271 struct expression *post_condition = stmt->iterator_post_condition;
1272 int loop_top = 0, loop_bottom = 0;
1273 struct storage *val;
1275 x86_symbol_decl(stmt->iterator_syms);
1276 x86_statement(pre_statement);
1277 if (pre_condition) {
1278 if (pre_condition->type == EXPR_VALUE) {
1279 if (!pre_condition->value) {
1280 loop_bottom = new_label();
1281 printf("\tjmp\t\t.L%d\n", loop_bottom);
1283 } else {
1284 loop_bottom = new_label();
1285 val = x86_expression(pre_condition);
1286 printf("\tje\t\tv%d, .L%d\n", val->pseudo, loop_bottom);
1289 if (!post_condition || post_condition->type != EXPR_VALUE || post_condition->value) {
1290 loop_top = new_label();
1291 printf(".L%d:\n", loop_top);
1293 x86_statement(statement);
1294 if (stmt->iterator_continue->used)
1295 printf(".L%p:\n", stmt->iterator_continue);
1296 x86_statement(post_statement);
1297 if (!post_condition) {
1298 printf("\tjmp\t\t.L%d\n", loop_top);
1299 } else if (post_condition->type == EXPR_VALUE) {
1300 if (post_condition->value)
1301 printf("\tjmp\t\t.L%d\n", loop_top);
1302 } else {
1303 val = x86_expression(post_condition);
1304 printf("\tjne\t\tv%d, .L%d\n", val->pseudo, loop_top);
1306 if (stmt->iterator_break->used)
1307 printf(".L%p:\n", stmt->iterator_break);
1308 if (loop_bottom)
1309 printf(".L%d:\n", loop_bottom);
1310 break;
1312 case STMT_NONE:
1313 break;
1315 case STMT_LABEL:
1316 printf(".L%p:\n", stmt->label_identifier);
1317 x86_statement(stmt->label_statement);
1318 break;
1320 case STMT_GOTO:
1321 if (stmt->goto_expression) {
1322 struct storage *val = x86_expression(stmt->goto_expression);
1323 printf("\tgoto *v%d\n", val->pseudo);
1324 } else {
1325 printf("\tgoto .L%p\n", stmt->goto_label);
1327 break;
1328 case STMT_ASM:
1329 printf("\tasm( .... )\n");
1330 break;
1333 return 0;
1336 static struct storage *x86_call_expression(struct expression *expr)
1338 struct function *f = current_func;
1339 struct symbol *direct;
1340 struct expression *arg, *fn;
1341 struct storage *retval, *fncall;
1342 int framesize;
1344 if (!expr->ctype) {
1345 warn(expr->pos, "\tcall with no type!");
1346 return NULL;
1349 framesize = 0;
1350 FOR_EACH_PTR_REVERSE(expr->args, arg) {
1351 struct storage *new = x86_expression(arg);
1352 int size = arg->ctype->bit_size;
1354 /* FIXME: pay attention to 'size' */
1355 insn("pushl", new, NULL,
1356 !framesize ? "begin function call" : NULL, 0);
1358 framesize += size >> 3;
1359 } END_FOR_EACH_PTR_REVERSE;
1361 fn = expr->fn;
1363 /* Remove dereference, if any */
1364 direct = NULL;
1365 if (fn->type == EXPR_PREOP) {
1366 if (fn->unop->type == EXPR_SYMBOL) {
1367 struct symbol *sym = fn->unop->symbol;
1368 if (sym->ctype.base_type->type == SYM_FN)
1369 direct = sym;
1372 if (direct) {
1373 char s[64];
1374 sprintf(s, "\tcall\t%s\n", show_ident(direct->ident));
1375 push_text_atom(f, s);
1376 } else {
1377 fncall = x86_expression(fn);
1378 printf("\tcall\t*v%d\n", fncall->pseudo);
1381 /* FIXME: pay attention to BITS_IN_POINTER */
1382 if (framesize) {
1383 struct storage *val = new_storage(STOR_VALUE);
1384 val->value = (long long) framesize;
1385 insn("addl", val, REG_ESP, "end function call", ATOM_FREE_OP1);
1388 retval = new_pseudo();
1389 printf("\tmov.%d\t\tv%d,retval\n", expr->ctype->bit_size, retval->pseudo);
1390 return retval;
1393 static struct storage *x86_regular_preop(struct expression *expr)
1395 struct storage *target = x86_expression(expr->unop);
1396 struct storage *new = new_pseudo();
1397 static const char *name[] = {
1398 ['!'] = "nonzero", ['-'] = "neg",
1399 ['~'] = "not",
1401 unsigned int op = expr->op;
1402 const char *opname;
1404 opname = show_special(op);
1405 if (op < sizeof(name)/sizeof(*name))
1406 opname = name[op];
1407 printf("\t%s.%d\t\tv%d,v%d\n", opname, expr->ctype->bit_size, new->pseudo, target->pseudo);
1408 return new;
1412 * FIXME! Not all accesses are memory loads. We should
1413 * check what kind of symbol is behind the dereference.
1415 static struct storage *x86_address_gen(struct expression *expr)
1417 if (expr->type == EXPR_PREOP)
1418 return x86_expression(expr->unop);
1419 return x86_expression(expr->address);
1422 static struct storage *x86_assignment(struct expression *expr)
1424 struct expression *target = expr->left;
1425 struct storage *val, *addr;
1426 int bits;
1428 if (!expr->ctype)
1429 return NULL;
1431 bits = expr->ctype->bit_size;
1432 val = x86_expression(expr->right);
1433 addr = x86_address_gen(target);
1434 emit_copy(val, expr->right->ctype, addr, expr->left->ctype);
1435 return val;
1438 static int x86_initialization(struct symbol *sym, struct expression *expr)
1440 struct storage *val, *addr;
1441 int bits;
1443 if (!expr->ctype)
1444 return 0;
1446 bits = expr->ctype->bit_size;
1447 val = x86_expression(expr);
1448 addr = x86_symbol_expr(sym);
1449 // FIXME! The "target" expression is for bitfield store information.
1450 // Leave it NULL, which works fine.
1451 emit_store(NULL, addr, val, bits);
1452 return 0;
1455 static struct storage *x86_access(struct expression *expr)
1457 return x86_address_gen(expr);
1460 static struct storage *x86_preop(struct expression *expr)
1463 * '*' is an lvalue access, and is fundamentally different
1464 * from an arithmetic operation. Maybe it should have an
1465 * expression type of its own..
1467 if (expr->op == '*')
1468 return x86_access(expr);
1469 if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT)
1470 return emit_inc_dec(expr, 0);
1471 return x86_regular_preop(expr);
1474 static struct storage *x86_symbol_expr(struct symbol *sym)
1476 struct storage *new = new_pseudo();
1478 if (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_EXTERN | MOD_STATIC)) {
1479 printf("\tmovi.%d\t\tv%d,$%s\n", BITS_IN_POINTER, new->pseudo, show_ident(sym->ident));
1480 return new;
1482 if (sym->ctype.modifiers & MOD_ADDRESSABLE) {
1483 printf("\taddi.%d\t\tv%d,vFP,$%lld\n", BITS_IN_POINTER, new->pseudo, sym->value);
1484 return new;
1486 printf("\taddi.%d\t\tv%d,vFP,$offsetof(%s:%p)\n", BITS_IN_POINTER, new->pseudo, show_ident(sym->ident), sym);
1487 return new;
1490 static void x86_symbol_init(struct symbol *sym)
1492 struct symbol_private *priv = sym->aux;
1493 struct expression *expr = sym->initializer;
1494 struct storage *new;
1496 if (expr)
1497 new = x86_expression(expr);
1498 else
1499 new = new_pseudo();
1501 if (!priv) {
1502 priv = calloc(1, sizeof(*priv));
1503 sym->aux = priv;
1504 /* FIXME: leak! we don't free... */
1505 /* (well, we don't free symbols either) */
1508 priv->addr = new;
1511 static int type_is_signed(struct symbol *sym)
1513 if (sym->type == SYM_NODE)
1514 sym = sym->ctype.base_type;
1515 if (sym->type == SYM_PTR)
1516 return 0;
1517 return !(sym->ctype.modifiers & MOD_UNSIGNED);
1520 static struct storage *x86_cast_expr(struct expression *expr)
1522 struct symbol *old_type, *new_type;
1523 struct storage *op = x86_expression(expr->cast_expression);
1524 int oldbits, newbits;
1525 int is_signed;
1526 struct storage *new;
1528 old_type = expr->cast_expression->ctype;
1529 new_type = expr->cast_type;
1531 oldbits = old_type->bit_size;
1532 newbits = new_type->bit_size;
1533 if (oldbits >= newbits)
1534 return op;
1535 new = new_pseudo();
1536 is_signed = type_is_signed(old_type);
1537 if (is_signed) {
1538 printf("\tsext%d.%d\tv%d,v%d\n", oldbits, newbits, new->pseudo, op->pseudo);
1539 } else {
1540 printf("\tandl.%d\t\tv%d,v%d,$%lu\n", newbits, new->pseudo, op->pseudo, (1UL << oldbits)-1);
1542 return new;
1545 static struct storage *show_string_expr(struct expression *expr)
1547 struct storage *new = new_pseudo();
1549 printf("\tmovi.%d\t\tv%d,&%s\n", BITS_IN_POINTER, new->pseudo,
1550 show_string(expr->string));
1551 return new;
1554 static struct storage *x86_bitfield_expr(struct expression *expr)
1556 return x86_access(expr);
1559 static struct storage *x86_label_expr(struct expression *expr)
1561 struct storage *new = new_pseudo();
1562 printf("\tmovi.%d\t\tv%d,.L%p\n",BITS_IN_POINTER, new->pseudo, expr->label_symbol);
1563 return new;
1566 static struct storage *x86_conditional_expr(struct expression *expr)
1568 struct storage *cond = x86_expression(expr->conditional);
1569 struct storage *true = x86_expression(expr->cond_true);
1570 struct storage *false = x86_expression(expr->cond_false);
1571 struct storage *new = new_pseudo();
1573 if (!true)
1574 true = cond;
1575 printf("[v%d]\tcmov.%d\t\tv%d,v%d,v%d\n",
1576 cond->pseudo, expr->ctype->bit_size, new->pseudo,
1577 true->pseudo, false->pseudo);
1578 return new;
1581 static struct storage *x86_statement_expr(struct expression *expr)
1583 return x86_statement(expr->statement);
1586 static int x86_position_expr(struct expression *expr, struct symbol *base)
1588 struct storage *new = x86_expression(expr->init_expr);
1589 struct symbol *ctype = expr->init_sym;
1591 printf("\tinsert v%d at [%d:%d] of %s\n", new->pseudo,
1592 expr->init_offset, ctype->bit_offset,
1593 show_ident(base->ident));
1594 return 0;
1597 static void x86_initializer_expr(struct expression *expr, struct symbol *ctype)
1599 struct expression *entry;
1601 FOR_EACH_PTR(expr->expr_list, entry) {
1602 // Nested initializers have their positions already
1603 // recursively calculated - just output them too
1604 if (entry->type == EXPR_INITIALIZER) {
1605 x86_initializer_expr(entry, ctype);
1606 continue;
1609 // Ignore initializer indexes and identifiers - the
1610 // evaluator has taken them into account
1611 if (entry->type == EXPR_IDENTIFIER || entry->type == EXPR_INDEX)
1612 continue;
1613 if (entry->type == EXPR_POS) {
1614 x86_position_expr(entry, ctype);
1615 continue;
1617 x86_initialization(ctype, entry);
1618 } END_FOR_EACH_PTR;
1621 static struct storage *x86_symbol_expr_init(struct symbol *sym)
1623 struct expression *expr = sym->initializer;
1624 struct symbol_private *priv = sym->aux;
1626 if (expr)
1627 x86_initializer_expr(expr, expr->ctype);
1629 if (priv == NULL) {
1630 fprintf(stderr, "WARNING! priv == NULL\n");
1631 priv = calloc(1, sizeof(*priv));
1632 sym->aux = priv;
1633 priv->addr = new_pseudo(); /* this is wrong! */
1636 return priv->addr;
1640 * Print out an expression. Return the pseudo that contains the
1641 * variable.
1643 static struct storage *x86_expression(struct expression *expr)
1645 if (!expr)
1646 return 0;
1648 if (!expr->ctype) {
1649 struct position *pos = &expr->pos;
1650 printf("\tno type at %s:%d:%d\n",
1651 input_streams[pos->stream].name,
1652 pos->line, pos->pos);
1653 return 0;
1656 switch (expr->type) {
1657 case EXPR_CALL:
1658 return x86_call_expression(expr);
1660 case EXPR_ASSIGNMENT:
1661 return x86_assignment(expr);
1663 case EXPR_COMPARE:
1664 return emit_compare(expr);
1665 case EXPR_BINOP:
1666 case EXPR_COMMA:
1667 case EXPR_LOGICAL:
1668 return emit_binop(expr);
1669 case EXPR_PREOP:
1670 return x86_preop(expr);
1671 case EXPR_POSTOP:
1672 return emit_postop(expr);
1673 case EXPR_SYMBOL:
1674 return x86_symbol_expr_init(expr->symbol);
1675 case EXPR_DEREF:
1676 case EXPR_SIZEOF:
1677 warn(expr->pos, "invalid expression after evaluation");
1678 return 0;
1679 case EXPR_CAST:
1680 return x86_cast_expr(expr);
1681 case EXPR_VALUE:
1682 return emit_value(expr);
1683 case EXPR_STRING:
1684 return show_string_expr(expr);
1685 case EXPR_BITFIELD:
1686 return x86_bitfield_expr(expr);
1687 case EXPR_INITIALIZER:
1688 x86_initializer_expr(expr, expr->ctype);
1689 return NULL;
1690 case EXPR_CONDITIONAL:
1691 return x86_conditional_expr(expr);
1692 case EXPR_STATEMENT:
1693 return x86_statement_expr(expr);
1694 case EXPR_LABEL:
1695 return x86_label_expr(expr);
1697 // None of these should exist as direct expressions: they are only
1698 // valid as sub-expressions of initializers.
1699 case EXPR_POS:
1700 warn(expr->pos, "unable to show plain initializer position expression");
1701 return 0;
1702 case EXPR_IDENTIFIER:
1703 warn(expr->pos, "unable to show identifier expression");
1704 return 0;
1705 case EXPR_INDEX:
1706 warn(expr->pos, "unable to show index expression");
1707 return 0;
1709 return 0;