diff options
Diffstat (limited to 'src/cmd/5g/gsubr.c')
-rw-r--r-- | src/cmd/5g/gsubr.c | 2005 |
1 files changed, 0 insertions, 2005 deletions
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c deleted file mode 100644 index 2d9218461..000000000 --- a/src/cmd/5g/gsubr.c +++ /dev/null @@ -1,2005 +0,0 @@ -// Derived from Inferno utils/5c/txt.c -// http://code.google.com/p/inferno-os/source/browse/utils/5c/txt.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 "gg.h" - -// TODO(kaib): Can make this bigger if we move -// the text segment up higher in 5l for all GOOS. -long unmappedzero = 4096; - -void -clearp(Prog *p) -{ - p->as = AEND; - p->reg = NREG; - p->scond = C_SCOND_NONE; - p->from.type = D_NONE; - p->from.name = D_NONE; - p->from.reg = NREG; - p->to.type = D_NONE; - p->to.name = D_NONE; - p->to.reg = NREG; - p->loc = pcloc; - pcloc++; -} - -/* - * generate and return proc with p->as = as, - * linked into program. pc is next instruction. - */ -Prog* -prog(int as) -{ - Prog *p; - - p = pc; - pc = mal(sizeof(*pc)); - - clearp(pc); - - if(lineno == 0) { - if(debug['K']) - warn("prog: line 0"); - } - - p->as = as; - p->lineno = lineno; - p->link = pc; - return p; -} - -/* - * generate a branch. - * t is ignored. - */ -Prog* -gbranch(int as, Type *t) -{ - Prog *p; - - p = prog(as); - p->to.type = D_BRANCH; - p->to.branch = P; - return p; -} - -/* - * patch previous branch to jump to to. - */ -void -patch(Prog *p, Prog *to) -{ - if(p->to.type != D_BRANCH) - fatal("patch: not a branch"); - p->to.branch = to; - p->to.offset = to->loc; -} - -Prog* -unpatch(Prog *p) -{ - Prog *q; - - if(p->to.type != D_BRANCH) - fatal("unpatch: not a branch"); - q = p->to.branch; - p->to.branch = P; - p->to.offset = 0; - return q; -} - -/* - * start a new Prog list. - */ -Plist* -newplist(void) -{ - Plist *pl; - - pl = mal(sizeof(*pl)); - if(plist == nil) - plist = pl; - else - plast->link = pl; - plast = pl; - - pc = mal(sizeof(*pc)); - clearp(pc); - pl->firstpc = pc; - - return pl; -} - -void -clearstk(void) -{ - Plist *pl; - Prog *p, *p1, *p2, *p3; - Node dst, end, zero, con; - - if(plast->firstpc->to.offset <= 0) - return; - - // reestablish context for inserting code - // at beginning of function. - pl = plast; - p1 = pl->firstpc; - p2 = p1->link; - pc = mal(sizeof(*pc)); - clearp(pc); - p1->link = pc; - - // zero stack frame - - // MOVW $4(SP), R1 - nodreg(&dst, types[tptr], 1); - p = gins(AMOVW, N, &dst); - p->from.type = D_CONST; - p->from.reg = REGSP; - p->from.offset = 4; - - // MOVW $n(R1), R2 - nodreg(&end, types[tptr], 2); - p = gins(AMOVW, N, &end); - p->from.type = D_CONST; - p->from.reg = 1; - p->from.offset = p1->to.offset; - - // MOVW $0, R3 - nodreg(&zero, types[TUINT32], 3); - nodconst(&con, types[TUINT32], 0); - gmove(&con, &zero); - - // L: - // MOVW.P R3, 0(R1) +4 - // CMP R1, R2 - // BNE L - p = gins(AMOVW, &zero, &dst); - p->to.type = D_OREG; - p->to.offset = 4; - p->scond |= C_PBIT; - p3 = p; - p = gins(ACMP, &dst, N); - raddr(&end, p); - patch(gbranch(ABNE, T), p3); - - // continue with original code. - gins(ANOP, N, N)->link = p2; - pc = P; -} - -void -gused(Node *n) -{ - gins(ANOP, n, N); // used -} - -Prog* -gjmp(Prog *to) -{ - Prog *p; - - p = gbranch(AB, T); - if(to != P) - patch(p, to); - return p; -} - -void -ggloblnod(Node *nam, int32 width) -{ - Prog *p; - - p = gins(AGLOBL, nam, N); - p->lineno = nam->lineno; - p->to.sym = S; - p->to.type = D_CONST; - p->to.offset = width; -} - -void -ggloblsym(Sym *s, int32 width, int dupok) -{ - Prog *p; - - p = gins(AGLOBL, N, N); - p->from.type = D_OREG; - p->from.name = D_EXTERN; - p->from.sym = s; - p->to.type = D_CONST; - p->to.name = D_NONE; - p->to.offset = width; - if(dupok) - p->reg = DUPOK; -} - -int -isfat(Type *t) -{ - if(t != T) - switch(t->etype) { - case TSTRUCT: - case TARRAY: - case TSTRING: - case TINTER: // maybe remove later - return 1; - } - return 0; -} - -/* - * naddr of func generates code for address of func. - * if using opcode that can take address implicitly, - * call afunclit to fix up the argument. - * also fix up direct register references to be D_OREG. - */ -void -afunclit(Addr *a) -{ - if(a->type == D_CONST && a->name == D_EXTERN || a->type == D_REG) { - a->type = D_OREG; - } -} - -static int resvd[] = -{ - 9, // reserved for m - 10, // reserved for g -}; - -void -ginit(void) -{ - int i; - - for(i=0; i<nelem(reg); i++) - reg[i] = 0; - for(i=0; i<nelem(resvd); i++) - reg[resvd[i]]++; -} - -void -gclean(void) -{ - int i; - - for(i=0; i<nelem(resvd); i++) - reg[resvd[i]]--; - - for(i=0; i<nelem(reg); i++) - if(reg[i]) - yyerror("reg %R left allocated\n", i); -} - -int32 -anyregalloc(void) -{ - int i, j; - - for(i=0; i<nelem(reg); i++) { - if(reg[i] == 0) - goto ok; - for(j=0; j<nelem(resvd); j++) - if(resvd[j] == i) - goto ok; - return 1; - ok:; - } - return 0; -} - -/* - * allocate register of type t, leave in n. - * if o != N, o is desired fixed register. - * caller must regfree(n). - */ -void -regalloc(Node *n, Type *t, Node *o) -{ - int i, et, fixfree, floatfree; - - if(debug['r']) { - fixfree = 0; - for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++) - if(reg[i] == 0) - fixfree++; - floatfree = 0; - for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++) - if(reg[i] == 0) - floatfree++; - print("regalloc fix %d float %d\n", fixfree, floatfree); - } - - if(t == T) - fatal("regalloc: t nil"); - et = simtype[t->etype]; - if(is64(t)) - fatal("regalloc: 64 bit type %T"); - - switch(et) { - case TINT8: - case TUINT8: - case TINT16: - case TUINT16: - case TINT32: - case TUINT32: - case TPTR32: - case TBOOL: - if(o != N && o->op == OREGISTER) { - i = o->val.u.reg; - if(i >= REGALLOC_R0 && i <= REGALLOC_RMAX) - goto out; - } - for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++) - if(reg[i] == 0) - goto out; - - yyerror("out of fixed registers"); - goto err; - - case TFLOAT32: - case TFLOAT64: - if(o != N && o->op == OREGISTER) { - i = o->val.u.reg; - if(i >= REGALLOC_F0 && i <= REGALLOC_FMAX) - goto out; - } - for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++) - if(reg[i] == 0) - goto out; - yyerror("out of floating point registers"); - goto err; - - case TCOMPLEX64: - case TCOMPLEX128: - tempname(n, t); - return; - } - yyerror("regalloc: unknown type %T", t); - -err: - nodreg(n, t, 0); - return; - -out: - reg[i]++; - nodreg(n, t, i); -} - -void -regfree(Node *n) -{ - int i, fixfree, floatfree; - - if(debug['r']) { - fixfree = 0; - for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++) - if(reg[i] == 0) - fixfree++; - floatfree = 0; - for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++) - if(reg[i] == 0) - floatfree++; - print("regalloc fix %d float %d\n", fixfree, floatfree); - } - - if(n->op == ONAME && iscomplex[n->type->etype]) - return; - if(n->op != OREGISTER && n->op != OINDREG) - fatal("regfree: not a register"); - i = n->val.u.reg; - if(i < 0 || i >= sizeof(reg)) - fatal("regfree: reg out of range"); - if(reg[i] <= 0) - fatal("regfree: reg not allocated"); - reg[i]--; -} - -/* - * initialize n to be register r of type t. - */ -void -nodreg(Node *n, Type *t, int r) -{ - if(t == T) - fatal("nodreg: t nil"); - - memset(n, 0, sizeof(*n)); - n->op = OREGISTER; - n->addable = 1; - ullmancalc(n); - n->val.u.reg = r; - n->type = t; -} - -/* - * initialize n to be indirect of register r; n is type t. - */ -void -nodindreg(Node *n, Type *t, int r) -{ - nodreg(n, t, r); - n->op = OINDREG; -} - -Node* -nodarg(Type *t, int fp) -{ - Node *n; - Type *first; - Iter savet; - - // entire argument struct, not just one arg - if(t->etype == TSTRUCT && t->funarg) { - n = nod(ONAME, N, N); - n->sym = lookup(".args"); - n->type = t; - first = structfirst(&savet, &t); - if(first == nil) - fatal("nodarg: bad struct"); - if(first->width == BADWIDTH) - fatal("nodarg: offset not computed for %T", t); - n->xoffset = first->width; - n->addable = 1; - goto fp; - } - - if(t->etype != TFIELD) - fatal("nodarg: not field %T", t); - - n = nod(ONAME, N, N); - n->type = t->type; - n->sym = t->sym; - if(t->width == BADWIDTH) - fatal("nodarg: offset not computed for %T", t); - n->xoffset = t->width; - n->addable = 1; - -fp: - switch(fp) { - default: - fatal("nodarg %T %d", t, fp); - - case 0: // output arg for calling another function - n->op = OINDREG; - n->val.u.reg = REGSP; - n->xoffset += 4; - break; - - case 1: // input arg to current function - n->class = PPARAM; - break; - } - return n; -} - -/* - * return constant i node. - * overwritten by next call, but useful in calls to gins. - */ -Node* -ncon(uint32 i) -{ - static Node n; - - if(n.type == T) - nodconst(&n, types[TUINT32], 0); - mpmovecfix(n.val.u.xval, i); - return &n; -} - -/* - * Is this node a memory operand? - */ -int -ismem(Node *n) -{ - switch(n->op) { - case OINDREG: - case ONAME: - case OPARAM: - return 1; - } - return 0; -} - -Node sclean[10]; -int nsclean; - -/* - * n is a 64-bit value. fill in lo and hi to refer to its 32-bit halves. - */ -void -split64(Node *n, Node *lo, Node *hi) -{ - Node n1; - int64 i; - - if(!is64(n->type)) - fatal("split64 %T", n->type); - - sclean[nsclean].op = OEMPTY; - if(nsclean >= nelem(sclean)) - fatal("split64 clean"); - nsclean++; - switch(n->op) { - default: - if(!dotaddable(n, &n1)) { - igen(n, &n1, N); - sclean[nsclean-1] = n1; - } - n = &n1; - goto common; - case ONAME: - if(n->class == PPARAMREF) { - cgen(n->heapaddr, &n1); - sclean[nsclean-1] = n1; - // fall through. - n = &n1; - } - goto common; - case OINDREG: - common: - *lo = *n; - *hi = *n; - lo->type = types[TUINT32]; - if(n->type->etype == TINT64) - hi->type = types[TINT32]; - else - hi->type = types[TUINT32]; - hi->xoffset += 4; - break; - - case OLITERAL: - convconst(&n1, n->type, &n->val); - i = mpgetfix(n1.val.u.xval); - nodconst(lo, types[TUINT32], (uint32)i); - i >>= 32; - if(n->type->etype == TINT64) - nodconst(hi, types[TINT32], (int32)i); - else - nodconst(hi, types[TUINT32], (uint32)i); - break; - } -} - -void -splitclean(void) -{ - if(nsclean <= 0) - fatal("splitclean"); - nsclean--; - if(sclean[nsclean].op != OEMPTY) - regfree(&sclean[nsclean]); -} - -#define CASE(a,b) (((a)<<16)|((b)<<0)) - -void -gmove(Node *f, Node *t) -{ - int a, ft, tt, fa, ta; - Type *cvt; - Node r1, r2, flo, fhi, tlo, thi, con; - Prog *p1; - - if(debug['M']) - print("gmove %N -> %N\n", f, t); - - ft = simsimtype(f->type); - tt = simsimtype(t->type); - cvt = t->type; - - if(iscomplex[ft] || iscomplex[tt]) { - complexmove(f, t); - return; - } - - // cannot have two memory operands; - // except 64-bit, which always copies via registers anyway. - if(!is64(f->type) && !is64(t->type) && ismem(f) && ismem(t)) - goto hard; - - // convert constant to desired type - if(f->op == OLITERAL) { - switch(tt) { - default: - convconst(&con, t->type, &f->val); - break; - - case TINT16: - case TINT8: - convconst(&con, types[TINT32], &f->val); - regalloc(&r1, con.type, t); - gins(AMOVW, &con, &r1); - gmove(&r1, t); - regfree(&r1); - return; - - case TUINT16: - case TUINT8: - convconst(&con, types[TUINT32], &f->val); - regalloc(&r1, con.type, t); - gins(AMOVW, &con, &r1); - gmove(&r1, t); - regfree(&r1); - return; - } - - f = &con; - ft = simsimtype(con.type); - - // constants can't move directly to memory - if(ismem(t) && !is64(t->type)) goto hard; - } - - // value -> value copy, only one memory operand. - // figure out the instruction to use. - // break out of switch for one-instruction gins. - // goto rdst for "destination must be register". - // goto hard for "convert to cvt type first". - // otherwise handle and return. - - switch(CASE(ft, tt)) { - default: - goto fatal; - - /* - * integer copy and truncate - */ - case CASE(TINT8, TINT8): // same size - case CASE(TUINT8, TINT8): - case CASE(TINT16, TINT8): // truncate - case CASE(TUINT16, TINT8): - case CASE(TINT32, TINT8): - case CASE(TUINT32, TINT8): - a = AMOVB; - break; - - case CASE(TINT8, TUINT8): - case CASE(TUINT8, TUINT8): - case CASE(TINT16, TUINT8): - case CASE(TUINT16, TUINT8): - case CASE(TINT32, TUINT8): - case CASE(TUINT32, TUINT8): - a = AMOVBU; - break; - - case CASE(TINT64, TINT8): // truncate low word - case CASE(TUINT64, TINT8): - a = AMOVB; - goto trunc64; - - case CASE(TINT64, TUINT8): - case CASE(TUINT64, TUINT8): - a = AMOVBU; - goto trunc64; - - case CASE(TINT16, TINT16): // same size - case CASE(TUINT16, TINT16): - case CASE(TINT32, TINT16): // truncate - case CASE(TUINT32, TINT16): - a = AMOVH; - break; - - case CASE(TINT16, TUINT16): - case CASE(TUINT16, TUINT16): - case CASE(TINT32, TUINT16): - case CASE(TUINT32, TUINT16): - a = AMOVHU; - break; - - case CASE(TINT64, TINT16): // truncate low word - case CASE(TUINT64, TINT16): - a = AMOVH; - goto trunc64; - - case CASE(TINT64, TUINT16): - case CASE(TUINT64, TUINT16): - a = AMOVHU; - goto trunc64; - - case CASE(TINT32, TINT32): // same size - case CASE(TINT32, TUINT32): - case CASE(TUINT32, TINT32): - case CASE(TUINT32, TUINT32): - a = AMOVW; - break; - - case CASE(TINT64, TINT32): // truncate - case CASE(TUINT64, TINT32): - case CASE(TINT64, TUINT32): - case CASE(TUINT64, TUINT32): - split64(f, &flo, &fhi); - regalloc(&r1, t->type, N); - gins(AMOVW, &flo, &r1); - gins(AMOVW, &r1, t); - regfree(&r1); - splitclean(); - return; - - case CASE(TINT64, TINT64): // same size - case CASE(TINT64, TUINT64): - case CASE(TUINT64, TINT64): - case CASE(TUINT64, TUINT64): - split64(f, &flo, &fhi); - split64(t, &tlo, &thi); - regalloc(&r1, flo.type, N); - regalloc(&r2, fhi.type, N); - gins(AMOVW, &flo, &r1); - gins(AMOVW, &fhi, &r2); - gins(AMOVW, &r1, &tlo); - gins(AMOVW, &r2, &thi); - regfree(&r1); - regfree(&r2); - splitclean(); - splitclean(); - return; - - /* - * integer up-conversions - */ - case CASE(TINT8, TINT16): // sign extend int8 - case CASE(TINT8, TUINT16): - case CASE(TINT8, TINT32): - case CASE(TINT8, TUINT32): - a = AMOVB; - goto rdst; - case CASE(TINT8, TINT64): // convert via int32 - case CASE(TINT8, TUINT64): - cvt = types[TINT32]; - goto hard; - - case CASE(TUINT8, TINT16): // zero extend uint8 - case CASE(TUINT8, TUINT16): - case CASE(TUINT8, TINT32): - case CASE(TUINT8, TUINT32): - a = AMOVBU; - goto rdst; - case CASE(TUINT8, TINT64): // convert via uint32 - case CASE(TUINT8, TUINT64): - cvt = types[TUINT32]; - goto hard; - - case CASE(TINT16, TINT32): // sign extend int16 - case CASE(TINT16, TUINT32): - a = AMOVH; - goto rdst; - case CASE(TINT16, TINT64): // convert via int32 - case CASE(TINT16, TUINT64): - cvt = types[TINT32]; - goto hard; - - case CASE(TUINT16, TINT32): // zero extend uint16 - case CASE(TUINT16, TUINT32): - a = AMOVHU; - goto rdst; - case CASE(TUINT16, TINT64): // convert via uint32 - case CASE(TUINT16, TUINT64): - cvt = types[TUINT32]; - goto hard; - - case CASE(TINT32, TINT64): // sign extend int32 - case CASE(TINT32, TUINT64): - split64(t, &tlo, &thi); - regalloc(&r1, tlo.type, N); - regalloc(&r2, thi.type, N); - gmove(f, &r1); - p1 = gins(AMOVW, &r1, &r2); - p1->from.type = D_SHIFT; - p1->from.offset = 2 << 5 | 31 << 7 | r1.val.u.reg; // r1->31 - p1->from.reg = NREG; -//print("gmove: %P\n", p1); - gins(AMOVW, &r1, &tlo); - gins(AMOVW, &r2, &thi); - regfree(&r1); - regfree(&r2); - splitclean(); - return; - - case CASE(TUINT32, TINT64): // zero extend uint32 - case CASE(TUINT32, TUINT64): - split64(t, &tlo, &thi); - gmove(f, &tlo); - regalloc(&r1, thi.type, N); - gins(AMOVW, ncon(0), &r1); - gins(AMOVW, &r1, &thi); - regfree(&r1); - splitclean(); - return; - - /* - * float to integer - */ - case CASE(TFLOAT32, TINT8): - case CASE(TFLOAT32, TUINT8): - case CASE(TFLOAT32, TINT16): - case CASE(TFLOAT32, TUINT16): - case CASE(TFLOAT32, TINT32): - case CASE(TFLOAT32, TUINT32): -// case CASE(TFLOAT32, TUINT64): - - case CASE(TFLOAT64, TINT8): - case CASE(TFLOAT64, TUINT8): - case CASE(TFLOAT64, TINT16): - case CASE(TFLOAT64, TUINT16): - case CASE(TFLOAT64, TINT32): - case CASE(TFLOAT64, TUINT32): -// case CASE(TFLOAT64, TUINT64): - fa = AMOVF; - a = AMOVFW; - if(ft == TFLOAT64) { - fa = AMOVD; - a = AMOVDW; - } - ta = AMOVW; - switch(tt) { - case TINT8: - ta = AMOVB; - break; - case TUINT8: - ta = AMOVBU; - break; - case TINT16: - ta = AMOVH; - break; - case TUINT16: - ta = AMOVHU; - break; - } - - regalloc(&r1, types[ft], f); - regalloc(&r2, types[tt], t); - gins(fa, f, &r1); // load to fpu - p1 = gins(a, &r1, &r1); // convert to w - switch(tt) { - case TUINT8: - case TUINT16: - case TUINT32: - p1->scond |= C_UBIT; - } - gins(AMOVW, &r1, &r2); // copy to cpu - gins(ta, &r2, t); // store - regfree(&r1); - regfree(&r2); - return; - - /* - * integer to float - */ - case CASE(TINT8, TFLOAT32): - case CASE(TUINT8, TFLOAT32): - case CASE(TINT16, TFLOAT32): - case CASE(TUINT16, TFLOAT32): - case CASE(TINT32, TFLOAT32): - case CASE(TUINT32, TFLOAT32): - case CASE(TINT8, TFLOAT64): - case CASE(TUINT8, TFLOAT64): - case CASE(TINT16, TFLOAT64): - case CASE(TUINT16, TFLOAT64): - case CASE(TINT32, TFLOAT64): - case CASE(TUINT32, TFLOAT64): - fa = AMOVW; - switch(ft) { - case TINT8: - fa = AMOVB; - break; - case TUINT8: - fa = AMOVBU; - break; - case TINT16: - fa = AMOVH; - break; - case TUINT16: - fa = AMOVHU; - break; - } - a = AMOVWF; - ta = AMOVF; - if(tt == TFLOAT64) { - a = AMOVWD; - ta = AMOVD; - } - regalloc(&r1, types[ft], f); - regalloc(&r2, types[tt], t); - gins(fa, f, &r1); // load to cpu - gins(AMOVW, &r1, &r2); // copy to fpu - p1 = gins(a, &r2, &r2); // convert - switch(ft) { - case TUINT8: - case TUINT16: - case TUINT32: - p1->scond |= C_UBIT; - } - gins(ta, &r2, t); // store - regfree(&r1); - regfree(&r2); - return; - - case CASE(TUINT64, TFLOAT32): - case CASE(TUINT64, TFLOAT64): - fatal("gmove UINT64, TFLOAT not implemented"); - return; - - - /* - * float to float - */ - case CASE(TFLOAT32, TFLOAT32): - a = AMOVF; - break; - - case CASE(TFLOAT64, TFLOAT64): - a = AMOVD; - break; - - case CASE(TFLOAT32, TFLOAT64): - regalloc(&r1, types[TFLOAT64], t); - gins(AMOVF, f, &r1); - gins(AMOVFD, &r1, &r1); - gins(AMOVD, &r1, t); - regfree(&r1); - return; - - case CASE(TFLOAT64, TFLOAT32): - regalloc(&r1, types[TFLOAT64], t); - gins(AMOVD, f, &r1); - gins(AMOVDF, &r1, &r1); - gins(AMOVF, &r1, t); - regfree(&r1); - return; - } - - gins(a, f, t); - return; - -rdst: - // TODO(kaib): we almost always require a register dest anyway, this can probably be - // removed. - // requires register destination - regalloc(&r1, t->type, t); - gins(a, f, &r1); - gmove(&r1, t); - regfree(&r1); - return; - -hard: - // requires register intermediate - regalloc(&r1, cvt, t); - gmove(f, &r1); - gmove(&r1, t); - regfree(&r1); - return; - -trunc64: - // truncate 64 bit integer - split64(f, &flo, &fhi); - regalloc(&r1, t->type, N); - gins(a, &flo, &r1); - gins(a, &r1, t); - regfree(&r1); - splitclean(); - return; - -fatal: - // should not happen - fatal("gmove %N -> %N", f, t); -} - -int -samaddr(Node *f, Node *t) -{ - - if(f->op != t->op) - return 0; - - switch(f->op) { - case OREGISTER: - if(f->val.u.reg != t->val.u.reg) - break; - return 1; - } - return 0; -} - -/* - * generate one instruction: - * as f, t - */ -Prog* -gins(int as, Node *f, Node *t) -{ -// Node nod; -// int32 v; - Prog *p; - Addr af, at; - - if(f != N && f->op == OINDEX) { - fatal("gins OINDEX not implemented"); -// regalloc(&nod, ®node, Z); -// v = constnode.vconst; -// cgen(f->right, &nod); -// constnode.vconst = v; -// idx.reg = nod.reg; -// regfree(&nod); - } - if(t != N && t->op == OINDEX) { - fatal("gins OINDEX not implemented"); -// regalloc(&nod, ®node, Z); -// v = constnode.vconst; -// cgen(t->right, &nod); -// constnode.vconst = v; -// idx.reg = nod.reg; -// regfree(&nod); - } - - memset(&af, 0, sizeof af); - memset(&at, 0, sizeof at); - if(f != N) - naddr(f, &af, 1); - if(t != N) - naddr(t, &at, 1); p = prog(as); - if(f != N) - p->from = af; - if(t != N) - p->to = at; - if(debug['g']) - print("%P\n", p); - return p; -} - -/* - * insert n into reg slot of p - */ -void -raddr(Node *n, Prog *p) -{ - Addr a; - - naddr(n, &a, 1); - if(a.type != D_REG && a.type != D_FREG) { - if(n) - fatal("bad in raddr: %O", n->op); - else - fatal("bad in raddr: <null>"); - p->reg = NREG; - } else - p->reg = a.reg; -} - -/* generate a comparison -TODO(kaib): one of the args can actually be a small constant. relax the constraint and fix call sites. - */ -Prog* -gcmp(int as, Node *lhs, Node *rhs) -{ - Prog *p; - - if(lhs->op != OREGISTER || rhs->op != OREGISTER) - fatal("bad operands to gcmp: %O %O", lhs->op, rhs->op); - - p = gins(as, rhs, N); - raddr(lhs, p); - return p; -} - -/* generate a constant shift - * arm encodes a shift by 32 as 0, thus asking for 0 shift is illegal. -*/ -Prog* -gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs) -{ - Prog *p; - - if(sval <= 0 || sval > 32) - fatal("bad shift value: %d", sval); - - sval = sval&0x1f; - - p = gins(as, N, rhs); - p->from.type = D_SHIFT; - p->from.offset = stype | sval<<7 | lhs->val.u.reg; - return p; -} - -/* generate a register shift -*/ -Prog * -gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs) -{ - Prog *p; - p = gins(as, N, rhs); - p->from.type = D_SHIFT; - p->from.offset = stype | reg->val.u.reg << 8 | 1<<4 | lhs->val.u.reg; - return p; -} - -static void -checkoffset(Addr *a, int canemitcode) -{ - Prog *p; - Node n1; - - if(a->offset < unmappedzero) - return; - if(!canemitcode) - fatal("checkoffset %#x, cannot emit code", a->offset); - - // cannot rely on unmapped nil page at 0 to catch - // reference with large offset. instead, emit explicit - // test of 0(reg). - regalloc(&n1, types[TUINTPTR], N); - p = gins(AMOVW, N, &n1); - p->from = *a; - p->from.offset = 0; - regfree(&n1); -} - -/* - * generate code to compute n; - * make a refer to result. - */ -void -naddr(Node *n, Addr *a, int canemitcode) -{ - a->type = D_NONE; - a->name = D_NONE; - a->reg = NREG; - a->node = N; - if(n == N) - return; - - switch(n->op) { - default: - fatal("naddr: bad %O %D", n->op, a); - break; - - case OREGISTER: - if(n->val.u.reg <= REGALLOC_RMAX) { - a->type = D_REG; - a->reg = n->val.u.reg; - } else { - a->type = D_FREG; - a->reg = n->val.u.reg - REGALLOC_F0; - } - a->sym = S; - break; - - case OINDEX: - case OIND: - fatal("naddr: OINDEX"); -// naddr(n->left, a); -// if(a->type >= D_AX && a->type <= D_DI) -// a->type += D_INDIR; -// else -// if(a->type == D_CONST) -// a->type = D_NONE+D_INDIR; -// else -// if(a->type == D_ADDR) { -// a->type = a->index; -// a->index = D_NONE; -// } else -// goto bad; -// if(n->op == OINDEX) { -// a->index = idx.reg; -// a->scale = n->scale; -// } -// break; - - case OINDREG: - a->type = D_OREG; - a->reg = n->val.u.reg; - a->sym = n->sym; - a->offset = n->xoffset; - checkoffset(a, canemitcode); - break; - - case OPARAM: - // n->left is PHEAP ONAME for stack parameter. - // compute address of actual parameter on stack. - a->etype = simtype[n->left->type->etype]; - a->width = n->left->type->width; - a->offset = n->xoffset; - a->sym = n->left->sym; - a->type = D_OREG; - a->name = D_PARAM; - break; - - case ONAME: - a->etype = 0; - a->width = 0; - a->reg = NREG; - if(n->type != T) { - a->etype = simtype[n->type->etype]; - a->width = n->type->width; - } - a->pun = n->pun; - a->offset = n->xoffset; - a->sym = n->sym; - if(a->sym == S) - a->sym = lookup(".noname"); - if(n->method) { - if(n->type != T) - if(n->type->sym != S) - if(n->type->sym->pkg != nil) - a->sym = pkglookup(a->sym->name, n->type->sym->pkg); - } - - a->type = D_OREG; - switch(n->class) { - default: - fatal("naddr: ONAME class %S %d\n", n->sym, n->class); - case PEXTERN: - a->name = D_EXTERN; - break; - case PAUTO: - a->name = D_AUTO; - if (n->sym) - a->node = n->orig; - break; - case PPARAM: - case PPARAMOUT: - a->name = D_PARAM; - break; - case PFUNC: - a->name = D_EXTERN; - a->type = D_CONST; - break; - } - break; - - case OLITERAL: - switch(n->val.ctype) { - default: - fatal("naddr: const %lT", n->type); - break; - case CTFLT: - a->type = D_FCONST; - a->dval = mpgetflt(n->val.u.fval); - break; - case CTINT: - a->sym = S; - a->type = D_CONST; - a->offset = mpgetfix(n->val.u.xval); - break; - case CTSTR: - datagostring(n->val.u.sval, a); - break; - case CTBOOL: - a->sym = S; - a->type = D_CONST; - a->offset = n->val.u.bval; - break; - case CTNIL: - a->sym = S; - a->type = D_CONST; - a->offset = 0; - break; - } - break; - - case OLEN: - // len of string or slice - naddr(n->left, a, canemitcode); - if(a->type == D_CONST && a->offset == 0) - break; // len(nil) - a->offset += Array_nel; - if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero) - checkoffset(a, canemitcode); - break; - - case OCAP: - // cap of string or slice - naddr(n->left, a, canemitcode); - if(a->type == D_CONST && a->offset == 0) - break; // cap(nil) - a->offset += Array_cap; - if(a->offset >= unmappedzero && a->offset-Array_cap < unmappedzero) - checkoffset(a, canemitcode); - break; - - case OADDR: - naddr(n->left, a, canemitcode); - switch(a->type) { - case D_OREG: - a->type = D_CONST; - break; - - case D_REG: - case D_CONST: - break; - - default: - fatal("naddr: OADDR %d\n", a->type); - } - } -} - -/* - * return Axxx for Oxxx on type t. - */ -int -optoas(int op, Type *t) -{ - int a; - - if(t == T) - fatal("optoas: t is nil"); - - a = AGOK; - switch(CASE(op, simtype[t->etype])) { - default: - fatal("optoas: no entry %O-%T etype %T simtype %T", op, t, types[t->etype], types[simtype[t->etype]]); - break; - -/* case CASE(OADDR, TPTR32): - a = ALEAL; - break; - - case CASE(OADDR, TPTR64): - a = ALEAQ; - break; -*/ - // TODO(kaib): make sure the conditional branches work on all edge cases - case CASE(OEQ, TBOOL): - case CASE(OEQ, TINT8): - case CASE(OEQ, TUINT8): - case CASE(OEQ, TINT16): - case CASE(OEQ, TUINT16): - case CASE(OEQ, TINT32): - case CASE(OEQ, TUINT32): - case CASE(OEQ, TINT64): - case CASE(OEQ, TUINT64): - case CASE(OEQ, TPTR32): - case CASE(OEQ, TPTR64): - case CASE(OEQ, TFLOAT32): - case CASE(OEQ, TFLOAT64): - a = ABEQ; - break; - - case CASE(ONE, TBOOL): - case CASE(ONE, TINT8): - case CASE(ONE, TUINT8): - case CASE(ONE, TINT16): - case CASE(ONE, TUINT16): - case CASE(ONE, TINT32): - case CASE(ONE, TUINT32): - case CASE(ONE, TINT64): - case CASE(ONE, TUINT64): - case CASE(ONE, TPTR32): - case CASE(ONE, TPTR64): - case CASE(ONE, TFLOAT32): - case CASE(ONE, TFLOAT64): - a = ABNE; - break; - - case CASE(OLT, TINT8): - case CASE(OLT, TINT16): - case CASE(OLT, TINT32): - case CASE(OLT, TINT64): - case CASE(OLT, TFLOAT32): - case CASE(OLT, TFLOAT64): - a = ABLT; - break; - - case CASE(OLT, TUINT8): - case CASE(OLT, TUINT16): - case CASE(OLT, TUINT32): - case CASE(OLT, TUINT64): - a = ABLO; - break; - - case CASE(OLE, TINT8): - case CASE(OLE, TINT16): - case CASE(OLE, TINT32): - case CASE(OLE, TINT64): - case CASE(OLE, TFLOAT32): - case CASE(OLE, TFLOAT64): - a = ABLE; - break; - - case CASE(OLE, TUINT8): - case CASE(OLE, TUINT16): - case CASE(OLE, TUINT32): - case CASE(OLE, TUINT64): - a = ABLS; - break; - - case CASE(OGT, TINT8): - case CASE(OGT, TINT16): - case CASE(OGT, TINT32): - case CASE(OGT, TINT64): - case CASE(OGT, TFLOAT32): - case CASE(OGT, TFLOAT64): - a = ABGT; - break; - - case CASE(OGT, TUINT8): - case CASE(OGT, TUINT16): - case CASE(OGT, TUINT32): - case CASE(OGT, TUINT64): - a = ABHI; - break; - - case CASE(OGE, TINT8): - case CASE(OGE, TINT16): - case CASE(OGE, TINT32): - case CASE(OGE, TINT64): - case CASE(OGE, TFLOAT32): - case CASE(OGE, TFLOAT64): - a = ABGE; - break; - - case CASE(OGE, TUINT8): - case CASE(OGE, TUINT16): - case CASE(OGE, TUINT32): - case CASE(OGE, TUINT64): - a = ABHS; - break; - - case CASE(OCMP, TBOOL): - case CASE(OCMP, TINT8): - case CASE(OCMP, TUINT8): - case CASE(OCMP, TINT16): - case CASE(OCMP, TUINT16): - case CASE(OCMP, TINT32): - case CASE(OCMP, TUINT32): - case CASE(OCMP, TPTR32): - a = ACMP; - break; - - case CASE(OCMP, TFLOAT32): - a = ACMPF; - break; - - case CASE(OCMP, TFLOAT64): - a = ACMPD; - break; - - case CASE(OAS, TBOOL): - case CASE(OAS, TINT8): - a = AMOVB; - break; - - case CASE(OAS, TUINT8): - a = AMOVBU; - break; - - case CASE(OAS, TINT16): - a = AMOVH; - break; - - case CASE(OAS, TUINT16): - a = AMOVHU; - break; - - case CASE(OAS, TINT32): - case CASE(OAS, TUINT32): - case CASE(OAS, TPTR32): - a = AMOVW; - break; - - case CASE(OAS, TFLOAT32): - a = AMOVF; - break; - - case CASE(OAS, TFLOAT64): - a = AMOVD; - break; - - case CASE(OADD, TINT8): - case CASE(OADD, TUINT8): - case CASE(OADD, TINT16): - case CASE(OADD, TUINT16): - case CASE(OADD, TINT32): - case CASE(OADD, TUINT32): - case CASE(OADD, TPTR32): - a = AADD; - break; - - case CASE(OADD, TFLOAT32): - a = AADDF; - break; - - case CASE(OADD, TFLOAT64): - a = AADDD; - break; - - case CASE(OSUB, TINT8): - case CASE(OSUB, TUINT8): - case CASE(OSUB, TINT16): - case CASE(OSUB, TUINT16): - case CASE(OSUB, TINT32): - case CASE(OSUB, TUINT32): - case CASE(OSUB, TPTR32): - a = ASUB; - break; - - case CASE(OSUB, TFLOAT32): - a = ASUBF; - break; - - case CASE(OSUB, TFLOAT64): - a = ASUBD; - break; - - case CASE(OAND, TINT8): - case CASE(OAND, TUINT8): - case CASE(OAND, TINT16): - case CASE(OAND, TUINT16): - case CASE(OAND, TINT32): - case CASE(OAND, TUINT32): - case CASE(OAND, TPTR32): - a = AAND; - break; - - case CASE(OOR, TINT8): - case CASE(OOR, TUINT8): - case CASE(OOR, TINT16): - case CASE(OOR, TUINT16): - case CASE(OOR, TINT32): - case CASE(OOR, TUINT32): - case CASE(OOR, TPTR32): - a = AORR; - break; - - case CASE(OXOR, TINT8): - case CASE(OXOR, TUINT8): - case CASE(OXOR, TINT16): - case CASE(OXOR, TUINT16): - case CASE(OXOR, TINT32): - case CASE(OXOR, TUINT32): - case CASE(OXOR, TPTR32): - a = AEOR; - break; - - case CASE(OLSH, TINT8): - case CASE(OLSH, TUINT8): - case CASE(OLSH, TINT16): - case CASE(OLSH, TUINT16): - case CASE(OLSH, TINT32): - case CASE(OLSH, TUINT32): - case CASE(OLSH, TPTR32): - a = ASLL; - break; - - case CASE(ORSH, TUINT8): - case CASE(ORSH, TUINT16): - case CASE(ORSH, TUINT32): - case CASE(ORSH, TPTR32): - a = ASRL; - break; - - case CASE(ORSH, TINT8): - case CASE(ORSH, TINT16): - case CASE(ORSH, TINT32): - a = ASRA; - break; - - case CASE(OMUL, TUINT8): - case CASE(OMUL, TUINT16): - case CASE(OMUL, TUINT32): - case CASE(OMUL, TPTR32): - a = AMULU; - break; - - case CASE(OMUL, TINT8): - case CASE(OMUL, TINT16): - case CASE(OMUL, TINT32): - a = AMUL; - break; - - case CASE(OMUL, TFLOAT32): - a = AMULF; - break; - - case CASE(OMUL, TFLOAT64): - a = AMULD; - break; - - case CASE(ODIV, TUINT8): - case CASE(ODIV, TUINT16): - case CASE(ODIV, TUINT32): - case CASE(ODIV, TPTR32): - a = ADIVU; - break; - - case CASE(ODIV, TINT8): - case CASE(ODIV, TINT16): - case CASE(ODIV, TINT32): - a = ADIV; - break; - - case CASE(OMOD, TUINT8): - case CASE(OMOD, TUINT16): - case CASE(OMOD, TUINT32): - case CASE(OMOD, TPTR32): - a = AMODU; - break; - - case CASE(OMOD, TINT8): - case CASE(OMOD, TINT16): - case CASE(OMOD, TINT32): - a = AMOD; - break; - -// case CASE(OEXTEND, TINT16): -// a = ACWD; -// break; - -// case CASE(OEXTEND, TINT32): -// a = ACDQ; -// break; - -// case CASE(OEXTEND, TINT64): -// a = ACQO; -// break; - - case CASE(ODIV, TFLOAT32): - a = ADIVF; - break; - - case CASE(ODIV, TFLOAT64): - a = ADIVD; - break; - - } - return a; -} - -enum -{ - ODynam = 1<<0, - OPtrto = 1<<1, -}; - -static Node clean[20]; -static int cleani = 0; - -void -sudoclean(void) -{ - if(clean[cleani-1].op != OEMPTY) - regfree(&clean[cleani-1]); - if(clean[cleani-2].op != OEMPTY) - regfree(&clean[cleani-2]); - cleani -= 2; -} - -int -dotaddable(Node *n, Node *n1) -{ - int o, oary[10]; - Node *nn; - - if(n->op != ODOT) - return 0; - - o = dotoffset(n, oary, &nn); - if(nn != N && nn->addable && o == 1 && oary[0] >= 0) { - *n1 = *nn; - n1->type = n->type; - n1->xoffset += oary[0]; - return 1; - } - return 0; -} - -/* - * generate code to compute address of n, - * a reference to a (perhaps nested) field inside - * an array or struct. - * return 0 on failure, 1 on success. - * on success, leaves usable address in a. - * - * caller is responsible for calling sudoclean - * after successful sudoaddable, - * to release the register used for a. - */ -int -sudoaddable(int as, Node *n, Addr *a, int *w) -{ - int o, i; - int oary[10]; - int64 v; - Node n1, n2, n3, n4, *nn, *l, *r; - Node *reg, *reg1; - Prog *p1, *p2; - Type *t; - - if(n->type == T) - return 0; - - switch(n->op) { - case OLITERAL: - if(n->val.ctype != CTINT) - break; - v = mpgetfix(n->val.u.xval); - if(v >= 32000 || v <= -32000) - break; - goto lit; - - case ODOT: - case ODOTPTR: - cleani += 2; - reg = &clean[cleani-1]; - reg1 = &clean[cleani-2]; - reg->op = OEMPTY; - reg1->op = OEMPTY; - goto odot; - - case OINDEX: - if(n->left->type->etype == TSTRING) - return 0; - cleani += 2; - reg = &clean[cleani-1]; - reg1 = &clean[cleani-2]; - reg->op = OEMPTY; - reg1->op = OEMPTY; - goto oindex; - } - return 0; - -lit: - switch(as) { - default: - return 0; - case AADD: case ASUB: case AAND: case AORR: case AEOR: - case AMOVB: case AMOVBU: case AMOVH: case AMOVHU: - case AMOVW: - break; - } - - cleani += 2; - reg = &clean[cleani-1]; - reg1 = &clean[cleani-2]; - reg->op = OEMPTY; - reg1->op = OEMPTY; - naddr(n, a, 1); - goto yes; - -odot: - o = dotoffset(n, oary, &nn); - if(nn == N) - goto no; - - if(nn->addable && o == 1 && oary[0] >= 0) { - // directly addressable set of DOTs - n1 = *nn; - n1.type = n->type; - n1.xoffset += oary[0]; - naddr(&n1, a, 1); - goto yes; - } - - regalloc(reg, types[tptr], N); - n1 = *reg; - n1.op = OINDREG; - if(oary[0] >= 0) { - agen(nn, reg); - n1.xoffset = oary[0]; - } else { - cgen(nn, reg); - n1.xoffset = -(oary[0]+1); - } - - for(i=1; i<o; i++) { - if(oary[i] >= 0) - fatal("cant happen"); - gins(AMOVW, &n1, reg); - n1.xoffset = -(oary[i]+1); - } - - a->type = D_NONE; - a->name = D_NONE; - naddr(&n1, a, 1); - goto yes; - -oindex: - l = n->left; - r = n->right; - if(l->ullman >= UINF && r->ullman >= UINF) - goto no; - - // set o to type of array - o = 0; - if(isptr[l->type->etype]) { - o += OPtrto; - if(l->type->type->etype != TARRAY) - fatal("not ptr ary"); - if(l->type->type->bound < 0) - o += ODynam; - } else { - if(l->type->etype != TARRAY) - fatal("not ary"); - if(l->type->bound < 0) - o += ODynam; - } - - *w = n->type->width; - if(isconst(r, CTINT)) - goto oindex_const; - - switch(*w) { - default: - goto no; - case 1: - case 2: - case 4: - case 8: - break; - } - - // load the array (reg) - if(l->ullman > r->ullman) { - regalloc(reg, types[tptr], N); - if(o & OPtrto) - cgen(l, reg); - else - agen(l, reg); - } - - // load the index (reg1) - t = types[TUINT32]; - if(issigned[r->type->etype]) - t = types[TINT32]; - regalloc(reg1, t, N); - regalloc(&n3, types[TINT32], reg1); - p2 = cgenindex(r, &n3); - gmove(&n3, reg1); - regfree(&n3); - - // load the array (reg) - if(l->ullman <= r->ullman) { - regalloc(reg, types[tptr], N); - if(o & OPtrto) - cgen(l, reg); - else - agen(l, reg); - } - - // check bounds - if(!debug['B']) { - if(o & ODynam) { - n2 = *reg; - n2.op = OINDREG; - n2.type = types[tptr]; - n2.xoffset = Array_nel; - } else { - if(l->type->width >= unmappedzero && l->op == OIND) { - // cannot rely on page protections to - // catch array ptr == 0, so dereference. - n2 = *reg; - n2.op = OINDREG; - n2.type = types[TUINTPTR]; - n2.xoffset = 0; - regalloc(&n3, n2.type, N); - gins(AMOVW, &n2, &n3); - regfree(&n3); - } - nodconst(&n2, types[TUINT32], l->type->bound); - if(o & OPtrto) - nodconst(&n2, types[TUINT32], l->type->type->bound); - } - regalloc(&n3, n2.type, N); - cgen(&n2, &n3); - gcmp(optoas(OCMP, types[TUINT32]), reg1, &n3); - regfree(&n3); - p1 = gbranch(optoas(OLT, types[TUINT32]), T); - if(p2) - patch(p2, pc); - ginscall(panicindex, 0); - patch(p1, pc); - } - - if(o & ODynam) { - n2 = *reg; - n2.op = OINDREG; - n2.type = types[tptr]; - n2.xoffset = Array_array; - gmove(&n2, reg); - } - - switch(*w) { - case 1: - gins(AADD, reg1, reg); - break; - case 2: - gshift(AADD, reg1, SHIFT_LL, 1, reg); - break; - case 4: - gshift(AADD, reg1, SHIFT_LL, 2, reg); - break; - case 8: - gshift(AADD, reg1, SHIFT_LL, 3, reg); - break; - } - - naddr(reg1, a, 1); - a->type = D_OREG; - a->reg = reg->val.u.reg; - a->offset = 0; - - goto yes; - -oindex_const: - // index is constant - // can check statically and - // can multiply by width statically - - regalloc(reg, types[tptr], N); - if(o & OPtrto) - cgen(l, reg); - else - agen(l, reg); - - v = mpgetfix(r->val.u.xval); - if(o & ODynam) { - - if(!debug['B'] && !n->etype) { - n1 = *reg; - n1.op = OINDREG; - n1.type = types[tptr]; - n1.xoffset = Array_nel; - nodconst(&n2, types[TUINT32], v); - regalloc(&n3, types[TUINT32], N); - cgen(&n2, &n3); - regalloc(&n4, n1.type, N); - cgen(&n1, &n4); - gcmp(optoas(OCMP, types[TUINT32]), &n4, &n3); - regfree(&n4); - regfree(&n3); - p1 = gbranch(optoas(OGT, types[TUINT32]), T); - ginscall(panicindex, 0); - patch(p1, pc); - } - - n1 = *reg; - n1.op = OINDREG; - n1.type = types[tptr]; - n1.xoffset = Array_array; - gmove(&n1, reg); - } - - n2 = *reg; - n2.op = OINDREG; - n2.xoffset = v * (*w); - a->type = D_NONE; - a->name = D_NONE; - naddr(&n2, a, 1); - goto yes; - -yes: - return 1; - -no: - sudoclean(); - return 0; -} |