| // Inferno utils/8c/swt.c |
| // http://code.google.com/p/inferno-os/source/browse/utils/8c/swt.c |
| // |
| // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. |
| // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) |
| // Portions Copyright © 1997-1999 Vita Nuova Limited |
| // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) |
| // Portions Copyright © 2004,2006 Bruce Ellis |
| // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) |
| // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others |
| // Portions Copyright © 2009 The Go Authors. All rights reserved. |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining a copy |
| // of this software and associated documentation files (the "Software"), to deal |
| // in the Software without restriction, including without limitation the rights |
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| // copies of the Software, and to permit persons to whom the Software is |
| // furnished to do so, subject to the following conditions: |
| // |
| // The above copyright notice and this permission notice shall be included in |
| // all copies or substantial portions of the Software. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| // THE SOFTWARE. |
| |
| #include "gc.h" |
| |
| void |
| swit1(C1 *q, int nc, int32 def, Node *n) |
| { |
| C1 *r; |
| int i; |
| Prog *sp; |
| |
| if(nc < 5) { |
| for(i=0; i<nc; i++) { |
| if(debug['W']) |
| print("case = %.8ux\n", q->val); |
| gopcode(OEQ, n->type, n, nodconst(q->val)); |
| patch(p, q->label); |
| q++; |
| } |
| gbranch(OGOTO); |
| patch(p, def); |
| return; |
| } |
| i = nc / 2; |
| r = q+i; |
| if(debug['W']) |
| print("case > %.8ux\n", r->val); |
| gopcode(OGT, n->type, n, nodconst(r->val)); |
| sp = p; |
| gbranch(OGOTO); |
| p->as = AJEQ; |
| patch(p, r->label); |
| swit1(q, i, def, n); |
| |
| if(debug['W']) |
| print("case < %.8ux\n", r->val); |
| patch(sp, pc); |
| swit1(r+1, nc-i-1, def, n); |
| } |
| |
| void |
| bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) |
| { |
| int sh; |
| int32 v; |
| Node *l; |
| |
| /* |
| * n1 gets adjusted/masked value |
| * n2 gets address of cell |
| * n3 gets contents of cell |
| */ |
| l = b->left; |
| if(n2 != Z) { |
| regalloc(n1, l, nn); |
| reglcgen(n2, l, Z); |
| regalloc(n3, l, Z); |
| gmove(n2, n3); |
| gmove(n3, n1); |
| } else { |
| regalloc(n1, l, nn); |
| cgen(l, n1); |
| } |
| if(b->type->shift == 0 && typeu[b->type->etype]) { |
| v = ~0 + (1L << b->type->nbits); |
| gopcode(OAND, types[TLONG], nodconst(v), n1); |
| } else { |
| sh = 32 - b->type->shift - b->type->nbits; |
| if(sh > 0) |
| gopcode(OASHL, types[TLONG], nodconst(sh), n1); |
| sh += b->type->shift; |
| if(sh > 0) |
| if(typeu[b->type->etype]) |
| gopcode(OLSHR, types[TLONG], nodconst(sh), n1); |
| else |
| gopcode(OASHR, types[TLONG], nodconst(sh), n1); |
| } |
| } |
| |
| void |
| bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) |
| { |
| int32 v; |
| Node nod; |
| int sh; |
| |
| regalloc(&nod, b->left, Z); |
| v = ~0 + (1L << b->type->nbits); |
| gopcode(OAND, types[TLONG], nodconst(v), n1); |
| gmove(n1, &nod); |
| if(nn != Z) |
| gmove(n1, nn); |
| sh = b->type->shift; |
| if(sh > 0) |
| gopcode(OASHL, types[TLONG], nodconst(sh), &nod); |
| v <<= sh; |
| gopcode(OAND, types[TLONG], nodconst(~v), n3); |
| gopcode(OOR, types[TLONG], n3, &nod); |
| gmove(&nod, n2); |
| |
| regfree(&nod); |
| regfree(n1); |
| regfree(n2); |
| regfree(n3); |
| } |
| |
| int32 |
| outstring(char *s, int32 n) |
| { |
| int32 r; |
| |
| if(suppress) |
| return nstring; |
| r = nstring; |
| while(n) { |
| string[mnstring] = *s++; |
| mnstring++; |
| nstring++; |
| if(mnstring >= NSNAME) { |
| gpseudo(ADATA, symstring, nodconst(0L)); |
| p->from.offset += nstring - NSNAME; |
| p->from.scale = NSNAME; |
| p->to.type = D_SCONST; |
| memmove(p->to.sval, string, NSNAME); |
| mnstring = 0; |
| } |
| n--; |
| } |
| return r; |
| } |
| |
| void |
| sextern(Sym *s, Node *a, int32 o, int32 w) |
| { |
| int32 e, lw; |
| |
| for(e=0; e<w; e+=NSNAME) { |
| lw = NSNAME; |
| if(w-e < lw) |
| lw = w-e; |
| gpseudo(ADATA, s, nodconst(0L)); |
| p->from.offset += o+e; |
| p->from.scale = lw; |
| p->to.type = D_SCONST; |
| memmove(p->to.sval, a->cstring+e, lw); |
| } |
| } |
| |
| void |
| gextern(Sym *s, Node *a, int32 o, int32 w) |
| { |
| if(a->op == OCONST && typev[a->type->etype]) { |
| gpseudo(ADATA, s, lo64(a)); |
| p->from.offset += o; |
| p->from.scale = 4; |
| gpseudo(ADATA, s, hi64(a)); |
| p->from.offset += o + 4; |
| p->from.scale = 4; |
| return; |
| } |
| gpseudo(ADATA, s, a); |
| p->from.offset += o; |
| p->from.scale = w; |
| switch(p->to.type) { |
| default: |
| p->to.index = p->to.type; |
| p->to.type = D_ADDR; |
| case D_CONST: |
| case D_FCONST: |
| case D_ADDR: |
| break; |
| } |
| } |
| |
| void zname(Biobuf*, Sym*, int); |
| void zaddr(Biobuf*, Adr*, int); |
| void outhist(Biobuf*); |
| |
| 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, "cannot open %s", outfile); |
| return; |
| } |
| Binit(&b, f, OWRITE); |
| |
| Bprint(&b, "go object %s %s %s\n", getgoos(), thestring, getgoversion()); |
| if(ndynimp > 0 || ndynexp > 0) { |
| int i; |
| |
| Bprint(&b, "\n"); |
| Bprint(&b, "$$ // exports\n\n"); |
| Bprint(&b, "$$ // local types\n\n"); |
| Bprint(&b, "$$ // dynimport\n", thestring); |
| for(i=0; i<ndynimp; i++) |
| Bprint(&b, "dynimport %s %s %s\n", dynimp[i].local, dynimp[i].remote, dynimp[i].path); |
| Bprint(&b, "\n$$ // dynexport\n", thestring); |
| for(i=0; i<ndynexp; i++) |
| Bprint(&b, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote); |
| Bprint(&b, "\n$$\n\n"); |
| } |
| Bprint(&b, "!\n"); |
| |
| 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; |
| if(t == D_ADDR) |
| t = p->from.index; |
| 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; |
| if(t == D_ADDR) |
| t = p->to.index; |
| 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; |
| } |
| Bputc(&b, p->as); |
| Bputc(&b, p->as>>8); |
| Bputc(&b, p->lineno); |
| Bputc(&b, p->lineno>>8); |
| Bputc(&b, p->lineno>>16); |
| Bputc(&b, p->lineno>>24); |
| zaddr(&b, &p->from, sf); |
| zaddr(&b, &p->to, st); |
| } |
| Bflush(&b); |
| close(f); |
| firstp = P; |
| lastp = P; |
| } |
| |
| 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; |
| |
| Bputc(b, pg.as); |
| Bputc(b, pg.as>>8); |
| Bputc(b, pg.lineno); |
| Bputc(b, pg.lineno>>8); |
| Bputc(b, pg.lineno>>16); |
| Bputc(b, pg.lineno>>24); |
| zaddr(b, &pg.from, 0); |
| zaddr(b, &pg.to, 0); |
| } |
| } |
| |
| void |
| zname(Biobuf *b, Sym *s, int t) |
| { |
| char *n; |
| uint32 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) |
| { |
| int32 l; |
| int i, t; |
| char *n; |
| Ieee e; |
| |
| t = 0; |
| if(a->index != D_NONE || a->scale != 0) |
| t |= T_INDEX; |
| if(s != 0) |
| t |= T_SYM; |
| |
| switch(a->type) { |
| default: |
| t |= T_TYPE; |
| case D_NONE: |
| if(a->offset != 0) |
| t |= T_OFFSET; |
| break; |
| case D_FCONST: |
| t |= T_FCONST; |
| break; |
| case D_SCONST: |
| t |= T_SCONST; |
| break; |
| case D_CONST2: |
| t |= T_OFFSET|T_OFFSET2; |
| break; |
| } |
| Bputc(b, t); |
| |
| if(t & T_INDEX) { /* implies index, scale */ |
| Bputc(b, a->index); |
| Bputc(b, a->scale); |
| } |
| 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_OFFSET2) { /* implies offset2 */ |
| l = a->offset2; |
| 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; |
| } |
| if(t & T_TYPE) |
| Bputc(b, a->type); |
| } |
| |
| int32 |
| align(int32 i, Type *t, int op, int32 *maxalign) |
| { |
| int32 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 = *maxalign; |
| if(w < 1) |
| w = 1; |
| if(packflg) |
| w = packflg; |
| break; |
| |
| case Ael1: /* initial align of struct element */ |
| for(v=t; v->etype==TARRAY; v=v->link) |
| ; |
| if(v->etype == TSTRUCT || v->etype == TUNION) |
| w = v->align; |
| else { |
| w = ewidth[v->etype]; |
| if(w == 8) |
| w = 4; |
| } |
| if(w < 1 || w > SZ_LONG) |
| fatal(Z, "align"); |
| 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, nil); |
| o = align(o, types[TIND], Aarg2, nil); |
| } |
| break; |
| |
| case Aarg1: /* initial align of parameter */ |
| w = ewidth[t->etype]; |
| if(w <= 0 || w >= SZ_LONG) { |
| w = SZ_LONG; |
| break; |
| } |
| w = 1; /* little endian no adjustment */ |
| break; |
| |
| case Aarg2: /* width of a parameter */ |
| o += t->width; |
| w = t->width; |
| if(w > SZ_LONG) |
| w = SZ_LONG; |
| break; |
| |
| case Aaut3: /* total align of automatic */ |
| o = align(o, t, Ael1, nil); |
| o = align(o, t, Ael2, nil); |
| break; |
| } |
| o = xround(o, w); |
| if(maxalign && *maxalign < w) |
| *maxalign = w; |
| if(debug['A']) |
| print("align %s %d %T = %d\n", bnames[op], i, t, o); |
| return o; |
| } |
| |
| int32 |
| maxround(int32 max, int32 v) |
| { |
| v += SZ_LONG-1; |
| if(v > max) |
| max = xround(v, SZ_LONG); |
| return max; |
| } |