aboutsummaryrefslogtreecommitdiffstats
path: root/lcc/src/asdl.c
diff options
context:
space:
mode:
Diffstat (limited to 'lcc/src/asdl.c')
-rwxr-xr-xlcc/src/asdl.c399
1 files changed, 399 insertions, 0 deletions
diff --git a/lcc/src/asdl.c b/lcc/src/asdl.c
new file mode 100755
index 0000000..1c01c0c
--- /dev/null
+++ b/lcc/src/asdl.c
@@ -0,0 +1,399 @@
+#include "c.h"
+#include "rcc.h"
+#if WIN32
+#include <fcntl.h>
+#include <io.h>
+#endif
+
+
+static list_ty interfaces;
+static rcc_program_ty pickle;
+
+char *string(const char *str) {
+ return (char *)Atom_string(str);
+}
+
+char *stringd(long n) {
+ return (char *)Atom_int(n);
+}
+
+char *stringn(const char *str, int len) {
+ return (char *)Atom_new(str, len);
+}
+
+static void put(rcc_interface_ty node) {
+ Seq_addhi(interfaces, node);
+}
+
+static int typeuid(Type ty) {
+ rcc_type_ty type;
+
+ assert(ty);
+ if (ty->x.typeno != 0)
+ return ty->x.typeno;
+ ty->x.typeno = pickle->nuids++;
+ switch (ty->op) {
+#define xx(op) case op: type = rcc_##op(ty->size, ty->align); break
+ xx(INT);
+ xx(UNSIGNED);
+ xx(FLOAT);
+ xx(VOID);
+#undef xx
+#define xx(op) case op: type = rcc_##op(ty->size, ty->align, typeuid(ty->type)); break
+ xx(POINTER);
+ xx(ARRAY);
+ xx(CONST);
+ xx(VOLATILE);
+#undef xx
+ case CONST+VOLATILE:
+ type = rcc_CONST(ty->size, ty->align, typeuid(ty->type));
+ break;
+ case ENUM: {
+ list_ty ids = Seq_new(0);
+ int i;
+ for (i = 0; ty->u.sym->u.idlist[i] != NULL; i++)
+ Seq_addhi(ids, rcc_enum_(ty->u.sym->u.idlist[i]->name,
+ ty->u.sym->u.idlist[i]->u.value));
+ assert(i > 0);
+ type = rcc_ENUM(ty->size, ty->align, ty->u.sym->name, ids);
+ break;
+ }
+ case STRUCT: case UNION: {
+ list_ty fields = Seq_new(0);
+ Field p = fieldlist(ty);
+ for ( ; p != NULL; p = p->link)
+ Seq_addhi(fields, rcc_field(p->name, typeuid(p->type), p->offset, p->bitsize, p->lsb));
+ if (ty->op == STRUCT)
+ type = rcc_STRUCT(ty->size, ty->align, ty->u.sym->name, fields);
+ else
+ type = rcc_UNION (ty->size, ty->align, ty->u.sym->name, fields);
+ break;
+ }
+ case FUNCTION: {
+ list_ty formals = Seq_new(0);
+ if (ty->u.f.proto != NULL && ty->u.f.proto[0] != NULL) {
+ int i;
+ for (i = 0; ty->u.f.proto[i] != NULL; i++)
+ Seq_addhi(formals, to_generic_int(typeuid(ty->u.f.proto[i])));
+ } else if (ty->u.f.proto != NULL && ty->u.f.proto[0] == NULL)
+ Seq_addhi(formals, to_generic_int(typeuid(voidtype)));
+ type = rcc_FUNCTION(ty->size, ty->align, typeuid(ty->type), formals);
+ break;
+ }
+ default: assert(0);
+ }
+ Seq_addhi(pickle->items, rcc_Type(ty->x.typeno, type));
+ return ty->x.typeno;
+}
+
+static int symboluid(Symbol p) {
+ assert(p);
+ assert(p->scope != CONSTANTS && p->scope != LABELS);
+ if (p->x.offset == 0)
+ p->x.offset = pickle->nuids++;
+ return p->x.offset;
+}
+
+static rcc_symbol_ty mk_symbol(Symbol p) {
+ int flags = 0, ref = 10000*p->ref;
+
+ if (p->ref > 0 && ref == 0)
+ ref++;
+#define xx(f,n) flags |= p->f<<n;
+ xx(structarg,0)
+ xx(addressed,1)
+ xx(computed,2)
+ xx(temporary,3)
+ xx(generated,4)
+#undef xx
+ return rcc_symbol(p->name, typeuid(p->type), p->scope, p->sclass, ref, flags);
+}
+
+static rcc_real_ty mk_real(int size, Value v) {
+ unsigned *p = (unsigned *)&v.d;
+ return rcc_real(p[swap], p[1-swap]);
+}
+
+static void asdl_segment(int n) {
+ static int cseg;
+
+ if (cseg != n)
+ put(rcc_Segment(cseg = n));
+}
+
+static void asdl_address(Symbol q, Symbol p, long n) {
+ assert(q->x.offset == 0);
+ put(rcc_Address(symboluid(q), mk_symbol(q), symboluid(p), n));
+}
+
+static void asdl_blockbeg(Env *e) {
+ put(rcc_Blockbeg());
+}
+
+static void asdl_blockend(Env *e) {
+ put(rcc_Blockend());
+}
+
+static void asdl_defaddress(Symbol p) {
+ if (p->scope == LABELS)
+ put(rcc_Deflabel(p->u.l.label));
+ else
+ put(rcc_Defaddress(symboluid(p)));
+}
+
+static void asdl_defconst(int suffix, int size, Value v) {
+ switch (suffix) {
+ case I: put(rcc_Defconst(suffix, size, v.i)); return;
+ case U: put(rcc_Defconst(suffix, size, v.u)); return;
+ case P: put(rcc_Defconst(suffix, size, (unsigned long)v.p)); return; /* FIXME */
+ case F: put(rcc_Defconstf(size, mk_real(size, v))); return;
+ assert(0);
+ }
+}
+
+static void asdl_defstring(int len, char *str) {
+ put(rcc_Defstring(Text_box(stringn(str, len), len)));
+}
+
+static void asdl_defsymbol(Symbol p) {
+ if (p->scope >= GLOBAL)
+ symboluid(p);
+}
+
+static Symbol temps;
+
+static rcc_node_ty visit(Node p) {
+ Symbol q;
+ rcc_node_ty left = NULL, right = NULL;
+ int suffix = optype(p->op), size = opsize(p->op);
+
+ assert(p);
+ for (q = temps; q; q = q->u.t.next)
+ if (q->u.t.cse == p) {
+ q->u.t.cse = NULL;
+ return rcc_CSE(0, 0, symboluid(q), visit(p));
+ }
+ if (p->kids[0] != NULL)
+ left = visit(p->kids[0]);
+ if (p->kids[1] != NULL)
+ right = visit(p->kids[1]);
+ switch (specific(p->op)) {
+ case CNST+F:
+ assert(p->syms[0]);
+ return rcc_CNSTF(suffix, size, mk_real(size, p->syms[0]->u.c.v));
+ case CALL+B:
+ assert(p->syms[0]);
+ assert(p->syms[0]->type);
+ return rcc_CALLB(suffix, size, left, right, typeuid(p->syms[0]->type));
+ case RET+V:
+ return rcc_RET(suffix, size);
+ case LABEL+V:
+ assert(p->syms[0]);
+ return rcc_LABEL(suffix, size, p->syms[0]->u.l.label);
+ }
+ switch (generic(p->op)) {
+ case CNST:
+ assert(p->syms[0]);
+ return rcc_CNST(suffix, size, p->syms[0]->u.c.v.i); /* FIXME */
+ case ARG:
+ assert(p->syms[0]);
+ return rcc_ARG(suffix, size, left, p->syms[0]->u.c.v.i, p->syms[1]->u.c.v.i);
+ case ASGN:
+ assert(p->syms[0]);
+ assert(p->syms[1]);
+ return rcc_ASGN(suffix, size, left, right, p->syms[0]->u.c.v.i, p->syms[1]->u.c.v.i);
+ case CVF: case CVI: case CVP: case CVU:
+ assert(p->syms[0]);
+ return rcc_CVT(suffix, size, generic(p->op), left, p->syms[0]->u.c.v.i);
+ case CALL:
+ assert(p->syms[0]);
+ assert(p->syms[0]->type);
+ return rcc_CALL(suffix, size, left, typeuid(p->syms[0]->type));
+#define xx(op) case op: return rcc_##op(suffix, size, symboluid(p->syms[0]))
+ xx(ADDRG);
+ xx(ADDRF);
+#undef xx
+ case ADDRL:
+ if (!p->syms[0]->defined)
+ (*IR->local)(p->syms[0]);
+ p->syms[0]->defined = 1;
+ return rcc_ADDRL(suffix, size, symboluid(p->syms[0]));
+ case JUMP:
+ if (p->syms[0] != NULL)
+ return rcc_BRANCH(suffix, size, p->syms[0]->u.l.label);
+ return rcc_Unary(suffix, size, generic(p->op), left);
+ case INDIR: case RET: case NEG: case BCOM:
+ return rcc_Unary(suffix, size, generic(p->op), left);
+ case BOR: case BAND: case BXOR: case RSH: case LSH:
+ case ADD: case SUB: case DIV: case MUL: case MOD:
+ return rcc_Binary(suffix, size, generic(p->op), left, right);
+ case EQ: case NE: case GT: case GE: case LE: case LT:
+ assert(p->syms[0]);
+ return rcc_Compare(suffix, size, generic(p->op), left, right, p->syms[0]->u.l.label);
+ }
+ assert(0);
+ return NULL;
+}
+
+static void asdl_emit(Node p) {}
+
+static void asdl_local(Symbol p) {
+ assert(p->x.offset == 0);
+ put(rcc_Local(symboluid(p), mk_symbol(p)));
+ if (p->temporary && p->u.t.cse) {
+ p->u.t.next = temps;
+ temps = p;
+ }
+}
+
+static Symbol pending = NULL;
+
+static void dopending(Symbol p) {
+ if (pending != NULL) {
+ int uid = symboluid(pending);
+ rcc_symbol_ty symbol = mk_symbol(pending);
+ Seq_addhi(pickle->items, rcc_Symbol(uid, symbol));
+ }
+ pending = p;
+}
+
+
+static void asdl_export(Symbol p) {
+ put(rcc_Export(symboluid(p)));
+}
+
+static void asdl_function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
+ list_ty codelist = Seq_new(0), save, calleelist = Seq_new(0), callerlist = Seq_new(0);
+ int i;
+
+ dopending(f);
+ for (i = 0; caller[i] != NULL; i++) {
+ asdl_local(caller[i]);
+ Seq_addhi(callerlist, to_generic_int(symboluid(caller[i])));
+ }
+ for (i = 0; callee[i] != NULL; i++) {
+ asdl_local(callee[i]);
+ Seq_addhi(calleelist, to_generic_int(symboluid(callee[i])));
+ }
+ save = interfaces;
+ interfaces = codelist;
+ gencode(caller, callee);
+ asdl_segment(CODE);
+ emitcode();
+ interfaces = save;
+ put(rcc_Function(symboluid(f), callerlist, calleelist, ncalls, codelist));
+}
+
+static Node asdl_gen(Node p) {
+ Node q;
+ list_ty forest = Seq_new(0);
+
+ for (q = p; p != NULL; p = p->link)
+ if (specific(p->op) == JUMP+V && specific(p->kids[0]->op) == ADDRG+P
+ && p->kids[0]->syms[0]->scope == LABELS) {
+ p->syms[0] = p->kids[0]->syms[0];
+ p->kids[0] = NULL;
+ }
+ for (p = q; p != NULL; p = p->link)
+ Seq_addhi(forest, visit(p));
+ put(rcc_Forest(forest));
+ temps = NULL;
+ return q;
+}
+
+static void asdl_global(Symbol p) {
+ dopending(p);
+ put(rcc_Global(symboluid(p), p->u.seg));
+}
+
+static void asdl_import(Symbol p) {
+ dopending(p);
+ put(rcc_Import(symboluid(p)));
+}
+
+static void asdl_progbeg(int argc, char *argv[]) {
+ int i;
+
+#if WIN32
+ _setmode(_fileno(stdout), _O_BINARY);
+#endif
+ pickle = rcc_program(1, 0, Seq_new(0), Seq_new(0), argc, Seq_new(0));
+ for (i = 0; i < argc; i++)
+ Seq_addhi(pickle->argv, to_generic_string(Text_box(argv[i], strlen(argv[i]) + 1)));
+ interfaces = pickle->interfaces;
+}
+
+static int checkuid(list_ty list) {
+ int i, n = 0, count = Seq_length(list);
+
+ for (i = 0; i < count; i++) {
+ rcc_interface_ty in = Seq_get(list, i);
+ if (in->kind == rcc_Local_enum
+ || in->kind == rcc_Address_enum)
+ n++;
+ else if (in->kind == rcc_Function_enum)
+ n += checkuid(in->v.rcc_Function.codelist);
+ }
+ return n;
+}
+
+static void asdl_progend(void) {
+ dopending(NULL);
+ {
+ int n = checkuid(pickle->interfaces) + Seq_length(pickle->items);
+ if (n != pickle->nuids - 1)
+ fprintf(stderr, "?bogus uid count: have %d should have %d\n",
+ n, pickle->nuids-1);
+ }
+ pickle->nlabels = genlabel(0);
+ write_int((int)(100*(assert(strstr(rcsid, ",v")), strtod(strstr(rcsid, ",v")+2, NULL))
+), stdout);
+ rcc_write_program(pickle, stdout);
+}
+static void asdl_space(int n) {
+ put(rcc_Space(n));
+}
+
+void asdl_init(int argc, char *argv[]) {
+ int i;
+ static int inited;
+
+ if (inited)
+ return;
+ inited = 1;
+ for (i = 1; i < argc; i++)
+ if (strcmp(argv[i], "-asdl") == 0) {
+#define xx(f) IR->f = asdl_##f
+ xx(address);
+ xx(blockbeg);
+ xx(blockend);
+ xx(defaddress);
+ xx(defconst);
+ xx(defstring);
+ xx(defsymbol);
+ xx(emit);
+ xx(export);
+ xx(function);
+ xx(gen);
+ xx(global);
+ xx(import);
+ xx(local);
+ xx(progbeg);
+ xx(progend);
+ xx(segment);
+ xx(space);
+#undef xx
+#define xx(f) IR->f = 0
+ xx(stabblock);
+ xx(stabend);
+ xx(stabfend);
+ xx(stabinit);
+ xx(stabline);
+ xx(stabsym);
+ xx(stabtype);
+#undef xx
+ IR->wants_dag = 0;
+ prunetemps = 0; /* pass2 prunes useless temps */
+ assignargs = 0; /* pass2 generates caller to callee assignments */
+ }
+}