summaryrefslogtreecommitdiff
path: root/sys/src/cmd/1c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/1c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/1c')
-rwxr-xr-xsys/src/cmd/1c/bits.c127
-rwxr-xr-xsys/src/cmd/1c/cgen.c1396
-rwxr-xr-xsys/src/cmd/1c/enam.c424
-rwxr-xr-xsys/src/cmd/1c/gc.h340
-rwxr-xr-xsys/src/cmd/1c/list.c319
-rwxr-xr-xsys/src/cmd/1c/mkfile32
-rwxr-xr-xsys/src/cmd/1c/mul.c174
-rwxr-xr-xsys/src/cmd/1c/peep.c1057
-rwxr-xr-xsys/src/cmd/1c/reg.c1221
-rwxr-xr-xsys/src/cmd/1c/sgen.c714
-rwxr-xr-xsys/src/cmd/1c/swt.c964
-rwxr-xr-xsys/src/cmd/1c/txt.c903
12 files changed, 7671 insertions, 0 deletions
diff --git a/sys/src/cmd/1c/bits.c b/sys/src/cmd/1c/bits.c
new file mode 100755
index 000000000..eb8932c4a
--- /dev/null
+++ b/sys/src/cmd/1c/bits.c
@@ -0,0 +1,127 @@
+#define EXTERN
+#include "gc.h"
+
+/*
+Bits
+bor(Bits a, Bits b)
+{
+ Bits c;
+ int i;
+
+ for(i=0; i<BITS; i++)
+ c.b[i] = a.b[i] | b.b[i];
+ return c;
+}
+*/
+
+/*
+Bits
+band(Bits a, Bits b)
+{
+ Bits c;
+ int i;
+
+ for(i=0; i<BITS; i++)
+ c.b[i] = a.b[i] & b.b[i];
+ return c;
+}
+*/
+
+/*
+Bits
+bnot(Bits a)
+{
+ Bits c;
+ int i;
+
+ for(i=0; i<BITS; i++)
+ c.b[i] = ~a.b[i];
+ return c;
+}
+*/
+
+int
+bany(Bits *a)
+{
+ int i;
+
+ for(i=0; i<BITS; i++)
+ if(a->b[i])
+ return 1;
+ return 0;
+}
+
+/*
+int
+beq(Bits a, Bits b)
+{
+ int i;
+
+ for(i=0; i<BITS; i++)
+ if(a.b[i] != b.b[i])
+ return 0;
+ return 1;
+}
+*/
+
+int
+bnum(Bits a)
+{
+ int i;
+ long b;
+
+ for(i=0; i<BITS; i++)
+ if(b = a.b[i])
+ return 32*i + bitno(b);
+ diag(Z, "bad in bnum");
+ return 0;
+}
+
+Bits
+blsh(unsigned n)
+{
+ Bits c;
+
+ c = zbits;
+ c.b[n/32] = 1L << (n%32);
+ return c;
+}
+
+/*
+int
+bset(Bits a, unsigned n)
+{
+ int i;
+
+ if(a.b[n/32] & (1L << (n%32)))
+ return 1;
+ return 0;
+}
+*/
+
+int
+Bconv(va_list *arg, Fconv *fp)
+{
+ char str[STRINGSZ], ss[STRINGSZ], *s;
+ Bits bits;
+ int i;
+
+ str[0] = 0;
+ bits = va_arg(*arg, Bits);
+ while(bany(&bits)) {
+ i = bnum(bits);
+ if(str[0])
+ strcat(str, " ");
+ if(var[i].sym == S) {
+ sprint(ss, "$%ld", var[i].offset);
+ s = ss;
+ } else
+ s = var[i].sym->name;
+ if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
+ break;
+ strcat(str, s);
+ bits.b[i/32] &= ~(1L << (i%32));
+ }
+ strconv(str, fp);
+ return 0;
+}
diff --git a/sys/src/cmd/1c/cgen.c b/sys/src/cmd/1c/cgen.c
new file mode 100755
index 000000000..2f121e510
--- /dev/null
+++ b/sys/src/cmd/1c/cgen.c
@@ -0,0 +1,1396 @@
+#include "gc.h"
+
+void
+cgen(Node *n, int result, Node *nn)
+{
+ Node *l, *r, nod;
+ int lg, rg, xg, yg, g, o;
+ long v;
+ Prog *p1;
+
+ if(n == Z || n->type == T)
+ return;
+ if(typesuv[n->type->etype]) {
+ sugen(n, result, nn, n->type->width);
+ return;
+ }
+ if(debug['g']) {
+ if(result == D_TREE)
+ prtree(nn, "result");
+ else
+ print("result = %R\n", result);
+ prtree(n, "cgen");
+ }
+ l = n->left;
+ r = n->right;
+ o = n->op;
+ if(n->addable >= INDEXED) {
+ if(result == D_NONE) {
+ if(nn == Z)
+ switch(o) {
+ default:
+ nullwarn(Z, Z);
+ break;
+ case OINDEX:
+ nullwarn(l, r);
+ break;
+ }
+ return;
+ }
+ gmove(n->type, nn->type, D_TREE, n, result, nn);
+ return;
+ }
+
+ v = 0; /* set */
+ switch(o) {
+ default:
+ diag(n, "unknown op in cgen: %O", o);
+ break;
+
+ case OAS:
+ if(l->op == OBIT)
+ goto bitas;
+ /*
+ * recursive use of result
+ */
+ if(result == D_NONE)
+ if(l->addable > INDEXED)
+ if(l->complex < FNX) {
+ cgen(r, D_TREE, l);
+ break;
+ }
+
+ /*
+ * function calls on both sides
+ */
+ if(l->complex >= FNX && r->complex >= FNX) {
+ cgen(r, D_TOS, r);
+ v = argoff;
+ lg = regaddr(result);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ adjsp(v - argoff);
+ gmove(r->type, l->type, D_TOS, r, lg, l);
+ if(result != D_NONE)
+ gmove(l->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ break;
+ }
+
+ rg = D_TREE;
+ lg = D_TREE;
+ if(r->complex >= l->complex) {
+ /*
+ * right side before left
+ */
+ if(result != D_NONE) {
+ rg = regalloc(n->type, result);
+ cgen(r, rg, n);
+ } else
+ if(r->complex >= FNX || r->addable < INDEXED) {
+ rg = regalloc(r->type, result);
+ cgen(r, rg, r);
+ }
+ if(l->addable < INDEXED) {
+ lg = regaddr(lg);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ }
+ } else {
+ /*
+ * left before right
+ */
+ if(l->complex >= FNX || l->addable < INDEXED) {
+ lg = regaddr(lg);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ }
+ if(result != D_NONE) {
+ rg = regalloc(n->type, result);
+ cgen(r, rg, n);
+ } else
+ if(r->addable < INDEXED) {
+ rg = regalloc(r->type, result);
+ cgen(r, rg, r);
+ }
+ }
+ if(result != D_NONE) {
+ gmove(n->type, l->type, rg, r, lg, l);
+ gmove(n->type, nn->type, rg, r, result, nn);
+ } else
+ gmove(r->type, l->type, rg, r, lg, l);
+ regfree(lg);
+ regfree(rg);
+ break;
+
+ bitas:
+ n = l->left;
+ rg = regalloc(tfield, result);
+ if(l->complex >= r->complex) {
+ lg = regaddr(D_NONE);
+ lcgen(n, lg, Z);
+ lg |= I_INDIR;
+ cgen(r, rg, r);
+ } else {
+ cgen(r, rg, r);
+ lg = regaddr(D_NONE);
+ lcgen(n, lg, Z);
+ lg |= I_INDIR;
+ }
+ g = regalloc(n->type, D_NONE);
+ gmove(l->type, l->type, lg, l, g, l);
+ bitstore(l, rg, lg, g, result, nn);
+ break;
+
+ case OBIT:
+ if(result == D_NONE) {
+ nullwarn(l, Z);
+ break;
+ }
+ g = bitload(n, D_NONE, D_NONE, result, nn);
+ gopcode(OAS, nn->type, g, n, result, nn);
+ regfree(g);
+ break;
+
+ case ODOT:
+ sugen(l, D_TREE, nodrat, l->type->width);
+ if(result != D_NONE) {
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += r->vconst;
+ nod.type = n->type;
+ cgen(&nod, result, nn);
+ }
+ break;
+
+ case OASLDIV:
+ case OASLMOD:
+ case OASDIV:
+ case OASMOD:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(typefd[n->type->etype])
+ goto asbinop;
+ rg = D_TREE;
+ if(l->complex >= FNX || r->complex >= FNX) {
+ rg = D_TOS;
+ cgen(r, rg, r);
+ v = argoff;
+ } else
+ if(r->addable < INDEXED) {
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ }
+ lg = D_TREE;
+ if(!simplv(l)) {
+ lg = regaddr(D_NONE);
+ lcgen(l, lg, Z); /* destroys register optimization */
+ lg |= I_INDIR;
+ }
+ g = regpair(result);
+ gmove(l->type, n->type, lg, l, g, n);
+ if(rg == D_TOS)
+ adjsp(v - argoff);
+ gopcode(o, n->type, rg, r, g, n);
+ if(o == OASLMOD || o == OASMOD)
+ gmove(n->type, l->type, g+1, n, lg, l);
+ else
+ gmove(n->type, l->type, g, n, lg, l);
+ if(result != D_NONE)
+ if(o == OASLMOD || o == OASMOD)
+ gmove(n->type, nn->type, g+1, n, result, nn);
+ else
+ gmove(n->type, nn->type, g, n, result, nn);
+ regfree(g);
+ regfree(g+1);
+ regfree(lg);
+ regfree(rg);
+ break;
+
+ case OASXOR:
+ case OASAND:
+ case OASOR:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(l->complex >= FNX ||
+ l->addable < INDEXED ||
+ result != D_NONE ||
+ typefd[n->type->etype])
+ goto asbinop;
+ rg = D_TREE;
+ if(r->op != OCONST) {
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ }
+ gopcode(o, l->type, rg, r, D_TREE, l);
+ regfree(rg);
+ break;
+
+ case OASADD:
+ case OASSUB:
+ if(l->op == OBIT ||
+ l->complex >= FNX ||
+ l->addable < INDEXED ||
+ result != D_NONE ||
+ typefd[n->type->etype])
+ goto asbinop;
+ v = vconst(r);
+ if(v > 0 && v <= 8) {
+ gopcode(o, n->type, D_TREE, r, D_TREE, l);
+ break;
+ }
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ gopcode(o, n->type, rg, r, D_TREE, l);
+ regfree(rg);
+ break;
+
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ if(l->op == OBIT ||
+ l->complex >= FNX ||
+ l->addable < INDEXED ||
+ result != D_NONE ||
+ typefd[n->type->etype])
+ goto asbinop;
+ rg = D_TREE;
+ v = vconst(r);
+ if(v <= 0 || v > 8) {
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ }
+ lg = regalloc(n->type, D_NONE);
+ cgen(l, lg, l);
+ gopcode(o, n->type, rg, r, lg, l);
+ gmove(n->type, n->type, lg, l, D_TREE, l);
+ regfree(lg);
+ regfree(rg);
+ break;
+
+ case OASLMUL:
+ case OASMUL:
+ asbinop:
+ if(l->op == OBIT)
+ goto asbitop;
+ rg = D_TREE;
+ if(l->complex >= FNX || r->complex >= FNX) {
+ rg = D_TOS;
+ cgen(r, rg, r);
+ v = argoff;
+ } else
+ if(r->addable < INDEXED) {
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ } else {
+ if(o == OASLSHR || o == OASASHR || o == OASASHL) {
+ v = vconst(r);
+ if(v <= 0 || v > 8) {
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ }
+ }
+ }
+ lg = D_TREE;
+ if(!simplv(l)) {
+ lg = regaddr(D_NONE);
+ lcgen(l, lg, Z); /* destroys register optimization */
+ lg |= I_INDIR;
+ }
+ g = regalloc(n->type, result);
+ gmove(l->type, n->type, lg, l, g, n);
+ if(rg == D_TOS)
+ adjsp(v - argoff);
+ if(o == OASXOR)
+ if(rg == D_TREE) {
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ }
+ if(o == OASXOR || o == OASLSHR || o == OASASHR || o == OASASHL)
+ if(rg == D_TOS) {
+ rg = regalloc(n->type, D_NONE);
+ gmove(n->type, n->type, D_TOS, n, rg, n);
+ }
+ gopcode(o, n->type, rg, r, g, n);
+ gmove(n->type, l->type, g, n, lg, l);
+ if(result != D_NONE)
+ gmove(n->type, nn->type, g, n, result, nn);
+ regfree(g);
+ regfree(lg);
+ regfree(rg);
+ break;
+
+ asbitop:
+ rg = regaddr(D_NONE);
+ lg = regalloc(tfield, D_NONE);
+ if(l->complex >= r->complex) {
+ g = bitload(l, lg, rg, result, nn);
+ xg = regalloc(r->type, D_NONE);
+ cgen(r, xg, nn);
+ } else {
+ xg = regalloc(r->type, D_NONE);
+ cgen(r, xg, nn);
+ g = bitload(l, lg, rg, result, nn);
+ }
+
+ if(!typefd[n->type->etype]) {
+ if(o == OASLDIV || o == OASDIV) {
+ yg = regpair(result);
+ gmove(tfield, n->type, g, l, yg, n);
+ gopcode(o, n->type, xg, r, yg, n);
+ gmove(n->type, tfield, yg, n, g, l);
+ regfree(yg);
+ regfree(yg+1);
+
+ regfree(xg);
+ bitstore(l, g, rg, lg, D_NONE, nn);
+ break;
+ }
+ if(o == OASLMOD || o == OASMOD) {
+ yg = regpair(result);
+ gmove(tfield, n->type, g, l, yg, n);
+ gopcode(o, n->type, xg, r, yg, n);
+ gmove(n->type, tfield, yg+1, n, g, l);
+ regfree(yg);
+ regfree(yg+1);
+
+ regfree(xg);
+ bitstore(l, g, rg, lg, D_NONE, nn);
+ break;
+ }
+ }
+
+ yg = regalloc(n->type, result);
+ gmove(tfield, n->type, g, l, yg, n);
+ gopcode(o, n->type, xg, r, yg, n);
+ gmove(n->type, tfield, yg, n, g, l);
+ regfree(yg);
+
+ regfree(xg);
+ bitstore(l, g, rg, lg, D_NONE, nn);
+ break;
+
+ case OCAST:
+ if(result == D_NONE) {
+ nullwarn(l, Z);
+ break;
+ }
+ lg = result;
+ if(l->complex >= FNX)
+ lg = regret(l->type);
+ lg = eval(l, lg);
+ if(nocast(l->type, n->type)) {
+ gmove(n->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ break;
+ }
+ if(nocast(n->type, nn->type)) {
+ gmove(l->type, n->type, lg, l, result, nn);
+ regfree(lg);
+ break;
+ }
+ rg = regalloc(n->type, result);
+ gmove(l->type, n->type, lg, l, rg, n);
+ gmove(n->type, nn->type, rg, n, result, nn);
+ regfree(rg);
+ regfree(lg);
+ break;
+
+ case OCOND:
+ doinc(l, PRE);
+ boolgen(l, 1, D_NONE, Z, l);
+ p1 = p;
+
+ inargs++;
+ doinc(r->left, PRE);
+ cgen(r->left, result, nn);
+ doinc(r->left, POST);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+
+ doinc(r->right, PRE);
+ cgen(r->right, result, nn);
+ doinc(r->right, POST);
+ patch(p1, pc);
+ inargs--;
+ break;
+
+ case OIND:
+ if(result == D_NONE) {
+ nullwarn(l, Z);
+ break;
+ }
+ lg = nodalloc(types[TIND], result, &nod);
+ nod.lineno = n->lineno;
+ if(l->op == OADD) {
+ if(l->left->op == OCONST) {
+ nod.xoffset += l->left->vconst;
+ l = l->right;
+ } else
+ if(l->right->op == OCONST) {
+ nod.xoffset += l->right->vconst;
+ l = l->left;
+ }
+ }
+ cgen(l, lg, l);
+ gmove(n->type, nn->type, D_TREE, &nod, result, nn);
+ regfree(lg);
+ break;
+
+ case OFUNC:
+ v = argoff;
+ inargs++;
+ gargs(r);
+ lg = D_TREE;
+ if(l->addable < INDEXED) {
+ lg = regaddr(result);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ }
+ inargs--;
+ doinc(r, POST);
+ doinc(l, POST);
+ gopcode(OFUNC, types[TCHAR], D_NONE, Z, lg, l);
+ regfree(lg);
+ if(inargs)
+ adjsp(v - argoff);
+ if(result != D_NONE) {
+ lg = regret(n->type);
+ gmove(n->type, nn->type, lg, n, result, nn);
+ }
+ break;
+
+ case OLDIV:
+ case OLMOD:
+ case ODIV:
+ case OMOD:
+ if(result == D_NONE) {
+ nullwarn(l, r);
+ break;
+ }
+ if(typefd[n->type->etype])
+ goto binop;
+ if(r->addable >= INDEXED && r->complex < FNX) {
+ lg = regpair(result);
+ cgen(l, lg, l);
+ rg = D_TREE;
+ } else {
+ cgen(r, D_TOS, r);
+ v = argoff;
+ lg = regpair(result);
+ cgen(l, lg, l);
+ adjsp(v - argoff);
+ rg = D_TOS;
+ }
+ gopcode(o, n->type, rg, r, lg, l);
+ if(o == OMOD || o == OLMOD)
+ gmove(l->type, nn->type, lg+1, l, result, nn);
+ else
+ gmove(l->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ regfree(lg+1);
+ break;
+
+ case OMUL:
+ case OLMUL:
+ if(l->op == OCONST)
+ if(mulcon(r, l, result, nn))
+ break;
+ if(r->op == OCONST)
+ if(mulcon(l, r, result, nn))
+ break;
+ if(debug['M'])
+ print("%L multiply\n", n->lineno);
+ goto binop;
+
+ case OAND:
+ if(r->op == OCONST)
+ if(typeil[n->type->etype])
+ if(l->op == OCAST) {
+ if(typec[l->left->type->etype])
+ if(!(r->vconst & ~0xff)) {
+ l = l->left;
+ goto binop;
+ }
+ if(typeh[l->left->type->etype])
+ if(!(r->vconst & ~0xffff)) {
+ l = l->left;
+ goto binop;
+ }
+ }
+ goto binop;
+
+ case OADD:
+ if(result == D_TOS)
+ if(r->addable >= INDEXED)
+ if(l->op == OCONST)
+ if(typeil[l->type->etype]) {
+ v = l->vconst;
+ if(v > -32768 && v < 32768) {
+ rg = regaddr(D_NONE);
+ gmove(r->type, r->type, D_TREE, r, rg, r);
+ gopcode(OADDR, types[TSHORT], D_NONE, Z, rg, r);
+ p->to.offset = v;
+ p->to.type |= I_INDIR;
+ regfree(rg);
+ break;
+ }
+ }
+
+ case OSUB:
+ if(result == D_TOS)
+ if(l->addable >= INDEXED)
+ if(r->op == OCONST)
+ if(typeil[r->type->etype]) {
+ v = r->vconst;
+ if(v > -32768 && v < 32768) {
+ if(n->op == OSUB)
+ v = -v;
+ lg = regaddr(D_NONE);
+ gmove(l->type, l->type, D_TREE, l, lg, l);
+ gopcode(OADDR, types[TSHORT], D_NONE, Z, lg, l);
+ p->to.offset = v;
+ p->to.type |= I_INDIR;
+ regfree(lg);
+ break;
+ }
+ }
+ goto binop;
+
+ case OOR:
+ case OXOR:
+ binop:
+ if(result == D_NONE) {
+ nullwarn(l, r);
+ break;
+ }
+ if(l->complex >= FNX && r->complex >= FNX) {
+ cgen(r, D_TOS, r);
+ v = argoff;
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ adjsp(v - argoff);
+ if(o == OXOR) {
+ rg = regalloc(r->type, D_NONE);
+ gmove(r->type, r->type, D_TOS, r, rg, r);
+ gopcode(o, n->type, rg, r, lg, l);
+ regfree(rg);
+ } else
+ gopcode(o, n->type, D_TOS, r, lg, l);
+ gmove(n->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ if(l->op == OADDR && (o == OADD || o == OSUB))
+ lg = regaddr(result);
+ else
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ rg = eval(r, D_NONE);
+ } else {
+ rg = regalloc(r->type, D_NONE);
+ cgen(r, rg, r);
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ }
+ if(o == OXOR) {
+ if(rg == D_TREE) {
+ rg = regalloc(r->type, D_NONE);
+ cgen(r, rg, r);
+ }
+ if(rg == D_TOS) {
+ rg = regalloc(r->type, D_NONE);
+ gmove(r->type, r->type, D_TOS, r, rg, r);
+ }
+ }
+ gopcode(o, n->type, rg, r, lg, l);
+ gmove(n->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ regfree(rg);
+ break;
+
+ case OASHL:
+ if(r->op == OCONST)
+ if(shlcon(l, r, result, nn))
+ break;
+ case OLSHR:
+ case OASHR:
+ if(result == D_NONE) {
+ nullwarn(l, r);
+ break;
+ }
+
+ if(l->complex >= FNX && r->complex >= FNX) {
+ cgen(r, D_TOS, r);
+ v = argoff;
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ adjsp(v - argoff);
+ rg = regalloc(r->type, D_NONE);
+ gopcode(OAS, r->type, D_TOS, r, rg, r);
+ gopcode(n->op, n->type, rg, r, lg, l);
+ gmove(n->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ regfree(rg);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ v = vconst(r);
+ if(v <= 0 || v > 8) {
+ rg = regalloc(r->type, D_NONE);
+ cgen(r, rg, r);
+ } else
+ rg = eval(r, D_NONE);
+ } else {
+ rg = regalloc(r->type, D_NONE);
+ cgen(r, rg, r);
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ }
+ gopcode(o, n->type, rg, r, lg, l);
+ gmove(n->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ regfree(rg);
+ break;
+
+ case ONEG:
+ case OCOM:
+ if(result == D_NONE) {
+ nullwarn(l, Z);
+ break;
+ }
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ gopcode(o, l->type, D_NONE, Z, lg, l);
+ gmove(n->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ break;
+
+ case OADDR:
+ if(result == D_NONE) {
+ nullwarn(l, Z);
+ break;
+ }
+ lcgen(l, result, nn);
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHI:
+ case OHS:
+ if(result == D_NONE) {
+ nullwarn(l, r);
+ break;
+ }
+ boolgen(n, 1, result, nn, Z);
+ break;
+
+ case OANDAND:
+ case OOROR:
+ boolgen(n, 1, result, nn, Z);
+ if(result == D_NONE)
+ patch(p, pc);
+ break;
+
+ case OCOMMA:
+ cgen(l, D_NONE, l);
+ doinc(l, POST);
+ doinc(r, PRE);
+ cgen(r, result, nn);
+ break;
+
+ case ONOT:
+ if(result == D_NONE) {
+ nullwarn(l, Z);
+ break;
+ }
+ boolgen(n, 1, result, nn, Z);
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPOSTDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+ if(nn == Z)
+ goto pre;
+
+ lg = D_TREE;
+ if(l->addable < INDEXED) {
+ lg = regaddr(D_NONE);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ }
+ if(result != D_NONE)
+ gmove(l->type, nn->type, lg, l, result, nn);
+ if(typefd[n->type->etype]) {
+ rg = regalloc(n->type, D_NONE);
+ gmove(l->type, l->type, lg, l, rg, l);
+ gopcode(o, n->type, D_CONST, nodconst(1), rg, l);
+ gmove(l->type, l->type, rg, l, lg, l);
+ regfree(rg);
+ } else {
+ if(v < 0)
+ gopcode(o, n->type, D_CONST, nodconst(-v), lg, l);
+ else
+ gopcode(o, n->type, D_CONST, nodconst(v), lg, l);
+ }
+ regfree(lg);
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPREDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+
+ pre:
+ lg = D_TREE;
+ if(l->addable < INDEXED) {
+ lg = regaddr(D_NONE);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ }
+ if(typefd[n->type->etype]) {
+ rg = regalloc(n->type, D_NONE);
+ gmove(l->type, l->type, lg, l, rg, l);
+ gopcode(o, n->type, D_CONST, nodconst(1), rg, l);
+ gmove(l->type, l->type, rg, l, lg, l);
+ regfree(rg);
+ } else {
+ if(v < 0)
+ gopcode(o, n->type, D_CONST, nodconst(-v), lg, l);
+ else
+ gopcode(o, n->type, D_CONST, nodconst(v), lg, l);
+ }
+ if(result != D_NONE)
+ gmove(l->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ break;
+
+ bitinc:
+ rg = regaddr(D_NONE);
+ lg = regalloc(tfield, D_NONE);
+ if(result != D_NONE && (o == OPOSTINC || o == OPOSTDEC)) {
+ g = bitload(l, lg, rg, D_NONE, nn);
+ if(nn != Z)
+ gmove(l->type, nn->type, g, l, result, nn);
+ if(v < 0)
+ gopcode(o, n->type, D_CONST, nodconst(-v), g, n);
+ else
+ gopcode(o, n->type, D_CONST, nodconst(v), g, n);
+ bitstore(l, g, rg, lg, D_NONE, nn);
+ break;
+ }
+ g = bitload(l, lg, rg, result, nn);
+ if(v < 0)
+ gopcode(o, n->type, D_CONST, nodconst(-v), g, n);
+ else
+ gopcode(o, n->type, D_CONST, nodconst(v), g, n);
+ if(result != D_NONE)
+ gmove(l->type, nn->type, g, l, result, nn);
+ bitstore(l, g, rg, lg, D_NONE, nn);
+ break;
+ }
+}
+
+void
+lcgen(Node *n, int result, Node *nn)
+{
+ Node rn;
+ Prog *p1;
+ int lg;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ if(result == D_TREE)
+ prtree(nn, "result");
+ else
+ print("result = %R\n", result);
+ prtree(n, "lcgen");
+ }
+ if(nn == Z) {
+ nn = &rn;
+ nn->type = types[TIND];
+ }
+ switch(n->op) {
+ case OCOMMA:
+ cgen(n->left, D_NONE, n->left);
+ doinc(n->left, POST);
+ doinc(n->right, PRE);
+ lcgen(n->right, result, nn);
+ break;
+
+ case OCOND:
+ doinc(n->left, PRE);
+ boolgen(n->left, 1, D_NONE, Z, n->left);
+ p1 = p;
+
+ inargs++;
+ doinc(n->right->left, PRE);
+ lcgen(n->right->left, result, nn);
+ doinc(n->right->left, POST);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+
+ doinc(n->right->right, PRE);
+ lcgen(n->right->right, result, nn);
+ doinc(n->right->right, POST);
+ patch(p1, pc);
+ inargs--;
+ break;
+
+ case OIND:
+ if(n->addable >= INDEXED) {
+ if(result >= D_A0 && result < D_A0+NREG) {
+ gopcode(OADDR, types[TLONG], D_TREE, n, result, nn);
+ break;
+ }
+ if(result == D_TOS) {
+ gopcode(OADDR, types[TSHORT], D_NONE, nn, D_TREE, n);
+ break;
+ }
+ }
+ cgen(n->left, result, nn);
+ break;
+
+ default:
+ if(n->addable < INDEXED) {
+ diag(n, "unknown op in lcgen: %O", n->op);
+ break;
+ }
+ if(result >= D_A0 && result < D_A0+NREG) {
+ gopcode(OADDR, types[TLONG], D_TREE, n, result, nn);
+ break;
+ }
+ if(result == D_TOS) {
+ gopcode(OADDR, types[TSHORT], D_NONE, nn, D_TREE, n);
+ break;
+ }
+ lg = regaddr(result);
+ gopcode(OADDR, types[TLONG], D_TREE, n, lg, nn);
+ gopcode(OAS, nn->type, lg, nn, result, nn);
+ regfree(lg);
+ break;
+ }
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+ boolgen(n, true, D_NONE, Z, Z);
+}
+
+void
+boolgen(Node *n, int true, int result, Node *nn, Node *post)
+{
+ Prog *p1, *p2;
+ Node *l, *r;
+ int lg, rg, fp, o;
+ long v;
+
+ if(debug['g']) {
+ if(result == D_TREE)
+ prtree(nn, "result");
+ else
+ print("result = %R\n", result);
+ prtree(n, "boolgen");
+ }
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ default:
+ lg = eval(n, result);
+ if(lg >= D_A0 && lg < D_A0+NREG) {
+ rg = regalloc(types[TLONG], D_NONE);
+ gopcode(OAS, types[TLONG], lg, n, rg, Z);
+ regfree(rg);
+ } else
+ gopcode(OTST, n->type, D_NONE, Z, lg, n);
+ regfree(lg);
+ o = ONE;
+ fp = typefd[n->type->etype];
+ goto genbool;
+
+ case OCONST:
+ fp = vconst(n);
+ if(!true)
+ fp = !fp;
+ gbranch(OGOTO);
+ if(fp) {
+ p1 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ }
+ goto com;
+
+ case ONOT:
+ boolgen(l, !true, result, nn, post);
+ break;
+
+ case OCOND:
+ doinc(l, PRE);
+ boolgen(l, 1, D_NONE, Z, l);
+ p1 = p;
+
+ inargs++;
+ doinc(r->left, PRE);
+ boolgen(r->left, true, result, nn, r->left);
+ if(result != D_NONE) {
+ doinc(r->left, POST);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+
+ doinc(r->right, PRE);
+ boolgen(r->right, !true, result, nn, r->right);
+ doinc(r->right, POST);
+ patch(p1, pc);
+ inargs--;
+ break;
+ }
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+
+ doinc(r->right, PRE);
+ boolgen(r->right, !true, result, nn, r->right);
+ patch(p2, pc);
+ p2 = p;
+ if(doinc(post, POST|TEST)) {
+ lg = regalloc(types[TSHORT], D_NONE);
+ gopcode(OAS, types[TSHORT], D_CCR, Z, lg, Z);
+ doinc(post, POST);
+ gopcode(OAS, types[TSHORT], lg, Z, D_CCR, Z);
+ regfree(lg);
+ }
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ inargs--;
+ goto com;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ doinc(l, PRE);
+ boolgen(l, true, D_NONE, Z, l);
+ p1 = p;
+ inargs++;
+ doinc(r, PRE);
+ boolgen(r, !true, D_NONE, Z, r);
+ p2 = p;
+ patch(p1, pc);
+ gbranch(OGOTO);
+ patch(p2, pc);
+ inargs--;
+ goto com;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ doinc(l, PRE);
+ boolgen(l, !true, D_NONE, Z, l);
+ p1 = p;
+ inargs++;
+ doinc(r, PRE);
+ boolgen(r, !true, D_NONE, Z, r);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ inargs--;
+ goto com;
+
+ case OEQ:
+ case ONE:
+ if(vconst(l) == 0) {
+ if(n->op == ONE) {
+ boolgen(r, true, result, nn, post);
+ break;
+ }
+ boolgen(r, !true, result, nn, post);
+ break;
+ }
+
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ fp = typefd[r->type->etype];
+ if(l->op == OCONST) {
+ v = vconst(l);
+ if(v == 0) { /* tst instruction */
+ o = invrel[relindex(n->op)];
+ rg = eval(r, result);
+ gopcode(OTST, r->type, D_NONE, Z, rg, r);
+ regfree(rg);
+ goto genbool;
+ }
+ if(!fp) { /* cmpi and movq, saves about .5% both time and space */
+ if(v < 128 && v >= -128 &&
+ ewidth[r->type->etype] == SZ_LONG) {
+ rg = eval(r, result);
+ lg = regalloc(l->type, D_NONE);
+ cgen(l, lg, l);
+ o = n->op;
+ gopcode(o, l->type, lg, l, rg, r);
+ regfree(lg);
+ regfree(rg);
+ goto genbool;
+ }
+ o = invrel[relindex(n->op)];
+ rg = eval(r, result);
+ gopcode(o, r->type, rg, r, D_TREE, l);
+ regfree(rg);
+ goto genbool;
+ }
+ }
+ lg = D_TOS;
+ if(r->complex < FNX)
+ lg = regalloc(l->type, lg);
+ cgen(l, lg, l);
+ v = argoff;
+ rg = eval(r, result);
+ if(lg == D_TOS) {
+ adjsp(v - argoff);
+ lg = regalloc(l->type, lg);
+ gopcode(OAS, l->type, D_TOS, l, lg, l);
+ }
+ o = n->op;
+ gopcode(o, l->type, lg, l, rg, r);
+ regfree(lg);
+ regfree(rg);
+
+ genbool:
+ if(true)
+ o = comrel[relindex(o)];
+ if(doinc(post, POST|TEST)) {
+ lg = regalloc(types[TSHORT], D_NONE);
+ gopcode(OAS, types[TSHORT], D_CCR, Z, lg, Z);
+ doinc(post, POST);
+ gopcode(OAS, types[TSHORT], lg, Z, D_CCR, Z);
+ regfree(lg);
+ }
+ gbranch(o);
+ if(fp)
+ fpbranch();
+
+ com:
+ if(result == D_NONE)
+ break;
+ p1 = p;
+ gopcode(OAS, nn->type, D_CONST, nodconst(1), result, nn);
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gopcode(OAS, nn->type, D_CONST, nodconst(0), result, nn);
+ patch(p2, pc);
+ break;
+ }
+}
+
+void
+sugen(Node *n, int result, Node *nn, long w)
+{
+ long s, v, o;
+ int lg, rg, ng;
+ Prog *p1;
+ Node *l, *r, nod;
+ Type *t;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ if(result == D_TREE)
+ prtree(nn, "result");
+ else
+ print("result = %R width = %ld\n", result, w);
+ prtree(n, "sugen");
+ }
+ s = argoff;
+ if(result == D_TREE) {
+ if(nn == nodrat)
+ if(w > nrathole)
+ nrathole = w;
+ }
+
+ if(n->addable >= INDEXED && n->op != OCONST)
+ goto copy;
+ switch(n->op) {
+ default:
+ diag(n, "unknown op in sugen: %O", n->op);
+ break;
+
+ case OCONST:
+ if(n->type && typev[n->type->etype]) {
+ if(result == D_NONE) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ lg = regaddr(D_NONE);
+ if(result == D_TOS) {
+ adjsp(s - argoff + w);
+ gopcode(OADDR, types[TIND], result, nn, lg, n);
+ } else
+ if(result == D_TREE) {
+ lcgen(nn, lg, Z);
+ } else
+ diag(n, "unknown su result: %R", result);
+
+ gopcode(OAS, types[TLONG], D_CONST, nodconst((long)(n->vconst>>32)),
+ lg|I_INDINC, n);
+ gopcode(OAS, types[TLONG], D_CONST, nodconst((long)(n->vconst)),
+ lg|I_INDINC, n);
+ regfree(lg);
+ break;
+ }
+ goto copy;
+
+ case ODOT:
+ l = n->left;
+ sugen(l, D_TREE, nodrat, l->type->width);
+ if(result != D_NONE) {
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ r = n->right;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += r->vconst;
+ nod.type = n->type;
+ sugen(&nod, result, nn, w);
+ }
+ break;
+
+ case OIND:
+ if(result == D_NONE) {
+ nullwarn(n->left, Z);
+ break;
+ }
+ goto copy;
+
+ case OSTRUCT:
+ lg = nodalloc(types[TIND], result, &nod);
+ nod.lineno = n->lineno;
+ if(result == D_TREE)
+ lcgen(nn, lg, Z);
+ else
+ if(result == D_TOS) {
+ adjsp(s - argoff + w);
+ gopcode(OADDR, types[TIND], result, nn, lg, n);
+ } else
+ diag(n, "unknown su result: %R", result);
+ o = 0;
+ r = n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ l = r;
+ if(r->op == OLIST) {
+ l = r->left;
+ r = r->right;
+ }
+ nod.type = t;
+ if(l->complex < FNX) {
+ nod.xoffset = 0;
+ if(o != t->offset) {
+ gopcode(OADD, types[TIND], D_CONST,
+ nodconst(t->offset-o), lg, Z);
+ o = t->offset;
+ }
+ cgen(l, D_TREE, &nod);
+ continue;
+ }
+ nod.xoffset = t->offset - o;
+ gopcode(OAS, types[TIND], lg, Z, D_TOS, Z);
+ s = argoff;
+ if(typesuv[t->etype]) {
+ sugen(l, D_TREE, nodrat, t->width);
+ adjsp(s - argoff);
+ gopcode(OAS, types[TIND], D_TOS, Z, lg, Z);
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, D_TREE, &nod, t->width);
+ continue;
+ }
+ rg = regalloc(t, D_NONE);
+ cgen(l, rg, l);
+ adjsp(s - argoff);
+ gopcode(OAS, types[TIND], D_TOS, Z, lg, Z);
+ gopcode(OAS, t, rg, Z, D_TREE, &nod);
+ regfree(rg);
+ }
+ regfree(lg);
+ break;
+
+ case OAS:
+ if(result == D_NONE) {
+ sugen(n->right, D_TREE, n->left, w);
+ break;
+ }
+ sugen(n->right, D_TREE, nodrat, w); /* could do better */
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, D_TREE, n->left, w);
+ sugen(nodrat, result, nn, w);
+ break;
+
+ case OFUNC:
+ if(result == D_NONE) {
+ sugen(n, D_TREE, nodrat, w);
+ break;
+ }
+ inargs++;
+ /* prepare zero-th arg: address of result */
+ if(result == D_TOS) {
+ adjsp(s - argoff + w);
+ v = argoff;
+ gargs(n->right);
+ gopcode(OADDR, types[TSHORT], D_NONE, nn, result, nn);
+ p->to.type = D_STACK;
+ p->to.offset = argoff - v;
+ } else
+ if(result == D_TREE) {
+ v = argoff;
+ gargs(n->right);
+ if(nn->complex >= FNX) {
+ rg = regalloc(types[TIND], regret(types[TIND]));
+ lcgen(nn, rg, Z);
+ gopcode(OAS, types[TIND], rg, Z, D_TOS, Z);
+ regfree(rg);
+ } else
+ lcgen(nn, D_TOS, Z);
+ } else {
+ diag(n, "unknown result in FUNC sugen");
+ break;
+ }
+ argoff += types[TIND]->width;
+ l = n->left;
+ lg = D_TREE;
+ if(l->addable < INDEXED) {
+ lg = regaddr(result);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ }
+ inargs--;
+ doinc(n->right, POST);
+ doinc(n->left, POST);
+ gopcode(OFUNC, types[TCHAR], D_NONE, Z, lg, l);
+ regfree(lg);
+ if(inargs)
+ adjsp(v - argoff);
+ break;
+
+ case OCOND:
+ doinc(n->left, PRE);
+ boolgen(n->left, 1, D_NONE, Z, n->left);
+ p1 = p;
+
+ inargs++;
+ doinc(n->right->left, PRE);
+ sugen(n->right->left, result, nn, w);
+ doinc(n->right->left, POST);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+
+ doinc(n->right->right, PRE);
+ sugen(n->right->right, result, nn, w);
+ doinc(n->right->right, POST);
+ patch(p1, pc);
+ inargs--;
+ break;
+
+ case OCOMMA:
+ cgen(n->left, D_NONE, n->left);
+ doinc(n->left, POST);
+ doinc(n->right, PRE);
+ sugen(n->right, result, nn, w);
+ break;
+ }
+ return;
+
+copy:
+ if(result == D_NONE)
+ return;
+ rg = regaddr(D_NONE);
+ lcgen(n, rg, Z);
+
+ lg = regaddr(D_NONE);
+ if(result == D_TOS) {
+ adjsp(s - argoff + w);
+ gopcode(OADDR, types[TIND], result, nn, lg, n);
+ } else
+ if(result == D_TREE) {
+ if(nn->complex >= FNX) {
+ gopcode(OAS, types[TIND], rg, n, D_TOS, n);
+ s = argoff;
+ lcgen(nn, lg, Z);
+ adjsp(s - argoff);
+ gopcode(OAS, types[TIND], D_TOS, n, rg, n);
+ } else
+ lcgen(nn, lg, Z);
+ } else
+ diag(n, "unknown su result: %R", result);
+
+ if(w % SZ_LONG)
+ diag(Z, "sucopy width not 0%%%d", SZ_LONG);
+ v = w / SZ_LONG;
+ if(v & 1) {
+ gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n);
+ v--;
+ }
+ if(v > 6) {
+ ng = regalloc(types[TLONG], D_NONE);
+ gopcode(OAS, types[TLONG], D_CONST, nodconst(v/2-1), ng, n);
+ v = pc;
+ gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n);
+ gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n);
+ gbranch(OGT);
+ patch(p, v);
+ p->from.type = ng;
+ p->as = ADBF;
+ regfree(ng);
+ } else
+ while(v > 0) {
+ gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n);
+ v--;
+ }
+
+ regfree(lg);
+ regfree(rg);
+}
diff --git a/sys/src/cmd/1c/enam.c b/sys/src/cmd/1c/enam.c
new file mode 100755
index 000000000..0633f1f60
--- /dev/null
+++ b/sys/src/cmd/1c/enam.c
@@ -0,0 +1,424 @@
+char *anames[] =
+{
+ "XXX",
+ "ABCD",
+ "ADDB",
+ "ADDL",
+ "ADDW",
+ "ADDXB",
+ "ADDXL",
+ "ADDXW",
+ "ADJSP",
+ "ANDB",
+ "ANDL",
+ "ANDW",
+ "ASLB",
+ "ASLL",
+ "ASLW",
+ "ASRB",
+ "ASRL",
+ "ASRW",
+ "BCASE",
+ "BCC",
+ "BCHG",
+ "BCLR",
+ "BCS",
+ "BEQ",
+ "BFCHG",
+ "BFCLR",
+ "BFEXTS",
+ "BFEXTU",
+ "BFFFO",
+ "BFINS",
+ "BFSET",
+ "BFTST",
+ "BGE",
+ "BGT",
+ "BHI",
+ "BKPT",
+ "BLE",
+ "BLS",
+ "BLT",
+ "BMI",
+ "BNE",
+ "BPL",
+ "BRA",
+ "BSET",
+ "BSR",
+ "BTST",
+ "BVC",
+ "BVS",
+ "CALLM",
+ "CAS2B",
+ "CAS2L",
+ "CAS2W",
+ "CASB",
+ "CASEW",
+ "CASL",
+ "CASW",
+ "CHK2B",
+ "CHK2L",
+ "CHK2W",
+ "CHKL",
+ "CHKW",
+ "CLRB",
+ "CLRL",
+ "CLRW",
+ "CMP2B",
+ "CMP2L",
+ "CMP2W",
+ "CMPB",
+ "CMPL",
+ "CMPW",
+ "DATA",
+ "DBCC",
+ "DBCS",
+ "DBEQ",
+ "DBF",
+ "DBGE",
+ "DBGT",
+ "DBHI",
+ "DBLE",
+ "DBLS",
+ "DBLT",
+ "DBMI",
+ "DBNE",
+ "DBPL",
+ "DBT",
+ "DBVC",
+ "DBVS",
+ "DIVSL",
+ "DIVSW",
+ "DIVUL",
+ "DIVUW",
+ "END",
+ "EORB",
+ "EORL",
+ "EORW",
+ "EXG",
+ "EXTBL",
+ "EXTBW",
+ "EXTWL",
+ "FABSB",
+ "FABSD",
+ "FABSF",
+ "FABSL",
+ "FABSW",
+ "FACOSB",
+ "FACOSD",
+ "FACOSF",
+ "FACOSL",
+ "FACOSW",
+ "FADDB",
+ "FADDD",
+ "FADDF",
+ "FADDL",
+ "FADDW",
+ "FASINB",
+ "FASIND",
+ "FASINF",
+ "FASINL",
+ "FASINW",
+ "FATANB",
+ "FATAND",
+ "FATANF",
+ "FATANHB",
+ "FATANHD",
+ "FATANHF",
+ "FATANHL",
+ "FATANHW",
+ "FATANL",
+ "FATANW",
+ "FBEQ",
+ "FBF",
+ "FBGE",
+ "FBGT",
+ "FBLE",
+ "FBLT",
+ "FBNE",
+ "FBT",
+ "FCMPB",
+ "FCMPD",
+ "FCMPF",
+ "FCMPL",
+ "FCMPW",
+ "FCOSB",
+ "FCOSD",
+ "FCOSF",
+ "FCOSHB",
+ "FCOSHD",
+ "FCOSHF",
+ "FCOSHL",
+ "FCOSHW",
+ "FCOSL",
+ "FCOSW",
+ "FDBEQ",
+ "FDBF",
+ "FDBGE",
+ "FDBGT",
+ "FDBLE",
+ "FDBLT",
+ "FDBNE",
+ "FDBT",
+ "FDIVB",
+ "FDIVD",
+ "FDIVF",
+ "FDIVL",
+ "FDIVW",
+ "FETOXB",
+ "FETOXD",
+ "FETOXF",
+ "FETOXL",
+ "FETOXM1B",
+ "FETOXM1D",
+ "FETOXM1F",
+ "FETOXM1L",
+ "FETOXM1W",
+ "FETOXW",
+ "FGETEXPB",
+ "FGETEXPD",
+ "FGETEXPF",
+ "FGETEXPL",
+ "FGETEXPW",
+ "FGETMANB",
+ "FGETMAND",
+ "FGETMANF",
+ "FGETMANL",
+ "FGETMANW",
+ "FINTB",
+ "FINTD",
+ "FINTF",
+ "FINTL",
+ "FINTRZB",
+ "FINTRZD",
+ "FINTRZF",
+ "FINTRZL",
+ "FINTRZW",
+ "FINTW",
+ "FLOG10B",
+ "FLOG10D",
+ "FLOG10F",
+ "FLOG10L",
+ "FLOG10W",
+ "FLOG2B",
+ "FLOG2D",
+ "FLOG2F",
+ "FLOG2L",
+ "FLOG2W",
+ "FLOGNB",
+ "FLOGND",
+ "FLOGNF",
+ "FLOGNL",
+ "FLOGNP1B",
+ "FLOGNP1D",
+ "FLOGNP1F",
+ "FLOGNP1L",
+ "FLOGNP1W",
+ "FLOGNW",
+ "FMODB",
+ "FMODD",
+ "FMODF",
+ "FMODL",
+ "FMODW",
+ "FMOVEB",
+ "FMOVED",
+ "FMOVEF",
+ "FMOVEL",
+ "FMOVEM",
+ "FMOVEMC",
+ "FMOVEW",
+ "FMULB",
+ "FMULD",
+ "FMULF",
+ "FMULL",
+ "FMULW",
+ "FNEGB",
+ "FNEGD",
+ "FNEGF",
+ "FNEGL",
+ "FNEGW",
+ "FREMB",
+ "FREMD",
+ "FREMF",
+ "FREML",
+ "FREMW",
+ "FRESTORE",
+ "FSAVE",
+ "FSCALEB",
+ "FSCALED",
+ "FSCALEF",
+ "FSCALEL",
+ "FSCALEW",
+ "FSEQ",
+ "FSF",
+ "FSGE",
+ "FSGT",
+ "FSINB",
+ "FSIND",
+ "FSINF",
+ "FSINHB",
+ "FSINHD",
+ "FSINHF",
+ "FSINHL",
+ "FSINHW",
+ "FSINL",
+ "FSINW",
+ "FSLE",
+ "FSLT",
+ "FSNE",
+ "FSQRTB",
+ "FSQRTD",
+ "FSQRTF",
+ "FSQRTL",
+ "FSQRTW",
+ "FST",
+ "FSUBB",
+ "FSUBD",
+ "FSUBF",
+ "FSUBL",
+ "FSUBW",
+ "FTANB",
+ "FTAND",
+ "FTANF",
+ "FTANHB",
+ "FTANHD",
+ "FTANHF",
+ "FTANHL",
+ "FTANHW",
+ "FTANL",
+ "FTANW",
+ "FTENTOXB",
+ "FTENTOXD",
+ "FTENTOXF",
+ "FTENTOXL",
+ "FTENTOXW",
+ "FTSTB",
+ "FTSTD",
+ "FTSTF",
+ "FTSTL",
+ "FTSTW",
+ "FTWOTOXB",
+ "FTWOTOXD",
+ "FTWOTOXF",
+ "FTWOTOXL",
+ "FTWOTOXW",
+ "GLOBL",
+ "GOK",
+ "HISTORY",
+ "ILLEG",
+ "INSTR",
+ "JMP",
+ "JSR",
+ "LEA",
+ "LINKL",
+ "LINKW",
+ "LOCATE",
+ "LONG",
+ "LSLB",
+ "LSLL",
+ "LSLW",
+ "LSRB",
+ "LSRL",
+ "LSRW",
+ "MOVB",
+ "MOVEM",
+ "MOVEPL",
+ "MOVEPW",
+ "MOVESB",
+ "MOVESL",
+ "MOVESW",
+ "MOVL",
+ "MOVW",
+ "MULSL",
+ "MULSW",
+ "MULUL",
+ "MULUW",
+ "NAME",
+ "NBCD",
+ "NEGB",
+ "NEGL",
+ "NEGW",
+ "NEGXB",
+ "NEGXL",
+ "NEGXW",
+ "NOP",
+ "NOTB",
+ "NOTL",
+ "NOTW",
+ "ORB",
+ "ORL",
+ "ORW",
+ "PACK",
+ "PEA",
+ "RESET",
+ "ROTLB",
+ "ROTLL",
+ "ROTLW",
+ "ROTRB",
+ "ROTRL",
+ "ROTRW",
+ "ROXLB",
+ "ROXLL",
+ "ROXLW",
+ "ROXRB",
+ "ROXRL",
+ "ROXRW",
+ "RTD",
+ "RTE",
+ "RTM",
+ "RTR",
+ "RTS",
+ "SBCD",
+ "SCC",
+ "SCS",
+ "SEQ",
+ "SF",
+ "SGE",
+ "SGT",
+ "SHI",
+ "SLE",
+ "SLS",
+ "SLT",
+ "SMI",
+ "SNE",
+ "SPL",
+ "ST",
+ "STOP",
+ "SUBB",
+ "SUBL",
+ "SUBW",
+ "SUBXB",
+ "SUBXL",
+ "SUBXW",
+ "SVC",
+ "SVS",
+ "SWAP",
+ "SYS",
+ "TAS",
+ "TEXT",
+ "TRAP",
+ "TRAPCC",
+ "TRAPCS",
+ "TRAPEQ",
+ "TRAPF",
+ "TRAPGE",
+ "TRAPGT",
+ "TRAPHI",
+ "TRAPLE",
+ "TRAPLS",
+ "TRAPLT",
+ "TRAPMI",
+ "TRAPNE",
+ "TRAPPL",
+ "TRAPT",
+ "TRAPV",
+ "TRAPVC",
+ "TRAPVS",
+ "TSTB",
+ "TSTL",
+ "TSTW",
+ "UNLK",
+ "UNPK",
+ "WORD",
+ "SIGNAME",
+};
diff --git a/sys/src/cmd/1c/gc.h b/sys/src/cmd/1c/gc.h
new file mode 100755
index 000000000..cb6eacacb
--- /dev/null
+++ b/sys/src/cmd/1c/gc.h
@@ -0,0 +1,340 @@
+#include "../cc/cc.h"
+#include "../2c/2.out.h"
+/*
+ * 1c/68020
+ * Motorola 68000
+ */
+
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_IND 4
+#define SZ_FLOAT 4
+#define SZ_VLONG 8
+#define SZ_DOUBLE 8
+
+#define ALLOP OEND
+#define NRGN 300
+#define FNX 100
+#define INDEXED 9
+
+#define PRE 1
+#define POST 2
+#define TEST 4
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Txt Txt;
+typedef struct Cases Case;
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+typedef struct Var Var;
+typedef struct Multab Multab;
+typedef struct C1 C1;
+
+struct Adr
+{
+ long displace;
+ long offset;
+
+ char sval[NSNAME];
+ double dval;
+
+ Sym* sym;
+ short type;
+ short field;
+ short etype;
+};
+#define A ((Adr*)0)
+
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog* link;
+ long lineno;
+ short as;
+};
+#define P ((Prog*)0)
+
+struct Txt
+{
+ short movas;
+ short postext;
+ char preclr;
+};
+
+struct Cases
+{
+ long val;
+ long label;
+ uchar def;
+ Case* link;
+};
+#define C ((Case*)0)
+
+struct Var
+{
+ long offset;
+ Sym* sym;
+ char type;
+ char etype;
+};
+
+struct Reg
+{
+ long pc;
+ long rpo; /* reverse post ordering */
+
+ Bits set;
+ Bits use1;
+ Bits use2;
+
+ Bits refbehind;
+ Bits refahead;
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ ulong regu;
+ long loop; /* could be shorter */
+
+ Reg* log5;
+ long active;
+
+ Reg* p1;
+ Reg* p2;
+ Reg* p2link;
+ Reg* s1;
+ Reg* s2;
+ Reg* link;
+ Prog* prog;
+};
+#define R ((Reg*)0)
+
+struct Rgn
+{
+ Reg* enter;
+ short costr;
+ short costa;
+ short varno;
+ short regno;
+};
+
+struct Multab
+{
+ short val;
+ char code[6];
+};
+
+struct C1
+{
+ long val;
+ long label;
+};
+
+#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
+
+#define CLOAD 8
+#define CREF 5
+#define CTEST 2
+#define CXREF 3
+#define CINF 1000
+#define LOOP 3
+
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits addrs;
+EXTERN ulong regbits;
+
+#define B_INDIR (1<<0)
+#define B_ADDR (1<<1)
+EXTERN int mvbits;
+EXTERN int changer;
+EXTERN int changea;
+
+EXTERN Txt txt[NTYPE][NTYPE];
+EXTERN short opxt[ALLOP][NTYPE];
+EXTERN Txt* txtp;
+EXTERN int multabsize;
+
+EXTERN Reg* firstr;
+EXTERN Reg* lastr;
+EXTERN Reg zreg;
+EXTERN Reg* freer;
+
+EXTERN long argoff;
+EXTERN long breakpc;
+EXTERN long nbreak;
+EXTERN Case* cases;
+EXTERN long continpc;
+EXTERN Prog* firstp;
+EXTERN Reg* firstr;
+EXTERN int inargs;
+EXTERN Prog* lastp;
+EXTERN int retok;
+EXTERN long mnstring;
+EXTERN Node* nodrat;
+EXTERN Node* nodret;
+EXTERN long nrathole;
+EXTERN long nstatic;
+EXTERN int nregion;
+EXTERN long nstring;
+EXTERN int nvar;
+EXTERN Prog* p;
+EXTERN long pc;
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN char string[NSNAME];
+EXTERN Sym* symrathole;
+EXTERN Sym* symstatic;
+EXTERN Var var[NVAR];
+EXTERN long* idom;
+EXTERN Reg** rpo2r;
+EXTERN long maxnr;
+EXTERN Prog zprog;
+
+EXTERN uchar regused[NREG];
+EXTERN uchar aregused[NREG];
+EXTERN uchar fregused[NREG];
+EXTERN uchar regbase[I_MASK];
+EXTERN long exregoffset;
+EXTERN long exaregoffset;
+EXTERN long exfregoffset;
+extern char* anames[];
+extern Multab multab[];
+
+void cgen(Node*, int, Node*);
+void lcgen(Node*, int, Node*);
+void bcgen(Node*, int);
+void boolgen(Node*, int, int, Node*, Node*);
+void sugen(Node*, int, Node*, long);
+
+
+void listinit(void);
+int Bconv(Fmt*);
+int Pconv(Fmt*);
+int Aconv(Fmt*);
+int Xconv(Fmt*);
+int Dconv(Fmt*);
+int Rconv(Fmt*);
+int Sconv(Fmt*);
+
+void peep(void);
+void excise(Reg*);
+Reg* uniqp(Reg*);
+Reg* uniqs(Reg*);
+int findtst(Reg*, Prog*, int);
+int setcc(Prog*, Prog*);
+int compat(Adr*, Adr*);
+int aregind(Adr*);
+int asize(int);
+int usedin(int, Adr*);
+Reg* findccr(Reg*);
+int setccr(Prog*);
+Reg* findop(Reg*, int, int, int);
+int regtyp(int);
+int anyvar(Adr*);
+int subprop(Reg*);
+int copyprop(Reg*);
+int copy1(Adr*, Adr*, Reg*, int);
+int copyu(Prog*, Adr*, Adr*);
+int copyas(Adr*, Adr*);
+int tasas(Adr*, Adr*);
+int copyau(Adr*, Adr*);
+int copysub(Adr*, Adr*, Adr*, Prog*, int);
+
+ulong RtoB(int);
+ulong AtoB(int);
+ulong FtoB(int);
+int BtoR(ulong);
+int BtoA(ulong);
+int BtoF(ulong);
+
+Reg* rega(void);
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Adr*, int);
+void prop(Reg*, Bits, Bits);
+void loopit(Reg*, long);
+void synch(Reg*, Bits);
+ulong allreg(ulong, Rgn*);
+void paint1(Reg*, int);
+ulong paint2(Reg*, int);
+void paint3(Reg*, int, ulong, int);
+void addreg(Adr*, int);
+
+void codgen(Node*, Node*);
+void gen(Node*);
+void noretval(int);
+void usedset(Node*, int);
+Node* nodconst(long);
+
+int swcmp(const void*, const void*);
+void doswit(int, Node*);
+void swit1(C1*, int, long, int, Node*);
+void casf(void);
+int bitload(Node*, int, int, int, Node*);
+void bitstore(Node*, int, int, int, int, Node*);
+long outstring(char*, long);
+int doinc(Node*, int);
+void setsp(void);
+void adjsp(long);
+int simplv(Node*);
+int eval(Node*, int);
+void outcode(void);
+void ieeedtod(Ieee*, double);
+int nodalloc(Type*, int, Node*);
+int mulcon(Node*, Node*, int, Node*);
+int shlcon(Node*, Node*, int, Node*);
+int mulcon1(Node*, long, int, Node*);
+void nullwarn(Node*, Node*);
+
+void tindex(Type*, Type*);
+void ginit(void);
+void gclean(void);
+void oinit(int, int, int, int, int, int);
+Prog* prg(void);
+void nextpc(void);
+void gargs(Node*);
+void naddr(Node*, Adr*, int);
+int regalloc(Type*, int);
+int regaddr(int);
+int regpair(int);
+int regret(Type*);
+void regfree(int);
+void gmove(Type*, Type*, int, Node*, int, Node*);
+void gopcode(int, Type*, int, Node*, int, Node*);
+void asopt(void);
+int relindex(int);
+void gbranch(int);
+void fpbranch(void);
+void patch(Prog*, long);
+void gpseudo(int, Sym*, int, long);
+void gpseudotree(int, Sym*, Node*);
+
+void indx(Node*);
+void bcomplex(Node*);
+
+/*
+ * com64
+ */
+int com64(Node*);
+void com64init(void);
+void bool64(Node*);
+
+#pragma varargck type "A" int
+#pragma varargck type "B" Bits
+#pragma varargck type "D" Adr*
+#pragma varargck type "N" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "S" char*
+#pragma varargck type "R" int
diff --git a/sys/src/cmd/1c/list.c b/sys/src/cmd/1c/list.c
new file mode 100755
index 000000000..f6bc2e620
--- /dev/null
+++ b/sys/src/cmd/1c/list.c
@@ -0,0 +1,319 @@
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('R', Rconv);
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('B', Bconv);
+}
+
+int
+Bconv(Fmt *fp)
+{
+ char str[STRINGSZ], ss[STRINGSZ], *s;
+ Bits bits;
+ int i;
+
+ str[0] = 0;
+ bits = va_arg(fp->args, Bits);
+ while(bany(&bits)) {
+ i = bnum(bits);
+ if(str[0])
+ strcat(str, " ");
+ if(var[i].sym == S) {
+ sprint(ss, "$%ld", var[i].offset);
+ s = ss;
+ } else
+ s = var[i].sym->name;
+ if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
+ break;
+ strcat(str, s);
+ bits.b[i/32] &= ~(1L << (i%32));
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ], s[20];
+ Prog *p;
+
+ p = va_arg(fp->args, Prog*);
+ sprint(str, " %A %D,%D", p->as, &p->from, &p->to);
+ if(p->from.field) {
+ sprint(s, ",%d,%d", p->to.field, p->from.field);
+ strcat(str, s);
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ int r;
+
+ r = va_arg(fp->args, int);
+ return fmtstrcpy(fp, anames[r]);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[40], s[20];
+ Adr *a;
+ int i, j;
+ long d;
+
+ a = va_arg(fp->args, Adr*);
+ i = a->type;
+ j = i & I_MASK;
+ if(j) {
+ a->type = i & D_MASK;
+ d = a->offset;
+ a->offset = 0;
+ switch(j) {
+ case I_INDINC:
+ sprint(str, "(%D)+", a);
+ break;
+
+ case I_INDDEC:
+ sprint(str, "-(%D)", a);
+ break;
+
+ case I_INDIR:
+ if(a->type == D_CONST)
+ sprint(str, "%ld", d);
+ else
+ if(d)
+ sprint(str, "%ld(%D)", d, a);
+ else
+ sprint(str, "(%D)", a);
+ break;
+
+ case I_ADDR:
+ a->offset = d;
+ sprint(str, "$%D", a);
+ break;
+ }
+ a->type = i;
+ a->offset = d;
+ goto out;
+ }
+ switch(i) {
+
+ default:
+ sprint(str, "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ sprint(str, "%ld(PC)", a->offset-pc);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%ld(SB)", a->sym->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%ld(SB)", a->sym->name, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s-%ld(SP)", a->sym->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ sprint(str, "%s+%ld(FP)", a->sym->name, a->offset);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%ld", a->offset);
+ break;
+
+ case D_STACK:
+ sprint(str, "TOS+%ld", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%.17e", a->dval);
+ goto out;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ goto out;
+ }
+ if(a->displace) {
+ sprint(s, "/%ld", a->displace);
+ strcat(str, s);
+ }
+out:
+ return fmtstrcpy(fp, str);
+}
+
+int
+Rconv(Fmt *fp)
+{
+ char str[20];
+ int r;
+
+ r = va_arg(fp->args, int);
+ if(r >= D_R0 && r < D_R0+NREG)
+ sprint(str, "R%d", r-D_R0);
+ else
+ if(r >= D_A0 && r < D_A0+NREG)
+ sprint(str, "A%d", r-D_A0);
+ else
+ if(r >= D_F0 && r < D_F0+NREG)
+ sprint(str, "F%d", r-D_F0);
+ else
+ switch(r) {
+
+ default:
+ sprint(str, "gok(%d)", r);
+ break;
+
+ case D_NONE:
+ sprint(str, "NONE");
+ break;
+
+ case D_TOS:
+ sprint(str, "TOS");
+ break;
+
+ case D_CCR:
+ sprint(str, "CCR");
+ break;
+
+ case D_SR:
+ sprint(str, "SR");
+ break;
+
+ case D_SFC:
+ sprint(str, "SFC");
+ break;
+
+ case D_DFC:
+ sprint(str, "DFC");
+ break;
+
+ case D_CACR:
+ sprint(str, "CACR");
+ break;
+
+ case D_USP:
+ sprint(str, "USP");
+ break;
+
+ case D_VBR:
+ sprint(str, "VBR");
+ break;
+
+ case D_CAAR:
+ sprint(str, "CAAR");
+ break;
+
+ case D_MSP:
+ sprint(str, "MSP");
+ break;
+
+ case D_ISP:
+ sprint(str, "ISP");
+ break;
+
+ case D_TREE:
+ sprint(str, "TREE");
+ break;
+
+ case D_FPCR:
+ sprint(str, "FPCR");
+ break;
+
+ case D_FPSR:
+ sprint(str, "FPSR");
+ break;
+
+ case D_FPIAR:
+ sprint(str, "FPIAR");
+ break;
+
+ case D_TC:
+ sprint(str, "TC");
+ break;
+
+ case D_ITT0:
+ sprint(str, "ITT0");
+ break;
+
+ case D_ITT1:
+ sprint(str, "ITT1");
+ break;
+
+ case D_DTT0:
+ sprint(str, "DTT0");
+ break;
+
+ case D_DTT1:
+ sprint(str, "DTT1");
+ break;
+
+ case D_MMUSR:
+ sprint(str, "MMUSR");
+ break;
+ case D_URP:
+ sprint(str, "URP");
+ break;
+
+ case D_SRP:
+ sprint(str, "SRP");
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[30], *p, *s;
+
+ s = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(double); i++) {
+ c = s[i] & 0xff;
+ if(c != '\\' && c != '"' && isprint(c)) {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = '0';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = ((c>>6) & 7) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = ((c>>0) & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
diff --git a/sys/src/cmd/1c/mkfile b/sys/src/cmd/1c/mkfile
new file mode 100755
index 000000000..7921943d8
--- /dev/null
+++ b/sys/src/cmd/1c/mkfile
@@ -0,0 +1,32 @@
+</$objtype/mkfile
+
+TARG=1c
+OFILES=\
+ cgen.$O\
+ reg.$O\
+ txt.$O\
+ peep.$O\
+ swt.$O\
+ sgen.$O\
+ list.$O\
+ enam.$O\
+ mul.$O\
+
+HFILES=\
+ gc.h\
+ ../2c/2.out.h\
+ ../cc/cc.h\
+
+LIB=../cc/cc.a$O
+
+BIN=/$objtype/bin
+</sys/src/cmd/mkone
+
+$LIB:
+ cd ../cc
+ mk install
+ mk clean
+
+%.$O: ../cc/%.c
+ $CC $CFLAGS ../cc/$stem.c
+
diff --git a/sys/src/cmd/1c/mul.c b/sys/src/cmd/1c/mul.c
new file mode 100755
index 000000000..65ddda2f5
--- /dev/null
+++ b/sys/src/cmd/1c/mul.c
@@ -0,0 +1,174 @@
+#include "gc.h"
+
+/*
+ * code sequences for multiply by constant
+ * all sequences start with leading '0'.
+ * if sequence starts with 'i', then the
+ * leading '0' is suppressed.
+ * '0' mov r0,r1
+ * '1' sub r0,r1
+ * '2' sub r1,r0
+ * '3' add r0,r1
+ * '4' add r1,r0
+ * '5' add r0,r0
+ * '6' add r1,r1
+ * 'b' lsh $2,r0
+ * 'c' lsh $3,r0
+ * 'd'-'h' ...
+ * 'j' lsh $2,r1
+ * 'k'-'p' ...
+ */
+Multab multab[] =
+{
+ 2, "i5",
+ 3, "64",
+ 4, "i55",
+ 5, "664",
+ 6, "645",
+ 7, "c2",
+ 9, "k4",
+ 10, "6645",
+ 11, "66364",
+ 12, "6455",
+ 13, "66464",
+ 14, "6d2",
+ 15, "d2",
+ 17, "l4",
+ 18, "6d4",
+ 19, "64k4",
+ 20, "66455",
+ 21, "664664",
+ 22, "64c2",
+ 23, "44c2",
+ 24, "64c",
+ 25, "63k4",
+ 26, "64c4",
+ 27, "663e2",
+ 28, "66e2",
+ 29, "63e2",
+ 30, "6e2",
+ 31, "e2",
+ 33, "m4",
+ 34, "6e4",
+ 35, "64l4",
+ 36, "66e4",
+ 37, "664k4",
+ 38, "64k45",
+ 39, "454c2",
+ 40, "664c",
+ 41, "663k4",
+ 42, "644c4",
+ 43, "643k4",
+ 44, "664c4",
+ 45, "640d2",
+ 46, "64d2",
+ 47, "44d2",
+ 48, "64d",
+ 49, "63l4",
+ 50, "64d4",
+ 51, "640l4",
+ 52, "646d4",
+ 53, "643d4",
+ 54, "6636f2",
+ 55, "k3f2",
+ 56, "kf2",
+ 57, "k2k4",
+ 58, "636f2",
+ 59, "663f2",
+ 60, "66f2",
+ 61, "63f2",
+ 62, "6f2",
+ 63, "f2",
+ 65, "n4",
+ 66, "6f4",
+ 67, "64m4",
+ 68, "66f4",
+ 69, "664l4",
+ 70, "64l45",
+ 71, "k1f4",
+ 72, "k4c",
+ 73, "k4k4",
+ 74, "664k45",
+ 75, "6640d2",
+ 76, "664d2",
+ 77, "434d2",
+ 78, "644d2",
+ 79, "454d2",
+ 80, "664d",
+ 81, "663l4",
+ 82, "644d4",
+ 83, "643l4",
+ 84, "664d4",
+ 85, "6640l4",
+ 86, "6634l4",
+ 87, "6443d4",
+ 88, "6646d4",
+ 89, "6643d4",
+ 90, "6406e2",
+ 91, "643e2",
+ 92, "646e2",
+ 93, "640e2",
+ 94, "64e2",
+ 95, "44e2",
+ 96, "64e",
+ 97, "63m4",
+ 98, "64e4",
+ 99, "640m4",
+ 100, "646e4",
+ 200, "66f364",
+ 300, "j40jf2",
+ 400, "64kg4",
+ 500, "66h212",
+ 600, "64m4c4",
+ 700, "j4c4d2",
+ 800, "64lh4",
+ 900, "6464g4",
+ 1000, "63g2c",
+ 1100, "j4d2p4",
+ 1200, "64k4f2",
+ 1300, "j4n4b4",
+ 1400, "64j4g2",
+ 1600, "64d4e",
+ 1800, "p4c2",
+ 2000, "63g2d",
+ 2100, "l4b2o4",
+ 2200, "k4d4p4",
+ 2300, "6644h2",
+ 2400, "j4k4f4",
+ 2500, "j4e2d4",
+ 2600, "j40n4c",
+ 3100, "jd12p2",
+ 3200, "64d4f",
+ 3600, "6d1p2",
+ 3800, "e3k3g2",
+ 3900, "jf20n4",
+ 4000, "o4e2",
+ 4100, "66p455",
+ 4200, "l4c3e2",
+ 4300, "l4b1f4",
+ 4400, "64o4d4",
+ 4600, "k45h2",
+ 4700, "k3j4g2",
+ 4800, "j40d2f",
+ 5000, "l4c3m4",
+ 5100, "j40h2b",
+ 5200, "j40n4d",
+ 6000, "d1o3h2",
+ 6100, "o1l4b2",
+ 6200, "ke12p2",
+ 6400, "64d4g",
+ 7200, "66e1p2",
+ 7400, "m3m4c2",
+ 7600, "l4f3c2",
+ 7800, "kg20n4",
+ 8000, "63g2f",
+ 8100, "m2b4p4",
+ 8200, "66p4c",
+ 8700, "66f4g2",
+ 8900, "l3j4g4",
+ 9200, "k45h25",
+ 9600, "j40d2g",
+ 9800, "k4f3d4",
+};
+
+int multabsize = sizeof(multab) / sizeof(multab[0]);
diff --git a/sys/src/cmd/1c/peep.c b/sys/src/cmd/1c/peep.c
new file mode 100755
index 000000000..7583da5dd
--- /dev/null
+++ b/sys/src/cmd/1c/peep.c
@@ -0,0 +1,1057 @@
+#include "gc.h"
+
+void
+peep(void)
+{
+ Reg *r, *r1, *r2;
+ Prog *p, *p1;
+ int t, s;
+/*
+ * complete R structure
+ */
+ t = 0;
+ for(r=firstr; r!=R; r=r1) {
+ r1 = r->link;
+ if(r1 == R)
+ break;
+ p = r->prog->link;
+ while(p != r1->prog)
+ switch(p->as) {
+ default:
+ r2 = rega();
+ r->link = r2;
+ r2->link = r1;
+
+ r2->prog = p;
+ r2->p1 = r;
+ r->s1 = r2;
+ r2->s1 = r1;
+ r1->p1 = r2;
+
+ r = r2;
+ t++;
+
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ p = p->link;
+ }
+ }
+
+loop1:
+ /*
+ * propigate move's by renaming
+ */
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ if(p->as == AMOVL || p->as == AFMOVEF || p->as == AFMOVED)
+ if(regtyp(p->from.type))
+ if(anyvar(&p->to)) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ }
+ if(t)
+ goto loop1;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ /*
+ * convert (A) ... A++ into (A)++
+ * and A-- ... (A) into --(A)
+ */
+ t = aregind(&p->from);
+ if(t == D_NONE)
+ goto out1;
+ s = asize(p->as);
+ if(s == 0)
+ goto out1;
+ r1 = findop(r, t, AADDL, s);
+ if(r1 != R) {
+ if(usedin(t, &p->to))
+ goto out1;
+ p->from.type += I_INDINC - I_INDIR;
+ excise(r1);
+ goto out1;
+ }
+ r1 = findop(r, t, ASUBL, s);
+ if(r1 != R) {
+ p->from.type += I_INDDEC - I_INDIR;
+ excise(r1);
+ }
+ out1:
+ t = aregind(&p->to);
+ if(t == D_NONE)
+ goto out2;
+ s = asize(p->as);
+ if(s == 0)
+ goto out2;
+ r1 = findop(r, t, AADDL, s);
+ if(r1 != R) {
+ p->to.type += I_INDINC - I_INDIR;
+ excise(r1);
+ goto out2;
+ }
+ r1 = findop(r, t, ASUBL, s);
+ if(r1 != R) {
+ if(usedin(t, &p->from))
+ goto out2;
+ p->to.type += I_INDDEC - I_INDIR;
+ excise(r1);
+ }
+ out2:
+ /*
+ * get rid of unneeded save/restore CCR
+ */
+ if(p->from.type == D_CCR) {
+ r1 = findccr(r);
+ if(r1 != R) {
+ excise(r);
+ excise(r1);
+ }
+ }
+ switch(p->as) {
+ case ATSTB:
+ case ATSTW:
+ case ATSTL:
+ if(findtst(r, r->prog, 0))
+ excise(r);
+ }
+ /*
+ * turn TSTB (A); BLT; ORB $128,(A) into TAS (A); BLT; NOP
+ */
+ if(p->as == ATSTB && (r1 = r->s1)) {
+ if((r1->prog->as == ABLT && (r2 = r1->s1)) ||
+ (r1->prog->as == ABGE && (r2 = r1->s2))) {
+ p1 = r2->prog;
+ if(p1->as == AORB)
+ if(p1->from.type == D_CONST)
+ if(p1->from.offset == 128)
+ if(r1 == uniqp(r2))
+ if(tasas(&p->to, &p1->to)) {
+ p->as = ATAS;
+ excise(r2);
+ }
+ }
+ }
+ }
+}
+
+void
+excise(Reg *r)
+{
+
+ p = r->prog;
+ p->as = ANOP;
+ p->from = zprog.from;
+ p->to = zprog.to;
+}
+
+Reg*
+uniqp(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->p1;
+ if(r1 == R) {
+ r1 = r->p2;
+ if(r1 == R || r1->p2link != R)
+ return R;
+ } else
+ if(r->p2 != R)
+ return R;
+ return r1;
+}
+
+Reg*
+uniqs(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->s1;
+ if(r1 == R) {
+ r1 = r->s2;
+ if(r1 == R)
+ return R;
+ } else
+ if(r->s2 != R)
+ return R;
+ return r1;
+}
+
+/*
+ * chase backward all cc setting.
+ * returns 1 if all set same.
+ */
+int
+findtst(Reg *r0, Prog *rp, int n)
+{
+ Reg *r;
+ int c;
+
+loop:
+ n++;
+ if(n >= 10)
+ return 0;
+ for(r=r0->p2; r!=R; r=r->p2link) {
+ c = setcc(r->prog, rp);
+ if(c > 0)
+ continue;
+ if(c == 0)
+ return 0;
+ if(findtst(r, rp, n) == 0)
+ return 0;
+ }
+ r = r0->p1;
+ if(r == R)
+ return 1;
+ c = setcc(r->prog, rp);
+ if(c > 0)
+ return 1;
+ if(c == 0)
+ return 0;
+ r0 = r;
+ goto loop;
+}
+
+/*
+ * tests cc
+ * returns -1 if no change
+ * returns 1 if set the same
+ * returns 0 if set different
+ */
+int
+setcc(Prog *p, Prog *rp)
+{
+ int s;
+
+ s = asize(rp->as);
+ switch(p->as) {
+ default:
+ if(debug['P'])
+ print("unknown setcc %A\n", p->as);
+ break;
+
+ case ACMPB:
+ case ACMPW:
+ case ACMPL:
+ case ABSR:
+ return 0;
+
+ case ABRA:
+ case ABGE:
+ case ABNE:
+ case ABLE:
+ case ABEQ:
+ case ABHI:
+ case ABLS:
+ case ABMI:
+ case ABPL:
+ case ABGT:
+ case ABLT:
+ case ABCC:
+ case ABCS:
+ case APEA:
+ case ALEA:
+ case ANOP:
+
+ case AFADDD:
+ case AFMULD:
+ case AFDIVD:
+ case AFSUBD:
+ case AFADDF:
+ case AFMULF:
+ case AFDIVF:
+ case AFSUBF:
+ case AADJSP:
+ return -1;
+
+ case AADDW:
+ case AADDL:
+ case ASUBW:
+ case ASUBL:
+ case ACLRL:
+ case ACLRW:
+ if(p->to.type >= D_A0 && p->to.type < D_A0+8)
+ goto areg;
+
+ case AADDB:
+ case ASUBB:
+ case AANDB:
+ case AANDW:
+ case AANDL:
+ case AORB:
+ case AORW:
+ case AORL:
+ case AEORB:
+ case AEORW:
+ case AEORL:
+ case ALSLB:
+ case ALSLW:
+ case ALSLL:
+ case ALSRB:
+ case ALSRW:
+ case ALSRL:
+ case AASLB:
+ case AASLW:
+ case AASLL:
+ case AASRB:
+ case AASRW:
+ case AASRL:
+ case ATSTB:
+ case ATSTW:
+ case ATSTL:
+ case ANEGB:
+ case ANEGW:
+ case ANEGL:
+ case ACLRB:
+ if(asize(p->as) != s)
+ break;
+ if(compat(&rp->to, &p->to))
+ return 1;
+ break;
+
+ case AMOVW:
+ case AMOVL:
+ if(p->to.type >= D_A0 && p->to.type < D_A0+8)
+ goto areg;
+ case AMOVB:
+ if(asize(p->as) != s)
+ break;
+ if(compat(&rp->to, &p->to))
+ return 1;
+ if(compat(&rp->to, &p->from))
+ return 1;
+ }
+ return 0;
+
+areg:
+ if((rp->to.type&D_MASK) == p->to.type)
+ return 0;
+ return -1;
+}
+
+int
+compat(Adr *a, Adr *b)
+{
+ int o;
+
+ o = a->type;
+ if((o >= D_R0 && o < D_R0+NREG) ||
+ (o >= D_A0 && o < D_A0+NREG))
+ return o == b->type;
+ o &= D_MASK;
+ if(o >= D_A0 && o < D_A0+NREG) {
+ if(o != (b->type&D_MASK))
+ return 0;
+ if(a->offset != b->offset)
+ return 0;
+ o = a->type & I_MASK;
+ if(o == I_INDIR) {
+ o = b->type & I_MASK;
+ if(o == I_INDIR || o == I_INDDEC)
+ return 1;
+ return 0;
+ }
+ if(o == I_INDINC) {
+ o = b->type & I_MASK;
+ if(o == I_INDIR) {
+ b->type += I_INDINC-I_INDIR;
+ return 1;
+ }
+ if(o == I_INDDEC) {
+ b->type += I_INDIR-I_INDDEC;
+ return 1;
+ }
+ return 0;
+ }
+ }
+ return 0;
+}
+
+int
+aregind(Adr *a)
+{
+ int t;
+
+ t = a->type;
+ if(t >= (D_A0|I_INDIR) && t < ((D_A0+NREG)|I_INDIR))
+ while(a->offset == 0)
+ return t & D_MASK;
+ return D_NONE;
+}
+
+int
+asize(int a)
+{
+
+ switch(a) {
+ case AFTSTD:
+ case AFMOVED:
+ case AFADDD:
+ case AFSUBD:
+ case AFMULD:
+ case AFDIVD:
+ case AFCMPD:
+ case AFNEGD:
+ return 8;
+
+ case AFTSTF:
+ case AFMOVEF:
+ case AFADDF:
+ case AFSUBF:
+ case AFMULF:
+ case AFDIVF:
+ case AFCMPF:
+ case AFNEGF:
+
+ case ACLRL:
+ case ATSTL:
+ case AMOVL:
+ case AADDL:
+ case ASUBL:
+ case ACMPL:
+ case AANDL:
+ case AORL:
+ case AEORL:
+ case ALSLL:
+ case ALSRL:
+ case AASLL:
+ case AASRL:
+ case ANEGL:
+ return 4;
+
+ case ACLRW:
+ case ATSTW:
+ case AMOVW:
+ case AADDW:
+ case ASUBW:
+ case ACMPW:
+ case AANDW:
+ case AORW:
+ case AEORW:
+ case ALSLW:
+ case ALSRW:
+ case AASLW:
+ case AASRW:
+ case ANEGW:
+ return 2;
+
+ case ACLRB:
+ case ATSTB:
+ case AMOVB:
+ case AADDB:
+ case ASUBB:
+ case ACMPB:
+ case AANDB:
+ case AORB:
+ case AEORB:
+ case ALSLB:
+ case ALSRB:
+ case AASLB:
+ case AASRB:
+ case ANEGB:
+ return 1;
+ }
+ if(debug['P'])
+ print("unknown asize %A\n", p->as);
+ return 0;
+}
+
+int
+usedin(int t, Adr *a)
+{
+
+ if((a->type&D_MASK) == t)
+ return 1;
+ return 0;
+}
+
+Reg*
+findccr(Reg *r)
+{
+ Prog *p;
+
+ for(;;) {
+ r = uniqs(r);
+ if(r == R)
+ break;
+ p = r->prog;
+ if(p->to.type == D_CCR)
+ return r;
+ if(setccr(p))
+ break;
+ }
+ return R;
+}
+
+int
+setccr(Prog *p)
+{
+
+ switch(p->as) {
+ case ANOP:
+ return 0;
+
+ case AADDL:
+ case AMOVL:
+ case ACLRL:
+ if(p->to.type >= D_A0 && p->to.type < D_A0+8)
+ return 0;
+ }
+ return 1;
+}
+
+Reg*
+findop(Reg *r, int t, int o, int s)
+{
+ Prog *p;
+ Reg *r1;
+
+ for(;;) {
+ if(o == AADDL) {
+ r1 = uniqs(r);
+ if(r1 == R)
+ break;
+ if(uniqp(r1) != r)
+ break;
+ } else {
+ r1 = uniqp(r);
+ if(r1 == R)
+ break;
+ if(uniqs(r1) != r)
+ break;
+ }
+ r = r1;
+ p = r->prog;
+ if(usedin(t, &p->from))
+ break;
+ if(usedin(t, &p->to)) {
+ if(p->as == o)
+ if(p->to.type == t)
+ if(p->from.type == D_CONST)
+ if(p->from.offset == s)
+ return r;
+ break;
+ }
+ }
+ return R;
+}
+
+int
+regtyp(int t)
+{
+
+ if(t >= D_R0 && t < D_R0+8)
+ return 1;
+ if(t >= D_A0 && t < D_A0+8)
+ return 1;
+ if(t >= D_F0 && t < D_F0+8)
+ return 1;
+ return 0;
+}
+
+int
+anyvar(Adr *a)
+{
+
+ if(regtyp(a->type))
+ return 1;
+ return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ * MOV a, R0
+ * ADD b, R0 / no use of R1
+ * MOV R0, R1
+ * would be converted to
+ * MOV a, R1
+ * ADD b, R1
+ * MOV R1, R0
+ * hopefully, then the former or latter MOVL
+ * will be eliminated by copy propagation.
+ */
+int
+subprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+ int t;
+
+ p = r0->prog;
+ v1 = &p->from;
+ if(!regtyp(v1->type))
+ return 0;
+ v2 = &p->to;
+ if(!regtyp(v2->type))
+ return 0;
+ for(r=uniqp(r0); r!=R; r=uniqp(r)) {
+ if(uniqs(r) == R)
+ break;
+ p = r->prog;
+ switch(p->as) {
+ case ADIVUW: /* these set Rn and Rn+1 */
+ case ADIVUL:
+ case ADIVSW:
+ case ADIVSL:
+ case ABSR:
+ return 0;
+
+ case AFMOVED:
+ case AFMOVEF:
+ case AMOVL:
+ if(p->to.type == v1->type)
+ goto gotit;
+ }
+ if(copyau(&p->from, v2) || copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, v1, v2, p, 0) || copysub(&p->to, v1, v2, p, 0))
+ break;
+ }
+ return 0;
+
+gotit:
+ copysub(&p->to, v1, v2, p, 1);
+ if(debug['P']) {
+ print("gotit: %D->%D\n%P", v1, v2, r->prog);
+ if(p->from.type == v2->type)
+ print(" excise");
+ print("\n");
+ }
+ if(p->from.type == v2->type)
+ excise(r);
+ for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+ p = r->prog;
+ copysub(&p->from, v1, v2, p, 1);
+ copysub(&p->to, v1, v2, p, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->type;
+ v1->type = v2->type;
+ v2->type = t;
+ if(debug['P'])
+ print("%P last\n", r->prog);
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * use v2 return fail
+ * -----------------
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * set v2 return success
+ */
+int
+copyprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+
+ p = r0->prog;
+ v1 = &p->from;
+ v2 = &p->to;
+ if(copyas(v1, v2))
+ return 1;
+ for(r=firstr; r!=R; r=r->link)
+ r->active = 0;
+ return copy1(v1, v2, r0->s1, 0);
+}
+
+int
+copy1(Adr *v1, Adr *v2, Reg *r, int f)
+{
+ int t;
+
+ if(r->active) {
+ if(debug['P'])
+ print("copyret 1\n");
+ return 1;
+ }
+ r->active = 1;
+ if(debug['P'])
+ print("copy %D->%D\n", v1, v2);
+ for(; r != R; r = r->s1) {
+ if(debug['P'])
+ print("%P", r->prog);
+ if(!f && uniqp(r) == R) {
+ f = 1;
+ if(debug['P'])
+ print("; merge; f=%d", f);
+ }
+ t = copyu(r->prog, v2, A);
+ switch(t) {
+ case 2: /* rar, cant split */
+ if(debug['P'])
+ print("; rar return 0\n");
+ return 0;
+ case 3: /* set */
+ if(debug['P'])
+ print("; set; return 1\n");
+ return 1;
+ case 1: /* used, substitute */
+ case 4: /* use and set */
+ if(f) {
+ if(debug['P'])
+ print("; used and f; return 0\n");
+ return 0;
+ }
+ if(copyu(r->prog, v2, v1)) {
+ if(debug['P'])
+ print("; sub fail; return 0\n");
+ return 0;
+ }
+ if(debug['P'])
+ print("; substitute");
+ if(t == 4) {
+ if(debug['P'])
+ print("; used and set; return 1\n");
+ return 1;
+ }
+ break;
+ }
+ if(!f) {
+ t = copyu(r->prog, v1, A);
+ if(!f && (t == 2 || t == 3 || t == 4)) {
+ if(debug['P'])
+ print("; f set used");
+ f = 1;
+ }
+ }
+ if(debug['P'])
+ print("\n");
+ if(r->s2)
+ if(!copy1(v1, v2, r->s2, f))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+int
+copyu(Prog *p, Adr *v, Adr *s)
+{
+ int t;
+
+ switch(p->as) {
+
+ default:
+ if(debug['P'])
+ print("unknown op %A\n", p->as);
+ return 2;
+
+ case APEA: /* rhs addr */
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+
+ case ALEA: /* lhs addr, rhs store */
+ if(copyas(&p->from, v))
+ return 2;
+
+ case AMOVL: /* rhs store */
+ case ACLRL:
+ case AFMOVEF:
+ case AFMOVED:
+ case AFMOVEB:
+ case AFMOVEW:
+ case AFMOVEL:
+ case ANOP:
+ if(copyas(&p->to, v)) {
+ if(s != A)
+ return copysub(&p->from, v, s, p, 1);
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ goto caseread;
+
+ case AADDL: /* rhs rar */
+ case AADDW:
+ case AADDB:
+ case ASUBL:
+ case ASUBW:
+ case ASUBB:
+ case AANDL:
+ case AANDW:
+ case AANDB:
+ case AORL:
+ case AORW:
+ case AORB:
+ case AEORL:
+ case AEORW:
+ case AEORB:
+ case AASRL:
+ case AASRW:
+ case AASRB:
+ case AASLL:
+ case AASLW:
+ case AASLB:
+ case ALSRL:
+ case ALSRW:
+ case ALSRB:
+ case ANOTL:
+ case ANOTW:
+ case ANOTB:
+ case ANEGL:
+ case ANEGW:
+ case ANEGB:
+ case AEXTBL:
+ case AEXTWL:
+ case AEXTBW:
+
+ case AMULSL:
+ case AMULUL:
+
+ case AMOVW: /* only sets part of register */
+ case AMOVB:
+ case ACLRW:
+ case ACLRB:
+
+ case AFADDD:
+ case AFMULD:
+ case AFDIVD:
+ case AFSUBD:
+ case AFNEGD:
+ case AFADDF:
+ case AFMULF:
+ case AFDIVF:
+ case AFSUBF:
+ case AFNEGF:
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+
+ case ADBF: /* lhs rar */
+ if(copyas(&p->from, v))
+ return 2;
+ goto caseread;
+
+ case ACMPL: /* read only */
+ case ACMPW:
+ case ACMPB:
+ case AFCMPF:
+ case AFCMPD:
+ case ATSTL:
+ case ATSTW:
+ case ATSTB:
+ case AFTSTF:
+ case AFTSTD:
+ caseread:
+ if(s != A) {
+ if(copysub(&p->from, v, s, p, 1))
+ return 1;
+ return copysub(&p->to, v, s, p, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ break;
+
+ case ABRA: /* no reference */
+ case ABGE:
+ case ABNE:
+ case ABLE:
+ case ABEQ:
+ case ABHI:
+ case ABLS:
+ case ABMI:
+ case ABPL:
+ case ABGT:
+ case ABLT:
+ case ABCC:
+ case ABCS:
+
+ case AFBEQ:
+ case AFBNE:
+ case AFBGT:
+ case AFBGE:
+ case AFBLE:
+ case AFBLT:
+
+ case AADJSP:
+ case ACASEW:
+ break;
+
+ case ADIVUW: /* these set Rn and Rn+1 */
+ case ADIVUL:
+ case ADIVSW:
+ case ADIVSL:
+ t = v->type;
+ if(t == p->to.type || t == p->to.type+1)
+ return 2;
+ goto caseread;
+
+ case ARTS: /* funny */
+ t = v->type;
+ if(t == D_R0 || t == D_F0)
+ return 2;
+ if(t >= D_R0 && t < D_R0+NREG)
+ if(t-D_R0 > exregoffset)
+ return 2;
+ if(t >= D_A0 && t < D_A0+NREG)
+ if(t-D_A0 > exaregoffset)
+ return 2;
+ if(t >= D_F0 && t < D_F0+NREG)
+ if(t-D_F0 > exfregoffset)
+ return 2;
+ return 3;
+
+ case ABSR: /* funny */
+ t = v->type;
+ if(t >= D_R0 && t < D_R0+NREG)
+ if(t-D_R0 > exregoffset)
+ return 2;
+ if(t >= D_A0 && t < D_A0+NREG)
+ if(t-D_A0 > exaregoffset)
+ return 2;
+ if(t >= D_F0 && t < D_F0+NREG)
+ if(t-D_F0 > exfregoffset)
+ return 2;
+ if(copyau(&p->to, v))
+ return 2;
+ return 3;
+ }
+ return 0;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+
+ if(a->type != v->type)
+ return 0;
+ if(regtyp(v->type))
+ return 1;
+ if(v->type == D_AUTO || v->type == D_PARAM) {
+ if(v->offset == a->offset)
+ return 1;
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * indirect
+ */
+int
+tasas(Adr *a, Adr *v)
+{
+ int t;
+
+ t = a->type;
+ if(t < I_INDIR+D_A0 && t >= I_INDIR+D_A0+8)
+ return 0;
+ if(v->type != t)
+ return 0;
+ if(a->displace != v->displace)
+ return 0;
+ return 1;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+ int t;
+
+ if(copyas(a, v))
+ return 1;
+ t = v->type;
+ if(regtyp(t)) {
+ if((a->type & D_MASK) == t)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, Prog *p, int f)
+{
+ int t;
+
+ if(copyas(a, v)) {
+ t = s->type;
+ if(t >= D_F0 && t < D_F0+8) {
+ if(f)
+ a->type = t;
+ return 0;
+ }
+ if(t >= D_R0 && t < D_R0+8) {
+ if(f)
+ a->type = t;
+ return 0;
+ }
+ if(!(t >= D_A0 && t < D_A0+8))
+ return 1;
+ switch(p->as) {
+ default:
+ return 1;
+
+ case AMOVL:
+ case AMOVW:
+ case ACMPL:
+ case ACMPW:
+ break;
+
+ case AADDL:
+ case AADDW:
+ case ASUBL:
+ case ASUBW:
+ if(a == &p->from && !regtyp(p->to.type))
+ return 1;
+ break;
+ }
+ if(f)
+ a->type = t;
+ return 0;
+ }
+ t = v->type;
+ if(regtyp(t)) {
+ if((a->type & D_MASK) == t) {
+ if((s->type ^ t) & ~(NREG-1))
+ return 1;
+ if(f)
+ a->type = (a->type & ~D_MASK) | s->type;
+ return 0;
+ }
+ return 0;
+ }
+ return 0;
+}
diff --git a/sys/src/cmd/1c/reg.c b/sys/src/cmd/1c/reg.c
new file mode 100755
index 000000000..ad4231c0d
--- /dev/null
+++ b/sys/src/cmd/1c/reg.c
@@ -0,0 +1,1221 @@
+#include "gc.h"
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = alloc(sizeof(*r));
+ } else
+ freer = r->link;
+
+ *r = zreg;
+ return r;
+}
+
+int
+rcmp(const void *a1, const void *a2)
+{
+ Rgn *p1, *p2;
+ int c1, c2;
+
+ p1 = (Rgn*)a1;
+ p2 = (Rgn*)a2;
+ c1 = p2->costr;
+ if(p2->costa > c1)
+ c1 = p2->costa;
+ c2 = p1->costr;
+ if(p1->costa > c2)
+ c2 = p1->costa;
+ if(c1 -= c2)
+ return c1;
+ return p2->varno - p1->varno;
+}
+
+void
+regopt(Prog *p)
+{
+ Reg *r, *r1, *r2;
+ Prog *p1;
+ int i, z;
+ long val, initpc, npc;
+ ulong vreg;
+ Bits bit;
+ Var *v;
+ struct {
+ long m;
+ long c;
+ Reg* p;
+ } log5[6], *lp;
+
+ firstr = R;
+ lastr = R;
+ nvar = 0;
+ for(z=0; z<BITS; z++) {
+ externs.b[z] = 0;
+ params.b[z] = 0;
+ addrs.b[z] = 0;
+ }
+ regbits = RtoB(0) | /* return reg */
+ AtoB(6) | AtoB(7) | /* sp and sb */
+ FtoB(0) | FtoB(1); /* floating return reg */
+ for(i=0; i<NREG; i++) {
+ if(regused[i])
+ regbits |= RtoB(i);
+ if(fregused[i])
+ regbits |= FtoB(i);
+ if(aregused[i])
+ regbits |= AtoB(i);
+ }
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ val = 5L * 5L * 5L * 5L * 5L;
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->m = val;
+ lp->c = 0;
+ lp->p = R;
+ val /= 5L;
+ lp++;
+ }
+ val = 0;
+ for(; p != P; p = p->link) {
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ continue;
+ }
+ r = rega();
+ if(firstr == R) {
+ firstr = r;
+ lastr = r;
+ } else {
+ lastr->link = r;
+ r->p1 = lastr;
+ lastr->s1 = r;
+ lastr = r;
+ }
+ r->prog = p;
+ r->pc = val;
+ val++;
+
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->c--;
+ if(lp->c <= 0) {
+ lp->c = lp->m;
+ if(lp->p != R)
+ lp->p->log5 = r;
+ lp->p = r;
+ (lp+1)->c = 0;
+ break;
+ }
+ lp++;
+ }
+
+ r1 = r->p1;
+ if(r1 != R)
+ switch(r1->prog->as) {
+ case ABRA:
+ case ARTS:
+ case ARTE:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+
+ bit = mkvar(&p->from, AGOK);
+ if(bany(&bit))
+ switch(p->as) {
+ case ALEA:
+ if(!(mvbits & B_INDIR))
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+
+ default:
+ if(mvbits & B_ADDR)
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+ }
+
+ bit = mkvar(&p->to, p->as);
+ if(bany(&bit))
+ switch(p->as) {
+ case ABSR: /* funny */
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ goto def;
+
+ case APEA:
+ if(!(mvbits & B_INDIR))
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+
+ def:
+ case ACMPB: case ACMPW: case ACMPL:
+ case AFCMPF: case AFCMPD:
+ case ATSTB: case ATSTW: case ATSTL:
+ case AFTSTF: case AFTSTD:
+ case ABFEXTU: case ABFEXTS:
+ if(mvbits & B_ADDR)
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ break;
+
+ default:
+ diag(Z, "reg: unknown asop: %A", p->as);
+
+ case AADDB: case AADDW: case AADDL:
+ case ASUBB: case ASUBW: case ASUBL:
+ case AANDB: case AANDW: case AANDL:
+ case AORB: case AORW: case AORL:
+ case AEORB: case AEORW: case AEORL:
+ case ABFINS:
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+
+ case ANOP:
+ case AMOVB: case AMOVW: case AMOVL:
+ case AFMOVEB: case AFMOVEW: case AFMOVEL:
+ case ACLRB: case ACLRW: case ACLRL:
+ case AFMOVEF: case AFMOVED:
+ if(mvbits & B_INDIR)
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ else
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ }
+ }
+ if(firstr == R)
+ return;
+ initpc = pc - val;
+ npc = val;
+
+ /*
+ * pass 2
+ * turn branch references to pointers
+ * build back pointers
+ */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH) {
+ val = p->to.offset - initpc;
+ r1 = firstr;
+ while(r1 != R) {
+ r2 = r1->log5;
+ if(r2 != R && val >= r2->pc) {
+ r1 = r2;
+ continue;
+ }
+ if(r1->pc == val)
+ break;
+ r1 = r1->link;
+ }
+ if(r1 == R) {
+ diag(Z, "ref not found\n%L:%P", p->lineno, p);
+ continue;
+ }
+ if(r1 == r) {
+ diag(Z, "ref to self");
+ continue;
+ }
+ r->s2 = r1;
+ r->p2link = r1->p2;
+ r1->p2 = r;
+ }
+ }
+ if(debug['R'])
+ print("\n%L %D\n", firstr->prog->lineno, &firstr->prog->from);
+
+ /*
+ * pass 2.5
+ * find looping structure
+ */
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ changer = 0;
+ loopit(firstr, npc);
+ if(debug['R'] && debug['v']) {
+ print("\nlooping structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ print("%ld:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->use1.b[z] |
+ r->use2.b[z] | r->set.b[z];
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->use1))
+ print(" u1=%B", r->use1);
+ if(bany(&r->use2))
+ print(" u2=%B", r->use2);
+ if(bany(&r->set))
+ print(" st=%B", r->set);
+ }
+ print("\n");
+ }
+ }
+
+ /*
+ * pass 3
+ * iterate propagating usage
+ * back until flow graph is complete
+ */
+loop1:
+ changer = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ for(r = firstr; r != R; r = r->link)
+ if(r->prog->as == ARTS)
+ prop(r, zbits, zbits);
+loop11:
+ /* pick up unreachable code */
+ i = 0;
+ for(r = firstr; r != R; r = r1) {
+ r1 = r->link;
+ if(r1 && r1->active && !r->active) {
+ prop(r, zbits, zbits);
+ i = 1;
+ }
+ }
+ if(i)
+ goto loop11;
+ if(changer)
+ goto loop1;
+
+ /*
+ * pass 4
+ * iterate propagating register/variable synchrony
+ * forward until graph is complete
+ */
+loop2:
+ changer = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ synch(firstr, zbits);
+ if(changer)
+ goto loop2;
+
+
+ /*
+ * pass 5
+ * isolate regions
+ * calculate costs (paint1)
+ */
+ r = firstr;
+ if(r) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+ ~(externs.b[z] | params.b[z] | addrs.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "used and not set: %B", bit);
+ if(debug['R'] && !debug['w'])
+ print("used and not set: %B\n", bit);
+
+ /*
+ * 68040 'feature':
+ * load of a denormalized fp will trap
+ */
+ while(bany(&bit)) {
+ i = bnum(bit);
+ bit.b[i/32] &= ~(1L << (i%32));
+ v = var + i;
+ if(v->type == D_AUTO) {
+ r->set.b[i/32] |= (1L << (i%32));
+ if(typefd[v->etype])
+ addmove(r, i, NREG+NREG, 1);
+ }
+ }
+ }
+ }
+ if(debug['R'] && debug['v'])
+ print("\nprop structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ if(debug['R'] && debug['v'])
+ print("%P\n set = %B; rah = %B; cal = %B\n",
+ r->prog, r->set, r->refahead, r->calahead);
+ r->act = zbits;
+ }
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = r->link) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] &
+ ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "set and not used: %B", bit);
+ if(debug['R'])
+ print("set an not used: %B\n", bit);
+ excise(r);
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ rgp->enter = r;
+ rgp->varno = i;
+ changer = 0;
+ changea = 0;
+ if(debug['R'] && debug['v'])
+ print("\n");
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(changer <= 0 && changea <= 0) {
+ if(debug['R'])
+ print("%L$%d.%d: %B\n",
+ r->prog->lineno,
+ changer, changea, blsh(i));
+ continue;
+ }
+ rgp->costr = changer;
+ rgp->costa = changea;
+ nregion++;
+ if(nregion >= NRGN) {
+ warn(Z, "too many regions");
+ goto brk;
+ }
+ rgp++;
+ }
+ }
+brk:
+ qsort(region, nregion, sizeof(region[0]), rcmp);
+
+ /*
+ * pass 6
+ * determine used registers (paint2)
+ * replace code (paint3)
+ */
+ rgp = region;
+ for(i=0; i<nregion; i++) {
+ bit = blsh(rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno);
+ vreg = allreg(vreg, rgp);
+ if(debug['R'])
+ print("%L$%d.%d %R: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->costr, rgp->costa,
+ rgp->regno,
+ bit);
+ if(rgp->regno != D_NONE)
+ paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+ rgp++;
+ }
+ /*
+ * pass 7
+ * peep-hole on basic block
+ */
+ if(!debug['R'] || debug['P'])
+ peep();
+
+ /*
+ * pass 8
+ * recalculate pc
+ */
+ val = initpc;
+ for(r = firstr; r != R; r = r1) {
+ r->pc = val;
+ p = r->prog;
+ p1 = P;
+ r1 = r->link;
+ if(r1 != R)
+ p1 = r1->prog;
+ for(; p != p1; p = p->link) {
+ switch(p->as) {
+ default:
+ val++;
+ break;
+
+ case ANOP:
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ break;
+ }
+ }
+ }
+ pc = val;
+
+ /*
+ * fix up branches
+ */
+ if(debug['R'])
+ if(bany(&addrs))
+ print("addrs: %B\n", addrs);
+
+ r1 = 0; /* set */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH)
+ p->to.offset = r->s2->pc;
+ r1 = r;
+ }
+
+ /*
+ * last pass
+ * eliminate nops
+ * free aux structures
+ */
+ for(p = firstr->prog; p != P; p = p->link){
+ while(p->link && p->link->as == ANOP)
+ p->link = p->link->link;
+ }
+ if(r1 != R) {
+ r1->link = freer;
+ freer = firstr;
+ }
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+ Prog *p, *p1;
+ Var *v;
+ int badccr;
+
+ badccr = 0;
+ p = r->prog;
+ p1 = p->link;
+ if(p1)
+ switch(p1->as) {
+ case AMOVW:
+ if(p1->from.type == D_CCR)
+ p = p1;
+ break;
+
+ case ABEQ:
+ case ABNE:
+ case ABLE:
+ case ABLS:
+ case ABLT:
+ case ABMI:
+ case ABGE:
+ case ABPL:
+ case ABGT:
+ case ABHI:
+ case ABCC:
+ case ABCS:
+ p1 = prg();
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ p1->from.type = D_CCR;
+ p1->to.type = D_TOS;
+ p1->as = AMOVW;
+ p = p1;
+ badccr = 1;
+ }
+ p1 = prg();
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ v = var + bn;
+ p1->from.sym = v->sym;
+ p1->from.type = v->type;
+ p1->from.offset = v->offset;
+ p1->from.etype = v->etype;
+ p1->to.type = rn;
+ if(f) {
+ p1->to = p1->from;
+ p1->from = zprog.from;
+ p1->from.type = rn;
+ }
+ p1->as = opxt[OAS][v->etype];
+ if(badccr) {
+ p = p1;
+ p1 = prg();
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ p1->from.type = D_TOS;
+ p1->to.type = D_CCR;
+ p1->as = AMOVW;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+Bits
+mkvar(Adr *a, int as)
+{
+ Var *v;
+ int i, t, z;
+ long o;
+ Bits bit;
+ Sym *s;
+
+ mvbits = 0;
+ t = a->type & D_MASK;
+ switch(t) {
+
+ default:
+ if(t >= D_R0 && t < D_R0+NREG) {
+ regbits |= RtoB(t-D_R0);
+ if(as == ADIVUL || as == ADIVSL)
+ regbits |= RtoB(t-D_R0+1);
+ }
+ if(t >= D_A0 && t < D_A0+NREG)
+ regbits |= AtoB(t-D_A0);
+ if(t >= D_F0 && t < D_F0+NREG)
+ regbits |= FtoB(t-D_F0);
+ goto none;
+
+ case D_EXTERN:
+ case D_STATIC:
+ case D_AUTO:
+ case D_PARAM:
+ break;
+ }
+ s = a->sym;
+ if(s == S)
+ goto none;
+
+ if((a->type & I_MASK) == I_ADDR)
+ mvbits |= B_ADDR;
+
+ o = a->offset;
+ v = var;
+ for(i=0; i<nvar; i++) {
+ if(s == v->sym)
+ if(t == v->type)
+ if(o == v->offset)
+ goto out;
+ v++;
+ }
+ if(s)
+ if(s->name[0] == '.')
+ goto none;
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && s)
+ warn(Z, "variable not optimized: %s", s->name);
+ goto none;
+ }
+ i = nvar;
+ nvar++;
+ v = &var[i];
+ v->sym = s;
+ v->offset = o;
+ v->etype = a->etype;
+ v->type = t;
+ if(debug['R'])
+ print("bit=%2d et=%2d %s (%p,%d,%ld)\n",
+ i, a->etype, s->name,
+ v->sym, v->type, v->offset);
+
+out:
+ bit = blsh(i);
+ if(t == D_EXTERN || t == D_STATIC)
+ for(z=0; z<BITS; z++)
+ externs.b[z] |= bit.b[z];
+ if(t == D_PARAM)
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ if(a->etype != v->etype || !typechlpfd[a->etype])
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z]; /* funny punning */
+ return bit;
+
+none:
+ return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+ Reg *r1, *r2;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->p1) {
+ for(z=0; z<BITS; z++) {
+ ref.b[z] |= r1->refahead.b[z];
+ if(ref.b[z] != r1->refahead.b[z]) {
+ r1->refahead.b[z] = ref.b[z];
+ changer++;
+ }
+ cal.b[z] |= r1->calahead.b[z];
+ if(cal.b[z] != r1->calahead.b[z]) {
+ r1->calahead.b[z] = cal.b[z];
+ changer++;
+ }
+ }
+ switch(r1->prog->as) {
+ case ABSR:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] |= ref.b[z] | externs.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ATEXT:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = 0;
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ARTS:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = externs.b[z];
+ ref.b[z] = 0;
+ }
+ }
+ for(z=0; z<BITS; z++) {
+ ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+ r1->use1.b[z] | r1->use2.b[z];
+ cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+ r1->refbehind.b[z] = ref.b[z];
+ r1->calbehind.b[z] = cal.b[z];
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ }
+ for(; r != r1; r = r->p1)
+ for(r2 = r->p2; r2 != R; r2 = r2->p2link)
+ prop(r2, r->refbehind, r->calbehind);
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ * the actual dominators if the flow graph is reducible
+ * otherwise, dominators plus some other non-dominators.
+ * See Matthew S. Hecht and Jeffrey D. Ullman,
+ * "Analysis of a Simple Algorithm for Global Data Flow Problems",
+ * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ * Oct. 1-3, 1973, pp. 207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ * such a node is a loop head.
+ * recursively, all preds with a greater rpo number are in the loop
+ */
+long
+postorder(Reg *r, Reg **rpo2r, long n)
+{
+ Reg *r1;
+
+ r->rpo = 1;
+ r1 = r->s1;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ r1 = r->s2;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ rpo2r[n] = r;
+ n++;
+ return n;
+}
+
+long
+rpolca(long *idom, long rpo1, long rpo2)
+{
+ long t;
+
+ if(rpo1 == -1)
+ return rpo2;
+ while(rpo1 != rpo2){
+ if(rpo1 > rpo2){
+ t = rpo2;
+ rpo2 = rpo1;
+ rpo1 = t;
+ }
+ while(rpo1 < rpo2){
+ t = idom[rpo2];
+ if(t >= rpo2)
+ fatal(Z, "bad idom");
+ rpo2 = t;
+ }
+ }
+ return rpo1;
+}
+
+int
+doms(long *idom, long r, long s)
+{
+ while(s > r)
+ s = idom[s];
+ return s == r;
+}
+
+int
+loophead(long *idom, Reg *r)
+{
+ long src;
+
+ src = r->rpo;
+ if(r->p1 != R && doms(idom, src, r->p1->rpo))
+ return 1;
+ for(r = r->p2; r != R; r = r->p2link)
+ if(doms(idom, src, r->rpo))
+ return 1;
+ return 0;
+}
+
+void
+loopmark(Reg **rpo2r, long head, Reg *r)
+{
+ if(r->rpo < head || r->active == head)
+ return;
+ r->active = head;
+ r->loop += LOOP;
+ if(r->p1 != R)
+ loopmark(rpo2r, head, r->p1);
+ for(r = r->p2; r != R; r = r->p2link)
+ loopmark(rpo2r, head, r);
+}
+
+void
+loopit(Reg *r, long nr)
+{
+ Reg *r1;
+ long i, d, me;
+
+ if(nr > maxnr) {
+ rpo2r = alloc(nr * sizeof(Reg*));
+ idom = alloc(nr * sizeof(long));
+ maxnr = nr;
+ }
+
+ d = postorder(r, rpo2r, 0);
+ if(d > nr)
+ fatal(Z, "too many reg nodes");
+ nr = d;
+ for(i = 0; i < nr / 2; i++){
+ r1 = rpo2r[i];
+ rpo2r[i] = rpo2r[nr - 1 - i];
+ rpo2r[nr - 1 - i] = r1;
+ }
+ for(i = 0; i < nr; i++)
+ rpo2r[i]->rpo = i;
+
+ idom[0] = 0;
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ me = r1->rpo;
+ d = -1;
+ if(r1->p1 != R && r1->p1->rpo < me)
+ d = r1->p1->rpo;
+ for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+ if(r1->rpo < me)
+ d = rpolca(idom, d, r1->rpo);
+ idom[i] = d;
+ }
+
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ r1->loop++;
+ if(r1->p2 != R && loophead(idom, r1))
+ loopmark(rpo2r, i, r1);
+ }
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+ Reg *r1;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->s1) {
+ for(z=0; z<BITS; z++) {
+ dif.b[z] = (dif.b[z] &
+ ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+ r1->set.b[z] | r1->regdiff.b[z];
+ if(dif.b[z] != r1->regdiff.b[z]) {
+ r1->regdiff.b[z] = dif.b[z];
+ changer++;
+ }
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ for(z=0; z<BITS; z++)
+ dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+ if(r1->s2 != R)
+ synch(r1->s2, dif);
+ }
+}
+
+ulong
+allreg(ulong b, Rgn *r)
+{
+ Var *v;
+ int i, j;
+
+ v = var + r->varno;
+ r->regno = D_NONE;
+ switch(v->etype) {
+
+ default:
+ diag(Z, "unknown etype");
+ break;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ i = BtoR(~b);
+ j = BtoA(~b);
+ if(r->costa == r->costr)
+ if(i > j)
+ i = NREG;
+ if(j < NREG && r->costa > 0)
+ if(r->costa > r->costr || i >= NREG) {
+ r->regno = D_A0 + j;
+ return AtoB(j);
+ }
+ if(i < NREG && r->costr > 0) {
+ r->regno = D_R0 + i;
+ return RtoB(i);
+ }
+ break;
+
+ case TDOUBLE:
+ case TFLOAT:
+ i = BtoF(~b);
+ if(i < NREG) {
+ r->regno = D_F0 + i;
+ return FtoB(i);
+ }
+ break;
+ }
+ return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+ int x;
+
+ z = bn/32;
+ bb = 1L<<(bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+ if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
+ changer -= CLOAD * r->loop;
+ changea -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tld %B $%d.%d\n", r->loop,
+ r->prog, blsh(bn), changer, changea);
+ }
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ changer += CREF * r->loop;
+ changea += CREF * r->loop;
+ switch(p->as) {
+ default:
+ changea = -CINF;
+ case AADDL:
+ case ASUBL:
+ case AMOVL:
+ case ACMPL:
+ break;
+ }
+ if(p->as == AMOVL) {
+ x = p->to.type;
+ if(x >= D_R0 && x < D_R0+NREG)
+ changer += r->loop;
+ if(x >= D_A0 && x < D_A0+NREG)
+ changea += r->loop;
+ }
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu1 %B $%d.%d\n", r->loop,
+ p, blsh(bn), changer, changea);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ changer += CREF * r->loop;
+ changea += CREF * r->loop;
+ switch(p->as) {
+ default:
+ changea = -CINF;
+ break;
+ case AMOVL:
+ case AADDL:
+ case ACMPL:
+ case ASUBL:
+ case ACLRL: /* can be faked */
+ case ATSTL: /* can be faked */
+ break;
+ }
+ if(p->as == AMOVL) {
+ x = p->from.type;
+ if(x >= D_R0 && x < D_R0+NREG)
+ changer += r->loop;
+ if(x >= D_A0 && x < D_A0+NREG)
+ changea += r->loop;
+ }
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu2 %B $%d.%d\n", r->loop,
+ p, blsh(bn), changer, changea);
+ }
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ changer -= CLOAD * r->loop;
+ changea -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tst %B $%d.%d\n", r->loop,
+ p, blsh(bn), changer, changea);
+ }
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint1(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint1(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+ulong
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ ulong bb, vreg;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ vreg = regbits;
+ if(!(r->act.b[z] & bb))
+ return vreg;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(!(r1->act.b[z] & bb))
+ break;
+ r = r1;
+ }
+ for(;;) {
+ r->act.b[z] &= ~bb;
+
+ vreg |= r->regu;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ vreg |= paint2(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ vreg |= paint2(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(!(r->act.b[z] & bb))
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+ return vreg;
+}
+
+void
+paint3(Reg *r, int bn, ulong rb, int rn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+ addmove(r, bn, rn, 0);
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->from, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->to, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+ if(STORE(r) & r->regdiff.b[z] & bb)
+ addmove(r, bn, rn, 1);
+ r->regu |= rb;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+void
+addreg(Adr *a, int rn)
+{
+ a->sym = 0;
+ if(rn >= D_R0 && rn < D_R0+NREG)
+ goto addr;
+ a->type = rn | (a->type & I_INDIR);
+ return;
+
+addr:
+ a->type = rn | (a->type & I_INDIR);
+}
+
+/*
+ * bit reg
+ * 0-7 R0-R7
+ * 8-15 A0-A7
+ * 16-23 F0-F7
+ */
+ulong
+RtoB(int r)
+{
+
+ if(r < 0 || r >= NREG)
+ return 0;
+ return 1L << (r + 0);
+}
+
+int
+BtoR(ulong b)
+{
+
+ b &= 0x0000ffL;
+ if(b == 0)
+ return NREG;
+ return bitno(b) - 0;
+}
+
+ulong
+AtoB(int a)
+{
+
+ if(a < 0 || a >= NREG)
+ return 0;
+ return 1L << (a + NREG);
+}
+
+int
+BtoA(ulong b)
+{
+
+ b &= 0x00ff00L;
+ if(b == 0)
+ return NREG;
+ return bitno(b) - NREG;
+}
+
+ulong
+FtoB(int f)
+{
+
+ if(f < 0 || f >= NREG)
+ return 0;
+ return 1L << (f + NREG+NREG);
+}
+
+int
+BtoF(ulong b)
+{
+
+ b &= 0xff0000L;
+ if(b == 0)
+ return NREG;
+ return bitno(b) - NREG-NREG;
+}
diff --git a/sys/src/cmd/1c/sgen.c b/sys/src/cmd/1c/sgen.c
new file mode 100755
index 000000000..0621c264c
--- /dev/null
+++ b/sys/src/cmd/1c/sgen.c
@@ -0,0 +1,714 @@
+#include "gc.h"
+
+void
+codgen(Node *n, Node *nn)
+{
+ Prog *sp;
+
+ argoff = 0;
+ inargs = 0;
+ for(;; nn = nn->left) {
+ if(nn == Z) {
+ diag(Z, "cant find function name");
+ return;
+ }
+ if(nn->op == ONAME)
+ break;
+ }
+ nearln = nn->lineno;
+ gpseudo(ATEXT, nn->sym, D_CONST, stkoff);
+ sp = p;
+
+ retok = 0;
+ gen(n);
+ if(!retok)
+ if(thisfn->link->etype != TVOID)
+ warn(Z, "no return at end of function: %s", nn->sym->name);
+
+ noretval(3);
+ gbranch(ORETURN);
+ if(!debug['N'] || debug['R'] || debug['P'])
+ regopt(sp);
+}
+
+void
+gen(Node *n)
+{
+ Node *l;
+ Prog *sp, *spc, *spb;
+ Case *cn;
+ long sbc, scc;
+ int snbreak;
+ int g, o;
+
+loop:
+ if(n == Z)
+ return;
+ nearln = n->lineno;
+ o = n->op;
+ if(debug['G'])
+ if(o != OLIST)
+ print("%L %O\n", nearln, o);
+
+ retok = 0;
+ switch(o) {
+
+ default:
+ complex(n);
+ doinc(n, PRE);
+ cgen(n, D_NONE, n);
+ doinc(n, POST);
+ break;
+
+ case OLIST:
+ gen(n->left);
+
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ retok = 1;
+ complex(n);
+ if(n->type == T)
+ break;
+ l = n->left;
+ if(l == Z) {
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ doinc(l, PRE);
+ if(typesuv[n->type->etype]) {
+ sugen(l, D_TREE, nodret, n->type->width);
+ doinc(l, POST);
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ g = regalloc(n->type, regret(n->type));
+ cgen(l, g, n);
+ doinc(l, POST);
+ if(typefd[n->type->etype])
+ noretval(1);
+ else
+ noretval(2);
+ gbranch(ORETURN);
+ regfree(g);
+ break;
+
+ case OLABEL:
+ l = n->left;
+ if(l) {
+ l->xoffset = pc;
+ if(l->label)
+ patch(l->label, pc);
+ }
+ gbranch(OGOTO); /* prevent self reference in reg */
+ patch(p, pc);
+ goto rloop;
+
+ case OGOTO:
+ retok = 1;
+ n = n->left;
+ if(n == Z)
+ return;
+ if(n->complex == 0) {
+ diag(Z, "label undefined: %s", n->sym->name);
+ return;
+ }
+ gbranch(OGOTO);
+ if(n->xoffset) {
+ patch(p, n->xoffset);
+ return;
+ }
+ if(n->label)
+ patch(n->label, pc-1);
+ n->label = p;
+ return;
+
+ case OCASE:
+ l = n->left;
+ if(cases == C)
+ diag(n, "case/default outside a switch");
+ if(l == Z) {
+ casf();
+ cases->val = 0;
+ cases->def = 1;
+ cases->label = pc;
+ setsp();;
+ goto rloop;
+ }
+ complex(l);
+ if(l->type == T)
+ goto rloop;
+ if(l->op == OCONST)
+ if(typechl[l->type->etype]) {
+ casf();
+ cases->val = l->vconst;
+ cases->def = 0;
+ cases->label = pc;
+ setsp();
+ goto rloop;
+ }
+ diag(n, "case expression must be integer constant");
+ goto rloop;
+
+ case OSWITCH:
+ l = n->left;
+ complex(l);
+ doinc(l, PRE);
+ if(l->type == T)
+ break;
+ if(!typechl[l->type->etype]) {
+ diag(n, "switch expression must be integer");
+ break;
+ }
+ g = regalloc(types[TLONG], D_NONE);
+ n->type = types[TLONG];
+ cgen(l, g, n);
+ regfree(g);
+ doinc(l, POST);
+ setsp();
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ cn = cases;
+ cases = C;
+ casf();
+
+ sbc = breakpc;
+ breakpc = pc;
+ snbreak = nbreak;
+ nbreak = 0;
+ gbranch(OGOTO);
+ spb = p;
+
+ gen(n->right);
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ nbreak++;
+
+ patch(sp, pc);
+ doswit(g, l);
+
+ patch(spb, pc);
+ cases = cn;
+ breakpc = sbc;
+ nbreak = snbreak;
+ setsp();
+ break;
+
+ case OWHILE:
+ case ODWHILE:
+ l = n->left;
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ snbreak = nbreak;
+ nbreak = 0;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ if(n->op == OWHILE)
+ patch(sp, pc);
+ bcomplex(l); /* test */
+ patch(p, breakpc);
+ if(l->op != OCONST || vconst(l) == 0)
+ nbreak++;
+
+ if(n->op == ODWHILE)
+ patch(sp, pc);
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ if(nbreak == 0)
+ retok = 1;
+ nbreak = snbreak;
+ break;
+
+ case OFOR:
+ l = n->left;
+ gen(l->right->left); /* init */
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ snbreak = nbreak;
+ nbreak = 0;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ gen(l->right->right); /* inc */
+ patch(sp, pc);
+ if(l->left != Z) { /* test */
+ bcomplex(l->left);
+ patch(p, breakpc);
+ if(l->left->op != OCONST || vconst(l->left) == 0)
+ nbreak++;
+ }
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ if(nbreak == 0)
+ retok = 1;
+ nbreak = snbreak;
+ break;
+
+ case OCONTINUE:
+ if(continpc < 0) {
+ diag(n, "continue not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, continpc);
+ break;
+
+ case OBREAK:
+ if(breakpc < 0) {
+ diag(n, "break not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ nbreak++;
+ break;
+
+ case OIF:
+ l = n->left;
+ bcomplex(l);
+ sp = p;
+ if(n->right->left != Z)
+ gen(n->right->left);
+ if(n->right->right != Z) {
+ gbranch(OGOTO);
+ patch(sp, pc);
+ sp = p;
+ gen(n->right->right);
+ }
+ patch(sp, pc);
+ break;
+
+ case OSET:
+ case OUSED:
+ usedset(n->left, o);
+ break;
+ }
+}
+
+void
+usedset(Node *n, int o)
+{
+ if(n->op == OLIST) {
+ usedset(n->left, o);
+ usedset(n->right, o);
+ return;
+ }
+ complex(n);
+ switch(n->op) {
+ case OADDR: /* volatile */
+ gopcode(OTST, types[TINT], D_TREE, n, D_NONE, Z);
+ p->as = ANOP;
+ break;
+ case ONAME:
+ if(o == OSET)
+ gopcode(OTST, types[TINT], D_NONE, Z, D_TREE, n);
+ else
+ gopcode(OTST, types[TINT], D_TREE, n, D_NONE, Z);
+ p->as = ANOP;
+ break;
+ }
+}
+
+void
+noretval(int n)
+{
+
+ if(n & 1) {
+ gopcode(OTST, types[TINT], D_NONE, Z, regret(types[TLONG]), Z);
+ p->as = ANOP;
+ }
+ if(n & 2) {
+ gopcode(OTST, types[TINT], D_NONE, Z, regret(types[TDOUBLE]), Z);
+ p->as = ANOP;
+ }
+}
+
+/*
+ * calculate addressability as follows
+ * REGISTER ==> 12 register
+ * NAME ==> 11 name+value(SB/SP)
+ * note that 10 is no longer generated
+ * CONST ==> 20 $value
+ * *(20) ==> 21 value
+ * &(10) ==> 12 $name+value(SB)
+ * &(11) ==> 1 $name+value(SP)
+ * (12) + (20) ==> 12 fold constants
+ * (1) + (20) ==> 1 fold constants
+ * *(12) ==> 10 back to name
+ * *(1) ==> 11 back to name
+ *
+ * (2,10,11) + (20) ==> 2 indirect w offset
+ * (2) ==> &13
+ * *(10,11) ==> 13 indirect, no index
+ *
+ * (20) * (X) ==> 7 multiplier in indexing
+ * (X,7) + (12,1) ==> 8 adder in indexing (addresses)
+ * (X,7) + (10,11,2) ==> 8 adder in indexing (names)
+ * (8) ==> &9 index, almost addressable
+ *
+ * (X)++ ==> X fake addressability
+ *
+ * calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+ Node *l, *r;
+ int g;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ n->complex = 0;
+ n->addable = 0;
+ switch(n->op) {
+ case OCONST:
+ n->addable = 20;
+ break;
+
+ case ONAME:
+ n->addable = 11; /* difference to make relocatable */
+ break;
+
+ case OREGISTER:
+ n->addable = 12;
+ break;
+
+ case OADDR:
+ xcom(l);
+ if(l->addable == 10)
+ n->addable = 12;
+ else
+ if(l->addable == 11)
+ n->addable = 1;
+ break;
+
+ case OADD:
+ xcom(l);
+ xcom(r);
+ if(n->type->etype != TIND)
+ break;
+
+ if(l->addable == 20)
+ switch(r->addable) {
+ case 12:
+ case 1:
+ n->addable = r->addable;
+ goto brk;
+ }
+ if(r->addable == 20)
+ switch(l->addable) {
+ case 12:
+ case 1:
+ n->addable = l->addable;
+ goto brk;
+ }
+ break;
+
+ case OIND:
+ xcom(l);
+ if(l->op == OADDR) {
+ l = l->left;
+ l->type = n->type;
+ *n = *l;
+ return;
+ }
+ switch(l->addable) {
+ case 20:
+ n->addable = 21;
+ break;
+ case 1:
+ n->addable = 11;
+ break;
+ case 12:
+ n->addable = 10;
+ break;
+ }
+ break;
+
+ case OASHL:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ g = vconst(r);
+ if(g >= 0 && g < 4)
+ n->addable = 7;
+ break;
+
+ case OMUL:
+ case OLMUL:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASHL;
+ r->vconst = g;
+ if(g < 4)
+ n->addable = 7;
+ break;
+ }
+ g = vlog(l);
+ if(g >= 0) {
+ n->left = r;
+ n->right = l;
+ l = r;
+ r = n->right;
+ n->op = OASHL;
+ r->vconst = g;
+ if(g < 4)
+ n->addable = 7;
+ break;
+ }
+ break;
+
+ case ODIV:
+ case OLDIV:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ g = vlog(r);
+ if(g >= 0) {
+ if(n->op == ODIV)
+ n->op = OASHR;
+ else
+ n->op = OLSHR;
+ r->vconst = g;
+ }
+ break;
+
+ case OSUB:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ if(vconst(l) == 0) {
+ n->op = ONEG;
+ n->left = r;
+ n->right = Z;
+ }
+ break;
+
+ case OXOR:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ if(vconst(l) == -1) {
+ n->op = OCOM;
+ n->left = r;
+ n->right = Z;
+ }
+ break;
+
+ case OASMUL:
+ case OASLMUL:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASASHL;
+ r->vconst = g;
+ }
+ goto aseae;
+
+ case OASDIV:
+ case OASLDIV:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ g = vlog(r);
+ if(g >= 0) {
+ if(n->op == OASDIV)
+ n->op = OASASHR;
+ else
+ n->op = OASLSHR;
+ r->vconst = g;
+ }
+ goto aseae;
+
+ case OASLMOD:
+ case OASMOD:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+
+ aseae: /* hack that there are no byte/short mul/div operators */
+ if(n->type->etype == TCHAR || n->type->etype == TSHORT) {
+ n->right = new1(OCAST, n->right, Z);
+ n->right->type = types[TLONG];
+ n->type = types[TLONG];
+ }
+ if(n->type->etype == TUCHAR || n->type->etype == TUSHORT) {
+ n->right = new1(OCAST, n->right, Z);
+ n->right->type = types[TULONG];
+ n->type = types[TULONG];
+ }
+ goto asop;
+
+ case OASXOR:
+ case OASOR:
+ case OASADD:
+ case OASSUB:
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ case OASAND:
+ case OAS:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+
+ asop:
+ if(l->addable > INDEXED &&
+ l->complex < FNX &&
+ r && r->complex < FNX)
+ n->addable = l->addable;
+ break;
+
+ case OPOSTINC:
+ case OPREINC:
+ case OPOSTDEC:
+ case OPREDEC:
+ xcom(l);
+ if(typev[n->type->etype])
+ break;
+ if(l->addable > INDEXED &&
+ l->complex < FNX)
+ n->addable = l->addable;
+ break;
+
+ default:
+ if(l != Z)
+ xcom(l);
+ if(r != Z)
+ xcom(r);
+ break;
+ }
+
+brk:
+ n->complex = 0;
+ if(n->addable >= 10)
+ return;
+ if(l != Z)
+ n->complex = l->complex;
+ if(r != Z) {
+ if(r->complex == n->complex)
+ n->complex = r->complex+1;
+ else
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ }
+ if(n->complex == 0)
+ n->complex++;
+
+ if(com64(n))
+ return;
+
+ switch(n->op) {
+
+ case OFUNC:
+ n->complex = FNX;
+ break;
+
+ case OADD:
+ case OMUL:
+ case OLMUL:
+ case OXOR:
+ case OAND:
+ case OOR:
+ /*
+ * symmetric operators, make right side simple
+ * if same, put constant on left to get movq
+ */
+ if(r->complex > l->complex ||
+ (r->complex == l->complex && r->addable == 20)) {
+ n->left = r;
+ n->right = l;
+ }
+ break;
+
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OEQ:
+ case ONE:
+ /*
+ * relational operators, make right side simple
+ * if same, put constant on left to get movq
+ */
+ if(r->complex > l->complex || r->addable == 20) {
+ n->left = r;
+ n->right = l;
+ n->op = invrel[relindex(n->op)];
+ }
+ break;
+ }
+}
+
+void
+bcomplex(Node *n)
+{
+
+ complex(n);
+ if(n->type != T)
+ if(tcompat(n, T, n->type, tnot))
+ n->type = T;
+ if(n->type != T) {
+ bool64(n);
+ doinc(n, PRE);
+ boolgen(n, 1, D_NONE, Z, n);
+ } else
+ gbranch(OGOTO);
+}
+
+Node*
+nodconst(long v)
+{
+
+ return (Node*)v;
+}
diff --git a/sys/src/cmd/1c/swt.c b/sys/src/cmd/1c/swt.c
new file mode 100755
index 000000000..34daeb1e5
--- /dev/null
+++ b/sys/src/cmd/1c/swt.c
@@ -0,0 +1,964 @@
+#include "gc.h"
+
+int
+swcmp(const void *a1, const void *a2)
+{
+ C1 *p1, *p2;
+
+ p1 = (C1*)a1;
+ p2 = (C1*)a2;
+ if(p1->val < p2->val)
+ return -1;
+ return p1->val > p2->val;
+}
+
+void
+doswit(int g, Node *n)
+{
+ Case *c;
+ C1 *q, *iq;
+ long def, nc, i;
+
+ def = 0;
+ nc = 0;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def) {
+ if(def)
+ diag(n, "more than one default in switch");
+ def = c->label;
+ continue;
+ }
+ nc++;
+ }
+
+ iq = alloc(nc*sizeof(C1));
+ q = iq;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def)
+ continue;
+ q->label = c->label;
+ q->val = c->val;
+ q++;
+ }
+ qsort(iq, nc, sizeof(C1), swcmp);
+ if(def == 0)
+ def = breakpc;
+ for(i=0; i<nc-1; i++)
+ if(iq[i].val == iq[i+1].val)
+ diag(n, "duplicate cases in switch %ld", iq[i].val);
+ swit1(iq, nc, def, g, n);
+}
+
+#define N1 4 /* ncase: always linear */
+ /* else binary */
+void
+swit1(C1 *q, int nc, long def, int g, Node *n)
+{
+ C1 *r;
+ int i;
+ long v;
+ Prog *sp1, *sp2;
+
+ /* note that g and g+1 are not allocated */
+ if(nc <= N1)
+ goto linear;
+
+ /*
+ * divide and conquer
+ */
+ i = nc / 2;
+ r = q+i;
+ v = r->val;
+ /* compare median */
+ if(v >= -128 && v < 128) {
+ gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n);
+ gopcode(OEQ, n->type, g, n, g+1, n);
+ } else
+ gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v));
+ gbranch(OLT);
+ sp1 = p;
+ gbranch(OGT);
+ sp2 = p;
+ gbranch(OGOTO);
+ patch(p, r->label);
+
+ patch(sp1, pc);
+ swit1(q, i, def, g, n);
+
+ patch(sp2, pc);
+ swit1(r+1, nc-i-1, def, g, n);
+ return;
+
+linear:
+ for(i=0; i<nc; i++) {
+ v = q->val;
+ if(v >= -128 && v < 128) {
+ gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n);
+ gopcode(OEQ, n->type, g+1, n, g, n);
+ } else
+ gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v));
+ gbranch(OEQ);
+ patch(p, q->label);
+ q++;
+ }
+ gbranch(OGOTO);
+ patch(p, def);
+}
+
+void
+casf(void)
+{
+ Case *c;
+
+ c = alloc(sizeof(*c));
+ c->link = cases;
+ cases = c;
+}
+
+
+int
+bitload(Node *b, int n1, int n2, int n3, Node *nn)
+{
+ int sh, g, gs;
+ long v;
+ Node *l;
+ Type *t;
+
+ /*
+ * n1 gets adjusted/masked value
+ * n2 gets address of cell
+ * n3 gets contents of cell
+ */
+ gs = 0;
+ t = tfield;
+
+ l = b->left;
+ g = regalloc(t, n3);
+ if(n2 != D_NONE) {
+ lcgen(l, n2, Z);
+ n2 |= I_INDIR;
+ gmove(t, t, n2, l, g, l);
+ gmove(t, t, g, l, n1, l);
+ } else
+ cgen(l, g, nn);
+ if(b->type->shift == 0 && typeu[b->type->etype]) {
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, t, D_CONST, nodconst(v), g, l);
+ } else {
+ sh = 32 - b->type->shift - b->type->nbits;
+ if(sh > 0)
+ if(sh >= 8) {
+ gs = regalloc(t, D_NONE);
+ gmove(t, t, D_CONST, nodconst(sh), gs, l);
+ gopcode(OASHL, t, gs, l, g, l);
+ if(b->type->shift)
+ regfree(gs);
+ } else
+ gopcode(OASHL, t, D_CONST, nodconst(sh), g, l);
+ sh += b->type->shift;
+ if(sh > 0) {
+ if(sh >= 8) {
+ if(b->type->shift) {
+ gs = regalloc(t, D_NONE);
+ gmove(t, t, D_CONST, nodconst(sh), gs, l);
+ }
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, t, gs, l, g, l);
+ else
+ gopcode(OASHR, t, gs, l, g, l);
+ regfree(gs);
+ } else {
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, t, D_CONST, nodconst(sh), g, l);
+ else
+ gopcode(OASHR, t, D_CONST, nodconst(sh), g, l);
+ }
+ }
+ }
+ return g;
+}
+
+void
+bitstore(Node *b, int n1, int n2, int n3, int result, Node *nn)
+{
+ long v;
+ Node *l;
+ Type *t;
+ int sh, g, gs;
+
+ /*
+ * n1 has adjusted/masked value
+ * n2 has address of cell
+ * n3 has contents of cell
+ */
+ t = tfield;
+
+ l = b->left;
+ g = regalloc(t, D_NONE);
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, t, D_CONST, nodconst(v), n1, l);
+ gmove(t, t, n1, l, g, l);
+ if(result != D_NONE)
+ gmove(t, nn->type, n1, l, result, nn);
+ sh = b->type->shift;
+ if(sh > 0) {
+ if(sh >= 8) {
+ gs = regalloc(t, D_NONE);
+ gmove(t, t, D_CONST, nodconst(sh), gs, l);
+ gopcode(OASHL, t, gs, l, g, l);
+ regfree(gs);
+ } else
+ gopcode(OASHL, t, D_CONST, nodconst(sh), g, l);
+ }
+ v <<= sh;
+ gopcode(OAND, t, D_CONST, nodconst(~v), n3, l);
+ gopcode(OOR, t, n3, l, g, l);
+ gmove(t, t, g, l, n2|I_INDIR, l);
+
+ regfree(g);
+ regfree(n1);
+ regfree(n2);
+ regfree(n3);
+}
+
+long
+outstring(char *s, long n)
+{
+ long r;
+
+ r = nstring;
+ while(n) {
+ string[mnstring] = *s++;
+ mnstring++;
+ nstring++;
+ if(mnstring >= NSNAME) {
+ gpseudo(ADATA, symstring, D_SCONST, 0L);
+ memmove(p->to.sval, string, NSNAME);
+ p->from.offset = nstring - NSNAME;
+ p->from.displace = NSNAME;
+ mnstring = 0;
+ }
+ n--;
+ }
+ return r;
+}
+
+long
+outlstring(ushort *s, long n)
+{
+ char buf[2];
+ int c;
+ long r;
+
+ while(nstring & 1)
+ outstring("", 1);
+ r = nstring;
+ while(n > 0) {
+ c = *s++;
+ if(align(0, types[TCHAR], Aarg1)) {
+ buf[0] = c>>8;
+ buf[1] = c;
+ } else {
+ buf[0] = c;
+ buf[1] = c>>8;
+ }
+ outstring(buf, 2);
+ n -= sizeof(ushort);
+ }
+ return r;
+}
+
+int
+doinc(Node *n, int f)
+{
+ Node *l;
+ int a;
+
+loop:
+ if(n == Z)
+ return 0;
+ l = n->left;
+ switch(n->op) {
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ if(f & POST) {
+ a = n->addable;
+ if(a >= INDEXED) {
+ if(f & TEST)
+ return 1;
+ n->addable = 0;
+ cgen(n, D_NONE, n);
+ n->addable = a;
+ }
+ }
+ break;
+
+ case OAS:
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ case OASXOR:
+ case OASOR:
+ case OASADD:
+ case OASSUB:
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ case OASAND:
+
+ case OPREINC:
+ case OPREDEC:
+ if(f & PRE) {
+ a = n->addable;
+ if(a >= INDEXED) {
+ if(f & TEST)
+ return 1;
+ n->addable = 0;
+ doinc(n, PRE);
+ cgen(n, D_NONE, n);
+ n->addable = a;
+ return 0;
+ }
+ }
+ break;
+
+ case OFUNC:
+ if(f & PRE)
+ break;
+ return 0;
+
+ case ONAME:
+ case OREGISTER:
+ case OSTRING:
+ case OCONST:
+
+ case OANDAND:
+ case OOROR:
+ return 0;
+
+ case OCOND:
+ return 0;
+
+ case OCOMMA:
+ n = n->right;
+ if(f & PRE)
+ n = l;
+ goto loop;
+ }
+ if(l != Z)
+ if(doinc(l, f))
+ return 1;
+ n = n->right;
+ goto loop;
+}
+
+void
+setsp(void)
+{
+
+ nextpc();
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = 0;
+}
+
+void
+adjsp(long o)
+{
+
+ if(o != 0) {
+ nextpc();
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = o;
+ argoff += o;
+ }
+}
+
+int
+simplv(Node *n)
+{
+
+ if(n->addable <= INDEXED)
+ return 0;
+ while(n->op == OIND)
+ n = n->left;
+ if(n->op == ONAME)
+ return 1;
+ return 0;
+}
+
+int
+eval(Node *n, int g)
+{
+
+ if(n->addable >= INDEXED)
+ return D_TREE;
+ g = regalloc(n->type, g);
+ cgen(n, g, n);
+ return g;
+}
+
+void outhist(Biobuf*);
+void zname(Biobuf*, Sym*, int);
+void zaddr(Biobuf*, Adr*, int);
+void zwrite(Biobuf*, Prog*, int, int);
+
+void
+outcode(void)
+{
+ struct { Sym *sym; short type; } h[NSYM];
+ Prog *p;
+ Sym *s;
+ int f, sf, st, t, sym;
+ Biobuf b;
+
+ if(debug['S']) {
+ for(p = firstp; p != P; p = p->link)
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc--;
+ for(p = firstp; p != P; p = p->link) {
+ print("%P\n", p);
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc++;
+ }
+ }
+ f = open(outfile, OWRITE);
+ if(f < 0) {
+ diag(Z, "cant open %s", outfile);
+ errorexit();
+ }
+ Binit(&b, f, OWRITE);
+ Bseek(&b, 0L, 2);
+ outhist(&b);
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+ for(p = firstp; p != P; p = p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.type & D_MASK;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(&b, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = p->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = p->to.type & D_MASK;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(&b, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ zwrite(&b, p, sf, st);
+ }
+ Bflush(&b);
+ close(f);
+ firstp = P;
+ lastp = P;
+}
+
+void
+zwrite(Biobuf *b, Prog *p, int sf, int st)
+{
+ long l;
+
+ l = p->as;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ l = p->lineno;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ zaddr(b, &p->from, sf);
+ zaddr(b, &p->to, st);
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ char *n;
+ ulong sig;
+
+ if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
+ sig = sign(s);
+ Bputc(b, ASIGNAME);
+ Bputc(b, ASIGNAME>>8);
+ Bputc(b, sig);
+ Bputc(b, sig>>8);
+ Bputc(b, sig>>16);
+ Bputc(b, sig>>24);
+ s->sig = SIGDONE;
+ }
+ else{
+ Bputc(b, ANAME); /* as */
+ Bputc(b, ANAME>>8); /* as */
+ }
+ Bputc(b, t); /* type */
+ Bputc(b, s->sym); /* sym */
+ n = s->name;
+ while(*n) {
+ Bputc(b, *n);
+ n++;
+ }
+ Bputc(b, 0);
+}
+
+void
+zaddr(Biobuf *b, Adr *a, int s)
+{
+ long l;
+ int i, t;
+ char *n;
+ Ieee e;
+
+ t = 0;
+ if(a->field)
+ t |= T_FIELD;
+ if(s)
+ t |= T_SYM;
+
+ switch(a->type) {
+ default:
+ if(a->offset)
+ t |= T_OFFSET;
+ if(a->displace)
+ t |= T_INDEX;
+ if(a->type & ~0xff)
+ t |= T_TYPE;
+ break;
+ case D_FCONST:
+ t |= T_FCONST;
+ break;
+ case D_SCONST:
+ t |= T_SCONST;
+ break;
+ }
+ Bputc(b, t);
+
+ if(t & T_FIELD) { /* implies field */
+ i = a->field;
+ Bputc(b, i);
+ Bputc(b, i>>8);
+ }
+ if(t & T_INDEX) { /* implies index, scale, displace */
+ i = D_NONE;
+ Bputc(b, i);
+ Bputc(b, i>>8);
+ Bputc(b, 0);
+ l = a->displace;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->offset;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ }
+ if(t & T_SYM) /* implies sym */
+ Bputc(b, s);
+ if(t & T_FCONST) {
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ l = e.h;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(b, *n);
+ n++;
+ }
+ return;
+ }
+ i = a->type;
+ Bputc(b, i);
+ if(t & T_TYPE)
+ Bputc(b, i>>8);
+}
+
+
+
+void
+outhist(Biobuf *b)
+{
+ Hist *h;
+ char *p, *q, *op, c;
+ Prog pg;
+ int n;
+
+ pg = zprog;
+ pg.as = AHISTORY;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = utfrune(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(b, ANAME);
+ Bputc(b, ANAME>>8);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ pg.lineno = h->line;
+ pg.to.type = zprog.to.type;
+ pg.to.offset = h->offset;
+ if(h->offset)
+ pg.to.type = D_CONST;
+
+ zwrite(b, &pg, 0, 0);
+ }
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (long)(fr*f);
+}
+
+int
+nodalloc(Type *t, int g, Node *n)
+{
+
+ n->type = t;
+ n->op = OREGISTER;
+ n->addable = 12;
+ n->complex = 0;
+ g = regaddr(g);
+ n->reg = g | I_INDIR;
+ n->xoffset = 0;
+ return g;
+}
+
+int
+mulcon(Node *n, Node *c, int result, Node *nn)
+{
+ long v;
+
+ if(typefd[n->type->etype])
+ return 0;
+ v = c->vconst;
+ if(mulcon1(n, v, result, nn))
+ return 1;
+ return 0;
+}
+
+int
+shlcon(Node *n, Node *c, int result, Node *nn)
+{
+ long v;
+
+ v = 1L << c->vconst;
+ return mulcon1(n, v, result, nn);
+}
+
+int
+mulcon1(Node *n, long v, int result, Node *nn)
+{
+ int g, g1, a1, a2, neg;
+ int o;
+ char code[10], *p;
+
+ if(result == D_NONE)
+ return 0;
+ neg = 0;
+ if(v < 0) {
+ v = -v;
+ neg++;
+ }
+ a1 = 0;
+ a2 = multabsize;
+ for(;;) {
+ if(a1 >= a2)
+ return 0;
+ g1 = (a2 + a1)/2;
+ if(v < multab[g1].val) {
+ a2 = g1;
+ continue;
+ }
+ if(v > multab[g1].val) {
+ a1 = g1+1;
+ continue;
+ }
+ break;
+ }
+ strcpy(code, "0");
+ strncat(code, multab[g1].code, sizeof(multab[0].code));
+ p = code;
+ if(p[1] == 'i')
+ p += 2;
+ g = regalloc(n->type, result);
+ cgen(n, g, n);
+ if(neg)
+ gopcode(ONEG, n->type, D_NONE, n, g, n);
+ g1 = regalloc(n->type, D_NONE);
+loop:
+ switch(*p) {
+ case 0:
+ regfree(g1);
+ gmove(n->type, nn->type, g, n, result, nn);
+ regfree(g);
+ return 1;
+ case '0':
+ o = OAS;
+ *p -= '0';
+ goto com;
+ case '1':
+ case '2':
+ o = OSUB;
+ *p -= '1';
+ goto com;
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ o = OADD;
+ *p -= '3';
+ com:
+ a1 = g;
+ if(*p == 1 || *p == 3)
+ a1 = g1;
+ a2 = g;
+ if(*p == 0 || *p == 3)
+ a2 = g1;
+ gopcode(o, n->type, a1, n, a2, n);
+ p++;
+ break;
+ default:
+ a1 = *p++ - 'a' + 1;
+ a2 = g;
+ if(a1 > 8) {
+ a2 = g1;
+ a1 -= 8;
+ }
+ gopcode(OASHL, n->type, D_CONST, nodconst(a1), a2, n);
+ break;
+ }
+ goto loop;
+}
+
+void
+nullwarn(Node *l, Node *r)
+{
+ warn(Z, "result of operation not used");
+ if(l != Z)
+ cgen(l, D_NONE, Z);
+ if(r != Z)
+ cgen(r, D_NONE, Z);
+}
+
+void
+sextern(Sym *s, Node *a, long o, long w)
+{
+ long e, lw;
+
+ for(e=0; e<w; e+=NSNAME) {
+ lw = NSNAME;
+ if(w-e < lw)
+ lw = w-e;
+ gpseudo(ADATA, s, D_SCONST, 0L);
+ p->from.offset += o+e;
+ p->from.displace = lw;
+ memmove(p->to.sval, a->cstring+e, lw);
+ }
+}
+
+void
+gextern(Sym *s, Node *a, long o, long w)
+{
+ if(a->op == OCONST && typev[a->type->etype]) {
+ gpseudo(ADATA, s, D_CONST, (long)(a->vconst>>32));
+ p->from.offset += o;
+ p->from.displace = 4;
+ gpseudo(ADATA, s, D_CONST, (long)(a->vconst));
+ p->from.offset += o + 4;
+ p->from.displace = 4;
+ return;
+ }
+ gpseudotree(ADATA, s, a);
+ p->from.offset += o;
+ p->from.displace = w;
+}
+
+long
+align(long i, Type *t, int op)
+{
+ long o;
+ Type *v;
+ int w;
+
+ o = i;
+ w = 1;
+ switch(op) {
+ default:
+ diag(Z, "unknown align opcode %d", op);
+ break;
+
+ case Asu2: /* padding at end of a struct */
+ w = SZ_LONG;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael1: /* initial allign of struct element */
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ w = ewidth[v->etype];
+ if(w <= 0 || w >= SZ_SHORT)
+ w = SZ_SHORT;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael2: /* width of a struct element */
+ o += t->width;
+ break;
+
+ case Aarg0: /* initial passbyptr argument in arg list */
+ if(typesuv[t->etype]) {
+ o = align(o, types[TIND], Aarg1);
+ o = align(o, types[TIND], Aarg2);
+ }
+ break;
+
+ case Aarg1: /* initial allign of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_LONG) {
+ w = SZ_LONG;
+ break;
+ }
+ o += SZ_LONG - w; /* big endian adjustment */
+ w = 1;
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = SZ_LONG;
+ break;
+
+ case Aaut3: /* total allign of automatic */
+ o = align(o, t, Ael1);
+ o = align(o, t, Ael2);
+ break;
+ }
+ o = round(o, w);
+ if(debug['A'])
+ print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ return o;
+}
+
+long
+maxround(long max, long v)
+{
+ v += SZ_LONG-1;
+ if(v > max)
+ max = round(v, SZ_LONG);
+ return max;
+}
diff --git a/sys/src/cmd/1c/txt.c b/sys/src/cmd/1c/txt.c
new file mode 100755
index 000000000..e439c40cb
--- /dev/null
+++ b/sys/src/cmd/1c/txt.c
@@ -0,0 +1,903 @@
+#include "gc.h"
+
+void
+tindex(Type *tf, Type *tt)
+{
+ int i, j;
+
+ j = 0;
+ if(tt != T) {
+ j = tt->etype;
+ if(j >= NTYPE)
+ j = 0;
+ }
+ i = 0;
+ if(tf != T) {
+ i = tf->etype;
+ if(i >= NTYPE)
+ if(typesu[i])
+ i = j;
+ else
+ i = 0;
+ }
+ txtp = &txt[i][j];
+}
+
+void
+ginit(void)
+{
+ int i, j, si, sj;
+
+ thestring = "68000";
+ thechar = '1';
+ exregoffset = 7;
+ exaregoffset = 5;
+ exfregoffset = 7;
+ listinit();
+ for(i=0; i<NREG; i++) {
+ regused[i] = 0;
+ fregused[i] = 0;
+ aregused[i] = 0;
+ }
+ regaddr(D_A0+6);
+ regaddr(D_A0+7);
+ for(i=0; i<sizeof(regbase); i++)
+ regbase[i] = D_NONE;
+ for(i=0; i<NREG; i++) {
+ regbase[D_R0+i] = D_R0+i;
+ regbase[D_A0+i] = D_A0+i;
+ regbase[D_F0+i] = D_F0+i;
+ }
+ regbase[D_TOS] = D_TOS;
+
+ for(i=0; i<NTYPE; i++)
+ for(j=0; j<NTYPE; j++) {
+ txtp = &txt[i][j];
+ txtp->movas = AGOK;
+ txtp->preclr = 0;
+ txtp->postext = AGOK;
+ if(!(typechlp[i] && typechlp[j]))
+ continue;
+ si = types[i]->width;
+ sj = types[j]->width;
+ if(sj < si)
+ txtp->preclr = -1;
+ if(sj > si) {
+ if(typeu[i]) {
+ txtp->preclr = 1;
+ } else {
+ if(sj == 2)
+ txtp->postext = AEXTBW;
+ else
+ if(sj == 4)
+ if(si == 1)
+ txtp->postext = AEXTBL;
+ else
+ txtp->postext = AEXTWL;
+ }
+ sj = si;
+ }
+ if(sj == 1)
+ txtp->movas = AMOVB;
+ if(sj == 2)
+ txtp->movas = AMOVW;
+ if(sj == 4)
+ txtp->movas = AMOVL;
+ }
+
+ for(i=0; i<ALLOP; i++)
+ for(j=0; j<NTYPE; j++)
+ opxt[i][j] = AGOK;
+ oinit(OFUNC, ABSR, ATRAP, AGOK, AGOK, AGOK);
+
+ oinit(OAS, AMOVB, AMOVW, AMOVL, AFMOVEF, AFMOVED);
+ oinit(OFAS, AFMOVEB, AFMOVEW, AFMOVEL, AFMOVEF, AFMOVED);
+ oinit(OADDR, AGOK, APEA, ALEA, AGOK, AGOK);
+ oinit(OPREINC, AADDB, AADDW, AADDL, AFADDF, AFADDD);
+ oinit(OPOSTINC, AADDB, AADDW, AADDL, AFADDF, AFADDD);
+ oinit(OPREDEC, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD);
+ oinit(OPOSTDEC, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD);
+ oinit(OADD, AADDB, AADDW, AADDL, AFADDF, AFADDD);
+ oinit(OASADD, AADDB, AADDW, AADDL, AFADDF, AFADDD);
+ oinit(OSUB, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD);
+ oinit(OASSUB, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD);
+ oinit(OMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD);
+ oinit(OLMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD);
+ oinit(OASMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD);
+ oinit(OASLMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD);
+ oinit(ODIV, AGOK, ADIVSW, ADIVSL, AFDIVF, AFDIVD);
+ oinit(OLDIV, AGOK, ADIVUW, ADIVUL, AFDIVF, AFDIVD);
+ oinit(OASDIV, AGOK, ADIVSW, ADIVSL, AFDIVF, AFDIVD);
+ oinit(OASLDIV, AGOK, ADIVUW, ADIVUL, AFDIVF, AFDIVD);
+ oinit(OMOD, AGOK, ADIVSW, ADIVSL, AFMODF, AFMODD);
+ oinit(OASMOD, AGOK, ADIVSW, ADIVSL, AGOK, AGOK);
+ oinit(OLMOD, AGOK, ADIVUW, ADIVUL, AGOK, AGOK);
+ oinit(OASLMOD, AGOK, ADIVUW, ADIVUL, AGOK, AGOK);
+ oinit(OAND, AANDB, AANDW, AANDL, AGOK, AGOK);
+ oinit(OASAND, AANDB, AANDW, AANDL, AGOK, AGOK);
+ oinit(OOR, AORB, AORW, AORL, AGOK, AGOK);
+ oinit(OASOR, AORB, AORW, AORL, AGOK, AGOK);
+ oinit(OXOR, AEORB, AEORW, AEORL, AGOK, AGOK);
+ oinit(OASXOR, AEORB, AEORW, AEORL, AGOK, AGOK);
+ oinit(ONEG, ANEGB, ANEGW, ANEGL, AFNEGF, AFNEGD);
+ oinit(OCOM, ANOTB, ANOTW, ANOTL, AGOK, AGOK);
+ oinit(OTST, ATSTB, ATSTW, ATSTL, AFTSTF, AFTSTD);
+ oinit(OEQ, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(ONE, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OGE, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OGT, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OLT, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OLE, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OLS, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OLO, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OHS, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OHI, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OASHR, AASRB, AASRW, AASRL, AGOK, AGOK);
+ oinit(OASASHR, AASRB, AASRW, AASRL, AGOK, AGOK);
+ oinit(OLSHR, ALSRB, ALSRW, ALSRL, AGOK, AGOK);
+ oinit(OASLSHR, ALSRB, ALSRW, ALSRL, AGOK, AGOK);
+ oinit(OASHL, AASLB, AASLW, AASLL, AGOK, AGOK);
+ oinit(OASASHL, AASLB, AASLW, AASLL, AGOK, AGOK);
+ oinit(OBIT, ABFEXTU, AGOK, AGOK, AGOK, AGOK);
+
+ nstring = 0;
+ mnstring = 0;
+ nrathole = 0;
+ nstatic = 0;
+ pc = 0;
+ breakpc = -1;
+ continpc = -1;
+ cases = C;
+ firstp = P;
+ lastp = P;
+ tfield = types[TLONG];
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.from.type = D_NONE;
+ zprog.to = zprog.from;
+
+ nodret = new(ONAME, Z, Z);
+ nodret->sym = slookup(".ret");
+ nodret->type = types[TIND];
+ nodret->etype = types[TIND]->etype;
+ nodret->class = CPARAM;
+ nodret = new(OIND, nodret, Z);
+ complex(nodret);
+
+ symrathole = slookup(".rathole");
+ symrathole->class = CGLOBL;
+ symrathole->type = typ(TARRAY, types[TCHAR]);
+ nodrat = new(ONAME, Z, Z);
+ nodrat->sym = symrathole;
+ nodrat->type = types[TIND];
+ nodrat->etype = TVOID;
+ nodrat->class = CGLOBL;
+ complex(nodrat);
+ nodrat->type = symrathole->type;
+
+ com64init();
+
+ symstatic = slookup(".static");
+ symstatic->class = CSTATIC;
+ symstatic->type = typ(TARRAY, types[TLONG]);
+}
+
+void
+gclean(void)
+{
+ int i;
+ Sym *s;
+
+ regfree(D_A0+6);
+ regfree(D_A0+7);
+ for(i=0; i<NREG; i++) {
+ if(regused[i])
+ diag(Z, "missing R%d", i);
+ if(aregused[i])
+ diag(Z, "missing A%d", i);
+ if(fregused[i])
+ diag(Z, "missing F%d", i);
+ }
+
+ while(mnstring)
+ outstring("", 1L);
+ symstring->type->width = nstring;
+ symstatic->type->width = nstatic;
+ symrathole->type->width = nrathole;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type == T)
+ continue;
+ if(s->type->width == 0)
+ continue;
+ if(s->class != CGLOBL && s->class != CSTATIC)
+ continue;
+ if(s->type == types[TENUM])
+ continue;
+ gpseudo(AGLOBL, s, D_CONST, s->type->width);
+ pc--;
+ }
+ nextpc();
+ p->as = AEND;
+ outcode();
+}
+
+void
+oinit(int o, int ab, int aw, int al, int af, int ad)
+{
+ int i;
+
+ i = o;
+ if(i >= ALLOP) {
+ diag(Z, "op(%d) >= ALLOP(%d)", i, ALLOP);
+ errorexit();
+ }
+ opxt[i][TCHAR] = ab;
+ opxt[i][TUCHAR] = ab;
+ opxt[i][TSHORT] = aw;
+ opxt[i][TUSHORT] = aw;
+ opxt[i][TINT] = al;
+ opxt[i][TUINT] = al;
+ opxt[i][TLONG] = al;
+ opxt[i][TULONG] = al;
+ opxt[i][TIND] = al;
+ opxt[i][TFLOAT] = af;
+ opxt[i][TDOUBLE] = ad;
+}
+
+Prog*
+prg(void)
+{
+ Prog *p;
+
+ p = alloc(sizeof(*p));
+ *p = zprog;
+ return p;
+}
+
+void
+nextpc(void)
+{
+
+ p = prg();
+ pc++;
+ p->lineno = nearln;
+ if(firstp == P) {
+ firstp = p;
+ lastp = p;
+ return;
+ }
+ lastp->link = p;
+ lastp = p;
+}
+
+void
+gargs(Node *n)
+{
+ long s;
+
+loop:
+ if(n == Z)
+ return;
+ if(n->op == OLIST) {
+ gargs(n->right);
+ n = n->left;
+ goto loop;
+ }
+ s = argoff;
+ cgen(n, D_TOS, n);
+ argoff = s + n->type->width;
+}
+
+void
+naddr(Node *n, Adr *a, int x)
+{
+ Node *l;
+ long v;
+
+ switch(n->op) {
+ default:
+ bad:
+ diag(n, "bad in naddr: %O", n->op);
+ break;
+
+ case OADDR:
+ case OIND:
+ naddr(n->left, a, x);
+ goto noadd;
+
+ case OREGISTER:
+ a->sym = S;
+ a->type = n->reg;
+ a->offset = n->xoffset;
+ a->displace = 0;
+ break;
+
+ case ONAME:
+ a->etype = n->etype;
+ a->displace = 0;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ a->type = D_STATIC;
+ if(n->class == CSTATIC)
+ break;
+ if(n->class == CEXTERN || n->class == CGLOBL) {
+ a->type = D_EXTERN;
+ break;
+ }
+ if(n->class == CAUTO) {
+ a->type = D_AUTO;
+ break;
+ }
+ if(n->class == CPARAM) {
+ a->type = D_PARAM;
+ break;
+ }
+ goto bad;
+
+ case OCONST:
+ a->displace = 0;
+ if(typefd[n->type->etype]) {
+ a->type = D_FCONST;
+ a->dval = n->fconst;
+ break;
+ }
+ a->type = D_CONST;
+ a->offset = n->vconst;
+ break;
+
+ case OADD:
+ l = n->left;
+ if(l->addable == 20) {
+ v = l->vconst;
+ naddr(n->right, a, x);
+ goto add;
+ }
+ l = n->right;
+ if(l->addable == 20) {
+ v = l->vconst;
+ naddr(n->left, a, x);
+ goto add;
+ }
+ goto bad;
+
+ noadd:
+ v = 0;
+ add:
+ switch(n->addable) {
+ default:
+ goto bad;
+ case 2:
+ a->displace += v;
+ break;
+ case 21:
+ a->type &= D_MASK;
+ a->type |= I_INDIR;
+ break;
+ case 1:
+ case 12:
+ a->offset += v;
+ a->type &= D_MASK;
+ a->type |= I_ADDR;
+ break;
+ case 10:
+ case 11:
+ case 20:
+ a->type &= D_MASK;
+ a->type |= I_DIR;
+ break;
+ }
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ case OPOSTINC:
+ case OPOSTDEC:
+
+ case OAS:
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ case OASXOR:
+ case OASOR:
+ case OASADD:
+ case OASSUB:
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ case OASAND:
+ naddr(n->left, a, x);
+ break;
+ }
+}
+
+int
+regalloc(Type *t, int g)
+{
+
+ if(t == T)
+ return D_NONE;
+ g &= D_MASK;
+ if(typefd[t->etype]) {
+ if(g >= D_F0 && g < D_F0+NREG) {
+ fregused[g-D_F0]++;
+ return g;
+ }
+ for(g=0; g<NREG; g++)
+ if(fregused[g] == 0) {
+ fregused[g]++;
+ return g + D_F0;
+ }
+ } else {
+ if(g >= D_R0 && g < D_R0+NREG) {
+ regused[g-D_R0]++;
+ return g;
+ }
+ for(g=0; g<NREG; g++)
+ if(regused[g] == 0) {
+ regused[g]++;
+ return g + D_R0;
+ }
+ }
+ diag(Z, "out of registers");
+ return D_TOS;
+}
+
+int
+regaddr(int g)
+{
+
+ if(g >= D_A0 && g < D_A0+NREG) {
+ aregused[g-D_A0]++;
+ return g;
+ }
+ for(g=0; g<NREG; g++)
+ if(aregused[g] == 0) {
+ aregused[g]++;
+ return g + D_A0;
+ }
+ diag(Z, "out of addr registers");
+ return D_TOS;
+}
+
+int
+regpair(int g)
+{
+
+ if(g >= D_R0+1 && g < D_R0+NREG)
+ if(!regused[g-D_R0-1]) {
+ regused[g-D_R0-1]++;
+ regused[g-D_R0]++;
+ return g-1;
+ }
+ if(g >= D_R0 && g < D_R0+NREG-1)
+ if(!regused[g-D_R0+1]) {
+ regused[g-D_R0+1]++;
+ regused[g-D_R0]++;
+ return g;
+ }
+ for(g = 0; g < NREG-1; g++)
+ if(!regused[g])
+ if(!regused[g+1]) {
+ regused[g]++;
+ regused[g+1]++;
+ return g + D_R0;
+ }
+ diag(Z, "out of register pairs");
+ return D_TOS;
+}
+
+int
+regret(Type *t)
+{
+
+ if(t == T)
+ return D_NONE;
+ if(typefd[t->etype])
+ return D_F0;
+ return D_R0;
+}
+
+void
+regfree(int g)
+{
+
+ g &= D_MASK;
+ if(g == D_TOS || g == D_TREE || g == D_NONE)
+ return;
+ if(g >= D_R0 && g < D_R0+NREG) {
+ regused[g-D_R0]--;
+ return;
+ }
+ if(g >= D_A0 && g < D_A0+NREG) {
+ aregused[g-D_A0]--;
+ return;
+ }
+ if(g >= D_F0 && g < D_F0+NREG) {
+ fregused[g-D_F0]--;
+ return;
+ }
+ diag(Z, "bad in regfree: %d", g);
+}
+
+void
+gmove(Type *tf, Type *tt, int gf, Node *f, int gt, Node *t)
+{
+ int g, a, b;
+ Prog *p1;
+
+ tindex(tf, tt);
+ if(txtp->preclr) {
+ if(gf >= D_R0 && gf < D_R0+NREG)
+ if(txtp->preclr < 0) {
+ gmove(tt, tt, gf, f, gt, t);
+ return;
+ }
+ g = regalloc(types[TLONG], gt);
+ if(g == gf) {
+ g = regalloc(types[TLONG], D_NONE);
+ regfree(gf);
+ }
+ if(txtp->preclr > 0)
+ gopcode(OAS, types[TLONG], D_CONST, nodconst(0), g, Z);
+ gopcode(OAS, tf, gf, f, g, Z);
+ if(g != gt)
+ gopcode(OAS, tt, g, Z, gt, t);
+ regfree(g);
+ return;
+ }
+ a = txtp->postext;
+ if(a != AGOK) {
+ if(gf >= D_R0 && gf < D_R0+NREG)
+ g = regalloc(types[TLONG], gf);
+ else
+ g = regalloc(types[TLONG], gt);
+ if(g != gf)
+ gopcode(OAS, tf, gf, f, g, Z);
+ nextpc();
+ p->as = a;
+ p->to.type = g;
+ if(debug['g'])
+ print("%P\n", p);
+ if(g != gt)
+ gopcode(OAS, tt, g, Z, gt, t);
+ regfree(g);
+ return;
+ }
+ if((regbase[gf] != D_NONE && regbase[gf] == regbase[gt]) ||
+ (gf == D_TREE && gt == D_TREE && f == t))
+ return;
+ if(typefd[tf->etype] || typefd[tt->etype]) {
+ if(typeu[tf->etype] && typefd[tt->etype]) { /* unsign->float */
+ a = regalloc(types[TLONG], D_NONE);
+ gmove(tf, types[TLONG], gf, f, a, t);
+ if(tf->etype == TULONG) {
+ b = regalloc(types[TDOUBLE], D_NONE);
+ gmove(types[TLONG], tt, a, t, b, t);
+ gopcode(OTST, types[TLONG], D_NONE, Z, a, t);
+ gbranch(OGE);
+ p1 = p;
+ gopcode(OASADD, types[TDOUBLE],
+ D_CONST, nodconst(100), b, t);
+ p->from.dval = 4294967296.;
+ patch(p1, pc);
+ gmove(types[TDOUBLE], tt, b, t, gt, t);
+ regfree(b);
+ } else
+ gmove(types[TLONG], tt, a, t, gt, t);
+ regfree(a);
+ return;
+ }
+ if(typefd[tf->etype] && !typefd[tt->etype]) { /* float->fix */
+ a = regalloc(types[TLONG], D_NONE);
+ gopcode(OAS, types[TLONG], D_FPCR, t, a, t);
+ gopcode(OAS, types[TLONG], D_CONST, nodconst(16), D_FPCR, t);
+ }
+ if(gf < D_F0 || gf >= D_F0+NREG) {
+ g = regalloc(types[TDOUBLE], gt);
+ gopcode(OFAS, tf, gf, f, g, t);
+ if(g != gt)
+ gopcode(OFAS, tt, g, t, gt, t);
+ regfree(g);
+ } else
+ gopcode(OFAS, tt, gf, f, gt, t);
+ if(typefd[tf->etype] && !typefd[tt->etype]) { /* float->fix */
+ gopcode(OAS, types[TLONG], a, t, D_FPCR, t);
+ regfree(a);
+ }
+ return;
+ }
+ gopcode(OAS, tt, gf, f, gt, t);
+}
+
+void
+gopcode(int o, Type *ty, int gf, Node *f, int gt, Node *t)
+{
+ int i, fidx, tidx;
+
+ if(o == OAS)
+ if(gf == gt)
+ if(gf != D_TREE || f == t)
+ return;
+
+ fidx = D_NONE;
+ tidx = D_NONE;
+ i = 0;
+ if(ty != T) {
+ i = ty->etype;
+ if(i >= NTYPE)
+ i = 0;
+ }
+ nextpc();
+ if(gf == D_TREE) {
+ naddr(f, &p->from, fidx);
+ } else {
+ p->from.type = gf;
+ if(gf == D_CONST) {
+ p->from.offset = (long)(uintptr)f;
+ if(typefd[i]) {
+ p->from.type = D_FCONST;
+ p->from.dval = (long)(uintptr)f;
+ }
+ }
+ }
+ p->as = opxt[o][i];
+ if(gt == D_TREE) {
+ naddr(t, &p->to, tidx);
+ } else {
+ p->to.type = gt;
+ if(gt == D_CONST)
+ p->to.offset = (long)(uintptr)t;
+ }
+ if(o == OBIT) {
+ p->from.field = f->type->nbits;
+ p->to.field = f->type->shift;
+ if(p->from.field == 0)
+ diag(Z, "BIT zero width bit field");
+ }
+ if(p->as == AMOVL || p->as == AMOVW || p->as == AMOVB)
+ asopt();
+ if(debug['g'])
+ print("%P\n", p);
+ if(p->as == AGOK)
+ diag(Z, "GOK in gopcode: %s", onames[o]);
+ if(fidx != D_NONE)
+ regfree(fidx);
+ if(tidx != D_NONE)
+ regfree(tidx);
+}
+
+void
+asopt(void)
+{
+ long v;
+ int g;
+ Prog *q;
+
+ /*
+ * mov $0, ...
+ * ==>
+ * clr , ...
+ */
+ v = 0;
+ if(p->from.type == D_CONST) {
+ v = p->from.offset;
+ if(v == 0) {
+ p->from.type = D_NONE;
+ if(p->as == AMOVL)
+ p->as = ACLRL;
+ if(p->as == AMOVW)
+ p->as = ACLRW;
+ if(p->as == AMOVB)
+ p->as = ACLRB;
+ return;
+ }
+ }
+ /*
+ * mov ..., TOS
+ * ==>
+ * pea (...)
+ */
+ if(p->as == AMOVL && p->to.type == D_TOS)
+ switch(p->from.type) {
+ case D_CONST:
+ p->from.type |= I_INDIR;
+ p->to = p->from;
+ p->from = zprog.from;
+ p->as = APEA;
+ return;
+
+ case I_ADDR|D_EXTERN:
+ case I_ADDR|D_STATIC:
+ p->from.type &= ~I_ADDR;
+ p->to = p->from;
+ p->from = zprog.from;
+ p->as = APEA;
+ return;
+ }
+ /*
+ * movL $Qx, ...
+ * ==>
+ * movL $Qx,R
+ * movL R, ...
+ */
+ if(p->as == AMOVL && p->from.type == D_CONST)
+ if(v >= -128 && v < 128)
+ if(p->to.type < D_R0 || p->to.type >= D_R0+NREG) {
+ g = regalloc(types[TLONG], D_NONE);
+ q = p;
+ nextpc();
+ p->as = AMOVL;
+ p->from.type = g;
+ p->to = q->to;
+ q->to = p->from;
+ regfree(g);
+ if(debug['g'])
+ print("%P\n", q);
+ return;
+ }
+}
+
+void
+gbranch(int o)
+{
+ int a;
+
+ a = ABNE;
+ switch(o) {
+ case ORETURN: a = ARTS; break;
+ case OGOTO: a = ABRA; break;
+ case OEQ: a = ABEQ; break;
+ case ONE: a = ABNE; break;
+ case OLE: a = ABLE; break;
+ case OLS: a = ABLS; break;
+ case OLT: a = ABLT; break;
+ case OLO: a = ABCS; break;
+ case OGE: a = ABGE; break;
+ case OHS: a = ABCC; break;
+ case OGT: a = ABGT; break;
+ case OHI: a = ABHI; break;
+ case OBIT: a = ABCS; break;
+ case OCASE: a = ABCASE; break;
+ }
+ nextpc();
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+ p->as = a;
+}
+
+void
+fpbranch(void)
+{
+ int a;
+
+ a = p->as;
+ switch(a) {
+ case ABEQ: a = AFBEQ; break;
+ case ABNE: a = AFBNE; break;
+ case ABLE: a = AFBLE; break;
+ case ABLT: a = AFBLT; break;
+ case ABGE: a = AFBGE; break;
+ case ABGT: a = AFBGT; break;
+ }
+ p->as = a;
+}
+
+void
+patch(Prog *op, long pc)
+{
+
+ op->to.offset = pc;
+ op->to.type = D_BRANCH;
+}
+
+void
+gpseudo(int a, Sym *s, int g, long v)
+{
+
+ nextpc();
+ if(a == ADATA)
+ pc--;
+ p->as = a;
+ p->to.type = g;
+ p->to.offset = v;
+ p->from.sym = s;
+ p->from.type = D_EXTERN;
+ if(s->class == CSTATIC)
+ p->from.type = D_STATIC;
+}
+
+void
+gpseudotree(int a, Sym *s, Node *n)
+{
+
+ nextpc();
+ if(a == ADATA)
+ pc--;
+ p->as = a;
+ naddr(n, &p->to, D_NONE);
+ p->from.sym = s;
+ p->from.type = D_EXTERN;
+ if(s->class == CSTATIC)
+ p->from.type = D_STATIC;
+}
+
+long
+exreg(Type *t)
+{
+ long o;
+
+ if(typechl[t->etype]) {
+ if(exregoffset <= 5)
+ return 0;
+ o = exregoffset + D_R0;
+ exregoffset--;
+ return o;
+ }
+ if(t->etype == TIND) {
+ if(exaregoffset <= 3)
+ return 0;
+ o = exaregoffset + D_A0;
+ exaregoffset--;
+ return o;
+ }
+ if(typefd[t->etype]) {
+ if(exfregoffset <= 5)
+ return 0;
+ o = exfregoffset + D_F0;
+ exfregoffset--;
+ return o;
+ }
+ return 0;
+}
+
+schar ewidth[NTYPE] =
+{
+ -1, /* [TXXX] */
+ SZ_CHAR, /* [TCHAR] */
+ SZ_CHAR, /* [TUCHAR] */
+ SZ_SHORT, /* [TSHORT] */
+ SZ_SHORT, /* [TUSHORT] */
+ SZ_INT, /* [TINT] */
+ SZ_INT, /* [TUINT] */
+ SZ_LONG, /* [TLONG] */
+ SZ_LONG, /* [TULONG] */
+ SZ_VLONG, /* [TVLONG] */
+ SZ_VLONG, /* [TUVLONG] */
+ SZ_FLOAT, /* [TFLOAT] */
+ SZ_DOUBLE, /* [TDOUBLE] */
+ SZ_IND, /* [TIND] */
+ 0, /* [TFUNC] */
+ -1, /* [TARRAY] */
+ 0, /* [TVOID] */
+ -1, /* [TSTRUCT] */
+ -1, /* [TUNION] */
+ SZ_INT, /* [TENUM] */
+};
+long ncast[NTYPE] =
+{
+ 0, /* [TXXX] */
+ BCHAR|BUCHAR, /* [TCHAR] */
+ BCHAR|BUCHAR, /* [TUCHAR] */
+ BSHORT|BUSHORT, /* [TSHORT] */
+ BSHORT|BUSHORT, /* [TUSHORT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TUINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TLONG] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TULONG] */
+ BVLONG|BUVLONG, /* [TVLONG] */
+ BVLONG|BUVLONG, /* [TUVLONG] */
+ BFLOAT, /* [TFLOAT] */
+ BDOUBLE, /* [TDOUBLE] */
+ BLONG|BULONG|BIND, /* [TIND] */
+ 0, /* [TFUNC] */
+ 0, /* [TARRAY] */
+ 0, /* [TVOID] */
+ BSTRUCT, /* [TSTRUCT] */
+ BUNION, /* [TUNION] */
+ 0, /* [TENUM] */
+};