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.c812
1 files changed, 621 insertions, 191 deletions
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 9cd4ee919..7dfd34a7a 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -2,16 +2,17 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#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* mapfndel(char*, Type*);
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 NodeList* ascompatte(int, Node*, int, Type**, NodeList*, int, NodeList**);
static Node* convas(Node*, NodeList**);
static void heapmoves(void);
static NodeList* paramstoheap(Type **argin, int out);
@@ -20,6 +21,7 @@ static NodeList* reorder3(NodeList*);
static Node* addstr(Node*, NodeList**);
static Node* appendslice(Node*, NodeList**);
static Node* append(Node*, NodeList**);
+static void walkcompare(Node**, NodeList**);
// can this code branch reach the end
// without an unconditional RETURN
@@ -60,7 +62,6 @@ walk(Node *fn)
{
char s[50];
NodeList *l;
- Node *n;
int lno;
curfn = fn;
@@ -74,15 +75,33 @@ walk(Node *fn)
yyerror("function ends without a return statement");
lno = lineno;
+
+ // Final typecheck for any unused variables.
+ // It's hard to be on the heap when not-used, but best to be consistent about &~PHEAP here and below.
+ for(l=fn->dcl; l; l=l->next)
+ if(l->n->op == ONAME && (l->n->class&~PHEAP) == PAUTO)
+ typecheck(&l->n, Erv | Easgn);
+
+ // Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
+ for(l=fn->dcl; l; l=l->next)
+ if(l->n->op == ONAME && (l->n->class&~PHEAP) == PAUTO && l->n->defn && l->n->defn->op == OTYPESW && l->n->used)
+ l->n->defn->left->used++;
+
for(l=fn->dcl; l; l=l->next) {
- n = l->n;
- if(n->op != ONAME || n->class != PAUTO)
+ if(l->n->op != ONAME || (l->n->class&~PHEAP) != PAUTO || l->n->sym->name[0] == '&' || l->n->used)
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);
- }
+ if(l->n->defn && l->n->defn->op == OTYPESW) {
+ if(l->n->defn->left->used)
+ continue;
+ lineno = l->n->defn->left->lineno;
+ yyerror("%S declared and not used", l->n->sym);
+ l->n->defn->left->used = 1; // suppress repeats
+ } else {
+ lineno = l->n->lineno;
+ yyerror("%S declared and not used", l->n->sym);
+ }
+ }
+
lineno = lno;
if(nerrors != 0)
return;
@@ -119,11 +138,12 @@ static int
paramoutheap(Node *fn)
{
NodeList *l;
-
+
for(l=fn->dcl; l; l=l->next) {
switch(l->n->class) {
+ case PPARAMOUT:
case PPARAMOUT|PHEAP:
- return 1;
+ return l->n->addrtaken;
case PAUTO:
case PAUTO|PHEAP:
// stop early - parameters are over
@@ -147,6 +167,8 @@ walkstmt(Node **np)
setlineno(n);
+ walkstmtlist(n->ninit);
+
switch(n->op) {
default:
if(n->op == ONAME)
@@ -162,7 +184,6 @@ walkstmt(Node **np)
case OAS2DOTTYPE:
case OAS2RECV:
case OAS2FUNC:
- case OAS2MAPW:
case OAS2MAPR:
case OCLOSE:
case OCOPY:
@@ -170,6 +191,7 @@ walkstmt(Node **np)
case OCALLINTER:
case OCALL:
case OCALLFUNC:
+ case ODELETE:
case OSEND:
case ORECV:
case OPRINT:
@@ -177,14 +199,12 @@ walkstmt(Node **np)
case OPANIC:
case OEMPTY:
case ORECOVER:
- if(n->typecheck == 0) {
- dump("missing typecheck:", n);
- fatal("missing typecheck");
- }
+ if(n->typecheck == 0)
+ fatal("missing typecheck: %+N", n);
init = n->ninit;
n->ninit = nil;
walkexpr(&n, &init);
- n->ninit = concat(init, n->ninit);
+ addinit(&n, init);
break;
case OBREAK:
@@ -223,20 +243,18 @@ walkstmt(Node **np)
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);
+ addinit(&n->ntest, init);
}
walkstmt(&n->nincr);
walkstmtlist(n->nbody);
break;
case OIF:
- walkstmtlist(n->ninit);
walkexpr(&n->ntest, &n->ninit);
walkstmtlist(n->nbody);
walkstmtlist(n->nelse);
@@ -279,15 +297,18 @@ walkstmt(Node **np)
// 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);
+ fatal("expected return of call, have %N", f);
n->list = concat(list1(f), ascompatet(n->op, rl, &f->type, 0, &n->ninit));
break;
}
+
+ // move function calls out, to make reorder3's job easier.
+ walkexprlistsafe(n->list, &n->ninit);
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);
+ ll = ascompatte(n->op, nil, 0, getoutarg(curfn->type), n->list, 1, &n->ninit);
n->list = ll;
break;
@@ -309,6 +330,9 @@ walkstmt(Node **np)
break;
}
+ if(n->op == ONAME)
+ fatal("walkstmt ended up with name: %+N", n);
+
*np = n;
}
@@ -361,6 +385,12 @@ walkexpr(Node **np, NodeList **init)
fatal("walkexpr init == &n->ninit");
}
+ if(n->ninit != nil) {
+ walkstmtlist(n->ninit);
+ *init = concat(*init, n->ninit);
+ n->ninit = nil;
+ }
+
// annoying case - not typechecked
if(n->op == OKEY) {
walkexpr(&n->left, init);
@@ -373,19 +403,14 @@ walkexpr(Node **np, NodeList **init)
if(debug['w'] > 1)
dump("walk-before", n);
- if(n->typecheck != 1) {
- dump("missed typecheck", n);
- fatal("missed typecheck");
- }
-
- t = T;
- et = Txxx;
+ if(n->typecheck != 1)
+ fatal("missed typecheck: %+N\n", n);
switch(n->op) {
default:
dump("walk", n);
fatal("walkexpr: switch 1 unknown op %N", n);
- goto ret;
+ break;
case OTYPE:
case ONONAME:
@@ -407,10 +432,14 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&n->left, init);
goto ret;
+ case OITAB:
+ 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;
@@ -422,7 +451,7 @@ walkexpr(Node **np, NodeList **init)
n->typecheck = 1;
}
goto ret;
-
+
case OLSH:
case ORSH:
case OAND:
@@ -430,8 +459,6 @@ walkexpr(Node **np, NodeList **init)
case OXOR:
case OSUB:
case OMUL:
- case OEQ:
- case ONE:
case OLT:
case OLE:
case OGE:
@@ -441,7 +468,14 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&n->left, init);
walkexpr(&n->right, init);
goto ret;
-
+
+ case OEQ:
+ case ONE:
+ walkexpr(&n->left, init);
+ walkexpr(&n->right, init);
+ walkcompare(&n, init);
+ goto ret;
+
case OANDAND:
case OOROR:
walkexpr(&n->left, init);
@@ -450,7 +484,7 @@ walkexpr(Node **np, NodeList **init)
// save elsewhere and store on the eventual n->right.
ll = nil;
walkexpr(&n->right, &ll);
- n->right->ninit = concat(n->right->ninit, ll);
+ addinit(&n->right, ll);
goto ret;
case OPRINT:
@@ -482,7 +516,7 @@ walkexpr(Node **np, NodeList **init)
goto ret;
walkexpr(&n->left, init);
walkexprlist(n->list, init);
- ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
+ ll = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init);
n->list = reorder1(ll);
goto ret;
@@ -499,7 +533,7 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&n->left, init);
walkexprlist(n->list, init);
- ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
+ ll = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init);
n->list = reorder1(ll);
goto ret;
@@ -509,8 +543,8 @@ walkexpr(Node **np, NodeList **init)
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 = ascompatte(n->op, n, 0, getthis(t), list1(n->left->left), 0, init);
+ lr = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init);
ll = concat(ll, lr);
n->left->left = N;
ullmancalc(n->left);
@@ -554,7 +588,7 @@ walkexpr(Node **np, NodeList **init)
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
@@ -563,8 +597,7 @@ walkexpr(Node **np, NodeList **init)
// and map index has an implicit one.
lpost = nil;
if(l->op == OINDEXMAP) {
- var = nod(OXXX, N, N);
- tempname(var, l->type);
+ var = temp(l->type);
n->list->n = var;
a = nod(OAS, l, var);
typecheck(&a, Etop);
@@ -572,8 +605,7 @@ walkexpr(Node **np, NodeList **init)
}
l = n->list->next->n;
if(l->op == OINDEXMAP) {
- var = nod(OXXX, N, N);
- tempname(var, l->type);
+ var = temp(l->type);
n->list->next->n = var;
a = nod(OAS, l, var);
typecheck(&a, Etop);
@@ -609,15 +641,13 @@ walkexpr(Node **np, NodeList **init)
n->op = OAS2FUNC;
goto as2func;
- case OAS2MAPW:
- // map[] = a,b - mapassign2
- // a,b = m[i];
+ case ODELETE:
*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, typename(t), l->left, l->right, n->rlist->n, n->rlist->next->n);
+ r = n->list->next->n;
+ t = l->type;
+ n = mkcall1(mapfndel("mapdelete", t), t->down, init, typename(t), l, r);
goto ret;
case OAS2DOTTYPE:
@@ -651,7 +681,7 @@ walkexpr(Node **np, NodeList **init)
if(n->op == ODOTTYPE2)
*p++ = '2';
*p = '\0';
-
+
fn = syslook(buf, 1);
ll = list1(typename(n->type));
ll = list(ll, n->left);
@@ -682,7 +712,7 @@ walkexpr(Node **np, NodeList **init)
else
*p++ = 'I';
*p = '\0';
-
+
fn = syslook(buf, 1);
ll = nil;
if(!isinter(n->left->type))
@@ -843,6 +873,7 @@ walkexpr(Node **np, NodeList **init)
// delayed until now because "abc"[2] is not
// an ideal constant.
nodconst(n, n->type, n->left->val.u.sval->s[v]);
+ n->typecheck = 1;
}
}
goto ret;
@@ -897,7 +928,7 @@ walkexpr(Node **np, NodeList **init)
}
if(v1 >= 0 && v2 >= 0 && v1 > v2)
yyerror("inverted slice range");
-
+
if(n->op == OSLICEARR)
goto slicearray;
@@ -928,7 +959,7 @@ walkexpr(Node **np, NodeList **init)
l,
nodintconst(t->type->width));
}
- n->etype = et; // preserve no-typecheck flag from OSLICE to the slice* call.
+ n->etype = et; // preserve no-typecheck flag from OSLICE to the slice* call.
goto ret;
slicearray:
@@ -953,29 +984,22 @@ walkexpr(Node **np, NodeList **init)
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;
- }
-
+ case OADDR:
walkexpr(&n->left, init);
goto ret;
case ONEW:
- n = callnew(n->type->type);
+ if(n->esc == EscNone && n->type->type->width < (1<<16)) {
+ r = temp(n->type->type);
+ r = nod(OAS, r, N); // zero temp
+ typecheck(&r, Etop);
+ *init = list(*init, r);
+ r = nod(OADDR, r->left, N);
+ typecheck(&r, Erv);
+ n = r;
+ } else {
+ n = callnew(n->type->type);
+ }
goto ret;
case OCMPSTR:
@@ -987,6 +1011,7 @@ walkexpr(Node **np, NodeList **init)
r = nod(n->etype, nod(OLEN, n->left, N), nod(OLEN, n->right, N));
typecheck(&r, Erv);
walkexpr(&r, init);
+ r->type = n->type;
n = r;
goto ret;
}
@@ -999,6 +1024,7 @@ walkexpr(Node **np, NodeList **init)
r = nod(n->etype, nod(OLEN, n->left->left, N), nodintconst(0));
typecheck(&r, Erv);
walkexpr(&r, init);
+ r->type = n->type;
n = r;
goto ret;
}
@@ -1025,6 +1051,8 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&r, nil);
}
typecheck(&r, Erv);
+ if(n->type->etype != TBOOL) fatal("cmp %T", n->type);
+ r->type = n->type;
n = r;
goto ret;
@@ -1049,10 +1077,14 @@ walkexpr(Node **np, NodeList **init)
l);
}
goto ret;
-
+
case OAPPEND:
- if(n->isddd)
- n = appendslice(n, init);
+ if(n->isddd) {
+ if(istype(n->type->type, TUINT8) && istype(n->list->next->n->type, TSTRING))
+ n = mkcall("appendstr", n->type, init, typename(n->type), n->list->n, n->list->next->n);
+ else
+ n = appendslice(n, init);
+ }
else
n = append(n, init);
goto ret;
@@ -1061,7 +1093,7 @@ walkexpr(Node **np, NodeList **init)
if(n->right->type->etype == TSTRING)
fn = syslook("slicestringcopy", 1);
else
- fn = syslook("slicecopy", 1);
+ fn = syslook("copy", 1);
argtype(fn, n->left->type);
argtype(fn, n->right->type);
n = mkcall1(fn, n->type, init,
@@ -1121,8 +1153,8 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case OARRAYRUNESTR:
- // sliceinttostring([]int) string;
- n = mkcall("sliceinttostring", n->type, init, n->left);
+ // slicerunetostring([]rune) string;
+ n = mkcall("slicerunetostring", n->type, init, n->left);
goto ret;
case OSTRARRAYBYTE:
@@ -1131,8 +1163,8 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case OSTRARRAYRUNE:
- // stringtosliceint(string) []int
- n = mkcall("stringtosliceint", n->type, init, n->left);
+ // stringtoslicerune(string) []rune
+ n = mkcall("stringtoslicerune", n->type, init, n->left);
goto ret;
case OCMPIFACE:
@@ -1146,20 +1178,27 @@ walkexpr(Node **np, NodeList **init)
argtype(fn, n->right->type);
argtype(fn, n->left->type);
r = mkcall1(fn, n->type, init, n->left, n->right);
- if(n->etype == ONE) {
+ if(n->etype == ONE)
r = nod(ONOT, r, N);
- typecheck(&r, Erv);
- }
+
+ // check itable/type before full compare.
+ if(n->etype == OEQ)
+ r = nod(OANDAND, nod(OEQ, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r);
+ else
+ r = nod(OOROR, nod(ONE, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r);
+ typecheck(&r, Erv);
+ walkexpr(&r, nil);
+ r->type = n->type;
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;
+ case OPTRLIT:
+ var = temp(n->type);
+ anylit(0, n, var, init);
+ n = var;
goto ret;
case OSEND:
@@ -1173,34 +1212,20 @@ walkexpr(Node **np, NodeList **init)
fatal("missing switch %O", n->op);
ret:
+ ullmancalc(n);
+
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)
{
+ USED(op);
+
return convas(nod(OAS, l, r), init);
}
@@ -1227,7 +1252,7 @@ ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init)
// cannot happen: caller checked that lists had same length
if(ll || lr)
- yyerror("error in shape across %O", op);
+ yyerror("error in shape across %+H %O %+H", nl, op, nr);
return nn;
}
@@ -1257,6 +1282,8 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
int ucount;
NodeList *nn, *mm;
+ USED(op);
+
/*
* check assign type list to
* a expression list. called in
@@ -1279,8 +1306,7 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
// 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);
+ tmp = temp(r->type);
typecheck(&tmp, Erv);
a = nod(OAS, l, tmp);
a = convas(a, init);
@@ -1298,10 +1324,11 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
}
if(ll != nil || r != T)
- yyerror("assignment count mismatch: %d = %d",
+ yyerror("ascompatet: assignment count mismatch: %d = %d",
count(nl), structcount(*nr));
+
if(ucount)
- fatal("reorder2: too many function calls evaluating parameters");
+ fatal("ascompatet: too many function calls evaluating parameters");
return concat(nn, mm);
}
@@ -1309,7 +1336,7 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
* 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)
+mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, int esc)
{
Node *a, *n;
Type *tslice;
@@ -1318,12 +1345,18 @@ mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init)
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);
+ if(count(lr0) == 0) {
+ n = nodnil();
+ n->type = tslice;
+ } else {
+ n = nod(OCOMPLIT, N, typenod(tslice));
+ n->list = lr0;
+ n->esc = esc;
+ 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));
@@ -1343,7 +1376,6 @@ dumptypes(Type **nl, char *what)
fmtstrinit(&fmt);
fmtprint(&fmt, "\t");
- l = structfirst(&savel, nl);
first = 1;
for(l = structfirst(&savel, nl); l != T; l = structnext(&savel)) {
if(first)
@@ -1387,8 +1419,9 @@ dumpnodetypes(NodeList *l, char *what)
* func(expr-list)
*/
static NodeList*
-ascompatte(int op, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init)
+ascompatte(int op, Node *call, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init)
{
+ int esc;
Type *l, *ll;
Node *r, *a;
NodeList *nn, *lr0, *alist;
@@ -1401,7 +1434,7 @@ ascompatte(int op, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init)
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
@@ -1411,13 +1444,12 @@ ascompatte(int op, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init)
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);
+ a = temp(l->type);
alist = list(alist, a);
}
a = nod(OAS2, N, N);
@@ -1452,7 +1484,10 @@ loop:
// normal case -- make a slice of all
// remaining arguments and pass it to
// the ddd parameter.
- nn = mkdotargslice(lr, nn, l, fp, init);
+ esc = EscUnknown;
+ if(call->right)
+ esc = call->right->esc;
+ nn = mkdotargslice(lr, nn, l, fp, init, esc);
goto ret;
}
@@ -1526,6 +1561,9 @@ walkprint(Node *nn, NodeList **init, int defer)
n = l->n;
if(n->op == OLITERAL) {
switch(n->val.ctype) {
+ case CTRUNE:
+ defaultlit(&n, runetype);
+ break;
case CTINT:
defaultlit(&n, types[TINT64]);
break;
@@ -1668,7 +1706,7 @@ callnew(Type *t)
dowidth(t);
fn = syslook("new", 1);
argtype(fn, t);
- return mkcall1(fn, ptrto(t), nil, nodintconst(t->width));
+ return mkcall1(fn, ptrto(t), nil, typename(t));
}
static Node*
@@ -1700,10 +1738,10 @@ convas(Node *n, NodeList **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);
@@ -1720,7 +1758,7 @@ out:
* then it is done first. otherwise must
* make temp variables
*/
-NodeList*
+static NodeList*
reorder1(NodeList *all)
{
Node *f, *a, *n;
@@ -1757,8 +1795,7 @@ reorder1(NodeList *all)
}
// make assignment of fncall to tempname
- a = nod(OXXX, N, N);
- tempname(a, n->right->type);
+ a = temp(n->right->type);
a = nod(OAS, a, n->right);
g = list(g, a);
@@ -1773,28 +1810,242 @@ reorder1(NodeList *all)
return concat(g, r);
}
+static void reorder3save(Node**, NodeList*, NodeList*, NodeList**);
+static int aliased(Node*, NodeList*, NodeList*);
+
/*
* from ascompat[ee]
* a,b = c,d
* simultaneous assignment. there cannot
* be later use of an earlier lvalue.
+ *
+ * function calls have been removed.
*/
+static NodeList*
+reorder3(NodeList *all)
+{
+ NodeList *list, *early;
+ Node *l;
+
+ // If a needed expression may be affected by an
+ // earlier assignment, make an early copy of that
+ // expression and use the copy instead.
+ early = nil;
+ for(list=all; list; list=list->next) {
+ l = list->n->left;
+
+ // Save subexpressions needed on left side.
+ // Drill through non-dereferences.
+ for(;;) {
+ if(l->op == ODOT || l->op == OPAREN) {
+ l = l->left;
+ continue;
+ }
+ if(l->op == OINDEX && isfixedarray(l->left->type)) {
+ reorder3save(&l->right, all, list, &early);
+ l = l->left;
+ continue;
+ }
+ break;
+ }
+ switch(l->op) {
+ default:
+ fatal("reorder3 unexpected lvalue %#O", l->op);
+ case ONAME:
+ break;
+ case OINDEX:
+ reorder3save(&l->left, all, list, &early);
+ reorder3save(&l->right, all, list, &early);
+ break;
+ case OIND:
+ case ODOTPTR:
+ reorder3save(&l->left, all, list, &early);
+ }
+ // Save expression on right side.
+ reorder3save(&list->n->right, all, list, &early);
+ }
+
+ return concat(early, all);
+}
+
+static int vmatch2(Node*, Node*);
+static int varexpr(Node*);
+
+/*
+ * if the evaluation of *np would be affected by the
+ * assignments in all up to but not including stop,
+ * copy into a temporary during *early and
+ * replace *np with that temp.
+ */
+static void
+reorder3save(Node **np, NodeList *all, NodeList *stop, NodeList **early)
+{
+ Node *n, *q;
+
+ n = *np;
+ if(!aliased(n, all, stop))
+ return;
+
+ q = temp(n->type);
+ q = nod(OAS, q, n);
+ typecheck(&q, Etop);
+ *early = list(*early, q);
+ *np = q->left;
+}
+
+/*
+ * what's the outer value that a write to n affects?
+ * outer value means containing struct or array.
+ */
+static Node*
+outervalue(Node *n)
+{
+ for(;;) {
+ if(n->op == ODOT || n->op == OPAREN) {
+ n = n->left;
+ continue;
+ }
+ if(n->op == OINDEX && isfixedarray(n->left->type)) {
+ n = n->left;
+ continue;
+ }
+ break;
+ }
+ return n;
+}
+
+/*
+ * Is it possible that the computation of n might be
+ * affected by writes in as up to but not including stop?
+ */
+static int
+aliased(Node *n, NodeList *all, NodeList *stop)
+{
+ int memwrite, varwrite;
+ Node *a;
+ NodeList *l;
+
+ if(n == N)
+ return 0;
+
+ // Look for obvious aliasing: a variable being assigned
+ // during the all list and appearing in n.
+ // Also record whether there are any writes to main memory.
+ // Also record whether there are any writes to variables
+ // whose addresses have been taken.
+ memwrite = 0;
+ varwrite = 0;
+ for(l=all; l!=stop; l=l->next) {
+ a = outervalue(l->n->left);
+ if(a->op != ONAME) {
+ memwrite = 1;
+ continue;
+ }
+ switch(n->class) {
+ default:
+ varwrite = 1;
+ continue;
+ case PAUTO:
+ case PPARAM:
+ case PPARAMOUT:
+ if(n->addrtaken) {
+ varwrite = 1;
+ continue;
+ }
+ if(vmatch2(a, n)) {
+ // Direct hit.
+ return 1;
+ }
+ }
+ }
+
+ // The variables being written do not appear in n.
+ // However, n might refer to computed addresses
+ // that are being written.
+
+ // If no computed addresses are affected by the writes, no aliasing.
+ if(!memwrite && !varwrite)
+ return 0;
+
+ // If n does not refer to computed addresses
+ // (that is, if n only refers to variables whose addresses
+ // have not been taken), no aliasing.
+ if(varexpr(n))
+ return 0;
+
+ // Otherwise, both the writes and n refer to computed memory addresses.
+ // Assume that they might conflict.
+ return 1;
+}
+
+/*
+ * does the evaluation of n only refer to variables
+ * whose addresses have not been taken?
+ * (and no other memory)
+ */
+static int
+varexpr(Node *n)
+{
+ if(n == N)
+ return 1;
+
+ switch(n->op) {
+ case OLITERAL:
+ return 1;
+ case ONAME:
+ switch(n->class) {
+ case PAUTO:
+ case PPARAM:
+ case PPARAMOUT:
+ if(!n->addrtaken)
+ return 1;
+ }
+ return 0;
+
+ case OADD:
+ case OSUB:
+ case OOR:
+ case OXOR:
+ case OMUL:
+ case ODIV:
+ case OMOD:
+ case OLSH:
+ case ORSH:
+ case OAND:
+ case OANDNOT:
+ case OPLUS:
+ case OMINUS:
+ case OCOM:
+ case OPAREN:
+ case OANDAND:
+ case OOROR:
+ case ODOT: // but not ODOTPTR
+ case OCONV:
+ case OCONVNOP:
+ case OCONVIFACE:
+ case ODOTTYPE:
+ return varexpr(n->left) && varexpr(n->right);
+ }
+
+ // Be conservative.
+ return 0;
+}
+
+/*
+ * is the name l mentioned in r?
+ */
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;
+ return l == r;
case OLITERAL:
return 0;
}
@@ -1808,6 +2059,10 @@ vmatch2(Node *l, Node *r)
return 0;
}
+/*
+ * is any name mentioned in l also mentioned in r?
+ * called by sinit.c
+ */
int
vmatch1(Node *l, Node *r)
{
@@ -1846,34 +2101,6 @@ vmatch1(Node *l, Node *r)
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
@@ -1940,7 +2167,7 @@ heapmoves(void)
{
NodeList *nn;
int32 lno;
-
+
lno = lineno;
lineno = curfn->lineno;
nn = paramstoheap(getthis(curfn->type), 0);
@@ -1960,7 +2187,7 @@ vmkcall(Node *fn, Type *t, NodeList **init, va_list va)
NodeList *args;
if(fn->type == T || fn->type->etype != TFUNC)
- fatal("mkcall %#N %T", fn, fn->type);
+ fatal("mkcall %N %T", fn, fn->type);
args = nil;
n = fn->type->intuple;
@@ -2002,7 +2229,7 @@ mkcall1(Node *fn, Type *t, NodeList **init, ...)
return r;
}
-static Node*
+Node*
conv(Node *n, Type *t)
{
if(eqtype(n->type, t))
@@ -2043,12 +2270,26 @@ mapfn(char *name, Type *t)
}
static Node*
+mapfndel(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);
+ 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
@@ -2077,7 +2318,7 @@ addstr(Node *n, NodeList **init)
typecheck(&r, Erv);
walkexpr(&r, init);
r->type = n->type;
-
+
return r;
}
@@ -2085,7 +2326,7 @@ static Node*
appendslice(Node *n, NodeList **init)
{
Node *f;
-
+
f = syslook("appendslice", 1);
argtype(f, n->type);
argtype(f, n->type->type);
@@ -2099,7 +2340,7 @@ appendslice(Node *n, NodeList **init)
// s := src
// const argc = len(args) - 1
// if cap(s) - len(s) < argc {
-// s = growslice(s, argc)
+// s = growslice(s, argc)
// }
// n := len(s)
// s = s[:n+argc]
@@ -2117,6 +2358,12 @@ append(Node *n, NodeList **init)
walkexprlistsafe(n->list, init);
+ // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
+ // and n are name or literal, but those may index the slice we're
+ // modifying here. Fix explicitly.
+ for(l=n->list; l; l=l->next)
+ l->n = cheapexpr(l->n, init);
+
nsrc = n->list->n;
argc = count(n->list) - 1;
if (argc < 1) {
@@ -2125,17 +2372,16 @@ append(Node *n, NodeList **init)
l = nil;
- ns = nod(OXXX, N, N); // var s
- tempname(ns, nsrc->type);
+ ns = temp(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
+ 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
+ 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),
@@ -2143,18 +2389,17 @@ append(Node *n, NodeList **init)
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)
+ nn = temp(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]
+ 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
+ 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
}
@@ -2164,3 +2409,188 @@ append(Node *n, NodeList **init)
*init = concat(*init, l);
return ns;
}
+
+static Node*
+eqfor(Type *t)
+{
+ int a;
+ Node *n;
+ Node *ntype;
+ Sym *sym;
+
+ // Should only arrive here with large memory or
+ // a struct/array containing a non-memory field/element.
+ // Small memory is handled inline, and single non-memory
+ // is handled during type check (OCMPSTR etc).
+ a = algtype1(t, nil);
+ if(a != AMEM && a != -1)
+ fatal("eqfor %T", t);
+
+ if(a == AMEM) {
+ n = syslook("memequal", 1);
+ argtype(n, t);
+ argtype(n, t);
+ return n;
+ }
+
+ sym = typesymprefix(".eq", t);
+ n = newname(sym);
+ n->class = PFUNC;
+ ntype = nod(OTFUNC, N, N);
+ ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(types[TBOOL]))));
+ ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+ ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
+ ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
+ typecheck(&ntype, Etype);
+ n->type = ntype->type;
+ return n;
+}
+
+static int
+countfield(Type *t)
+{
+ Type *t1;
+ int n;
+
+ n = 0;
+ for(t1=t->type; t1!=T; t1=t1->down)
+ n++;
+ return n;
+}
+
+static void
+walkcompare(Node **np, NodeList **init)
+{
+ Node *n, *l, *r, *fn, *call, *a, *li, *ri, *expr;
+ int andor, i;
+ Type *t, *t1;
+ static Node *tempbool;
+
+ n = *np;
+
+ // Must be comparison of array or struct.
+ // Otherwise back end handles it.
+ t = n->left->type;
+ switch(t->etype) {
+ default:
+ return;
+ case TARRAY:
+ if(isslice(t))
+ return;
+ break;
+ case TSTRUCT:
+ break;
+ }
+
+ if(!islvalue(n->left) || !islvalue(n->right))
+ goto hard;
+
+ l = temp(ptrto(t));
+ a = nod(OAS, l, nod(OADDR, n->left, N));
+ a->right->etype = 1; // addr does not escape
+ typecheck(&a, Etop);
+ *init = list(*init, a);
+
+ r = temp(ptrto(t));
+ a = nod(OAS, r, nod(OADDR, n->right, N));
+ a->right->etype = 1; // addr does not escape
+ typecheck(&a, Etop);
+ *init = list(*init, a);
+
+ expr = N;
+ andor = OANDAND;
+ if(n->op == ONE)
+ andor = OOROR;
+
+ if(t->etype == TARRAY &&
+ t->bound <= 4 &&
+ issimple[t->type->etype]) {
+ // Four or fewer elements of a basic type.
+ // Unroll comparisons.
+ for(i=0; i<t->bound; i++) {
+ li = nod(OINDEX, l, nodintconst(i));
+ ri = nod(OINDEX, r, nodintconst(i));
+ a = nod(n->op, li, ri);
+ if(expr == N)
+ expr = a;
+ else
+ expr = nod(andor, expr, a);
+ }
+ if(expr == N)
+ expr = nodbool(n->op == OEQ);
+ typecheck(&expr, Erv);
+ walkexpr(&expr, init);
+ expr->type = n->type;
+ *np = expr;
+ return;
+ }
+
+ if(t->etype == TSTRUCT && countfield(t) <= 4) {
+ // Struct of four or fewer fields.
+ // Inline comparisons.
+ for(t1=t->type; t1; t1=t1->down) {
+ li = nod(OXDOT, l, newname(t1->sym));
+ ri = nod(OXDOT, r, newname(t1->sym));
+ a = nod(n->op, li, ri);
+ if(expr == N)
+ expr = a;
+ else
+ expr = nod(andor, expr, a);
+ }
+ if(expr == N)
+ expr = nodbool(n->op == OEQ);
+ typecheck(&expr, Erv);
+ walkexpr(&expr, init);
+ expr->type = n->type;
+ *np = expr;
+ return;
+ }
+
+ // Chose not to inline, but still have addresses.
+ // Call equality function directly.
+ // The equality function requires a bool pointer for
+ // storing its address, because it has to be callable
+ // from C, and C can't access an ordinary Go return value.
+ // To avoid creating many temporaries, cache one per function.
+ if(tempbool == N || tempbool->curfn != curfn)
+ tempbool = temp(types[TBOOL]);
+
+ call = nod(OCALL, eqfor(t), N);
+ a = nod(OADDR, tempbool, N);
+ a->etype = 1; // does not escape
+ call->list = list(call->list, a);
+ call->list = list(call->list, nodintconst(t->width));
+ call->list = list(call->list, l);
+ call->list = list(call->list, r);
+ typecheck(&call, Etop);
+ walkstmt(&call);
+ *init = list(*init, call);
+
+ if(n->op == OEQ)
+ r = tempbool;
+ else
+ r = nod(ONOT, tempbool, N);
+ typecheck(&r, Erv);
+ walkexpr(&r, init);
+ *np = r;
+ return;
+
+hard:
+ // Cannot take address of one or both of the operands.
+ // Instead, pass directly to runtime helper function.
+ // Easier on the stack than passing the address
+ // of temporary variables, because we are better at reusing
+ // the argument space than temporary variable space.
+ fn = syslook("equal", 1);
+ l = n->left;
+ r = n->right;
+ argtype(fn, n->left->type);
+ argtype(fn, n->left->type);
+ r = mkcall1(fn, n->type, init, typename(n->left->type), l, r);
+ if(n->op == ONE) {
+ r = nod(ONOT, r, N);
+ typecheck(&r, Erv);
+ }
+ *np = r;
+ return;
+}