diff options
Diffstat (limited to 'src/cmd/gc/walk.c')
-rw-r--r-- | src/cmd/gc/walk.c | 2177 |
1 files changed, 0 insertions, 2177 deletions
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c deleted file mode 100644 index c9ca9b3b3..000000000 --- a/src/cmd/gc/walk.c +++ /dev/null @@ -1,2177 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go.h" - -static Node* walkprint(Node*, NodeList**, int); -static Node* conv(Node*, Type*); -static Node* mapfn(char*, Type*); -static Node* makenewvar(Type*, NodeList**, Node**); -static Node* ascompatee1(int, Node*, Node*, NodeList**); -static NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**); -static NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**); -static NodeList* ascompatte(int, int, Type**, NodeList*, int, NodeList**); -static Node* convas(Node*, NodeList**); -static void heapmoves(void); -static NodeList* paramstoheap(Type **argin, int out); -static NodeList* reorder1(NodeList*); -static NodeList* reorder3(NodeList*); -static Node* addstr(Node*, NodeList**); -static Node* appendslice(Node*, NodeList**); -static Node* append(Node*, NodeList**); - -// can this code branch reach the end -// without an unconditional RETURN -// this is hard, so it is conservative -static int -walkret(NodeList *l) -{ - Node *n; - -loop: - while(l && l->next) - l = l->next; - if(l == nil) - return 1; - - // at this point, we have the last - // statement of the function - n = l->n; - switch(n->op) { - case OBLOCK: - l = n->list; - goto loop; - - case OGOTO: - case ORETURN: - case OPANIC: - return 0; - break; - } - - // all other statements - // will flow to the end - return 1; -} - -void -walk(Node *fn) -{ - char s[50]; - NodeList *l; - Node *n; - int lno; - - curfn = fn; - - if(debug['W']) { - snprint(s, sizeof(s), "\nbefore %S", curfn->nname->sym); - dumplist(s, curfn->nbody); - } - if(curfn->type->outtuple) - if(walkret(curfn->nbody)) - yyerror("function ends without a return statement"); - - lno = lineno; - for(l=fn->dcl; l; l=l->next) { - n = l->n; - if(n->op != ONAME || n->class != PAUTO) - continue; - lineno = n->lineno; - typecheck(&n, Erv | Easgn); // only needed for unused variables - if(!n->used && n->sym->name[0] != '&' && !nsyntaxerrors) - yyerror("%S declared and not used", n->sym); - } - lineno = lno; - if(nerrors != 0) - return; - walkstmtlist(curfn->nbody); - if(debug['W']) { - snprint(s, sizeof(s), "after walk %S", curfn->nname->sym); - dumplist(s, curfn->nbody); - } - heapmoves(); - if(debug['W'] && curfn->enter != nil) { - snprint(s, sizeof(s), "enter %S", curfn->nname->sym); - dumplist(s, curfn->enter); - } -} - - -void -walkstmtlist(NodeList *l) -{ - for(; l; l=l->next) - walkstmt(&l->n); -} - -static int -samelist(NodeList *a, NodeList *b) -{ - for(; a && b; a=a->next, b=b->next) - if(a->n != b->n) - return 0; - return a == b; -} - -static int -paramoutheap(Node *fn) -{ - NodeList *l; - - for(l=fn->dcl; l; l=l->next) { - switch(l->n->class) { - case PPARAMOUT|PHEAP: - return 1; - case PAUTO: - case PAUTO|PHEAP: - // stop early - parameters are over - return 0; - } - } - return 0; -} - -void -walkstmt(Node **np) -{ - NodeList *init; - NodeList *ll, *rl; - int cl; - Node *n, *f; - - n = *np; - if(n == N) - return; - - setlineno(n); - - switch(n->op) { - default: - if(n->op == ONAME) - yyerror("%S is not a top level statement", n->sym); - else - yyerror("%O is not a top level statement", n->op); - dump("nottop", n); - break; - - case OASOP: - case OAS: - case OAS2: - case OAS2DOTTYPE: - case OAS2RECV: - case OAS2FUNC: - case OAS2MAPW: - case OAS2MAPR: - case OCLOSE: - case OCOPY: - case OCALLMETH: - case OCALLINTER: - case OCALL: - case OCALLFUNC: - case OSEND: - case ORECV: - case OPRINT: - case OPRINTN: - case OPANIC: - case OEMPTY: - case ORECOVER: - if(n->typecheck == 0) { - dump("missing typecheck:", n); - fatal("missing typecheck"); - } - init = n->ninit; - n->ninit = nil; - walkexpr(&n, &init); - n->ninit = concat(init, n->ninit); - break; - - case OBREAK: - case ODCL: - case OCONTINUE: - case OFALL: - case OGOTO: - case OLABEL: - case ODCLCONST: - case ODCLTYPE: - break; - - case OBLOCK: - walkstmtlist(n->list); - break; - - case OXCASE: - yyerror("case statement out of place"); - n->op = OCASE; - case OCASE: - walkstmt(&n->right); - break; - - case ODEFER: - hasdefer = 1; - switch(n->left->op) { - case OPRINT: - case OPRINTN: - walkexprlist(n->left->list, &n->ninit); - n->left = walkprint(n->left, &n->ninit, 1); - break; - default: - walkexpr(&n->left, &n->ninit); - break; - } - break; - - case OFOR: - walkstmtlist(n->ninit); - if(n->ntest != N) { - walkstmtlist(n->ntest->ninit); - init = n->ntest->ninit; - n->ntest->ninit = nil; - walkexpr(&n->ntest, &init); - n->ntest->ninit = concat(init, n->ntest->ninit); - } - walkstmt(&n->nincr); - walkstmtlist(n->nbody); - break; - - case OIF: - walkstmtlist(n->ninit); - walkexpr(&n->ntest, &n->ninit); - walkstmtlist(n->nbody); - walkstmtlist(n->nelse); - break; - - case OPROC: - switch(n->left->op) { - case OPRINT: - case OPRINTN: - walkexprlist(n->left->list, &n->ninit); - n->left = walkprint(n->left, &n->ninit, 1); - break; - default: - walkexpr(&n->left, &n->ninit); - break; - } - break; - - case ORETURN: - walkexprlist(n->list, &n->ninit); - if(n->list == nil) - break; - if((curfn->type->outnamed && count(n->list) > 1) || paramoutheap(curfn)) { - // assign to the function out parameters, - // so that reorder3 can fix up conflicts - rl = nil; - for(ll=curfn->dcl; ll != nil; ll=ll->next) { - cl = ll->n->class & ~PHEAP; - if(cl == PAUTO) - break; - if(cl == PPARAMOUT) - rl = list(rl, ll->n); - } - if(samelist(rl, n->list)) { - // special return in disguise - n->list = nil; - break; - } - if(count(n->list) == 1 && count(rl) > 1) { - // OAS2FUNC in disguise - f = n->list->n; - if(f->op != OCALLFUNC && f->op != OCALLMETH && f->op != OCALLINTER) - fatal("expected return of call, have %#N", f); - n->list = concat(list1(f), ascompatet(n->op, rl, &f->type, 0, &n->ninit)); - break; - } - ll = ascompatee(n->op, rl, n->list, &n->ninit); - n->list = reorder3(ll); - break; - } - ll = ascompatte(n->op, 0, getoutarg(curfn->type), n->list, 1, &n->ninit); - n->list = ll; - break; - - case OSELECT: - walkselect(n); - break; - - case OSWITCH: - walkswitch(n); - break; - - case ORANGE: - walkrange(n); - break; - - case OXFALL: - yyerror("fallthrough statement out of place"); - n->op = OFALL; - break; - } - - *np = n; -} - - -/* - * walk the whole tree of the body of an - * expression or simple statement. - * the types expressions are calculated. - * compile-time constants are evaluated. - * complex side effects like statements are appended to init - */ - -void -walkexprlist(NodeList *l, NodeList **init) -{ - for(; l; l=l->next) - walkexpr(&l->n, init); -} - -void -walkexprlistsafe(NodeList *l, NodeList **init) -{ - for(; l; l=l->next) { - l->n = safeexpr(l->n, init); - walkexpr(&l->n, init); - } -} - -void -walkexpr(Node **np, NodeList **init) -{ - Node *r, *l, *var, *a; - NodeList *ll, *lr, *lpost; - Type *t; - int et; - int64 v, v1, v2, len; - int32 lno; - Node *n, *fn; - char buf[100], *p; - - n = *np; - - if(n == N) - return; - - if(init == &n->ninit) { - // not okay to use n->ninit when walking n, - // because we might replace n with some other node - // and would lose the init list. - fatal("walkexpr init == &n->ninit"); - } - - // annoying case - not typechecked - if(n->op == OKEY) { - walkexpr(&n->left, init); - walkexpr(&n->right, init); - return; - } - - lno = setlineno(n); - - if(debug['w'] > 1) - dump("walk-before", n); - - if(n->typecheck != 1) { - dump("missed typecheck", n); - fatal("missed typecheck"); - } - - t = T; - et = Txxx; - - switch(n->op) { - default: - dump("walk", n); - fatal("walkexpr: switch 1 unknown op %N", n); - goto ret; - - case OTYPE: - case ONONAME: - case OINDREG: - case OEMPTY: - goto ret; - - case ONOT: - case OMINUS: - case OPLUS: - case OCOM: - case OREAL: - case OIMAG: - case ODOT: - case ODOTPTR: - case ODOTMETH: - case ODOTINTER: - case OIND: - walkexpr(&n->left, init); - goto ret; - - case OLEN: - case OCAP: - walkexpr(&n->left, init); - - // replace len(*[10]int) with 10. - // delayed until now to preserve side effects. - t = n->left->type; - if(isptr[t->etype]) - t = t->type; - if(isfixedarray(t)) { - safeexpr(n->left, init); - nodconst(n, n->type, t->bound); - n->typecheck = 1; - } - goto ret; - - case OLSH: - case ORSH: - case OAND: - case OOR: - case OXOR: - case OSUB: - case OMUL: - case OEQ: - case ONE: - case OLT: - case OLE: - case OGE: - case OGT: - case OADD: - case OCOMPLEX: - walkexpr(&n->left, init); - walkexpr(&n->right, init); - goto ret; - - case OANDAND: - case OOROR: - walkexpr(&n->left, init); - // cannot put side effects from n->right on init, - // because they cannot run before n->left is checked. - // save elsewhere and store on the eventual n->right. - ll = nil; - walkexpr(&n->right, &ll); - n->right->ninit = concat(n->right->ninit, ll); - goto ret; - - case OPRINT: - case OPRINTN: - walkexprlist(n->list, init); - n = walkprint(n, init, 0); - goto ret; - - case OPANIC: - n = mkcall("panic", T, init, n->left); - goto ret; - - case ORECOVER: - n = mkcall("recover", n->type, init, nod(OADDR, nodfp, N)); - goto ret; - - case OLITERAL: - n->addable = 1; - goto ret; - - case ONAME: - if(!(n->class & PHEAP) && n->class != PPARAMREF) - n->addable = 1; - goto ret; - - case OCALLINTER: - t = n->left->type; - if(n->list && n->list->n->op == OAS) - goto ret; - walkexpr(&n->left, init); - walkexprlist(n->list, init); - ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init); - n->list = reorder1(ll); - goto ret; - - case OCALLFUNC: - t = n->left->type; - if(n->list && n->list->n->op == OAS) - goto ret; - - if(n->left->op == OCLOSURE) { - walkcallclosure(n, init); - t = n->left->type; - } - - walkexpr(&n->left, init); - walkexprlist(n->list, init); - - ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init); - n->list = reorder1(ll); - if(isselect(n)) { - // special prob with selectsend and selectrecv: - // if chan is nil, they don't know big the channel - // element is and therefore don't know how to find - // the output bool, so we clear it before the call. - Node *b; - b = nodbool(0); - typecheck(&b, Erv); - lr = ascompatte(n->op, 0, getoutarg(t), list1(b), 0, init); - n->list = concat(n->list, lr); - } - goto ret; - - case OCALLMETH: - t = n->left->type; - if(n->list && n->list->n->op == OAS) - goto ret; - walkexpr(&n->left, init); - walkexprlist(n->list, init); - ll = ascompatte(n->op, 0, getthis(t), list1(n->left->left), 0, init); - lr = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init); - ll = concat(ll, lr); - n->left->left = N; - ullmancalc(n->left); - n->list = reorder1(ll); - goto ret; - - case OAS: - *init = concat(*init, n->ninit); - n->ninit = nil; - walkexpr(&n->left, init); - n->left = safeexpr(n->left, init); - - if(oaslit(n, init)) - goto ret; - - walkexpr(&n->right, init); - if(n->left != N && n->right != N) { - r = convas(nod(OAS, n->left, n->right), init); - r->dodata = n->dodata; - n = r; - } - - goto ret; - - case OAS2: - *init = concat(*init, n->ninit); - n->ninit = nil; - walkexprlistsafe(n->list, init); - walkexprlistsafe(n->rlist, init); - ll = ascompatee(OAS, n->list, n->rlist, init); - ll = reorder3(ll); - n = liststmt(ll); - goto ret; - - case OAS2FUNC: - as2func: - // a,b,... = fn() - *init = concat(*init, n->ninit); - n->ninit = nil; - r = n->rlist->n; - walkexprlistsafe(n->list, init); - walkexpr(&r, init); - l = n->list->n; - - // all the really hard stuff - explicit function calls and so on - - // is gone, but map assignments remain. - // if there are map assignments here, assign via - // temporaries, because ascompatet assumes - // the targets can be addressed without function calls - // and map index has an implicit one. - lpost = nil; - if(l->op == OINDEXMAP) { - var = nod(OXXX, N, N); - tempname(var, l->type); - n->list->n = var; - a = nod(OAS, l, var); - typecheck(&a, Etop); - lpost = list(lpost, a); - } - l = n->list->next->n; - if(l->op == OINDEXMAP) { - var = nod(OXXX, N, N); - tempname(var, l->type); - n->list->next->n = var; - a = nod(OAS, l, var); - typecheck(&a, Etop); - lpost = list(lpost, a); - } - ll = ascompatet(n->op, n->list, &r->type, 0, init); - walkexprlist(lpost, init); - n = liststmt(concat(concat(list1(r), ll), lpost)); - goto ret; - - case OAS2RECV: - *init = concat(*init, n->ninit); - n->ninit = nil; - r = n->rlist->n; - walkexprlistsafe(n->list, init); - walkexpr(&r->left, init); - fn = chanfn("chanrecv2", 2, r->left->type); - r = mkcall1(fn, getoutargx(fn->type), init, r->left); - n->rlist->n = r; - n->op = OAS2FUNC; - goto as2func; - - case OAS2MAPR: - // a,b = m[i]; - *init = concat(*init, n->ninit); - n->ninit = nil; - r = n->rlist->n; - walkexprlistsafe(n->list, init); - walkexpr(&r->left, init); - fn = mapfn("mapaccess2", r->left->type); - r = mkcall1(fn, getoutargx(fn->type), init, r->left, r->right); - n->rlist = list1(r); - n->op = OAS2FUNC; - goto as2func; - - case OAS2MAPW: - // map[] = a,b - mapassign2 - // a,b = m[i]; - *init = concat(*init, n->ninit); - n->ninit = nil; - walkexprlistsafe(n->list, init); - l = n->list->n; - t = l->left->type; - n = mkcall1(mapfn("mapassign2", t), T, init, l->left, l->right, n->rlist->n, n->rlist->next->n); - goto ret; - - case OAS2DOTTYPE: - // a,b = i.(T) - *init = concat(*init, n->ninit); - n->ninit = nil; - r = n->rlist->n; - walkexprlistsafe(n->list, init); - r->op = ODOTTYPE2; - walkexpr(&r, init); - ll = ascompatet(n->op, n->list, &r->type, 0, init); - n = liststmt(concat(list1(r), ll)); - goto ret; - - case ODOTTYPE: - case ODOTTYPE2: - // Build name of function: assertI2E2 etc. - strcpy(buf, "assert"); - p = buf+strlen(buf); - if(isnilinter(n->left->type)) - *p++ = 'E'; - else - *p++ = 'I'; - *p++ = '2'; - if(isnilinter(n->type)) - *p++ = 'E'; - else if(isinter(n->type)) - *p++ = 'I'; - else - *p++ = 'T'; - if(n->op == ODOTTYPE2) - *p++ = '2'; - *p = '\0'; - - fn = syslook(buf, 1); - ll = list1(typename(n->type)); - ll = list(ll, n->left); - argtype(fn, n->left->type); - argtype(fn, n->type); - n = nod(OCALL, fn, N); - n->list = ll; - typecheck(&n, Erv | Efnstruct); - walkexpr(&n, init); - goto ret; - - case OCONVIFACE: - // Build name of function: convI2E etc. - // Not all names are possible - // (e.g., we'll never generate convE2E or convE2I). - walkexpr(&n->left, init); - strcpy(buf, "conv"); - p = buf+strlen(buf); - if(isnilinter(n->left->type)) - *p++ = 'E'; - else if(isinter(n->left->type)) - *p++ = 'I'; - else - *p++ = 'T'; - *p++ = '2'; - if(isnilinter(n->type)) - *p++ = 'E'; - else - *p++ = 'I'; - *p = '\0'; - - fn = syslook(buf, 1); - ll = nil; - if(!isinter(n->left->type)) - ll = list(ll, typename(n->left->type)); - if(!isnilinter(n->type)) - ll = list(ll, typename(n->type)); - ll = list(ll, n->left); - argtype(fn, n->left->type); - argtype(fn, n->type); - dowidth(fn->type); - n = nod(OCALL, fn, N); - n->list = ll; - typecheck(&n, Erv); - walkexpr(&n, init); - goto ret; - - case OCONV: - case OCONVNOP: - if(thechar == '5') { - if(isfloat[n->left->type->etype]) { - if(n->type->etype == TINT64) { - n = mkcall("float64toint64", n->type, init, conv(n->left, types[TFLOAT64])); - goto ret; - } - if(n->type->etype == TUINT64) { - n = mkcall("float64touint64", n->type, init, conv(n->left, types[TFLOAT64])); - goto ret; - } - } - if(isfloat[n->type->etype]) { - if(n->left->type->etype == TINT64) { - n = mkcall("int64tofloat64", n->type, init, conv(n->left, types[TINT64])); - goto ret; - } - if(n->left->type->etype == TUINT64) { - n = mkcall("uint64tofloat64", n->type, init, conv(n->left, types[TUINT64])); - goto ret; - } - } - } - walkexpr(&n->left, init); - goto ret; - - case OASOP: - if(n->etype == OANDNOT) { - n->etype = OAND; - n->right = nod(OCOM, n->right, N); - typecheck(&n->right, Erv); - } - n->left = safeexpr(n->left, init); - walkexpr(&n->left, init); - l = n->left; - walkexpr(&n->right, init); - - /* - * on 32-bit arch, rewrite 64-bit ops into l = l op r. - * on 386, rewrite float ops into l = l op r. - * everywhere, rewrite map ops into l = l op r. - * everywhere, rewrite string += into l = l op r. - * everywhere, rewrite complex /= into l = l op r. - * TODO(rsc): Maybe this rewrite should be done always? - */ - et = n->left->type->etype; - if((widthptr == 4 && (et == TUINT64 || et == TINT64)) || - (thechar == '8' && isfloat[et]) || - l->op == OINDEXMAP || - et == TSTRING || - (iscomplex[et] && n->etype == ODIV)) { - l = safeexpr(n->left, init); - a = l; - if(a->op == OINDEXMAP) { - // map index has "lhs" bit set in a->etype. - // make a copy so we can clear it on the rhs. - a = nod(OXXX, N, N); - *a = *l; - a->etype = 0; - } - r = nod(OAS, l, nod(n->etype, a, n->right)); - typecheck(&r, Etop); - walkexpr(&r, init); - n = r; - } - goto ret; - - case OANDNOT: - walkexpr(&n->left, init); - walkexpr(&n->right, init); - n->op = OAND; - n->right = nod(OCOM, n->right, N); - typecheck(&n->right, Erv); - goto ret; - - case ODIV: - case OMOD: - walkexpr(&n->left, init); - walkexpr(&n->right, init); - /* - * rewrite complex div into function call. - */ - et = n->left->type->etype; - if(iscomplex[et] && n->op == ODIV) { - t = n->type; - n = mkcall("complex128div", types[TCOMPLEX128], init, - conv(n->left, types[TCOMPLEX128]), - conv(n->right, types[TCOMPLEX128])); - n = conv(n, t); - goto ret; - } - /* - * rewrite div and mod into function calls - * on 32-bit architectures. - */ - if(widthptr > 4 || (et != TUINT64 && et != TINT64)) - goto ret; - if(et == TINT64) - strcpy(namebuf, "int64"); - else - strcpy(namebuf, "uint64"); - if(n->op == ODIV) - strcat(namebuf, "div"); - else - strcat(namebuf, "mod"); - n = mkcall(namebuf, n->type, init, - conv(n->left, types[et]), conv(n->right, types[et])); - goto ret; - - case OINDEX: - walkexpr(&n->left, init); - walkexpr(&n->right, init); - - // if range of type cannot exceed static array bound, - // disable bounds check - if(isfixedarray(n->left->type)) - if(n->right->type->width < 4) - if((1<<(8*n->right->type->width)) <= n->left->type->bound) - n->etype = 1; - - if(isconst(n->left, CTSTR)) - if(n->right->type->width < 4) - if((1<<(8*n->right->type->width)) <= n->left->val.u.sval->len) - n->etype = 1; - - // check for static out of bounds - if(isconst(n->right, CTINT) && !n->etype) { - v = mpgetfix(n->right->val.u.xval); - len = 1LL<<60; - t = n->left->type; - if(isconst(n->left, CTSTR)) - len = n->left->val.u.sval->len; - if(t != T && isptr[t->etype]) - t = t->type; - if(isfixedarray(t)) - len = t->bound; - if(v < 0 || v >= (1LL<<31) || v >= len) - yyerror("index out of bounds"); - else if(isconst(n->left, CTSTR)) { - // replace "abc"[2] with 'b'. - // delayed until now because "abc"[2] is not - // an ideal constant. - nodconst(n, n->type, n->left->val.u.sval->s[v]); - } - } - goto ret; - - case OINDEXMAP: - if(n->etype == 1) - goto ret; - - t = n->left->type; - n = mkcall1(mapfn("mapaccess1", t), t->type, init, n->left, n->right); - goto ret; - - case ORECV: - walkexpr(&n->left, init); - walkexpr(&n->right, init); - n = mkcall1(chanfn("chanrecv1", 2, n->left->type), n->type, init, n->left); - goto ret; - - case OSLICE: - case OSLICEARR: - walkexpr(&n->left, init); - n->left = safeexpr(n->left, init); - walkexpr(&n->right->left, init); - n->right->left = safeexpr(n->right->left, init); - walkexpr(&n->right->right, init); - n->right->right = safeexpr(n->right->right, init); - - len = 1LL<<60; - t = n->left->type; - if(t != T && isptr[t->etype]) - t = t->type; - if(isfixedarray(t)) - len = t->bound; - - // check for static out of bounds - // NOTE: v > len not v >= len. - v1 = -1; - v2 = -1; - if(isconst(n->right->left, CTINT)) { - v1 = mpgetfix(n->right->left->val.u.xval); - if(v1 < 0 || v1 >= (1LL<<31) || v1 > len) { - yyerror("slice index out of bounds"); - v1 = -1; - } - } - if(isconst(n->right->right, CTINT)) { - v2 = mpgetfix(n->right->right->val.u.xval); - if(v2 < 0 || v2 >= (1LL<<31) || v2 > len) { - yyerror("slice index out of bounds"); - v2 = -1; - } - } - if(v1 >= 0 && v2 >= 0 && v1 > v2) - yyerror("inverted slice range"); - - if(n->op == OSLICEARR) - goto slicearray; - - // dynamic slice - // sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any) - // sliceslice1(old []any, lb uint64, width uint64) (ary []any) - t = n->type; - et = n->etype; - if(n->right->left == N) - l = nodintconst(0); - else - l = conv(n->right->left, types[TUINT64]); - if(n->right->right != N) { - fn = syslook("sliceslice", 1); - argtype(fn, t->type); // any-1 - argtype(fn, t->type); // any-2 - n = mkcall1(fn, t, init, - n->left, - l, - conv(n->right->right, types[TUINT64]), - nodintconst(t->type->width)); - } else { - fn = syslook("sliceslice1", 1); - argtype(fn, t->type); // any-1 - argtype(fn, t->type); // any-2 - n = mkcall1(fn, t, init, - n->left, - l, - nodintconst(t->type->width)); - } - n->etype = et; // preserve no-typecheck flag from OSLICE to the slice* call. - goto ret; - - slicearray: - // static slice - // slicearray(old *any, uint64 nel, lb uint64, hb uint64, width uint64) (ary []any) - t = n->type; - fn = syslook("slicearray", 1); - argtype(fn, n->left->type->type); // any-1 - argtype(fn, t->type); // any-2 - if(n->right->left == N) - l = nodintconst(0); - else - l = conv(n->right->left, types[TUINT64]); - if(n->right->right == N) - r = nodintconst(n->left->type->type->bound); - else - r = conv(n->right->right, types[TUINT64]); - n = mkcall1(fn, t, init, - n->left, nodintconst(n->left->type->type->bound), - l, - r, - nodintconst(t->type->width)); - goto ret; - - case OADDR:; - Node *nvar, *nstar; - - // turn &Point(1, 2) or &[]int(1, 2) or &[...]int(1, 2) into allocation. - // initialize with - // nvar := new(*Point); - // *nvar = Point(1, 2); - // and replace expression with nvar - switch(n->left->op) { - case OARRAYLIT: - case OMAPLIT: - case OSTRUCTLIT: - nvar = makenewvar(n->type, init, &nstar); - anylit(0, n->left, nstar, init); - n = nvar; - goto ret; - } - - walkexpr(&n->left, init); - goto ret; - - case ONEW: - n = callnew(n->type->type); - goto ret; - - case OCMPSTR: - // If one argument to the comparison is an empty string, - // comparing the lengths instead will yield the same result - // without the function call. - if((isconst(n->left, CTSTR) && n->left->val.u.sval->len == 0) || - (isconst(n->right, CTSTR) && n->right->val.u.sval->len == 0)) { - r = nod(n->etype, nod(OLEN, n->left, N), nod(OLEN, n->right, N)); - typecheck(&r, Erv); - walkexpr(&r, init); - n = r; - goto ret; - } - - // s + "badgerbadgerbadger" == "badgerbadgerbadger" - if((n->etype == OEQ || n->etype == ONE) && - isconst(n->right, CTSTR) && - n->left->op == OADDSTR && isconst(n->left->right, CTSTR) && - cmpslit(n->right, n->left->right) == 0) { - r = nod(n->etype, nod(OLEN, n->left->left, N), nodintconst(0)); - typecheck(&r, Erv); - walkexpr(&r, init); - n = r; - goto ret; - } - - // prepare for rewrite below - if(n->etype == OEQ || n->etype == ONE) { - n->left = cheapexpr(n->left, init); - n->right = cheapexpr(n->right, init); - } - - // sys_cmpstring(s1, s2) :: 0 - r = mkcall("cmpstring", types[TINT], init, - conv(n->left, types[TSTRING]), - conv(n->right, types[TSTRING])); - r = nod(n->etype, r, nodintconst(0)); - - // quick check of len before full compare for == or != - if(n->etype == OEQ || n->etype == ONE) { - if(n->etype == OEQ) - r = nod(OANDAND, nod(OEQ, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r); - else - r = nod(OOROR, nod(ONE, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r); - typecheck(&r, Erv); - walkexpr(&r, nil); - } - typecheck(&r, Erv); - n = r; - goto ret; - - case OADDSTR: - n = addstr(n, init); - goto ret; - - case OSLICESTR: - // sys_slicestring(s, lb, hb) - if(n->right->left == N) - l = nodintconst(0); - else - l = conv(n->right->left, types[TINT]); - if(n->right->right) { - n = mkcall("slicestring", n->type, init, - conv(n->left, types[TSTRING]), - l, - conv(n->right->right, types[TINT])); - } else { - n = mkcall("slicestring1", n->type, init, - conv(n->left, types[TSTRING]), - l); - } - goto ret; - - case OAPPEND: - if(n->isddd) - n = appendslice(n, init); - else - n = append(n, init); - goto ret; - - case OCOPY: - if(n->right->type->etype == TSTRING) - fn = syslook("slicestringcopy", 1); - else - fn = syslook("slicecopy", 1); - argtype(fn, n->left->type); - argtype(fn, n->right->type); - n = mkcall1(fn, n->type, init, - n->left, n->right, - nodintconst(n->left->type->type->width)); - goto ret; - - case OCLOSE: - // cannot use chanfn - closechan takes any, not chan any - fn = syslook("closechan", 1); - argtype(fn, n->left->type); - n = mkcall1(fn, T, init, n->left); - goto ret; - - case OMAKECHAN: - n = mkcall1(chanfn("makechan", 1, n->type), n->type, init, - typename(n->type->type), - conv(n->left, types[TINT64])); - goto ret; - - case OMAKEMAP: - t = n->type; - - fn = syslook("makemap", 1); - argtype(fn, t->down); // any-1 - argtype(fn, t->type); // any-2 - - n = mkcall1(fn, n->type, init, - typename(t->down), // key type - typename(t->type), // value type - conv(n->left, types[TINT64])); - goto ret; - - case OMAKESLICE: - // makeslice(t *Type, nel int64, max int64) (ary []any) - l = n->left; - r = n->right; - if(r == nil) - l = r = safeexpr(l, init); - t = n->type; - fn = syslook("makeslice", 1); - argtype(fn, t->type); // any-1 - n = mkcall1(fn, n->type, init, - typename(n->type), - conv(l, types[TINT64]), - conv(r, types[TINT64])); - goto ret; - - case ORUNESTR: - // sys_intstring(v) - n = mkcall("intstring", n->type, init, - conv(n->left, types[TINT64])); - goto ret; - - case OARRAYBYTESTR: - // slicebytetostring([]byte) string; - n = mkcall("slicebytetostring", n->type, init, n->left); - goto ret; - - case OARRAYRUNESTR: - // sliceinttostring([]int) string; - n = mkcall("sliceinttostring", n->type, init, n->left); - goto ret; - - case OSTRARRAYBYTE: - // stringtoslicebyte(string) []byte; - n = mkcall("stringtoslicebyte", n->type, init, conv(n->left, types[TSTRING])); - goto ret; - - case OSTRARRAYRUNE: - // stringtosliceint(string) []int - n = mkcall("stringtosliceint", n->type, init, n->left); - goto ret; - - case OCMPIFACE: - // ifaceeq(i1 any-1, i2 any-2) (ret bool); - if(!eqtype(n->left->type, n->right->type)) - fatal("ifaceeq %O %T %T", n->op, n->left->type, n->right->type); - if(isnilinter(n->left->type)) - fn = syslook("efaceeq", 1); - else - fn = syslook("ifaceeq", 1); - argtype(fn, n->right->type); - argtype(fn, n->left->type); - r = mkcall1(fn, n->type, init, n->left, n->right); - if(n->etype == ONE) { - r = nod(ONOT, r, N); - typecheck(&r, Erv); - } - n = r; - goto ret; - - case OARRAYLIT: - case OMAPLIT: - case OSTRUCTLIT: - nvar = nod(OXXX, N, N); - tempname(nvar, n->type); - anylit(0, n, nvar, init); - n = nvar; - goto ret; - - case OSEND: - n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, n->left, n->right); - goto ret; - - case OCLOSURE: - n = walkclosure(n, init); - goto ret; - } - fatal("missing switch %O", n->op); - -ret: - if(debug['w'] && n != N) - dump("walk", n); - - ullmancalc(n); - lineno = lno; - *np = n; -} - -static Node* -makenewvar(Type *t, NodeList **init, Node **nstar) -{ - Node *nvar, *nas; - - nvar = nod(OXXX, N, N); - tempname(nvar, t); - nas = nod(OAS, nvar, callnew(t->type)); - typecheck(&nas, Etop); - walkexpr(&nas, init); - *init = list(*init, nas); - - *nstar = nod(OIND, nvar, N); - typecheck(nstar, Erv); - return nvar; -} - -static Node* -ascompatee1(int op, Node *l, Node *r, NodeList **init) -{ - return convas(nod(OAS, l, r), init); -} - -static NodeList* -ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init) -{ - NodeList *ll, *lr, *nn; - - /* - * check assign expression list to - * a expression list. called in - * expr-list = expr-list - */ - - // ensure order of evaluation for function calls - for(ll=nl; ll; ll=ll->next) - ll->n = safeexpr(ll->n, init); - for(lr=nr; lr; lr=lr->next) - lr->n = safeexpr(lr->n, init); - - nn = nil; - for(ll=nl, lr=nr; ll && lr; ll=ll->next, lr=lr->next) - nn = list(nn, ascompatee1(op, ll->n, lr->n, init)); - - // cannot happen: caller checked that lists had same length - if(ll || lr) - yyerror("error in shape across %O", op); - return nn; -} - -/* - * l is an lv and rt is the type of an rv - * return 1 if this implies a function call - * evaluating the lv or a function call - * in the conversion of the types - */ -static int -fncall(Node *l, Type *rt) -{ - if(l->ullman >= UINF || l->op == OINDEXMAP) - return 1; - if(eqtype(l->type, rt)) - return 0; - return 1; -} - -static NodeList* -ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init) -{ - Node *l, *tmp, *a; - NodeList *ll; - Type *r; - Iter saver; - int ucount; - NodeList *nn, *mm; - - /* - * check assign type list to - * a expression list. called in - * expr-list = func() - */ - r = structfirst(&saver, nr); - nn = nil; - mm = nil; - ucount = 0; - for(ll=nl; ll; ll=ll->next) { - if(r == T) - break; - l = ll->n; - if(isblank(l)) { - r = structnext(&saver); - continue; - } - - // any lv that causes a fn call must be - // deferred until all the return arguments - // have been pulled from the output arguments - if(fncall(l, r->type)) { - tmp = nod(OXXX, N, N); - tempname(tmp, r->type); - typecheck(&tmp, Erv); - a = nod(OAS, l, tmp); - a = convas(a, init); - mm = list(mm, a); - l = tmp; - } - - a = nod(OAS, l, nodarg(r, fp)); - a = convas(a, init); - ullmancalc(a); - if(a->ullman >= UINF) - ucount++; - nn = list(nn, a); - r = structnext(&saver); - } - - if(ll != nil || r != T) - yyerror("assignment count mismatch: %d = %d", - count(nl), structcount(*nr)); - if(ucount) - fatal("reorder2: too many function calls evaluating parameters"); - return concat(nn, mm); -} - - /* - * package all the arguments that match a ... T parameter into a []T. - */ -static NodeList* -mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init) -{ - Node *a, *n; - Type *tslice; - - tslice = typ(TARRAY); - tslice->type = l->type->type; - tslice->bound = -1; - - n = nod(OCOMPLIT, N, typenod(tslice)); - n->list = lr0; - typecheck(&n, Erv); - if(n->type == T) - fatal("mkdotargslice: typecheck failed"); - walkexpr(&n, init); - - a = nod(OAS, nodarg(l, fp), n); - nn = list(nn, convas(a, init)); - return nn; -} - -/* - * helpers for shape errors - */ -static char* -dumptypes(Type **nl, char *what) -{ - int first; - Type *l; - Iter savel; - Fmt fmt; - - fmtstrinit(&fmt); - fmtprint(&fmt, "\t"); - l = structfirst(&savel, nl); - first = 1; - for(l = structfirst(&savel, nl); l != T; l = structnext(&savel)) { - if(first) - first = 0; - else - fmtprint(&fmt, ", "); - fmtprint(&fmt, "%T", l); - } - if(first) - fmtprint(&fmt, "[no arguments %s]", what); - return fmtstrflush(&fmt); -} - -static char* -dumpnodetypes(NodeList *l, char *what) -{ - int first; - Node *r; - Fmt fmt; - - fmtstrinit(&fmt); - fmtprint(&fmt, "\t"); - first = 1; - for(; l; l=l->next) { - r = l->n; - if(first) - first = 0; - else - fmtprint(&fmt, ", "); - fmtprint(&fmt, "%T", r->type); - } - if(first) - fmtprint(&fmt, "[no arguments %s]", what); - return fmtstrflush(&fmt); -} - -/* - * check assign expression list to - * a type list. called in - * return expr-list - * func(expr-list) - */ -static NodeList* -ascompatte(int op, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init) -{ - Type *l, *ll; - Node *r, *a; - NodeList *nn, *lr0, *alist; - Iter savel; - char *l1, *l2; - - lr0 = lr; - l = structfirst(&savel, nl); - r = N; - if(lr) - r = lr->n; - nn = nil; - - // f(g()) where g has multiple return values - if(r != N && lr->next == nil && r->type->etype == TSTRUCT && r->type->funarg) { - // optimization - can do block copy - if(eqtypenoname(r->type, *nl)) { - a = nodarg(*nl, fp); - a->type = r->type; - nn = list1(convas(nod(OAS, a, r), init)); - goto ret; - } - - // conversions involved. - // copy into temporaries. - alist = nil; - for(l=structfirst(&savel, &r->type); l; l=structnext(&savel)) { - a = nod(OXXX, N, N); - tempname(a, l->type); - alist = list(alist, a); - } - a = nod(OAS2, N, N); - a->list = alist; - a->rlist = lr; - typecheck(&a, Etop); - walkstmt(&a); - *init = list(*init, a); - lr = alist; - r = lr->n; - l = structfirst(&savel, nl); - } - -loop: - if(l != T && l->isddd) { - // the ddd parameter must be last - ll = structnext(&savel); - if(ll != T) - yyerror("... must be last argument"); - - // special case -- - // only if we are assigning a single ddd - // argument to a ddd parameter then it is - // passed thru unencapsulated - if(r != N && lr->next == nil && isddd && eqtype(l->type, r->type)) { - a = nod(OAS, nodarg(l, fp), r); - a = convas(a, init); - nn = list(nn, a); - goto ret; - } - - // normal case -- make a slice of all - // remaining arguments and pass it to - // the ddd parameter. - nn = mkdotargslice(lr, nn, l, fp, init); - goto ret; - } - - if(l == T || r == N) { - if(l != T || r != N) { - l1 = dumptypes(nl, "expected"); - l2 = dumpnodetypes(lr0, "given"); - if(l != T) - yyerror("not enough arguments to %O\n%s\n%s", op, l1, l2); - else - yyerror("too many arguments to %O\n%s\n%s", op, l1, l2); - } - goto ret; - } - - a = nod(OAS, nodarg(l, fp), r); - a = convas(a, init); - nn = list(nn, a); - - l = structnext(&savel); - r = N; - lr = lr->next; - if(lr != nil) - r = lr->n; - goto loop; - -ret: - for(lr=nn; lr; lr=lr->next) - lr->n->typecheck = 1; - return nn; -} - -// generate code for print -static Node* -walkprint(Node *nn, NodeList **init, int defer) -{ - Node *r; - Node *n; - NodeList *l, *all; - Node *on; - Type *t; - int notfirst, et, op; - NodeList *calls, *intypes, *args; - Fmt fmt; - - on = nil; - op = nn->op; - all = nn->list; - calls = nil; - notfirst = 0; - intypes = nil; - args = nil; - - memset(&fmt, 0, sizeof fmt); - if(defer) { - // defer print turns into defer printf with format string - fmtstrinit(&fmt); - intypes = list(intypes, nod(ODCLFIELD, N, typenod(types[TSTRING]))); - args = list1(nod(OXXX, N, N)); - } - - for(l=all; l; l=l->next) { - if(notfirst) { - if(defer) - fmtprint(&fmt, " "); - else - calls = list(calls, mkcall("printsp", T, init)); - } - notfirst = op == OPRINTN; - - n = l->n; - if(n->op == OLITERAL) { - switch(n->val.ctype) { - case CTINT: - defaultlit(&n, types[TINT64]); - break; - case CTFLT: - defaultlit(&n, types[TFLOAT64]); - break; - } - } - if(n->op != OLITERAL && n->type && n->type->etype == TIDEAL) - defaultlit(&n, types[TINT64]); - defaultlit(&n, nil); - l->n = n; - if(n->type == T || n->type->etype == TFORW) - continue; - - t = n->type; - et = n->type->etype; - if(isinter(n->type)) { - if(defer) { - if(isnilinter(n->type)) - fmtprint(&fmt, "%%e"); - else - fmtprint(&fmt, "%%i"); - } else { - if(isnilinter(n->type)) - on = syslook("printeface", 1); - else - on = syslook("printiface", 1); - argtype(on, n->type); // any-1 - } - } else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR) { - if(defer) { - fmtprint(&fmt, "%%p"); - } else { - on = syslook("printpointer", 1); - argtype(on, n->type); // any-1 - } - } else if(isslice(n->type)) { - if(defer) { - fmtprint(&fmt, "%%a"); - } else { - on = syslook("printslice", 1); - argtype(on, n->type); // any-1 - } - } else if(isint[et]) { - if(defer) { - if(et == TUINT64) - fmtprint(&fmt, "%%U"); - else { - fmtprint(&fmt, "%%D"); - t = types[TINT64]; - } - } else { - if(et == TUINT64) - on = syslook("printuint", 0); - else - on = syslook("printint", 0); - } - } else if(isfloat[et]) { - if(defer) { - fmtprint(&fmt, "%%f"); - t = types[TFLOAT64]; - } else - on = syslook("printfloat", 0); - } else if(iscomplex[et]) { - if(defer) { - fmtprint(&fmt, "%%C"); - t = types[TCOMPLEX128]; - } else - on = syslook("printcomplex", 0); - } else if(et == TBOOL) { - if(defer) - fmtprint(&fmt, "%%t"); - else - on = syslook("printbool", 0); - } else if(et == TSTRING) { - if(defer) - fmtprint(&fmt, "%%S"); - else - on = syslook("printstring", 0); - } else { - badtype(OPRINT, n->type, T); - continue; - } - - if(!defer) { - t = *getinarg(on->type); - if(t != nil) - t = t->type; - if(t != nil) - t = t->type; - } - - if(!eqtype(t, n->type)) { - n = nod(OCONV, n, N); - n->type = t; - } - - if(defer) { - intypes = list(intypes, nod(ODCLFIELD, N, typenod(t))); - args = list(args, n); - } else { - r = nod(OCALL, on, N); - r->list = list1(n); - calls = list(calls, r); - } - } - - if(defer) { - if(op == OPRINTN) - fmtprint(&fmt, "\n"); - on = syslook("goprintf", 1); - on->type = functype(nil, intypes, nil); - args->n = nod(OLITERAL, N, N); - args->n->val.ctype = CTSTR; - args->n->val.u.sval = strlit(fmtstrflush(&fmt)); - r = nod(OCALL, on, N); - r->list = args; - typecheck(&r, Etop); - walkexpr(&r, init); - } else { - if(op == OPRINTN) - calls = list(calls, mkcall("printnl", T, nil)); - typechecklist(calls, Etop); - walkexprlist(calls, init); - - r = nod(OEMPTY, N, N); - typecheck(&r, Etop); - walkexpr(&r, init); - r->ninit = calls; - } - return r; -} - -Node* -callnew(Type *t) -{ - Node *fn; - - dowidth(t); - fn = syslook("new", 1); - argtype(fn, t); - return mkcall1(fn, ptrto(t), nil, nodintconst(t->width)); -} - -static Node* -convas(Node *n, NodeList **init) -{ - Type *lt, *rt; - - if(n->op != OAS) - fatal("convas: not OAS %O", n->op); - - n->typecheck = 1; - - if(n->left == N || n->right == N) - goto out; - - lt = n->left->type; - rt = n->right->type; - if(lt == T || rt == T) - goto out; - - if(isblank(n->left)) { - defaultlit(&n->right, T); - goto out; - } - - if(n->left->op == OINDEXMAP) { - n = mkcall1(mapfn("mapassign1", n->left->left->type), T, init, - n->left->left, n->left->right, n->right); - goto out; - } - - if(eqtype(lt, rt)) - goto out; - - n->right = assignconv(n->right, lt, "assignment"); - walkexpr(&n->right, init); - -out: - ullmancalc(n); - return n; -} - -/* - * from ascompat[te] - * evaluating actual function arguments. - * f(a,b) - * if there is exactly one function expr, - * then it is done first. otherwise must - * make temp variables - */ -NodeList* -reorder1(NodeList *all) -{ - Node *f, *a, *n; - NodeList *l, *r, *g; - int c, d, t; - - c = 0; // function calls - t = 0; // total parameters - - for(l=all; l; l=l->next) { - n = l->n; - t++; - ullmancalc(n); - if(n->ullman >= UINF) - c++; - } - if(c == 0 || t == 1) - return all; - - g = nil; // fncalls assigned to tempnames - f = N; // last fncall assigned to stack - r = nil; // non fncalls and tempnames assigned to stack - d = 0; - for(l=all; l; l=l->next) { - n = l->n; - if(n->ullman < UINF) { - r = list(r, n); - continue; - } - d++; - if(d == c) { - f = n; - continue; - } - - // make assignment of fncall to tempname - a = nod(OXXX, N, N); - tempname(a, n->right->type); - a = nod(OAS, a, n->right); - g = list(g, a); - - // put normal arg assignment on list - // with fncall replaced by tempname - n->right = a->left; - r = list(r, n); - } - - if(f != N) - g = list(g, f); - return concat(g, r); -} - -/* - * from ascompat[ee] - * a,b = c,d - * simultaneous assignment. there cannot - * be later use of an earlier lvalue. - */ - -static int -vmatch2(Node *l, Node *r) -{ - NodeList *ll; - - /* - * isolate all right sides - */ - if(r == N) - return 0; - switch(r->op) { - case ONAME: - // match each right given left - if(l == r) - return 1; - case OLITERAL: - return 0; - } - if(vmatch2(l, r->left)) - return 1; - if(vmatch2(l, r->right)) - return 1; - for(ll=r->list; ll; ll=ll->next) - if(vmatch2(l, ll->n)) - return 1; - return 0; -} - -int -vmatch1(Node *l, Node *r) -{ - NodeList *ll; - - /* - * isolate all left sides - */ - if(l == N || r == N) - return 0; - switch(l->op) { - case ONAME: - switch(l->class) { - case PPARAM: - case PPARAMREF: - case PAUTO: - break; - default: - // assignment to non-stack variable - // must be delayed if right has function calls. - if(r->ullman >= UINF) - return 1; - break; - } - return vmatch2(l, r); - case OLITERAL: - return 0; - } - if(vmatch1(l->left, r)) - return 1; - if(vmatch1(l->right, r)) - return 1; - for(ll=l->list; ll; ll=ll->next) - if(vmatch1(ll->n, r)) - return 1; - return 0; -} - -NodeList* -reorder3(NodeList *all) -{ - Node *n1, *n2, *q; - int c1, c2; - NodeList *l1, *l2, *r; - - r = nil; - for(l1=all, c1=0; l1; l1=l1->next, c1++) { - n1 = l1->n; - for(l2=all, c2=0; l2; l2=l2->next, c2++) { - n2 = l2->n; - if(c2 > c1) { - if(vmatch1(n1->left, n2->right)) { - // delay assignment to n1->left - q = nod(OXXX, N, N); - tempname(q, n1->right->type); - q = nod(OAS, n1->left, q); - n1->left = q->right; - r = list(r, q); - break; - } - } - } - } - return concat(all, r); -} - -/* - * walk through argin parameters. - * generate and return code to allocate - * copies of escaped parameters to the heap. - */ -static NodeList* -paramstoheap(Type **argin, int out) -{ - Type *t; - Iter savet; - Node *v; - NodeList *nn; - - nn = nil; - for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) { - v = t->nname; - if(v == N && out && hasdefer) { - // Defer might stop a panic and show the - // return values as they exist at the time of panic. - // Make sure to zero them on entry to the function. - nn = list(nn, nod(OAS, nodarg(t, 1), N)); - } - if(v == N || !(v->class & PHEAP)) - continue; - - // generate allocation & copying code - if(v->alloc == nil) - v->alloc = callnew(v->type); - nn = list(nn, nod(OAS, v->heapaddr, v->alloc)); - if((v->class & ~PHEAP) != PPARAMOUT) - nn = list(nn, nod(OAS, v, v->stackparam)); - } - return nn; -} - -/* - * walk through argout parameters copying back to stack - */ -static NodeList* -returnsfromheap(Type **argin) -{ - Type *t; - Iter savet; - Node *v; - NodeList *nn; - - nn = nil; - for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) { - v = t->nname; - if(v == N || v->class != (PHEAP|PPARAMOUT)) - continue; - nn = list(nn, nod(OAS, v->stackparam, v)); - } - return nn; -} - -/* - * take care of migrating any function in/out args - * between the stack and the heap. adds code to - * curfn's before and after lists. - */ -static void -heapmoves(void) -{ - NodeList *nn; - int32 lno; - - lno = lineno; - lineno = curfn->lineno; - nn = paramstoheap(getthis(curfn->type), 0); - nn = concat(nn, paramstoheap(getinarg(curfn->type), 0)); - nn = concat(nn, paramstoheap(getoutarg(curfn->type), 1)); - curfn->enter = concat(curfn->enter, nn); - lineno = curfn->endlineno; - curfn->exit = returnsfromheap(getoutarg(curfn->type)); - lineno = lno; -} - -static Node* -vmkcall(Node *fn, Type *t, NodeList **init, va_list va) -{ - int i, n; - Node *r; - NodeList *args; - - if(fn->type == T || fn->type->etype != TFUNC) - fatal("mkcall %#N %T", fn, fn->type); - - args = nil; - n = fn->type->intuple; - for(i=0; i<n; i++) - args = list(args, va_arg(va, Node*)); - - r = nod(OCALL, fn, N); - r->list = args; - if(fn->type->outtuple > 0) - typecheck(&r, Erv | Efnstruct); - else - typecheck(&r, Etop); - walkexpr(&r, init); - r->type = t; - return r; -} - -Node* -mkcall(char *name, Type *t, NodeList **init, ...) -{ - Node *r; - va_list va; - - va_start(va, init); - r = vmkcall(syslook(name, 0), t, init, va); - va_end(va); - return r; -} - -Node* -mkcall1(Node *fn, Type *t, NodeList **init, ...) -{ - Node *r; - va_list va; - - va_start(va, init); - r = vmkcall(fn, t, init, va); - va_end(va); - return r; -} - -static Node* -conv(Node *n, Type *t) -{ - if(eqtype(n->type, t)) - return n; - n = nod(OCONV, n, N); - n->type = t; - typecheck(&n, Erv); - return n; -} - -Node* -chanfn(char *name, int n, Type *t) -{ - Node *fn; - int i; - - if(t->etype != TCHAN) - fatal("chanfn %T", t); - fn = syslook(name, 1); - for(i=0; i<n; i++) - argtype(fn, t->type); - return fn; -} - -static Node* -mapfn(char *name, Type *t) -{ - Node *fn; - - if(t->etype != TMAP) - fatal("mapfn %T", t); - fn = syslook(name, 1); - argtype(fn, t->down); - argtype(fn, t->type); - argtype(fn, t->down); - argtype(fn, t->type); - return fn; -} - -static Node* -addstr(Node *n, NodeList **init) -{ - Node *r, *cat, *typstr; - NodeList *in, *args; - int i, count; - - count = 0; - for(r=n; r->op == OADDSTR; r=r->left) - count++; // r->right - count++; // r - - // prepare call of runtime.catstring of type int, string, string, string - // with as many strings as we have. - cat = syslook("concatstring", 1); - cat->type = T; - cat->ntype = nod(OTFUNC, N, N); - in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // count - typstr = typenod(types[TSTRING]); - for(i=0; i<count; i++) - in = list(in, nod(ODCLFIELD, N, typstr)); - cat->ntype->list = in; - cat->ntype->rlist = list1(nod(ODCLFIELD, N, typstr)); - - args = nil; - for(r=n; r->op == OADDSTR; r=r->left) - args = concat(list1(conv(r->right, types[TSTRING])), args); - args = concat(list1(conv(r, types[TSTRING])), args); - args = concat(list1(nodintconst(count)), args); - - r = nod(OCALL, cat, N); - r->list = args; - typecheck(&r, Erv); - walkexpr(&r, init); - r->type = n->type; - - return r; -} - -static Node* -appendslice(Node *n, NodeList **init) -{ - Node *f; - - f = syslook("appendslice", 1); - argtype(f, n->type); - argtype(f, n->type->type); - argtype(f, n->type); - return mkcall1(f, n->type, init, typename(n->type), n->list->n, n->list->next->n); -} - -// expand append(src, a [, b]* ) to -// -// init { -// s := src -// const argc = len(args) - 1 -// if cap(s) - len(s) < argc { -// s = growslice(s, argc) -// } -// n := len(s) -// s = s[:n+argc] -// s[n] = a -// s[n+1] = b -// ... -// } -// s -static Node* -append(Node *n, NodeList **init) -{ - NodeList *l, *a; - Node *nsrc, *ns, *nn, *na, *nx, *fn; - int argc; - - walkexprlistsafe(n->list, init); - - nsrc = n->list->n; - argc = count(n->list) - 1; - if (argc < 1) { - return nsrc; - } - - l = nil; - - ns = nod(OXXX, N, N); // var s - tempname(ns, nsrc->type); - l = list(l, nod(OAS, ns, nsrc)); // s = src - - na = nodintconst(argc); // const argc - nx = nod(OIF, N, N); // if cap(s) - len(s) < argc - nx->ntest = nod(OLT, nod(OSUB, nod(OCAP, ns, N), nod(OLEN, ns, N)), na); - - fn = syslook("growslice", 1); // growslice(<type>, old []T, n int64) (ret []T) - argtype(fn, ns->type->type); // 1 old []any - argtype(fn, ns->type->type); // 2 ret []any - - nx->nbody = list1(nod(OAS, ns, mkcall1(fn, ns->type, &nx->ninit, - typename(ns->type), - ns, - conv(na, types[TINT64])))); - l = list(l, nx); - - nn = nod(OXXX, N, N); // var n - tempname(nn, types[TINT]); - l = list(l, nod(OAS, nn, nod(OLEN, ns, N))); // n = len(s) - - nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na))); // ...s[:n+argc] - nx->etype = 1; // disable bounds check - l = list(l, nod(OAS, ns, nx)); // s = s[:n+argc] - - for (a = n->list->next; a != nil; a = a->next) { - nx = nod(OINDEX, ns, nn); // s[n] ... - nx->etype = 1; // disable bounds check - l = list(l, nod(OAS, nx, a->n)); // s[n] = arg - if (a->next != nil) - l = list(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1)))); // n = n + 1 - } - - typechecklist(l, Etop); - walkstmtlist(l); - *init = concat(*init, l); - return ns; -} |