diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/1c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/1c')
-rwxr-xr-x | sys/src/cmd/1c/bits.c | 127 | ||||
-rwxr-xr-x | sys/src/cmd/1c/cgen.c | 1396 | ||||
-rwxr-xr-x | sys/src/cmd/1c/enam.c | 424 | ||||
-rwxr-xr-x | sys/src/cmd/1c/gc.h | 340 | ||||
-rwxr-xr-x | sys/src/cmd/1c/list.c | 319 | ||||
-rwxr-xr-x | sys/src/cmd/1c/mkfile | 32 | ||||
-rwxr-xr-x | sys/src/cmd/1c/mul.c | 174 | ||||
-rwxr-xr-x | sys/src/cmd/1c/peep.c | 1057 | ||||
-rwxr-xr-x | sys/src/cmd/1c/reg.c | 1221 | ||||
-rwxr-xr-x | sys/src/cmd/1c/sgen.c | 714 | ||||
-rwxr-xr-x | sys/src/cmd/1c/swt.c | 964 | ||||
-rwxr-xr-x | sys/src/cmd/1c/txt.c | 903 |
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] */ +}; |