summaryrefslogtreecommitdiff
path: root/src/cmd/gc/walk.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/walk.c')
-rw-r--r--src/cmd/gc/walk.c2177
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;
-}