diff options
Diffstat (limited to 'src/cmd/5g')
-rw-r--r-- | src/cmd/5g/cgen.c | 922 | ||||
-rw-r--r-- | src/cmd/5g/cgen64.c | 82 | ||||
-rw-r--r-- | src/cmd/5g/doc.go | 4 | ||||
-rw-r--r-- | src/cmd/5g/galign.c | 1 | ||||
-rw-r--r-- | src/cmd/5g/gg.h | 40 | ||||
-rw-r--r-- | src/cmd/5g/ggen.c | 552 | ||||
-rw-r--r-- | src/cmd/5g/gobj.c | 143 | ||||
-rw-r--r-- | src/cmd/5g/gsubr.c | 195 | ||||
-rw-r--r-- | src/cmd/5g/list.c | 21 | ||||
-rw-r--r-- | src/cmd/5g/opt.h | 22 | ||||
-rw-r--r-- | src/cmd/5g/peep.c | 125 | ||||
-rw-r--r-- | src/cmd/5g/reg.c | 110 |
12 files changed, 1250 insertions, 967 deletions
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c index cccef94c9..9e35f9566 100644 --- a/src/cmd/5g/cgen.c +++ b/src/cmd/5g/cgen.c @@ -15,8 +15,8 @@ void cgen(Node *n, Node *res) { Node *nl, *nr, *r; - Node n1, n2, n3, f0, f1; - int a, w; + Node n1, n2, f0, f1; + int a, w, rg; Prog *p1, *p2, *p3; Addr addr; @@ -30,6 +30,27 @@ cgen(Node *n, Node *res) if(res == N || res->type == T) fatal("cgen: res nil"); + switch(n->op) { + case OSLICE: + case OSLICEARR: + case OSLICESTR: + if (res->op != ONAME || !res->addable) { + tempname(&n1, n->type); + cgen_slice(n, &n1); + cgen(&n1, res); + } else + cgen_slice(n, res); + return; + case OEFACE: + if (res->op != ONAME || !res->addable) { + tempname(&n1, n->type); + cgen_eface(n, &n1); + cgen(&n1, res); + } else + cgen_eface(n, res); + return; + } + while(n->op == OCONVNOP) n = n->left; @@ -156,6 +177,7 @@ cgen(Node *n, Node *res) case OADD: case OSUB: case OMUL: + case OLROT: case OLSH: case ORSH: case OAND: @@ -171,7 +193,7 @@ cgen(Node *n, Node *res) switch(n->op) { default: dump("cgen", n); - fatal("cgen: unknown op %N", n); + fatal("cgen: unknown op %+hN", n); break; case OREAL: @@ -190,12 +212,12 @@ cgen(Node *n, Node *res) case OGE: case OGT: case ONOT: - p1 = gbranch(AB, T); + p1 = gbranch(AB, T, 0); p2 = pc; gmove(nodbool(1), res); - p3 = gbranch(AB, T); + p3 = gbranch(AB, T, 0); patch(p1, pc); - bgen(n, 1, p2); + bgen(n, 1, 0, p2); gmove(nodbool(0), res); patch(p3, pc); goto ret; @@ -218,13 +240,10 @@ cgen(Node *n, Node *res) case OMINUS: regalloc(&n1, nl->type, N); cgen(nl, &n1); - nodconst(&n3, nl->type, 0); - regalloc(&n2, nl->type, res); - gmove(&n3, &n2); - gins(optoas(OSUB, nl->type), &n1, &n2); - gmove(&n2, res); + nodconst(&n2, nl->type, 0); + gins(optoas(OMINUS, nl->type), &n2, &n1); + gmove(&n1, res); regfree(&n1); - regfree(&n2); goto ret; // symmetric binary @@ -241,9 +260,14 @@ cgen(Node *n, Node *res) a = optoas(n->op, nl->type); goto abop; + case OHMUL: + cgen_hmul(nl, nr, res); + break; + + case OLROT: case OLSH: case ORSH: - cgen_shift(n->op, nl, nr, res); + cgen_shift(n->op, n->bounded, nl, nr, res); break; case OCONV: @@ -284,17 +308,11 @@ cgen(Node *n, Node *res) break; case OITAB: - // itable of interface value + // interface table is first word of interface value igen(nl, &n1, res); - n1.op = OREGISTER; // was OINDREG - regalloc(&n2, n->type, &n1); - n1.op = OINDREG; n1.type = n->type; - n1.xoffset = 0; - gmove(&n1, &n2); - gmove(&n2, res); + gmove(&n1, res); regfree(&n1); - regfree(&n2); break; case OLEN: @@ -305,11 +323,8 @@ cgen(Node *n, Node *res) cgen(nl, &n1); nodconst(&n2, types[tptr], 0); - regalloc(&n3, n2.type, N); - gmove(&n2, &n3); - gcmp(optoas(OCMP, types[tptr]), &n1, &n3); - regfree(&n3); - p1 = gbranch(optoas(OEQ, types[tptr]), T); + gcmp(optoas(OCMP, types[tptr]), &n1, &n2); + p1 = gbranch(optoas(OEQ, types[tptr]), T, -1); n2 = n1; n2.op = OINDREG; @@ -325,15 +340,10 @@ cgen(Node *n, Node *res) if(istype(nl->type, TSTRING) || isslice(nl->type)) { // both slice and string have len one pointer into the struct. igen(nl, &n1, res); - n1.op = OREGISTER; // was OINDREG - regalloc(&n2, types[TUINT32], &n1); - n1.op = OINDREG; n1.type = types[TUINT32]; - n1.xoffset = Array_nel; - gmove(&n1, &n2); - gmove(&n2, res); + n1.xoffset += Array_nel; + gmove(&n1, res); regfree(&n1); - regfree(&n2); break; } fatal("cgen: OLEN: unknown type %lT", nl->type); @@ -347,11 +357,8 @@ cgen(Node *n, Node *res) cgen(nl, &n1); nodconst(&n2, types[tptr], 0); - regalloc(&n3, n2.type, N); - gmove(&n2, &n3); - gcmp(optoas(OCMP, types[tptr]), &n1, &n3); - regfree(&n3); - p1 = gbranch(optoas(OEQ, types[tptr]), T); + gcmp(optoas(OCMP, types[tptr]), &n1, &n2); + p1 = gbranch(optoas(OEQ, types[tptr]), T, -1); n2 = n1; n2.op = OINDREG; @@ -366,11 +373,9 @@ cgen(Node *n, Node *res) break; } if(isslice(nl->type)) { - regalloc(&n1, types[tptr], res); - agen(nl, &n1); - n1.op = OINDREG; + igen(nl, &n1, res); n1.type = types[TUINT32]; - n1.xoffset = Array_cap; + n1.xoffset += Array_cap; gmove(&n1, res); regfree(&n1); break; @@ -383,7 +388,22 @@ cgen(Node *n, Node *res) break; case OCALLMETH: - cgen_callmeth(n, 0); + case OCALLFUNC: + // Release res so that it is available for cgen_call. + // Pick it up again after the call. + rg = -1; + if(n->ullman >= UINF) { + if(res != N && (res->op == OREGISTER || res->op == OINDREG)) { + rg = res->val.u.reg; + reg[rg]--; + } + } + if(n->op == OCALLMETH) + cgen_callmeth(n, 0); + else + cgen_call(n, 0); + if(rg >= 0) + reg[rg]++; cgen_callret(n, res); break; @@ -392,11 +412,6 @@ cgen(Node *n, Node *res) cgen_callret(n, res); break; - case OCALLFUNC: - cgen_call(n, 0); - cgen_callret(n, res); - break; - case OMOD: case ODIV: a = optoas(n->op, nl->type); @@ -416,18 +431,43 @@ abop: // asymmetric binary if(nl->ullman >= nr->ullman) { regalloc(&n1, nl->type, res); cgen(nl, &n1); - regalloc(&n2, nr->type, N); - cgen(nr, &n2); + switch(n->op) { + case OADD: + case OSUB: + case OAND: + case OOR: + case OXOR: + if(smallintconst(nr)) { + n2 = *nr; + break; + } + default: + regalloc(&n2, nr->type, N); + cgen(nr, &n2); + } } else { - regalloc(&n2, nr->type, res); - cgen(nr, &n2); + switch(n->op) { + case OADD: + case OSUB: + case OAND: + case OOR: + case OXOR: + if(smallintconst(nr)) { + n2 = *nr; + break; + } + default: + regalloc(&n2, nr->type, res); + cgen(nr, &n2); + } regalloc(&n1, nl->type, N); cgen(nl, &n1); } gins(a, &n2, &n1); gmove(&n1, res); regfree(&n1); - regfree(&n2); + if(n2.op != OLITERAL) + regfree(&n2); goto ret; flt: // floating-point. @@ -478,7 +518,7 @@ ret: * returns Prog* to patch to panic call. */ Prog* -cgenindex(Node *n, Node *res) +cgenindex(Node *n, Node *res, int bounded) { Node tmp, lo, hi, zero, n1, n2; @@ -491,7 +531,7 @@ cgenindex(Node *n, Node *res) cgen(n, &tmp); split64(&tmp, &lo, &hi); gmove(&lo, res); - if(debug['B']) { + if(bounded) { splitclean(); return nil; } @@ -504,7 +544,7 @@ cgenindex(Node *n, Node *res) regfree(&n2); regfree(&n1); splitclean(); - return gbranch(ABNE, T); + return gbranch(ABNE, T, -1); } /* @@ -514,11 +554,8 @@ cgenindex(Node *n, Node *res) void agen(Node *n, Node *res) { - Node *nl, *nr; - Node n1, n2, n3, n4, n5, tmp; - Prog *p1, *p2; - uint32 w; - uint64 v; + Node *nl; + Node n1, n2, n3; int r; if(debug['g']) { @@ -531,6 +568,21 @@ agen(Node *n, Node *res) while(n->op == OCONVNOP) n = n->left; + if(isconst(n, CTNIL) && n->type->width > widthptr) { + // Use of a nil interface or nil slice. + // Create a temporary we can take the address of and read. + // The generated code is just going to panic, so it need not + // be terribly efficient. See issue 3670. + tempname(&n1, n->type); + clearfat(&n1); + regalloc(&n2, types[tptr], res); + gins(AMOVW, &n1, &n2); + gmove(&n2, res); + regfree(&n2); + goto ret; + } + + if(n->addable) { memset(&n1, 0, sizeof n1); n1.op = OADDR; @@ -543,11 +595,10 @@ agen(Node *n, Node *res) } nl = n->left; - nr = n->right; switch(n->op) { default: - fatal("agen: unknown op %N", n); + fatal("agen: unknown op %+hN", n); break; case OCALLMETH: @@ -575,16 +626,305 @@ agen(Node *n, Node *res) cgen_aret(n, res); break; + case OSLICE: + case OSLICEARR: + case OSLICESTR: + tempname(&n1, n->type); + cgen_slice(n, &n1); + agen(&n1, res); + break; + + case OEFACE: + tempname(&n1, n->type); + cgen_eface(n, &n1); + agen(&n1, res); + break; + + case OINDEX: + agenr(n, &n1, res); + gmove(&n1, res); + regfree(&n1); + break; + + case ONAME: + // should only get here with names in this func. + if(n->funcdepth > 0 && n->funcdepth != funcdepth) { + dump("bad agen", n); + fatal("agen: bad ONAME funcdepth %d != %d", + n->funcdepth, funcdepth); + } + + // should only get here for heap vars or paramref + if(!(n->class & PHEAP) && n->class != PPARAMREF) { + dump("bad agen", n); + fatal("agen: bad ONAME class %#x", n->class); + } + cgen(n->heapaddr, res); + if(n->xoffset != 0) { + nodconst(&n1, types[TINT32], n->xoffset); + regalloc(&n2, n1.type, N); + regalloc(&n3, types[TINT32], N); + gmove(&n1, &n2); + gmove(res, &n3); + gins(optoas(OADD, types[tptr]), &n2, &n3); + gmove(&n3, res); + regfree(&n2); + regfree(&n3); + } + break; + + case OIND: + cgen(nl, res); + break; + + case ODOT: + agen(nl, res); + if(n->xoffset != 0) { + nodconst(&n1, types[TINT32], n->xoffset); + regalloc(&n2, n1.type, N); + regalloc(&n3, types[TINT32], N); + gmove(&n1, &n2); + gmove(res, &n3); + gins(optoas(OADD, types[tptr]), &n2, &n3); + gmove(&n3, res); + regfree(&n2); + regfree(&n3); + } + break; + + case ODOTPTR: + cgen(nl, res); + if(n->xoffset != 0) { + // explicit check for nil if struct is large enough + // that we might derive too big a pointer. + if(nl->type->type->width >= unmappedzero) { + regalloc(&n1, types[tptr], N); + gmove(res, &n1); + regalloc(&n2, types[TUINT8], &n1); + n1.op = OINDREG; + n1.type = types[TUINT8]; + n1.xoffset = 0; + gmove(&n1, &n2); + regfree(&n1); + regfree(&n2); + } + nodconst(&n1, types[TINT32], n->xoffset); + regalloc(&n2, n1.type, N); + regalloc(&n3, types[tptr], N); + gmove(&n1, &n2); + gmove(res, &n3); + gins(optoas(OADD, types[tptr]), &n2, &n3); + gmove(&n3, res); + regfree(&n2); + regfree(&n3); + } + break; + } + +ret: + ; +} + +/* + * generate: + * newreg = &n; + * res = newreg + * + * on exit, a has been changed to be *newreg. + * caller must regfree(a). + */ +void +igen(Node *n, Node *a, Node *res) +{ + Node n1, n2; + int r; + + if(debug['g']) { + dump("\nigen-n", n); + } + switch(n->op) { + case ONAME: + if((n->class&PHEAP) || n->class == PPARAMREF) + break; + *a = *n; + return; + + case OINDREG: + // Increase the refcount of the register so that igen's caller + // has to call regfree. + if(n->val.u.reg != REGSP) + reg[n->val.u.reg]++; + *a = *n; + return; + + case ODOT: + igen(n->left, a, res); + a->xoffset += n->xoffset; + a->type = n->type; + return; + + case ODOTPTR: + if(n->left->addable + || n->left->op == OCALLFUNC + || n->left->op == OCALLMETH + || n->left->op == OCALLINTER) { + // igen-able nodes. + igen(n->left, &n1, res); + regalloc(a, types[tptr], &n1); + gmove(&n1, a); + regfree(&n1); + } else { + regalloc(a, types[tptr], res); + cgen(n->left, a); + } + if(n->xoffset != 0) { + // explicit check for nil if struct is large enough + // that we might derive too big a pointer. + if(n->left->type->type->width >= unmappedzero) { + regalloc(&n1, types[tptr], N); + gmove(a, &n1); + regalloc(&n2, types[TUINT8], &n1); + n1.op = OINDREG; + n1.type = types[TUINT8]; + n1.xoffset = 0; + gmove(&n1, &n2); + regfree(&n1); + regfree(&n2); + } + } + a->op = OINDREG; + a->xoffset = n->xoffset; + a->type = n->type; + return; + + case OCALLMETH: + case OCALLFUNC: + case OCALLINTER: + // Release res so that it is available for cgen_call. + // Pick it up again after the call. + r = -1; + if(n->ullman >= UINF) { + if(res != N && (res->op == OREGISTER || res->op == OINDREG)) { + r = res->val.u.reg; + reg[r]--; + } + } + switch(n->op) { + case OCALLMETH: + cgen_callmeth(n, 0); + break; + case OCALLFUNC: + cgen_call(n, 0); + break; + case OCALLINTER: + cgen_callinter(n, N, 0); + break; + } + if(r >= 0) + reg[r]++; + regalloc(a, types[tptr], res); + cgen_aret(n, a); + a->op = OINDREG; + a->type = n->type; + return; + } + + agenr(n, a, res); + a->op = OINDREG; + a->type = n->type; +} + +/* + * allocate a register in res and generate + * newreg = &n + * The caller must call regfree(a). + */ +void +cgenr(Node *n, Node *a, Node *res) +{ + Node n1; + + if(debug['g']) + dump("cgenr-n", n); + + if(isfat(n->type)) + fatal("cgenr on fat node"); + + if(n->addable) { + regalloc(a, types[tptr], res); + gmove(n, a); + return; + } + + switch(n->op) { + case ONAME: + case ODOT: + case ODOTPTR: + case OINDEX: + case OCALLFUNC: + case OCALLMETH: + case OCALLINTER: + igen(n, &n1, res); + regalloc(a, types[tptr], &n1); + gmove(&n1, a); + regfree(&n1); + break; + default: + regalloc(a, n->type, res); + cgen(n, a); + break; + } +} + +/* + * generate: + * newreg = &n; + * + * caller must regfree(a). + */ +void +agenr(Node *n, Node *a, Node *res) +{ + Node *nl, *nr; + Node n1, n2, n3, n4, tmp; + Prog *p1, *p2; + uint32 w; + uint64 v; + int bounded; + + if(debug['g']) + dump("agenr-n", n); + + nl = n->left; + nr = n->right; + + switch(n->op) { + case ODOT: + case ODOTPTR: + case OCALLFUNC: + case OCALLMETH: + case OCALLINTER: + igen(n, &n1, res); + regalloc(a, types[tptr], &n1); + agen(&n1, a); + regfree(&n1); + break; + + case OIND: + cgenr(n->left, a, res); + break; + case OINDEX: p2 = nil; // to be patched to panicindex. w = n->type->width; + bounded = debug['B'] || n->bounded; if(nr->addable) { if(!isconst(nr, CTINT)) tempname(&tmp, types[TINT32]); if(!isconst(nl, CTSTR)) agenr(nl, &n3, res); if(!isconst(nr, CTINT)) { - p2 = cgenindex(nr, &tmp); + p2 = cgenindex(nr, &tmp, bounded); regalloc(&n1, tmp.type, N); gmove(&tmp, &n1); } @@ -592,17 +932,16 @@ agen(Node *n, Node *res) if(nl->addable) { if(!isconst(nr, CTINT)) { tempname(&tmp, types[TINT32]); - p2 = cgenindex(nr, &tmp); + p2 = cgenindex(nr, &tmp, bounded); regalloc(&n1, tmp.type, N); gmove(&tmp, &n1); } if(!isconst(nl, CTSTR)) { - regalloc(&n3, types[tptr], res); - agen(nl, &n3); + agenr(nl, &n3, res); } } else { tempname(&tmp, types[TINT32]); - p2 = cgenindex(nr, &tmp); + p2 = cgenindex(nr, &tmp, bounded); nr = &tmp; if(!isconst(nl, CTSTR)) agenr(nl, &n3, res); @@ -614,26 +953,37 @@ agen(Node *n, Node *res) // i is in &n1 (if not constant) // w is width + // explicit check for nil if array is large enough + // that we might derive too big a pointer. + if(isfixedarray(nl->type) && nl->type->width >= unmappedzero) { + regalloc(&n4, types[tptr], N); + gmove(&n3, &n4); + regalloc(&tmp, types[TUINT8], &n4); + n4.op = OINDREG; + n4.type = types[TUINT8]; + n4.xoffset = 0; + gmove(&n4, &tmp); + regfree(&n4); + regfree(&tmp); + } + // constant index if(isconst(nr, CTINT)) { if(isconst(nl, CTSTR)) fatal("constant string constant index"); v = mpgetfix(nr->val.u.xval); if(isslice(nl->type) || nl->type->etype == TSTRING) { - if(!debug['B'] && !n->etype) { + if(!debug['B'] && !n->bounded) { n1 = n3; n1.op = OINDREG; n1.type = types[tptr]; n1.xoffset = Array_nel; regalloc(&n4, n1.type, N); - cgen(&n1, &n4); + gmove(&n1, &n4); nodconst(&n2, types[TUINT32], v); - regalloc(&n5, n2.type, N); - gmove(&n2, &n5); - gcmp(optoas(OCMP, types[TUINT32]), &n4, &n5); + gcmp(optoas(OCMP, types[TUINT32]), &n4, &n2); regfree(&n4); - regfree(&n5); - p1 = gbranch(optoas(OGT, types[TUINT32]), T); + p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1); ginscall(panicindex, 0); patch(p1, pc); } @@ -646,13 +996,8 @@ agen(Node *n, Node *res) } nodconst(&n2, types[tptr], v*w); - regalloc(&n4, n2.type, N); - gmove(&n2, &n4); - gins(optoas(OADD, types[tptr]), &n4, &n3); - regfree(&n4); - - gmove(&n3, res); - regfree(&n3); + gins(optoas(OADD, types[tptr]), &n2, &n3); + *a = n3; break; } @@ -660,25 +1005,24 @@ agen(Node *n, Node *res) gmove(&n1, &n2); regfree(&n1); - if(!debug['B'] && !n->etype) { + if(!debug['B'] && !n->bounded) { // check bounds - regalloc(&n4, types[TUINT32], N); if(isconst(nl, CTSTR)) { - nodconst(&n1, types[TUINT32], nl->val.u.sval->len); - gmove(&n1, &n4); + nodconst(&n4, types[TUINT32], nl->val.u.sval->len); } else if(isslice(nl->type) || nl->type->etype == TSTRING) { n1 = n3; n1.op = OINDREG; n1.type = types[tptr]; n1.xoffset = Array_nel; - cgen(&n1, &n4); - } else { - nodconst(&n1, types[TUINT32], nl->type->bound); + regalloc(&n4, types[TUINT32], N); gmove(&n1, &n4); + } else { + nodconst(&n4, types[TUINT32], nl->type->bound); } gcmp(optoas(OCMP, types[TUINT32]), &n2, &n4); - regfree(&n4); - p1 = gbranch(optoas(OLT, types[TUINT32]), T); + if(n4.op == OREGISTER) + regfree(&n4); + p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1); if(p2) patch(p2, pc); ginscall(panicindex, 0); @@ -713,7 +1057,7 @@ agen(Node *n, Node *res) else if(w == 4) gshift(AADD, &n2, SHIFT_LL, 2, &n3); else if(w == 8) - gshift(AADD, &n2, SHIFT_LL, 3, &n3); + gshift(AADD, &n2, SHIFT_LL, 3, &n3); } else { regalloc(&n4, types[TUINT32], N); nodconst(&n1, types[TUINT32], w); @@ -721,122 +1065,21 @@ agen(Node *n, Node *res) gins(optoas(OMUL, types[TUINT32]), &n4, &n2); gins(optoas(OADD, types[tptr]), &n2, &n3); regfree(&n4); - gmove(&n3, res); } - gmove(&n3, res); + *a = n3; regfree(&n2); - regfree(&n3); break; - case ONAME: - // should only get here with names in this func. - if(n->funcdepth > 0 && n->funcdepth != funcdepth) { - dump("bad agen", n); - fatal("agen: bad ONAME funcdepth %d != %d", - n->funcdepth, funcdepth); - } - - // should only get here for heap vars or paramref - if(!(n->class & PHEAP) && n->class != PPARAMREF) { - dump("bad agen", n); - fatal("agen: bad ONAME class %#x", n->class); - } - cgen(n->heapaddr, res); - if(n->xoffset != 0) { - nodconst(&n1, types[TINT32], n->xoffset); - regalloc(&n2, n1.type, N); - regalloc(&n3, types[TINT32], N); - gmove(&n1, &n2); - gmove(res, &n3); - gins(optoas(OADD, types[tptr]), &n2, &n3); - gmove(&n3, res); - regfree(&n2); - regfree(&n3); - } - break; - - case OIND: - cgen(nl, res); - break; - - case ODOT: - agen(nl, res); - if(n->xoffset != 0) { - nodconst(&n1, types[TINT32], n->xoffset); - regalloc(&n2, n1.type, N); - regalloc(&n3, types[TINT32], N); - gmove(&n1, &n2); - gmove(res, &n3); - gins(optoas(OADD, types[tptr]), &n2, &n3); - gmove(&n3, res); - regfree(&n2); - regfree(&n3); - } - break; - - case ODOTPTR: - cgen(nl, res); - if(n->xoffset != 0) { - // explicit check for nil if struct is large enough - // that we might derive too big a pointer. - if(nl->type->type->width >= unmappedzero) { - regalloc(&n1, types[tptr], N); - gmove(res, &n1); - p1 = gins(AMOVW, &n1, &n1); - p1->from.type = D_OREG; - p1->from.offset = 0; - regfree(&n1); - } - nodconst(&n1, types[TINT32], n->xoffset); - regalloc(&n2, n1.type, N); - regalloc(&n3, types[tptr], N); - gmove(&n1, &n2); - gmove(res, &n3); - gins(optoas(OADD, types[tptr]), &n2, &n3); - gmove(&n3, res); - regfree(&n2); - regfree(&n3); - } + default: + regalloc(a, types[tptr], res); + agen(n, a); break; } - -ret: - ; } -/* - * generate: - * newreg = &n; - * res = newreg - * - * on exit, a has been changed to be *newreg. - * caller must regfree(a). - */ void -igen(Node *n, Node *a, Node *res) -{ - regalloc(a, types[tptr], res); - agen(n, a); - a->op = OINDREG; - a->type = n->type; -} - -/* - * generate: - * newreg = &n; - * - * caller must regfree(a). - */ -void -agenr(Node *n, Node *a, Node *res) -{ - regalloc(a, types[tptr], res); - agen(n, a); -} - -void -gencmp0(Node *n, Type *t, int o, Prog *to) +gencmp0(Node *n, Type *t, int o, int likely, Prog *to) { Node n1, n2, n3; int a; @@ -853,7 +1096,7 @@ gencmp0(Node *n, Type *t, int o, Prog *to) } else gins(ATST, &n1, N); a = optoas(o, t); - patch(gbranch(a, t), to); + patch(gbranch(a, t, likely), to); regfree(&n1); } @@ -862,7 +1105,7 @@ gencmp0(Node *n, Type *t, int o, Prog *to) * if(n == true) goto to; */ void -bgen(Node *n, int true, Prog *to) +bgen(Node *n, int true, int likely, Prog *to) { int et, a; Node *nl, *nr, *r; @@ -900,13 +1143,13 @@ bgen(Node *n, int true, Prog *to) a = ONE; if(!true) a = OEQ; - gencmp0(n, n->type, a, to); + gencmp0(n, n->type, a, likely, to); goto ret; case OLITERAL: // need to ask if it is bool? if(!true == !n->val.u.bval) - patch(gbranch(AB, T), to); + patch(gbranch(AB, T, 0), to); goto ret; case OANDAND: @@ -914,12 +1157,12 @@ bgen(Node *n, int true, Prog *to) goto caseor; caseand: - p1 = gbranch(AB, T); - p2 = gbranch(AB, T); + p1 = gbranch(AB, T, 0); + p2 = gbranch(AB, T, 0); patch(p1, pc); - bgen(n->left, !true, p2); - bgen(n->right, !true, p2); - p1 = gbranch(AB, T); + bgen(n->left, !true, -likely, p2); + bgen(n->right, !true, -likely, p2); + p1 = gbranch(AB, T, 0); patch(p1, to); patch(p2, pc); goto ret; @@ -929,8 +1172,8 @@ bgen(Node *n, int true, Prog *to) goto caseand; caseor: - bgen(n->left, true, to); - bgen(n->right, true, to); + bgen(n->left, true, likely, to); + bgen(n->right, true, likely, to); goto ret; case OEQ: @@ -952,7 +1195,7 @@ bgen(Node *n, int true, Prog *to) switch(n->op) { case ONOT: - bgen(nl, !true, to); + bgen(nl, !true, likely, to); goto ret; case OEQ: @@ -965,14 +1208,14 @@ bgen(Node *n, int true, Prog *to) if(!true) { if(isfloat[nl->type->etype]) { // brcom is not valid on floats when NaN is involved. - p1 = gbranch(AB, T); - p2 = gbranch(AB, T); + p1 = gbranch(AB, T, 0); + p2 = gbranch(AB, T, 0); patch(p1, pc); ll = n->ninit; n->ninit = nil; - bgen(n, 1, p2); + bgen(n, 1, -likely, p2); n->ninit = ll; - patch(gbranch(AB, T), to); + patch(gbranch(AB, T, 0), to); patch(p2, pc); goto ret; } @@ -995,34 +1238,12 @@ bgen(Node *n, int true, Prog *to) break; } - regalloc(&n1, types[tptr], N); - agen(nl, &n1); - n2 = n1; - n2.op = OINDREG; - n2.xoffset = Array_array; - gencmp0(&n2, types[tptr], a, to); - regfree(&n1); - break; - -#ifdef NOTDEF - a = optoas(a, types[tptr]); - regalloc(&n1, types[tptr], N); - regalloc(&n3, types[tptr], N); - regalloc(&n4, types[tptr], N); - agen(nl, &n1); - n2 = n1; - n2.op = OINDREG; - n2.xoffset = Array_array; - gmove(&n2, &n4); - nodconst(&tmp, types[tptr], 0); - gmove(&tmp, &n3); - gcmp(optoas(OCMP, types[tptr]), &n4, &n3); - patch(gbranch(a, types[tptr]), to); - regfree(&n4); - regfree(&n3); + igen(nl, &n1, N); + n1.xoffset += Array_array; + n1.type = types[tptr]; + gencmp0(&n1, types[tptr], a, likely, to); regfree(&n1); break; -#endif } if(isinter(nl->type)) { @@ -1032,38 +1253,16 @@ bgen(Node *n, int true, Prog *to) break; } - regalloc(&n1, types[tptr], N); - agen(nl, &n1); - n2 = n1; - n2.op = OINDREG; - n2.xoffset = 0; - gencmp0(&n2, types[tptr], a, to); - regfree(&n1); - break; - -#ifdef NOTDEF - a = optoas(a, types[tptr]); - regalloc(&n1, types[tptr], N); - regalloc(&n3, types[tptr], N); - regalloc(&n4, types[tptr], N); - agen(nl, &n1); - n2 = n1; - n2.op = OINDREG; - n2.xoffset = 0; - gmove(&n2, &n4); - nodconst(&tmp, types[tptr], 0); - gmove(&tmp, &n3); - gcmp(optoas(OCMP, types[tptr]), &n4, &n3); - patch(gbranch(a, types[tptr]), to); + igen(nl, &n1, N); + n1.type = types[tptr]; + n1.xoffset += 0; + gencmp0(&n1, types[tptr], a, likely, to); regfree(&n1); - regfree(&n3); - regfree(&n4); break; -#endif } if(iscomplex[nl->type->etype]) { - complexbool(a, nl, nr, true, to); + complexbool(a, nl, nr, true, likely, to); break; } @@ -1078,17 +1277,17 @@ bgen(Node *n, int true, Prog *to) cgen(nr, &n2); nr = &n2; } - cmp64(nl, nr, a, to); + cmp64(nl, nr, a, likely, to); break; } if(nr->op == OLITERAL) { if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) == 0) { - gencmp0(nl, nl->type, a, to); + gencmp0(nl, nl->type, a, likely, to); break; } if(nr->val.ctype == CTNIL) { - gencmp0(nl, nl->type, a, to); + gencmp0(nl, nl->type, a, likely, to); break; } } @@ -1110,7 +1309,7 @@ bgen(Node *n, int true, Prog *to) cgen(&tmp, &n1); gcmp(optoas(OCMP, nr->type), &n1, &n2); - patch(gbranch(a, nr->type), to); + patch(gbranch(a, nr->type, likely), to); regfree(&n1); regfree(&n2); @@ -1131,14 +1330,17 @@ bgen(Node *n, int true, Prog *to) gcmp(optoas(OCMP, nr->type), &n1, &n2); if(isfloat[nl->type->etype]) { - p1 = gbranch(ABVS, nr->type); - patch(gbranch(a, nr->type), to); - if(n->op == ONE) + if(n->op == ONE) { + p1 = gbranch(ABVS, nr->type, likely); + patch(gbranch(a, nr->type, likely), to); patch(p1, to); - else + } else { + p1 = gbranch(ABVS, nr->type, -likely); + patch(gbranch(a, nr->type, likely), to); patch(p1, pc); + } } else { - patch(gbranch(a, nr->type), to); + patch(gbranch(a, nr->type, likely), to); } regfree(&n1); regfree(&n2); @@ -1241,6 +1443,10 @@ sgen(Node *n, Node *res, int64 w) return; } + // Avoid taking the address for simple enough types. + if(componentgen(n, res)) + return; + // determine alignment. // want to avoid unaligned access, so have to use // smaller operations for less aligned types. @@ -1284,16 +1490,14 @@ sgen(Node *n, Node *res, int64 w) if(osrc < odst && odst < osrc+w) dir = -dir; - regalloc(&dst, types[tptr], res); if(n->ullman >= res->ullman) { - agen(n, &dst); // temporarily use dst + agenr(n, &dst, res); // temporarily use dst regalloc(&src, types[tptr], N); gins(AMOVW, &dst, &src); agen(res, &dst); } else { - agen(res, &dst); - regalloc(&src, types[tptr], N); - agen(n, &src); + agenr(res, &dst, res); + agenr(n, &src, N); } regalloc(&tmp, types[TUINT32], N); @@ -1338,7 +1542,7 @@ sgen(Node *n, Node *res, int64 w) p = gins(ACMP, &src, N); raddr(&nend, p); - patch(gbranch(ABNE, T), ploop); + patch(gbranch(ABNE, T, 0), ploop); regfree(&nend); } else { while(c-- > 0) { @@ -1358,3 +1562,157 @@ sgen(Node *n, Node *res, int64 w) regfree(&src); regfree(&tmp); } + +static int +cadable(Node *n) +{ + if(!n->addable) { + // dont know how it happens, + // but it does + return 0; + } + + switch(n->op) { + case ONAME: + return 1; + } + return 0; +} + +/* + * copy a composite value by moving its individual components. + * Slices, strings and interfaces are supported. + * nr is N when assigning a zero value. + * return 1 if can do, 0 if cant. + */ +int +componentgen(Node *nr, Node *nl) +{ + Node nodl, nodr, tmp; + int freel, freer; + + freel = 0; + freer = 0; + + switch(nl->type->etype) { + default: + goto no; + + case TARRAY: + if(!isslice(nl->type)) + goto no; + case TSTRING: + case TINTER: + break; + } + + nodl = *nl; + if(!cadable(nl)) { + if(nr == N || !cadable(nr)) + goto no; + igen(nl, &nodl, N); + freel = 1; + } + + if(nr != N) { + nodr = *nr; + if(!cadable(nr)) { + igen(nr, &nodr, N); + freer = 1; + } + } else { + // When zeroing, prepare a register containing zero. + nodconst(&tmp, nl->type, 0); + regalloc(&nodr, types[TUINT], N); + gmove(&tmp, &nodr); + freer = 1; + } + + switch(nl->type->etype) { + case TARRAY: + nodl.xoffset += Array_array; + nodl.type = ptrto(nl->type->type); + + if(nr != N) { + nodr.xoffset += Array_array; + nodr.type = nodl.type; + } + gmove(&nodr, &nodl); + + nodl.xoffset += Array_nel-Array_array; + nodl.type = types[simtype[TUINT]]; + + if(nr != N) { + nodr.xoffset += Array_nel-Array_array; + nodr.type = nodl.type; + } + gmove(&nodr, &nodl); + + nodl.xoffset += Array_cap-Array_nel; + nodl.type = types[simtype[TUINT]]; + + if(nr != N) { + nodr.xoffset += Array_cap-Array_nel; + nodr.type = nodl.type; + } + gmove(&nodr, &nodl); + + goto yes; + + case TSTRING: + nodl.xoffset += Array_array; + nodl.type = ptrto(types[TUINT8]); + + if(nr != N) { + nodr.xoffset += Array_array; + nodr.type = nodl.type; + } + gmove(&nodr, &nodl); + + nodl.xoffset += Array_nel-Array_array; + nodl.type = types[simtype[TUINT]]; + + if(nr != N) { + nodr.xoffset += Array_nel-Array_array; + nodr.type = nodl.type; + } + gmove(&nodr, &nodl); + + goto yes; + + case TINTER: + nodl.xoffset += Array_array; + nodl.type = ptrto(types[TUINT8]); + + if(nr != N) { + nodr.xoffset += Array_array; + nodr.type = nodl.type; + } + gmove(&nodr, &nodl); + + nodl.xoffset += Array_nel-Array_array; + nodl.type = ptrto(types[TUINT8]); + + if(nr != N) { + nodr.xoffset += Array_nel-Array_array; + nodr.type = nodl.type; + } + gmove(&nodr, &nodl); + + goto yes; + } + +no: + if(freer) + regfree(&nodr); + if(freel) + regfree(&nodl); + return 0; + +yes: + if(freer) + regfree(&nodr); + if(freel) + regfree(&nodl); + return 1; +} diff --git a/src/cmd/5g/cgen64.c b/src/cmd/5g/cgen64.c index 1235d1ace..ef11e2adb 100644 --- a/src/cmd/5g/cgen64.c +++ b/src/cmd/5g/cgen64.c @@ -94,6 +94,7 @@ cgen64(Node *n, Node *res) case OAND: case OOR: case OXOR: + case OLROT: // binary operators. // common setup below. break; @@ -175,7 +176,7 @@ cgen64(Node *n, Node *res) p1->from.type = D_REG; p1->from.reg = bl.val.u.reg; p1->reg = ch.val.u.reg; - p1->to.type = D_REGREG; + p1->to.type = D_REGREG2; p1->to.reg = ah.val.u.reg; p1->to.offset = ah.val.u.reg; //print("%P\n", p1); @@ -185,7 +186,7 @@ cgen64(Node *n, Node *res) p1->from.type = D_REG; p1->from.reg = bh.val.u.reg; p1->reg = cl.val.u.reg; - p1->to.type = D_REGREG; + p1->to.type = D_REGREG2; p1->to.reg = ah.val.u.reg; p1->to.offset = ah.val.u.reg; //print("%P\n", p1); @@ -197,6 +198,47 @@ cgen64(Node *n, Node *res) break; + case OLROT: + // We only rotate by a constant c in [0,64). + // if c >= 32: + // lo, hi = hi, lo + // c -= 32 + // if c == 0: + // no-op + // else: + // t = hi + // shld hi:lo, c + // shld lo:t, c + v = mpgetfix(r->val.u.xval); + regalloc(&bl, lo1.type, N); + regalloc(&bh, hi1.type, N); + if(v >= 32) { + // reverse during load to do the first 32 bits of rotate + v -= 32; + gins(AMOVW, &hi1, &bl); + gins(AMOVW, &lo1, &bh); + } else { + gins(AMOVW, &hi1, &bh); + gins(AMOVW, &lo1, &bl); + } + if(v == 0) { + gins(AMOVW, &bh, &ah); + gins(AMOVW, &bl, &al); + } else { + // rotate by 1 <= v <= 31 + // MOVW bl<<v, al + // MOVW bh<<v, ah + // OR bl>>(32-v), ah + // OR bh>>(32-v), al + gshift(AMOVW, &bl, SHIFT_LL, v, &al); + gshift(AMOVW, &bh, SHIFT_LL, v, &ah); + gshift(AORR, &bl, SHIFT_LR, 32-v, &ah); + gshift(AORR, &bh, SHIFT_LR, 32-v, &al); + } + regfree(&bl); + regfree(&bh); + break; + case OLSH: regalloc(&bl, lo1.type, N); regalloc(&bh, hi1.type, N); @@ -243,7 +285,7 @@ cgen64(Node *n, Node *res) split64(r, &cl, &ch); gmove(&ch, &s); gins(ATST, &s, N); - p6 = gbranch(ABNE, T); + p6 = gbranch(ABNE, T, 0); gmove(&cl, &s); splitclean(); } else { @@ -257,7 +299,7 @@ cgen64(Node *n, Node *res) p1->scond = C_SCOND_EQ; p1 = gins(AMOVW, &bh, &ah); p1->scond = C_SCOND_EQ; - p2 = gbranch(ABEQ, T); + p2 = gbranch(ABEQ, T, 0); // shift is < 32 nodconst(&n1, types[TUINT32], 32); @@ -281,14 +323,14 @@ cgen64(Node *n, Node *res) p1->scond = C_SCOND_LO; // BLO end - p3 = gbranch(ABLO, T); + p3 = gbranch(ABLO, T, 0); // shift == 32 p1 = gins(AEOR, &al, &al); p1->scond = C_SCOND_EQ; p1 = gins(AMOVW, &bl, &ah); p1->scond = C_SCOND_EQ; - p4 = gbranch(ABEQ, T); + p4 = gbranch(ABEQ, T, 0); // shift is < 64 nodconst(&n1, types[TUINT32], 64); @@ -311,7 +353,7 @@ cgen64(Node *n, Node *res) p1 = gregshift(AMOVW, &bl, SHIFT_LL, &s, &ah); p1->scond = C_SCOND_LO; - p5 = gbranch(ABLO, T); + p5 = gbranch(ABLO, T, 0); // shift >= 64 if (p6 != P) patch(p6, pc); @@ -406,7 +448,7 @@ olsh_break: else p1 = gins(AEOR, &ah, &ah); p1->scond = C_SCOND_NE; - p6 = gbranch(ABNE, T); + p6 = gbranch(ABNE, T, 0); gmove(&cl, &s); splitclean(); } else { @@ -420,7 +462,7 @@ olsh_break: p1->scond = C_SCOND_EQ; p1 = gins(AMOVW, &bh, &ah); p1->scond = C_SCOND_EQ; - p2 = gbranch(ABEQ, T); + p2 = gbranch(ABEQ, T, 0); // check if shift is < 32 nodconst(&n1, types[TUINT32], 32); @@ -449,7 +491,7 @@ olsh_break: p1->scond = C_SCOND_LO; // BLO end - p3 = gbranch(ABLO, T); + p3 = gbranch(ABLO, T, 0); // shift == 32 p1 = gins(AMOVW, &bh, &al); @@ -458,7 +500,7 @@ olsh_break: gshift(AMOVW, &bh, SHIFT_AR, 31, &ah); else gins(AEOR, &ah, &ah); - p4 = gbranch(ABEQ, T); + p4 = gbranch(ABEQ, T, 0); // check if shift is < 64 nodconst(&n1, types[TUINT32], 64); @@ -484,7 +526,7 @@ olsh_break: } // BLO end - p5 = gbranch(ABLO, T); + p5 = gbranch(ABLO, T, 0); // s >= 64 if(p6 != P) @@ -633,7 +675,7 @@ orsh_break: * nl is memory; nr is constant or memory. */ void -cmp64(Node *nl, Node *nr, int op, Prog *to) +cmp64(Node *nl, Node *nr, int op, int likely, Prog *to) { Node lo1, hi1, lo2, hi2, r1, r2; Prog *br; @@ -663,14 +705,14 @@ cmp64(Node *nl, Node *nr, int op, Prog *to) // cmp lo // beq to // L: - br = gbranch(ABNE, T); + br = gbranch(ABNE, T, -likely); break; case ONE: // cmp hi // bne to // cmp lo // bne to - patch(gbranch(ABNE, T), to); + patch(gbranch(ABNE, T, likely), to); break; case OGE: case OGT: @@ -680,8 +722,8 @@ cmp64(Node *nl, Node *nr, int op, Prog *to) // cmp lo // bge to (or bgt to) // L: - patch(gbranch(optoas(OGT, t), T), to); - br = gbranch(optoas(OLT, t), T); + patch(gbranch(optoas(OGT, t), T, likely), to); + br = gbranch(optoas(OLT, t), T, -likely); break; case OLE: case OLT: @@ -691,8 +733,8 @@ cmp64(Node *nl, Node *nr, int op, Prog *to) // cmp lo // ble to (or jlt to) // L: - patch(gbranch(optoas(OLT, t), T), to); - br = gbranch(optoas(OGT, t), T); + patch(gbranch(optoas(OLT, t), T, likely), to); + br = gbranch(optoas(OGT, t), T, -likely); break; } @@ -707,7 +749,7 @@ cmp64(Node *nl, Node *nr, int op, Prog *to) regfree(&r2); // jump again - patch(gbranch(optoas(op, t), T), to); + patch(gbranch(optoas(op, t), T, likely), to); // point first branch down here if appropriate if(br != P) diff --git a/src/cmd/5g/doc.go b/src/cmd/5g/doc.go index 5a4a772fb..aebdcab71 100644 --- a/src/cmd/5g/doc.go +++ b/src/cmd/5g/doc.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build ignore + /* 5g is the version of the gc compiler for the ARM. @@ -10,4 +12,4 @@ The $GOARCH for these tools is arm. It reads .go files and outputs .5 files. The flags are documented in ../gc/doc.go. */ -package documentation +package main diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c index 070804217..1fbf633f9 100644 --- a/src/cmd/5g/galign.c +++ b/src/cmd/5g/galign.c @@ -27,6 +27,7 @@ void betypeinit(void) { widthptr = 4; + widthint = 4; zprog.link = P; zprog.as = AGOK; diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h index 7dbf3beec..45a9a887e 100644 --- a/src/cmd/5g/gg.h +++ b/src/cmd/5g/gg.h @@ -15,32 +15,36 @@ struct Addr { int32 offset; int32 offset2; - double dval; - Prog* branch; - char sval[NSNAME]; + + union { + double dval; + vlong vval; + Prog* branch; + char sval[NSNAME]; + } u; Sym* sym; + Sym* gotype; Node* node; int width; uchar type; char name; uchar reg; - char pun; uchar etype; }; #define A ((Addr*)0) struct Prog { - short as; // opcode uint32 loc; // pc offset in this func uint32 lineno; // source line that generated this - Addr from; // src address - Addr to; // dst address Prog* link; // next instruction in this func void* regp; // points to enclosing Reg struct + short as; // opcode uchar reg; // doubles as width in DATA op uchar scond; + Addr from; // src address + Addr to; // dst address }; #define TEXTFLAG reg @@ -78,22 +82,20 @@ void cgen_callinter(Node*, Node*, int); void cgen_proc(Node*, int); void cgen_callret(Node*, Node*); void cgen_dcl(Node*); -int cgen_inline(Node*, Node*); int needconvert(Type*, Type*); void genconv(Type*, Type*); void allocparams(void); -void checklabels(); +void checklabels(void); void ginscall(Node*, int); /* * cgen */ void agen(Node*, Node*); -Prog* cgenindex(Node *, Node *); +Prog* cgenindex(Node *, Node *, int); void igen(Node*, Node*, Node*); void agenr(Node *n, Node *a, Node *res); vlong fieldoffset(Type*, Node*); -void bgen(Node*, int, Prog*); void sgen(Node*, Node*, int64); void gmove(Node*, Node*); Prog* gins(int, Node*, Node*); @@ -104,12 +106,14 @@ Prog* gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs); Prog * gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs); void naddr(Node*, Addr*, int); void cgen_aret(Node*, Node*); -void cgen_shift(int, Node*, Node*, Node*); +void cgen_hmul(Node*, Node*, Node*); +void cgen_shift(int, int, Node*, Node*, Node*); +int componentgen(Node*, Node*); /* * cgen64.c */ -void cmp64(Node*, Node*, int, Prog*); +void cmp64(Node*, Node*, int, int, Prog*); void cgen64(Node*, Node*); /* @@ -117,16 +121,13 @@ void cgen64(Node*, Node*); */ void clearp(Prog*); void proglist(void); -Prog* gbranch(int, Type*); +Prog* gbranch(int, Type*, int); Prog* prog(int); -void gaddoffset(Node*); void gconv(int, int); int conv2pt(Type*); vlong convvtox(vlong, int); void fnparam(Type*, int, int); Prog* gop(int, Node*, Node*, Node*); -void setconst(Addr*, vlong); -void setaddr(Addr*, Node*); int optoas(int, Type*); void ginit(void); void gclean(void); @@ -141,11 +142,12 @@ int isfat(Type*); int dotaddable(Node*, Node*); void sudoclean(void); int sudoaddable(int, Node*, Addr*, int*); -void afunclit(Addr*); +void afunclit(Addr*, Node*); void datagostring(Strlit*, Addr*); void split64(Node*, Node*, Node*); void splitclean(void); Node* ncon(uint32 i); +void gtrack(Sym*); /* * obj.c @@ -164,7 +166,7 @@ int Rconv(Fmt*); int Yconv(Fmt*); void listinit(void); -void zaddr(Biobuf*, Addr*, int); +void zaddr(Biobuf*, Addr*, int, int); #pragma varargck type "D" Addr* #pragma varargck type "M" Addr* diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c index de100620b..de1671bb6 100644 --- a/src/cmd/5g/ggen.c +++ b/src/cmd/5g/ggen.c @@ -28,6 +28,9 @@ void markautoused(Prog* p) { for (; p; p = p->link) { + if (p->as == ATYPE) + continue; + if (p->from.name == D_AUTO && p->from.node) p->from.node->used = 1; @@ -40,27 +43,38 @@ markautoused(Prog* p) void fixautoused(Prog* p) { - for (; p; p = p->link) { + Prog **lp; + + for (lp=&p; (p=*lp) != P; ) { + if (p->as == ATYPE && p->from.node && p->from.name == D_AUTO && !p->from.node->used) { + *lp = p->link; + continue; + } + if (p->from.name == D_AUTO && p->from.node) p->from.offset += p->from.node->stkdelta; if (p->to.name == D_AUTO && p->to.node) p->to.offset += p->to.node->stkdelta; + + lp = &p->link; } } /* * generate: * call f + * proc=-1 normal call but no return * proc=0 normal call * proc=1 goroutine run in new proc * proc=2 defer call save away stack + * proc=3 normal call to C pointer (not Go func value) */ void ginscall(Node *f, int proc) { Prog *p; - Node n1, r, con; + Node n1, r, r1, con; switch(proc) { default: @@ -68,8 +82,26 @@ ginscall(Node *f, int proc) break; case 0: // normal call - p = gins(ABL, N, f); - afunclit(&p->to); + case -1: // normal call but no return + if(f->op == ONAME && f->class == PFUNC) { + p = gins(ABL, N, f); + afunclit(&p->to, f); + if(proc == -1 || noreturn(p)) + gins(AUNDEF, N, N); + break; + } + nodreg(&r, types[tptr], 7); + nodreg(&r1, types[tptr], 1); + gmove(f, &r); + r.op = OINDREG; + gmove(&r, &r1); + r.op = OREGISTER; + r1.op = OINDREG; + gins(ABL, &r, &r1); + break; + + case 3: // normal call of c function pointer + gins(ABL, N, f); break; case 1: // call in new proc (go) @@ -120,7 +152,7 @@ ginscall(Node *f, int proc) nodconst(&con, types[TINT32], 0); p = gins(ACMP, &con, N); p->reg = 0; - patch(gbranch(ABNE, T), retpc); + patch(gbranch(ABNE, T, -1), retpc); } break; } @@ -136,6 +168,7 @@ cgen_callinter(Node *n, Node *res, int proc) int r; Node *i, *f; Node tmpi, nodo, nodr, nodsp; + Prog *p; i = n->left; if(i->op != ODOTINTER) @@ -180,7 +213,17 @@ cgen_callinter(Node *n, Node *res, int proc) cgen(&nodo, &nodr); // REG = 0(REG) -- i.tab nodo.xoffset = n->left->xoffset + 3*widthptr + 8; - cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f] + + if(proc == 0) { + // plain call: use direct c function pointer - more efficient + cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f] + nodr.op = OINDREG; + proc = 3; + } else { + // go/defer. generate go func value. + p = gins(AMOVW, &nodo, &nodr); + p->from.type = D_CONST; // REG = &(20+offset(REG)) -- i.tab->fun[f] + } // BOTCH nodr.type = fntype; nodr.type = n->left->type; @@ -368,14 +411,19 @@ cgen_asop(Node *n) case OOR: a = optoas(n->etype, nl->type); if(nl->addable) { - regalloc(&n3, nr->type, N); - cgen(nr, &n3); + if(smallintconst(nr)) + n3 = *nr; + else { + regalloc(&n3, nr->type, N); + cgen(nr, &n3); + } regalloc(&n2, nl->type, N); cgen(nl, &n2); gins(a, &n3, &n2); cgen(&n2, nl); regfree(&n2); - regfree(&n3); + if(n3.op != OLITERAL) + regfree(&n3); goto ret; } if(nr->ullman < UINF) @@ -399,7 +447,9 @@ cgen_asop(Node *n) hard: n2.op = 0; n1.op = 0; - if(nr->ullman >= nl->ullman || nl->addable) { + if(nr->op == OLITERAL) { + // don't allocate a register for literals. + } else if(nr->ullman >= nl->ullman || nl->addable) { regalloc(&n2, nr->type, N); cgen(nr, &n2); nr = &n2; @@ -464,24 +514,99 @@ samereg(Node *a, Node *b) } /* + * generate high multiply + * res = (nl * nr) >> wordsize + */ +void +cgen_hmul(Node *nl, Node *nr, Node *res) +{ + int w; + Node n1, n2, *tmp; + Type *t; + Prog *p; + + if(nl->ullman < nr->ullman) { + tmp = nl; + nl = nr; + nr = tmp; + } + t = nl->type; + w = t->width * 8; + regalloc(&n1, t, res); + cgen(nl, &n1); + regalloc(&n2, t, N); + cgen(nr, &n2); + switch(simtype[t->etype]) { + case TINT8: + case TINT16: + gins(optoas(OMUL, t), &n2, &n1); + gshift(AMOVW, &n1, SHIFT_AR, w, &n1); + break; + case TUINT8: + case TUINT16: + gins(optoas(OMUL, t), &n2, &n1); + gshift(AMOVW, &n1, SHIFT_LR, w, &n1); + break; + case TINT32: + case TUINT32: + // perform a long multiplication. + if(issigned[t->etype]) + p = gins(AMULL, &n2, N); + else + p = gins(AMULLU, &n2, N); + // n2 * n1 -> (n1 n2) + p->reg = n1.val.u.reg; + p->to.type = D_REGREG; + p->to.reg = n1.val.u.reg; + p->to.offset = n2.val.u.reg; + break; + default: + fatal("cgen_hmul %T", t); + break; + } + cgen(&n1, res); + regfree(&n1); + regfree(&n2); +} + +/* * generate shift according to op, one of: * res = nl << nr * res = nl >> nr */ void -cgen_shift(int op, Node *nl, Node *nr, Node *res) +cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res) { Node n1, n2, n3, nt, t, lo, hi; - int w; + int w, v; Prog *p1, *p2, *p3; Type *tr; uvlong sc; + USED(bounded); if(nl->type->width > 4) fatal("cgen_shift %T", nl->type); w = nl->type->width * 8; + if(op == OLROT) { + v = mpgetfix(nr->val.u.xval); + regalloc(&n1, nl->type, res); + if(w == 32) { + cgen(nl, &n1); + gshift(AMOVW, &n1, SHIFT_RR, w-v, &n1); + } else { + regalloc(&n2, nl->type, N); + cgen(nl, &n2); + gshift(AMOVW, &n2, SHIFT_LL, v, &n1); + gshift(AORR, &n2, SHIFT_LR, w-v, &n1); + regfree(&n2); + } + gmove(&n1, res); + regfree(&n1); + return; + } + if(nr->op == OLITERAL) { regalloc(&n1, nl->type, res); cgen(nl, &n1); @@ -524,6 +649,7 @@ cgen_shift(int op, Node *nl, Node *nr, Node *res) regalloc(&n3, types[TUINT32], N); gmove(&lo, &n1); gmove(&hi, &n3); + splitclean(); gins(ATST, &n3, N); nodconst(&t, types[TUINT32], w); p1 = gins(AMOVW, &t, &n1); @@ -546,9 +672,10 @@ cgen_shift(int op, Node *nl, Node *nr, Node *res) // test for shift being 0 gins(ATST, &n1, N); - p3 = gbranch(ABEQ, T); + p3 = gbranch(ABEQ, T, -1); // test and fix up large shifts + // TODO: if(!bounded), don't emit some of this. regalloc(&n3, tr, N); nodconst(&t, types[TUINT32], w); gmove(&t, &n3); @@ -589,7 +716,12 @@ clearfat(Node *nl) if(debug['g']) dump("\nclearfat", nl); + w = nl->type->width; + // Avoid taking the address for simple enough types. + if(componentgen(N, nl)) + return; + c = w % 4; // bytes q = w / 4; // quads @@ -613,7 +745,7 @@ clearfat(Node *nl) p = gins(ACMP, &dst, N); raddr(&end, p); - patch(gbranch(ABNE, T), pl); + patch(gbranch(ABNE, T, 0), pl); regfree(&end); } else @@ -637,395 +769,3 @@ clearfat(Node *nl) regfree(&dst); regfree(&nz); } - -static int -regcmp(const void *va, const void *vb) -{ - Node *ra, *rb; - - ra = (Node*)va; - rb = (Node*)vb; - return ra->local - rb->local; -} - -static Prog* throwpc; - -// We're only going to bother inlining if we can -// convert all the arguments to 32 bits safely. Can we? -static int -fix64(NodeList *nn, int n) -{ - NodeList *l; - Node *r; - int i; - - l = nn; - for(i=0; i<n; i++) { - r = l->n->right; - if(is64(r->type) && !smallintconst(r)) { - if(r->op == OCONV) - r = r->left; - if(is64(r->type)) - return 0; - } - l = l->next; - } - return 1; -} - -void -getargs(NodeList *nn, Node *reg, int n) -{ - NodeList *l; - int i; - - throwpc = nil; - - l = nn; - for(i=0; i<n; i++) { - if(!smallintconst(l->n->right) && !isslice(l->n->right->type)) { - regalloc(reg+i, l->n->right->type, N); - cgen(l->n->right, reg+i); - } else - reg[i] = *l->n->right; - if(reg[i].local != 0) - yyerror("local used"); - reg[i].local = l->n->left->xoffset; - l = l->next; - } - qsort((void*)reg, n, sizeof(*reg), regcmp); - for(i=0; i<n; i++) - reg[i].local = 0; -} - -void -cmpandthrow(Node *nl, Node *nr) -{ - vlong cl; - Prog *p1; - int op; - Node *c, n1, n2; - - op = OLE; - if(smallintconst(nl)) { - cl = mpgetfix(nl->val.u.xval); - if(cl == 0) - return; - if(smallintconst(nr)) - return; - - // put the constant on the right - op = brrev(op); - c = nl; - nl = nr; - nr = c; - } - - n1.op = OXXX; - if(nr->op != OREGISTER) { - regalloc(&n1, types[TUINT32], N); - gmove(nr, &n1); - nr = &n1; - } - n2.op = OXXX; - if(nl->op != OREGISTER) { - regalloc(&n2, types[TUINT32], N); - gmove(nl, &n2); - nl = &n2; - } - gcmp(optoas(OCMP, types[TUINT32]), nl, nr); - if(nr == &n1) - regfree(&n1); - if(nl == &n2) - regfree(&n2); - if(throwpc == nil) { - p1 = gbranch(optoas(op, types[TUINT32]), T); - throwpc = pc; - ginscall(panicslice, 0); - patch(p1, pc); - } else { - op = brcom(op); - p1 = gbranch(optoas(op, types[TUINT32]), T); - patch(p1, throwpc); - } -} - -int -sleasy(Node *n) -{ - if(n->op != ONAME) - return 0; - if(!n->addable) - return 0; - return 1; -} - -// generate inline code for -// slicearray -// sliceslice -// arraytoslice -int -cgen_inline(Node *n, Node *res) -{ - Node nodes[5]; - Node n1, n2, n3, nres, ntemp; - vlong v; - int i, narg; - - if(n->op != OCALLFUNC) - goto no; - if(!n->left->addable) - goto no; - if(n->left->sym == S) - goto no; - if(n->left->sym->pkg != runtimepkg) - goto no; - if(strcmp(n->left->sym->name, "slicearray") == 0) - goto slicearray; - if(strcmp(n->left->sym->name, "sliceslice") == 0) { - narg = 4; - goto sliceslice; - } - if(strcmp(n->left->sym->name, "sliceslice1") == 0) { - narg = 3; - goto sliceslice; - } - goto no; - -slicearray: - if(!sleasy(res)) - goto no; - if(!fix64(n->list, 5)) - goto no; - getargs(n->list, nodes, 5); - - // if(hb[3] > nel[1]) goto throw - cmpandthrow(&nodes[3], &nodes[1]); - - // if(lb[2] > hb[3]) goto throw - cmpandthrow(&nodes[2], &nodes[3]); - - // len = hb[3] - lb[2] (destroys hb) - n2 = *res; - n2.type = types[TUINT32]; - n2.xoffset += Array_nel; - - if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) { - v = mpgetfix(nodes[3].val.u.xval) - - mpgetfix(nodes[2].val.u.xval); - nodconst(&n1, types[TUINT32], v); - gmove(&n1, &n2); - } else { - regalloc(&n1, types[TUINT32], &nodes[3]); - gmove(&nodes[3], &n1); - if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1); - gmove(&n1, &n2); - regfree(&n1); - } - - // cap = nel[1] - lb[2] (destroys nel) - n2 = *res; - n2.type = types[TUINT32]; - n2.xoffset += Array_cap; - - if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) { - v = mpgetfix(nodes[1].val.u.xval) - - mpgetfix(nodes[2].val.u.xval); - nodconst(&n1, types[TUINT32], v); - gmove(&n1, &n2); - } else { - regalloc(&n1, types[TUINT32], &nodes[1]); - gmove(&nodes[1], &n1); - if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1); - gmove(&n1, &n2); - regfree(&n1); - } - - // if slice could be too big, dereference to - // catch nil array pointer. - if(nodes[0].op == OREGISTER && nodes[0].type->type->width >= unmappedzero) { - n2 = nodes[0]; - n2.xoffset = 0; - n2.op = OINDREG; - n2.type = types[TUINT8]; - regalloc(&n1, types[TUINT32], N); - gins(AMOVB, &n2, &n1); - regfree(&n1); - } - - // ary = old[0] + (lb[2] * width[4]) (destroys old) - n2 = *res; - n2.type = types[tptr]; - n2.xoffset += Array_array; - - if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) { - v = mpgetfix(nodes[2].val.u.xval) * - mpgetfix(nodes[4].val.u.xval); - if(v != 0) { - nodconst(&n1, types[tptr], v); - gins(optoas(OADD, types[tptr]), &n1, &nodes[0]); - } - } else { - regalloc(&n1, types[tptr], &nodes[2]); - gmove(&nodes[2], &n1); - if(!smallintconst(&nodes[4]) || mpgetfix(nodes[4].val.u.xval) != 1) { - regalloc(&n3, types[tptr], N); - gmove(&nodes[4], &n3); - gins(optoas(OMUL, types[tptr]), &n3, &n1); - regfree(&n3); - } - gins(optoas(OADD, types[tptr]), &n1, &nodes[0]); - regfree(&n1); - } - gmove(&nodes[0], &n2); - - for(i=0; i<5; i++) { - if(nodes[i].op == OREGISTER) - regfree(&nodes[i]); - } - return 1; - -sliceslice: - if(!fix64(n->list, narg)) - goto no; - ntemp.op = OXXX; - if(!sleasy(n->list->n->right)) { - Node *n0; - - n0 = n->list->n->right; - tempname(&ntemp, res->type); - cgen(n0, &ntemp); - n->list->n->right = &ntemp; - getargs(n->list, nodes, narg); - n->list->n->right = n0; - } else - getargs(n->list, nodes, narg); - - nres = *res; // result - if(!sleasy(res)) { - if(ntemp.op == OXXX) - tempname(&ntemp, res->type); - nres = ntemp; - } - - if(narg == 3) { // old[lb:] - // move width to where it would be for old[lb:hb] - nodes[3] = nodes[2]; - nodes[2].op = OXXX; - - // if(lb[1] > old.nel[0]) goto throw; - n2 = nodes[0]; - n2.xoffset += Array_nel; - n2.type = types[TUINT32]; - cmpandthrow(&nodes[1], &n2); - - // ret.nel = old.nel[0]-lb[1]; - n2 = nodes[0]; - n2.type = types[TUINT32]; - n2.xoffset += Array_nel; - - regalloc(&n1, types[TUINT32], N); - gmove(&n2, &n1); - if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1); - - n2 = nres; - n2.type = types[TUINT32]; - n2.xoffset += Array_nel; - gmove(&n1, &n2); - regfree(&n1); - } else { // old[lb:hb] - // if(hb[2] > old.cap[0]) goto throw; - n2 = nodes[0]; - n2.xoffset += Array_cap; - n2.type = types[TUINT32]; - cmpandthrow(&nodes[2], &n2); - - // if(lb[1] > hb[2]) goto throw; - cmpandthrow(&nodes[1], &nodes[2]); - - // ret.len = hb[2]-lb[1]; (destroys hb[2]) - n2 = nres; - n2.type = types[TUINT32]; - n2.xoffset += Array_nel; - - if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) { - v = mpgetfix(nodes[2].val.u.xval) - - mpgetfix(nodes[1].val.u.xval); - nodconst(&n1, types[TUINT32], v); - gmove(&n1, &n2); - } else { - regalloc(&n1, types[TUINT32], &nodes[2]); - gmove(&nodes[2], &n1); - if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1); - gmove(&n1, &n2); - regfree(&n1); - } - } - - // ret.cap = old.cap[0]-lb[1]; (uses hb[2]) - n2 = nodes[0]; - n2.type = types[TUINT32]; - n2.xoffset += Array_cap; - - regalloc(&n1, types[TUINT32], &nodes[2]); - gmove(&n2, &n1); - if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1); - - n2 = nres; - n2.type = types[TUINT32]; - n2.xoffset += Array_cap; - gmove(&n1, &n2); - regfree(&n1); - - // ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1]) - n2 = nodes[0]; - n2.type = types[tptr]; - n2.xoffset += Array_array; - regalloc(&n3, types[tptr], N); - gmove(&n2, &n3); - - regalloc(&n1, types[tptr], &nodes[1]); - if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) { - gmove(&n2, &n1); - v = mpgetfix(nodes[1].val.u.xval) * - mpgetfix(nodes[3].val.u.xval); - if(v != 0) { - nodconst(&n2, types[tptr], v); - gins(optoas(OADD, types[tptr]), &n3, &n1); - } - } else { - gmove(&nodes[1], &n1); - if(!smallintconst(&nodes[3]) || mpgetfix(nodes[3].val.u.xval) != 1) { - regalloc(&n2, types[tptr], N); - gmove(&nodes[3], &n2); - gins(optoas(OMUL, types[tptr]), &n2, &n1); - regfree(&n2); - } - gins(optoas(OADD, types[tptr]), &n3, &n1); - } - regfree(&n3); - - n2 = nres; - n2.type = types[tptr]; - n2.xoffset += Array_array; - gmove(&n1, &n2); - regfree(&n1); - - for(i=0; i<4; i++) { - if(nodes[i].op == OREGISTER) - regfree(&nodes[i]); - } - - if(!sleasy(res)) { - cgen(&nres, res); - } - return 1; - -no: - return 0; -} diff --git a/src/cmd/5g/gobj.c b/src/cmd/5g/gobj.c index 2763e7b16..9c5fb2a96 100644 --- a/src/cmd/5g/gobj.c +++ b/src/cmd/5g/gobj.c @@ -65,17 +65,17 @@ zhist(Biobuf *b, int line, vlong offset) Bputc(b, line>>8); Bputc(b, line>>16); Bputc(b, line>>24); - zaddr(b, &zprog.from, 0); + zaddr(b, &zprog.from, 0, 0); a = zprog.to; if(offset != 0) { a.offset = offset; a.type = D_CONST; } - zaddr(b, &a, 0); + zaddr(b, &a, 0, 0); } void -zaddr(Biobuf *b, Addr *a, int s) +zaddr(Biobuf *b, Addr *a, int s, int gotype) { int32 l; uint64 e; @@ -95,6 +95,7 @@ zaddr(Biobuf *b, Addr *a, int s) Bputc(b, a->reg); Bputc(b, s); Bputc(b, a->name); + Bputc(b, gotype); } switch(a->type) { @@ -128,9 +129,9 @@ zaddr(Biobuf *b, Addr *a, int s) break; case D_BRANCH: - if(a->branch == nil) + if(a->u.branch == nil) fatal("unpatched branch"); - a->offset = a->branch->loc; + a->offset = a->u.branch->loc; l = a->offset; Bputc(b, l); Bputc(b, l>>8); @@ -139,7 +140,7 @@ zaddr(Biobuf *b, Addr *a, int s) break; case D_SCONST: - n = a->sval; + n = a->u.sval; for(i=0; i<NSNAME; i++) { Bputc(b, *n); n++; @@ -147,11 +148,12 @@ zaddr(Biobuf *b, Addr *a, int s) break; case D_REGREG: + case D_REGREG2: Bputc(b, a->offset); break; case D_FCONST: - ieeedtod(&e, a->dval); + ieeedtod(&e, a->u.dval); l = e; Bputc(b, l); Bputc(b, l>>8); @@ -166,20 +168,66 @@ zaddr(Biobuf *b, Addr *a, int s) } } +static struct { + struct { Sym *sym; short type; } h[NSYM]; + int sym; +} z; + +static void +zsymreset(void) +{ + for(z.sym=0; z.sym<NSYM; z.sym++) { + z.h[z.sym].sym = S; + z.h[z.sym].type = 0; + } + z.sym = 1; +} + +static int +zsym(Sym *s, int t, int *new) +{ + int i; + + *new = 0; + if(s == S) + return 0; + + i = s->sym; + if(i < 0 || i >= NSYM) + i = 0; + if(z.h[i].type == t && z.h[i].sym == s) + return i; + i = z.sym; + s->sym = i; + zname(bout, s, t); + z.h[i].sym = s; + z.h[i].type = t; + if(++z.sym >= NSYM) + z.sym = 1; + *new = 1; + return i; +} + +static int +zsymaddr(Addr *a, int *new) +{ + int t; + + t = a->name; + if(t == D_ADDR) + t = a->name; + return zsym(a->sym, t, new); +} + void dumpfuncs(void) { Plist *pl; - int sf, st, t, sym; - struct { Sym *sym; short type; } h[NSYM]; + int sf, st, gf, gt, new; Sym *s; Prog *p; - for(sym=0; sym<NSYM; sym++) { - h[sym].sym = S; - h[sym].type = 0; - } - sym = 1; + zsymreset(); // fix up pc pcloc = 0; @@ -209,53 +257,20 @@ dumpfuncs(void) } for(p=pl->firstpc; 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.name; - if(t == D_ADDR) - t = p->from.name; - if(h[sf].type == t) - if(h[sf].sym == s) - break; - s->sym = sym; - zname(bout, 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.name; - if(t == D_ADDR) - t = p->to.name; - if(h[st].type == t) - if(h[st].sym == s) - break; - s->sym = sym; - zname(bout, s, t); - h[sym].sym = s; - h[sym].type = t; - st = sym; - sym++; - if(sym >= NSYM) - sym = 1; - if(st == sf) - goto jackpot; + for(;;) { + sf = zsymaddr(&p->from, &new); + gf = zsym(p->from.gotype, D_EXTERN, &new); + if(new && sf == gf) + continue; + st = zsymaddr(&p->to, &new); + if(new && (st == sf || st == gf)) + continue; + gt = zsym(p->to.gotype, D_EXTERN, &new); + if(new && (gt == sf || gt == gf || gt == st)) + continue; break; } + Bputc(bout, p->as); Bputc(bout, p->scond); Bputc(bout, p->reg); @@ -263,8 +278,8 @@ dumpfuncs(void) Bputc(bout, p->lineno>>8); Bputc(bout, p->lineno>>16); Bputc(bout, p->lineno>>24); - zaddr(bout, &p->from, sf); - zaddr(bout, &p->to, st); + zaddr(bout, &p->from, sf, gf); + zaddr(bout, &p->to, st, gt); } } } @@ -288,7 +303,7 @@ dsname(Sym *sym, int off, char *t, int n) p->to.name = D_NONE; p->to.reg = NREG; p->to.offset = 0; - memmove(p->to.sval, t, n); + memmove(p->to.u.sval, t, n); return off + n; } @@ -372,13 +387,13 @@ gdatacomplex(Node *nam, Mpcplx *cval) p = gins(ADATA, nam, N); p->reg = w; p->to.type = D_FCONST; - p->to.dval = mpgetflt(&cval->real); + p->to.u.dval = mpgetflt(&cval->real); p = gins(ADATA, nam, N); p->reg = w; p->from.offset += w; p->to.type = D_FCONST; - p->to.dval = mpgetflt(&cval->imag); + p->to.u.dval = mpgetflt(&cval->imag); } void diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c index 9acf93670..191c755b8 100644 --- a/src/cmd/5g/gsubr.c +++ b/src/cmd/5g/gsubr.c @@ -108,17 +108,22 @@ dumpdata(void) /* * generate a branch. * t is ignored. + * likely values are for branch prediction: + * -1 unlikely + * 0 no opinion + * +1 likely */ Prog* -gbranch(int as, Type *t) +gbranch(int as, Type *t, int likely) { Prog *p; USED(t); + USED(likely); // TODO: record this for linker p = prog(as); p->to.type = D_BRANCH; - p->to.branch = P; + p->to.u.branch = P; return p; } @@ -130,7 +135,7 @@ patch(Prog *p, Prog *to) { if(p->to.type != D_BRANCH) fatal("patch: not a branch"); - p->to.branch = to; + p->to.u.branch = to; p->to.offset = to->loc; } @@ -141,8 +146,8 @@ unpatch(Prog *p) if(p->to.type != D_BRANCH) fatal("unpatch: not a branch"); - q = p->to.branch; - p->to.branch = P; + q = p->to.u.branch; + p->to.u.branch = P; p->to.offset = 0; return q; } @@ -170,64 +175,6 @@ newplist(void) } 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 @@ -238,22 +185,23 @@ gjmp(Prog *to) { Prog *p; - p = gbranch(AB, T); + p = gbranch(AB, T, 0); if(to != P) patch(p, to); return p; } void -ggloblnod(Node *nam, int32 width) +ggloblnod(Node *nam) { Prog *p; p = gins(AGLOBL, nam, N); p->lineno = nam->lineno; + p->from.gotype = ngotype(nam); p->to.sym = S; p->to.type = D_CONST; - p->to.offset = width; + p->to.offset = nam->type->width; if(nam->readonly) p->reg = RODATA; if(nam->type != T && !haspointers(nam->type)) @@ -261,7 +209,7 @@ ggloblnod(Node *nam, int32 width) } void -ggloblsym(Sym *s, int32 width, int dupok) +ggloblsym(Sym *s, int32 width, int dupok, int rodata) { Prog *p; @@ -273,8 +221,20 @@ ggloblsym(Sym *s, int32 width, int dupok) p->to.name = D_NONE; p->to.offset = width; if(dupok) - p->reg = DUPOK; - p->reg |= RODATA; + p->reg |= DUPOK; + if(rodata) + p->reg |= RODATA; +} + +void +gtrack(Sym *s) +{ + Prog *p; + + p = gins(AUSEFIELD, N, N); + p->from.type = D_OREG; + p->from.name = D_EXTERN; + p->from.sym = s; } int @@ -298,17 +258,20 @@ isfat(Type *t) * also fix up direct register references to be D_OREG. */ void -afunclit(Addr *a) +afunclit(Addr *a, Node *n) { if(a->type == D_CONST && a->name == D_EXTERN || a->type == D_REG) { a->type = D_OREG; + if(n->op == ONAME) + a->sym = n->sym; } } static int resvd[] = { - 9, // reserved for m - 10, // reserved for g + 9, // reserved for m + 10, // reserved for g + REGSP, // reserved for SP }; void @@ -401,6 +364,7 @@ regalloc(Node *n, Type *t, Node *o) regpc[i] = (uintptr)getcallerpc(&n); goto out; } + print("registers allocated at\n"); for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++) print("%d %p\n", i, regpc[i]); yyerror("out of fixed registers"); @@ -452,15 +416,17 @@ regfree(Node *n) print("regalloc fix %d float %d\n", fixfree, floatfree); } - if(n->op == ONAME && iscomplex[n->type->etype]) + if(n->op == ONAME) return; if(n->op != OREGISTER && n->op != OINDREG) fatal("regfree: not a register"); i = n->val.u.reg; + if(i == REGSP) + return; if(i < 0 || i >= nelem(reg) || i >= nelem(regpc)) fatal("regfree: reg out of range"); if(reg[i] <= 0) - fatal("regfree: reg not allocated"); + fatal("regfree: reg %R not allocated", i); reg[i]--; if(reg[i] == 0) regpc[i] = 0; @@ -597,9 +563,9 @@ split64(Node *n, Node *lo, Node *hi) if(!is64(n->type)) fatal("split64 %T", n->type); - sclean[nsclean].op = OEMPTY; if(nsclean >= nelem(sclean)) fatal("split64 clean"); + sclean[nsclean].op = OEMPTY; nsclean++; switch(n->op) { default: @@ -1155,7 +1121,7 @@ gcmp(int as, Node *lhs, Node *rhs) { Prog *p; - if(lhs->op != OREGISTER || rhs->op != OREGISTER) + if(lhs->op != OREGISTER) fatal("bad operands to gcmp: %O %O", lhs->op, rhs->op); p = gins(as, rhs, N); @@ -1194,6 +1160,27 @@ gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs) return p; } +// Generate an instruction referencing *n +// to force segv on nil pointer dereference. +void +checkref(Node *n) +{ + Node m1, m2; + + if(n->type->type->width < unmappedzero) + return; + + regalloc(&m1, types[TUINTPTR], n); + regalloc(&m2, types[TUINT8], n); + cgen(n, &m1); + m1.xoffset = 0; + m1.op = OINDREG; + m1.type = types[TUINT8]; + gins(AMOVBU, &m1, &m2); + regfree(&m2); + regfree(&m1); +} + static void checkoffset(Addr *a, int canemitcode) { @@ -1209,7 +1196,7 @@ checkoffset(Addr *a, int canemitcode) // reference with large offset. instead, emit explicit // test of 0(reg). regalloc(&n1, types[TUINTPTR], N); - p = gins(AMOVW, N, &n1); + p = gins(AMOVB, N, &n1); p->from = *a; p->from.offset = 0; regfree(&n1); @@ -1222,14 +1209,22 @@ checkoffset(Addr *a, int canemitcode) void naddr(Node *n, Addr *a, int canemitcode) { + Prog *p; + a->type = D_NONE; a->name = D_NONE; a->reg = NREG; + a->gotype = S; a->node = N; a->etype = 0; if(n == N) return; + if(n->type != T && n->type->etype != TIDEAL) { + dowidth(n->type); + a->width = n->type->width; + } + switch(n->op) { default: fatal("naddr: bad %O %D", n->op, a); @@ -1286,6 +1281,25 @@ naddr(Node *n, Addr *a, int canemitcode) a->name = D_PARAM; a->node = n->left->orig; break; + + case OCLOSUREVAR: + if(!canemitcode) + fatal("naddr OCLOSUREVAR cannot emit code"); + p = gins(AMOVW, N, N); + p->from.type = D_OREG; + p->from.reg = 7; + p->from.offset = n->xoffset; + p->to.type = D_REG; + p->to.reg = 1; + a->type = D_REG; + a->reg = 1; + a->sym = S; + break; + + case OCFUNC: + naddr(n->left, a, canemitcode); + a->sym = n->left->sym; + break; case ONAME: a->etype = 0; @@ -1326,6 +1340,7 @@ naddr(Node *n, Addr *a, int canemitcode) case PFUNC: a->name = D_EXTERN; a->type = D_CONST; + a->sym = funcsym(a->sym); break; } break; @@ -1337,7 +1352,7 @@ naddr(Node *n, Addr *a, int canemitcode) break; case CTFLT: a->type = D_FCONST; - a->dval = mpgetflt(n->val.u.fval); + a->u.dval = mpgetflt(n->val.u.fval); break; case CTINT: case CTRUNE: @@ -1409,6 +1424,9 @@ naddr(Node *n, Addr *a, int canemitcode) fatal("naddr: OADDR %d\n", a->type); } } + + if(a->width < 0) + fatal("naddr: bad width for %N -> %D", n, a); } /* @@ -1619,6 +1637,16 @@ optoas(int op, Type *t) a = ASUBD; break; + case CASE(OMINUS, TINT8): + case CASE(OMINUS, TUINT8): + case CASE(OMINUS, TINT16): + case CASE(OMINUS, TUINT16): + case CASE(OMINUS, TINT32): + case CASE(OMINUS, TUINT32): + case CASE(OMINUS, TPTR32): + a = ARSB; + break; + case CASE(OAND, TINT8): case CASE(OAND, TUINT8): case CASE(OAND, TINT16): @@ -1825,6 +1853,9 @@ sudoaddable(int as, Node *n, Addr *a, int *w) goto odot; case OINDEX: + return 0; + // disabled: OINDEX case is now covered by agenr + // for a more suitable register allocation pattern. if(n->left->type->etype == TSTRING) return 0; cleani += 2; @@ -1942,7 +1973,7 @@ oindex: t = types[TINT32]; regalloc(reg1, t, N); regalloc(&n3, types[TINT32], reg1); - p2 = cgenindex(r, &n3); + p2 = cgenindex(r, &n3, debug['B'] || n->bounded); gmove(&n3, reg1); regfree(&n3); @@ -1982,7 +2013,7 @@ oindex: cgen(&n2, &n3); gcmp(optoas(OCMP, types[TUINT32]), reg1, &n3); regfree(&n3); - p1 = gbranch(optoas(OLT, types[TUINT32]), T); + p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1); if(p2) patch(p2, pc); ginscall(panicindex, 0); @@ -2032,7 +2063,7 @@ oindex_const: v = mpgetfix(r->val.u.xval); if(o & ODynam) { - if(!debug['B'] && !n->etype) { + if(!debug['B'] && !n->bounded) { n1 = *reg; n1.op = OINDREG; n1.type = types[tptr]; @@ -2045,7 +2076,7 @@ oindex_const: gcmp(optoas(OCMP, types[TUINT32]), &n4, &n3); regfree(&n4); regfree(&n3); - p1 = gbranch(optoas(OGT, types[TUINT32]), T); + p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1); ginscall(panicindex, 0); patch(p1, pc); } diff --git a/src/cmd/5g/list.c b/src/cmd/5g/list.c index f0da24742..6c3f1d744 100644 --- a/src/cmd/5g/list.c +++ b/src/cmd/5g/list.c @@ -153,6 +153,12 @@ Dconv(Fmt *fp) sprint(str, "%M(R%d)(REG)", a, a->reg); break; + case D_REGREG2: + sprint(str, "R%d,R%d", a->reg, (int)a->offset); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%M(R%d)(REG)", a, a->reg); + break; + case D_FREG: sprint(str, "F%d", a->reg); if(a->name != D_NONE || a->sym != S) @@ -160,24 +166,24 @@ Dconv(Fmt *fp) break; case D_BRANCH: - if(a->branch == P || a->branch->loc == 0) { + if(a->u.branch == P || a->u.branch->loc == 0) { if(a->sym != S) sprint(str, "%s+%d(APC)", a->sym->name, a->offset); else sprint(str, "%d(APC)", a->offset); } else if(a->sym != S) - sprint(str, "%s+%d(APC)", a->sym->name, a->branch->loc); + sprint(str, "%s+%d(APC)", a->sym->name, a->u.branch->loc); else - sprint(str, "%d(APC)", a->branch->loc); + sprint(str, "%d(APC)", a->u.branch->loc); break; case D_FCONST: - snprint(str, sizeof(str), "$(%.17e)", a->dval); + snprint(str, sizeof(str), "$(%.17e)", a->u.dval); break; case D_SCONST: - snprint(str, sizeof(str), "$\"%Y\"", a->sval); + snprint(str, sizeof(str), "$\"%Y\"", a->u.sval); break; // TODO(kaib): Add back @@ -190,7 +196,10 @@ Dconv(Fmt *fp) // goto conv; } conv: - return fmtstrcpy(fp, str); + fmtstrcpy(fp, str); + if(a->gotype) + fmtprint(fp, "{%s}", a->gotype->name); + return 0; } int diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h index 7a0070fc9..af7d654de 100644 --- a/src/cmd/5g/opt.h +++ b/src/cmd/5g/opt.h @@ -34,8 +34,6 @@ #define D_HI D_NONE #define D_LO D_NONE -#define isregtype(t) ((t)>= D_AX && (t)<=D_R15) - #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]) @@ -49,12 +47,16 @@ typedef struct Reg Reg; typedef struct Rgn Rgn; +// A Reg is a wrapper around a single Prog (one instruction) that holds +// register optimization information while the optimizer runs. +// r->prog is the instruction. +// r->prog->regp points back to r. struct Reg { - Bits set; - Bits use1; - Bits use2; + Bits set; // variables written by this instruction. + Bits use1; // variables read by prog->from. + Bits use2; // variables read by prog->to. Bits refbehind; Bits refahead; @@ -70,13 +72,13 @@ struct Reg uint16 loop; // x5 for every loop uchar refset; // diagnostic generated - Reg* p1; - Reg* p2; + Reg* p1; // predecessors of this instruction: p1, + Reg* p2; // and then p2 linked though p2link. Reg* p2link; - Reg* s1; + Reg* s1; // successors of this instruction (at most two: s1 and s2). Reg* s2; - Reg* link; - Prog* prog; + Reg* link; // next instruction in function code + Prog* prog; // actual instruction }; #define R ((Reg*)0) diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c index e87f5d697..b6202a882 100644 --- a/src/cmd/5g/peep.c +++ b/src/cmd/5g/peep.c @@ -1,5 +1,5 @@ // Inferno utils/5c/peep.c -// http://code.google.com/p/inferno-os/source/browse/utils/5g/peep.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/peep.c // // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) @@ -49,7 +49,6 @@ peep(void) int t; p1 = nil; - USED(p1); // ... in unreachable code... /* * complete R structure */ @@ -77,6 +76,8 @@ peep(void) case AGLOBL: case ANAME: case ASIGNAME: + case ALOCALS: + case ATYPE: p = p->link; } } @@ -120,7 +121,7 @@ loop1: } break; -#ifdef NOTDEF +#ifdef NOTDEF if(p->scond == C_SCOND_NONE) if(regtyp(&p->to)) if(isdconst(&p->from)) { @@ -133,26 +134,24 @@ loop1: if(t) goto loop1; -return; -#ifdef NOTDEF for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { -// case AEOR: -// /* -// * EOR -1,x,y => MVN x,y -// */ -// if(isdconst(&p->from) && p->from.offset == -1) { -// p->as = AMVN; -// p->from.type = D_REG; -// if(p->reg != NREG) -// p->from.reg = p->reg; -// else -// p->from.reg = p->to.reg; -// p->reg = NREG; -// } -// break; + case AEOR: + /* + * EOR -1,x,y => MVN x,y + */ + if(isdconst(&p->from) && p->from.offset == -1) { + p->as = AMVN; + p->from.type = D_REG; + if(p->reg != NREG) + p->from.reg = p->reg; + else + p->from.reg = p->to.reg; + p->reg = NREG; + } + break; case AMOVH: case AMOVHU: @@ -161,6 +160,7 @@ return; /* * look for MOVB x,R; MOVB R,R */ + r1 = r->link; if(p->to.type != D_REG) break; if(r1 == R) @@ -175,23 +175,22 @@ return; excise(r1); break; } - r1 = r->link; } -// for(r=firstr; r!=R; r=r->link) { -// p = r->prog; -// switch(p->as) { -// case AMOVW: -// case AMOVB: -// case AMOVBU: -// if(p->from.type == D_OREG && p->from.offset == 0) -// xtramodes(r, &p->from); -// else -// if(p->to.type == D_OREG && p->to.offset == 0) -// xtramodes(r, &p->to); -// else -// continue; -// break; + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + switch(p->as) { + case AMOVW: + case AMOVB: + case AMOVBU: + if(p->from.type == D_OREG && p->from.offset == 0) + xtramodes(r, &p->from); + else + if(p->to.type == D_OREG && p->to.offset == 0) + xtramodes(r, &p->to); + else + continue; + break; // case ACMP: // /* // * elide CMP $0,x if calculation of x can set condition codes @@ -259,13 +258,17 @@ return; // r2->prog->as = t; // excise(r); // continue; -// } -// } + } + } - predicate(); -#endif +// predicate(); } +/* + * uniqp returns a "unique" predecessor to instruction r. + * If the instruction is the first one or has multiple + * predecessors due to jump, R is returned. + */ Reg* uniqp(Reg *r) { @@ -738,6 +741,11 @@ shiftprop(Reg *r) return 1; } +/* + * findpre returns the last instruction mentioning v + * before r. It must be a set, and there must be + * a unique path from that instruction to r. + */ Reg* findpre(Reg *r, Adr *v) { @@ -758,6 +766,10 @@ findpre(Reg *r, Adr *v) return R; } +/* + * findinc finds ADD instructions with a constant + * argument which falls within the immed_12 range. + */ Reg* findinc(Reg *r, Reg *r2, Adr *v) { @@ -848,6 +860,19 @@ finduse(Reg *r, Adr *v) return findu1(r, v); } +/* + * xtramodes enables the ARM post increment and + * shift offset addressing modes to transform + * MOVW 0(R3),R1 + * ADD $4,R3,R3 + * into + * MOVW.P 4(R3),R1 + * and + * ADD R0,R1 + * MOVBU 0(R1),R0 + * into + * MOVBU R0<<0(R1),R0 + */ int xtramodes(Reg *r, Adr *a) { @@ -856,8 +881,6 @@ xtramodes(Reg *r, Adr *a) Adr v; p = r->prog; - if(debug['h'] && p->as == AMOVB && p->from.type == D_OREG) /* byte load */ - return 0; v = *a; v.type = D_REG; r1 = findpre(r, &v); @@ -866,6 +889,9 @@ xtramodes(Reg *r, Adr *a) if(p1->to.type == D_REG && p1->to.reg == v.reg) switch(p1->as) { case AADD: + if(p1->scond & C_SBIT) + // avoid altering ADD.S/ADC sequences. + break; if(p1->from.type == D_REG || (p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 && (p->as != AMOVB || (a == &p->from && (p1->from.offset&~0xf) == 0))) || @@ -1032,6 +1058,7 @@ copyu(Prog *p, Adr *v, Adr *s) return 0; case AMULLU: /* read, read, write, write */ + case AMULL: case AMULA: case AMVN: return 2; @@ -1135,12 +1162,9 @@ copyu(Prog *p, Adr *v, Adr *s) return 0; case ARET: /* funny */ - if(v->type == D_REG) - if(v->reg == REGRET) - return 2; - if(v->type == D_FREG) - if(v->reg == FREGRET) - return 2; + if(s != A) + return 1; + return 3; case ABL: /* funny */ if(v->type == D_REG) { @@ -1152,6 +1176,8 @@ copyu(Prog *p, Adr *v, Adr *s) if(v->type == D_FREG) if(v->reg <= FREGEXT && v->reg > exfregoffset) return 2; + if(p->from.type == D_REG && v->type == D_REG && p->from.reg == v->reg) + return 2; if(s != A) { if(copysub(&p->to, v, s, 1)) @@ -1167,6 +1193,9 @@ copyu(Prog *p, Adr *v, Adr *s) if(v->reg == (uchar)REGARG) return 3; return 0; + + case ALOCALS: /* funny */ + return 0; } } @@ -1213,7 +1242,7 @@ copyau(Adr *a, Adr *v) if(a->reg == v->reg) return 1; } else - if(a->type == D_REGREG) { + if(a->type == D_REGREG || a->type == D_REGREG2) { if(a->reg == v->reg) return 1; if(a->offset == v->reg) @@ -1276,7 +1305,7 @@ copysub(Adr *a, Adr *v, Adr *s, int f) if((a->offset&(1<<4)) && (a->offset>>8) == v->reg) a->offset = (a->offset&~(0xf<<8))|(s->reg<<8); } else - if(a->type == D_REGREG) { + if(a->type == D_REGREG || a->type == D_REGREG2) { if(a->offset == v->reg) a->offset = s->reg; if(a->reg == v->reg) diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c index 393266973..eaaaf9be3 100644 --- a/src/cmd/5g/reg.c +++ b/src/cmd/5g/reg.c @@ -1,5 +1,5 @@ // Inferno utils/5c/reg.c -// http://code.google.com/p/inferno-os/source/browse/utils/5g/reg.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/reg.c // // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) @@ -34,8 +34,8 @@ #include "gg.h" #include "opt.h" -#define NREGVAR 24 -#define REGBITS ((uint32)0xffffff) +#define NREGVAR 32 +#define REGBITS ((uint32)0xffffffff) #define P2R(p) (Reg*)(p->reg) void addsplits(void); @@ -95,7 +95,7 @@ setoutvar(void) ovar.b[z] |= bit.b[z]; t = structnext(&save); } -//if(bany(ovar)) +//if(bany(&ovar)) //print("ovar = %Q\n", ovar); } @@ -160,8 +160,18 @@ static char* regname[] = { ".F5", ".F6", ".F7", + ".F8", + ".F9", + ".F10", + ".F11", + ".F12", + ".F13", + ".F14", + ".F15", }; +static Node* regnodes[NREGVAR]; + void regopt(Prog *firstp) { @@ -197,7 +207,6 @@ regopt(Prog *firstp) return; } - r1 = R; firstr = R; lastr = R; @@ -208,8 +217,11 @@ regopt(Prog *firstp) */ nvar = NREGVAR; memset(var, 0, NREGVAR*sizeof var[0]); - for(i=0; i<NREGVAR; i++) - var[i].node = newname(lookup(regname[i])); + for(i=0; i<NREGVAR; i++) { + if(regnodes[i] == N) + regnodes[i] = newname(lookup(regname[i])); + var[i].node = regnodes[i]; + } regbits = RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC); for(z=0; z<BITS; z++) { @@ -236,6 +248,8 @@ regopt(Prog *firstp) case AGLOBL: case ANAME: case ASIGNAME: + case ALOCALS: + case ATYPE: continue; } r = rega(); @@ -263,6 +277,10 @@ regopt(Prog *firstp) } } + // Avoid making variables for direct-called functions. + if(p->as == ABL && p->to.type == D_EXTERN) + continue; + /* * left side always read */ @@ -408,10 +426,14 @@ regopt(Prog *firstp) addrs.b[z] |= bit.b[z]; } -// print("bit=%2d addr=%d et=%-6E w=%-2d s=%S + %lld\n", -// i, v->addr, v->etype, v->width, v->sym, v->offset); + if(debug['R'] && debug['v']) + print("bit=%2d addr=%d et=%-6E w=%-2d s=%N + %lld\n", + i, v->addr, v->etype, v->width, v->node, v->offset); } + if(debug['R'] && debug['v']) + dumpit("pass1", firstr); + /* * pass 2 * turn branch references to pointers @@ -420,9 +442,9 @@ regopt(Prog *firstp) for(r=firstr; r!=R; r=r->link) { p = r->prog; if(p->to.type == D_BRANCH) { - if(p->to.branch == P) + if(p->to.u.branch == P) fatal("pnil %P", p); - r1 = p->to.branch->regp; + r1 = p->to.u.branch->regp; if(r1 == R) fatal("rnil %P", p); if(r1 == r) { @@ -440,6 +462,9 @@ regopt(Prog *firstp) print(" addr = %Q\n", addrs); } + if(debug['R'] && debug['v']) + dumpit("pass2", firstr); + /* * pass 2.5 * find looping structure @@ -449,6 +474,9 @@ regopt(Prog *firstp) change = 0; loopit(firstr, nr); + if(debug['R'] && debug['v']) + dumpit("pass2.5", firstr); + /* * pass 3 * iterate propagating usage @@ -476,6 +504,9 @@ loop11: if(change) goto loop1; + if(debug['R'] && debug['v']) + dumpit("pass3", firstr); + /* * pass 4 @@ -492,6 +523,9 @@ loop2: addsplits(); + if(debug['R'] && debug['v']) + dumpit("pass4", firstr); + if(debug['R'] > 1) { print("\nprop structure:\n"); for(r = firstr; r != R; r = r->link) { @@ -543,6 +577,9 @@ loop2: r->act.b[0] &= ~REGBITS; } + if(debug['R'] && debug['v']) + dumpit("pass4.5", firstr); + /* * pass 5 * isolate regions @@ -605,6 +642,9 @@ loop2: brk: qsort(region, nregion, sizeof(region[0]), rcmp); + if(debug['R'] && debug['v']) + dumpit("pass5", firstr); + /* * pass 6 * determine used registers (paint2) @@ -633,6 +673,10 @@ brk: paint3(rgp->enter, rgp->varno, vreg, rgp->regno); rgp++; } + + if(debug['R'] && debug['v']) + dumpit("pass6", firstr); + /* * pass 7 * peep-hole on basic block @@ -641,6 +685,9 @@ brk: peep(); } + if(debug['R'] && debug['v']) + dumpit("pass7", firstr); + /* * last pass * eliminate nops @@ -662,8 +709,8 @@ brk: while(p->link != P && p->link->as == ANOP) p->link = p->link->link; if(p->to.type == D_BRANCH) - while(p->to.branch != P && p->to.branch->as == ANOP) - p->to.branch = p->to.branch->link; + while(p->to.u.branch != P && p->to.u.branch->as == ANOP) + p->to.u.branch = p->to.u.branch->link; if(p->as == AMOVW && p->to.reg == 13) { if(p->scond & C_WBIT) { vreg = -p->to.offset; // in adjust region @@ -866,6 +913,7 @@ mkvar(Reg *r, Adr *a) goto onereg; case D_REGREG: + case D_REGREG2: bit = zbits; if(a->offset != NREG) bit.b[0] |= RtoB(a->offset); @@ -926,6 +974,8 @@ mkvar(Reg *r, Adr *a) et = a->etype; o = a->offset; w = a->width; + if(w < 0) + fatal("bad width %d for %D", w, a); for(i=0; i<nvar; i++) { v = var+i; @@ -947,8 +997,6 @@ mkvar(Reg *r, Adr *a) switch(et) { case 0: case TFUNC: - case TARRAY: - case TSTRING: goto none; } @@ -964,14 +1012,13 @@ mkvar(Reg *r, Adr *a) v = var+i; v->offset = o; v->name = n; -// v->gotype = a->gotype; v->etype = et; v->width = w; v->addr = flag; // funny punning v->node = node; if(debug['R']) - print("bit=%2d et=%2d w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr); + print("bit=%2d et=%2E w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr); bit = blsh(i); if(n == D_EXTERN || n == D_STATIC) @@ -1033,8 +1080,12 @@ prop(Reg *r, Bits ref, Bits cal) default: // Work around for issue 1304: // flush modified globals before each instruction. - for(z=0; z<BITS; z++) + for(z=0; z<BITS; z++) { cal.b[z] |= externs.b[z]; + // issue 4066: flush modified return variables in case of panic + if(hasdefer) + cal.b[z] |= ovar.b[z]; + } break; } for(z=0; z<BITS; z++) { @@ -1486,11 +1537,12 @@ addreg(Adr *a, int rn) * 1 R1 * ... ... * 10 R10 + * 12 R12 */ int32 RtoB(int r) { - if(r >= REGTMP-2) // excluded R9 and R10 for m and g + if(r >= REGTMP-2 && r != 12) // excluded R9 and R10 for m and g, but not R12 return 0; return 1L << r; } @@ -1498,7 +1550,7 @@ RtoB(int r) int BtoR(int32 b) { - b &= 0x01fcL; // excluded R9 and R10 for m and g + b &= 0x11fcL; // excluded R9 and R10 for m and g, but not R12 if(b == 0) return 0; return bitno(b); @@ -1509,7 +1561,7 @@ BtoR(int32 b) * 18 F2 * 19 F3 * ... ... - * 23 F7 + * 31 F15 */ int32 FtoB(int f) @@ -1524,7 +1576,7 @@ int BtoF(int32 b) { - b &= 0xfc0000L; + b &= 0xfffc0000L; if(b == 0) return 0; return bitno(b) - 16; @@ -1643,7 +1695,7 @@ chasejmp(Prog *p, int *jmploop) *jmploop = 1; break; } - p = p->to.branch; + p = p->to.u.branch; } return p; } @@ -1665,8 +1717,8 @@ mark(Prog *firstp) if(p->regp != dead) break; p->regp = alive; - if(p->as != ABL && p->to.type == D_BRANCH && p->to.branch) - mark(p->to.branch); + if(p->as != ABL && p->to.type == D_BRANCH && p->to.u.branch) + mark(p->to.u.branch); if(p->as == AB || p->as == ARET || (p->as == ABL && noreturn(p))) break; } @@ -1686,8 +1738,8 @@ fixjmp(Prog *firstp) for(p=firstp; p; p=p->link) { if(debug['R'] && debug['v']) print("%P\n", p); - if(p->as != ABL && p->to.type == D_BRANCH && p->to.branch && p->to.branch->as == AB) { - p->to.branch = chasejmp(p->to.branch, &jmploop); + if(p->as != ABL && p->to.type == D_BRANCH && p->to.u.branch && p->to.u.branch->as == AB) { + p->to.u.branch = chasejmp(p->to.u.branch, &jmploop); if(debug['R'] && debug['v']) print("->%P\n", p); } @@ -1695,7 +1747,7 @@ fixjmp(Prog *firstp) } if(debug['R'] && debug['v']) print("\n"); - + // pass 2: mark all reachable code alive mark(firstp); @@ -1723,7 +1775,7 @@ fixjmp(Prog *firstp) if(!jmploop) { last = nil; for(p=firstp; p; p=p->link) { - if(p->as == AB && p->to.type == D_BRANCH && p->to.branch == p->link) { + if(p->as == AB && p->to.type == D_BRANCH && p->to.u.branch == p->link) { if(debug['R'] && debug['v']) print("del %P\n", p); continue; |