mirror of
https://github.com/UberGames/ioef.git
synced 2024-12-03 17:43:13 +00:00
399 lines
9.7 KiB
C
399 lines
9.7 KiB
C
#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 */
|
|
}
|
|
}
|