This source file includes following definitions.
- walk
- walkstmtlist
- samelist
- paramoutheap
- walkstmt
- walkexprlist
- walkexprlistsafe
- walkexpr
- ascompatee1
- ascompatee
- fncall
- ascompatet
- mkdotargslice
- dumptypes
- dumpnodetypes
- ascompatte
- walkprint
- callnew
- convas
- reorder1
- reorder3
- reorder3save
- outervalue
- aliased
- varexpr
- vmatch2
- vmatch1
- paramstoheap
- returnsfromheap
- heapmoves
- vmkcall
- mkcall
- mkcall1
- conv
- chanfn
- mapfn
- mapfndel
- addstr
- appendslice
- append
- copyany
- sliceany
- eqfor
- countfield
- walkcompare
- samecheap
- walkrotate
- walkmul
- walkdiv
- bounded
- usefield
- candiscardlist
- candiscard
#include <u.h>
#include <libc.h>
#include "go.h"
static Node* walkprint(Node*, NodeList**, int);
static Node* mapfn(char*, Type*);
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, Node*, 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**);
static Node* copyany(Node*, NodeList**, int);
static Node* sliceany(Node*, NodeList**);
static void walkcompare(Node**, NodeList**);
static void walkrotate(Node**);
static void walkmul(Node**, NodeList**);
static void walkdiv(Node**, NodeList**);
static int bounded(Node*, int64);
static Mpint mpzero;
void
walk(Node *fn)
{
char s[50];
NodeList *l;
int lno;
curfn = fn;
if(debug['W']) {
snprint(s, sizeof(s), "\nbefore %S", curfn->nname->sym);
dumplist(s, curfn->nbody);
}
lno = lineno;
for(l=fn->dcl; l; l=l->next)
if(l->n->op == ONAME && (l->n->class&~PHEAP) == PAUTO)
typecheck(&l->n, Erv | Easgn);
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) {
if(l->n->op != ONAME || (l->n->class&~PHEAP) != PAUTO || l->n->sym->name[0] == '&' || l->n->used)
continue;
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;
} else {
lineno = l->n->lineno;
yyerror("%S declared and not used", l->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:
case PPARAMOUT|PHEAP:
return l->n->addrtaken;
case PAUTO:
case PAUTO|PHEAP:
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);
walkstmtlist(n->ninit);
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 OAS:
case OASOP:
case OAS2:
case OAS2DOTTYPE:
case OAS2RECV:
case OAS2FUNC:
case OAS2MAPR:
case OCLOSE:
case OCOPY:
case OCALLMETH:
case OCALLINTER:
case OCALL:
case OCALLFUNC:
case ODELETE:
case OSEND:
case OPRINT:
case OPRINTN:
case OPANIC:
case OEMPTY:
case ORECOVER:
if(n->typecheck == 0)
fatal("missing typecheck: %+N", n);
init = n->ninit;
n->ninit = nil;
walkexpr(&n, &init);
addinit(&n, init);
if((*np)->op == OCOPY && n->op == OCONVNOP)
n->op = OEMPTY;
break;
case ORECV:
if(n->typecheck == 0)
fatal("missing typecheck: %+N", n);
init = n->ninit;
n->ninit = nil;
walkexpr(&n->left, &init);
n = mkcall1(chanfn("chanrecv1", 2, n->left->type), T, &init, typename(n->left->type), n->left, nodnil());
walkexpr(&n, &init);
addinit(&n, init);
break;
case OBREAK:
case ODCL:
case OCONTINUE:
case OFALL:
case OGOTO:
case OLABEL:
case ODCLCONST:
case ODCLTYPE:
case OCHECKNIL:
case OVARKILL:
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;
case OCOPY:
n->left = copyany(n->left, &n->ninit, 1);
break;
default:
walkexpr(&n->left, &n->ninit);
break;
}
break;
case OFOR:
if(n->ntest != N) {
walkstmtlist(n->ntest->ninit);
init = n->ntest->ninit;
n->ntest->ninit = nil;
walkexpr(&n->ntest, &init);
addinit(&n->ntest, init);
}
walkstmt(&n->nincr);
walkstmtlist(n->nbody);
break;
case OIF:
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;
case OCOPY:
n->left = copyany(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)) {
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)) {
n->list = nil;
break;
}
if(count(n->list) == 1 && count(rl) > 1) {
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;
}
walkexprlistsafe(n->list, &n->ninit);
ll = ascompatee(n->op, rl, n->list, &n->ninit);
n->list = reorder3(ll);
break;
}
ll = ascompatte(n->op, nil, 0, getoutarg(curfn->type), n->list, 1, &n->ninit);
n->list = ll;
break;
case ORETJMP:
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;
}
if(n->op == ONAME)
fatal("walkstmt ended up with name: %+N", n);
*np = n;
}
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;
Node *map, *key;
NodeList *ll, *lr;
Type *t;
int et, old_safemode;
int64 v;
int32 lno;
Node *n, *fn, *n1, *n2;
Sym *sym;
char buf[100], *p;
n = *np;
if(n == N)
return;
if(init == &n->ninit) {
fatal("walkexpr init == &n->ninit");
}
if(n->ninit != nil) {
walkstmtlist(n->ninit);
*init = concat(*init, n->ninit);
n->ninit = nil;
}
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)
fatal("missed typecheck: %+N\n", n);
switch(n->op) {
default:
dump("walk", n);
fatal("walkexpr: switch 1 unknown op %+hN", n);
break;
case OTYPE:
case ONONAME:
case OINDREG:
case OEMPTY:
goto ret;
case ONOT:
case OMINUS:
case OPLUS:
case OCOM:
case OREAL:
case OIMAG:
case ODOTMETH:
case ODOTINTER:
walkexpr(&n->left, init);
goto ret;
case OIND:
walkexpr(&n->left, init);
goto ret;
case ODOT:
usefield(n);
walkexpr(&n->left, init);
goto ret;
case ODOTPTR:
usefield(n);
if(n->op == ODOTPTR && n->left->type->type->width == 0) {
n->left = cheapexpr(n->left, init);
checknil(n->left, init);
}
walkexpr(&n->left, init);
goto ret;
case OEFACE:
walkexpr(&n->left, init);
walkexpr(&n->right, init);
goto ret;
case OSPTR:
case OITAB:
walkexpr(&n->left, init);
goto ret;
case OLEN:
case OCAP:
walkexpr(&n->left, init);
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:
walkexpr(&n->left, init);
walkexpr(&n->right, init);
t = n->left->type;
n->bounded = bounded(n->right, 8*t->width);
if(debug['m'] && n->etype && !isconst(n->right, CTINT))
warn("shift bounds check elided");
goto ret;
case OAND:
case OSUB:
case OHMUL:
case OLT:
case OLE:
case OGE:
case OGT:
case OADD:
case OCOMPLEX:
case OLROT:
if(n->op == OCOMPLEX && n->left == N && n->right == N) {
n->left = n->list->n;
n->right = n->list->next->n;
}
walkexpr(&n->left, init);
walkexpr(&n->right, init);
goto ret;
case OOR:
case OXOR:
walkexpr(&n->left, init);
walkexpr(&n->right, init);
walkrotate(&n);
goto ret;
case OEQ:
case ONE:
walkexpr(&n->left, init);
walkexpr(&n->right, init);
old_safemode = safemode;
safemode = 0;
walkcompare(&n, init);
safemode = old_safemode;
goto ret;
case OANDAND:
case OOROR:
walkexpr(&n->left, init);
ll = nil;
walkexpr(&n->right, &ll);
addinit(&n->right, 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 OCLOSUREVAR:
case OCFUNC:
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, 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;
walkexpr(&n->left, init);
walkexprlist(n->list, init);
ll = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init);
n->list = reorder1(ll);
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, 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);
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;
if(n->right == N)
goto ret;
switch(n->right->op) {
default:
walkexpr(&n->right, init);
break;
case ORECV:
walkexpr(&n->right->left, init);
n1 = nod(OADDR, n->left, N);
r = n->right->left;
n = mkcall1(chanfn("chanrecv1", 2, r->type), T, init, typename(r->type), r, n1);
walkexpr(&n, init);
goto ret;
}
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:
*init = concat(*init, n->ninit);
n->ninit = nil;
r = n->rlist->n;
walkexprlistsafe(n->list, init);
walkexpr(&r, init);
ll = ascompatet(n->op, n->list, &r->type, 0, init);
n = liststmt(concat(list1(r), ll));
goto ret;
case OAS2RECV:
*init = concat(*init, n->ninit);
n->ninit = nil;
r = n->rlist->n;
walkexprlistsafe(n->list, init);
walkexpr(&r->left, init);
if(isblank(n->list->n))
n1 = nodnil();
else
n1 = nod(OADDR, n->list->n, N);
n1->etype = 1;
fn = chanfn("chanrecv2", 2, r->left->type);
r = mkcall1(fn, types[TBOOL], init, typename(r->left->type), r->left, n1);
n = nod(OAS, n->list->next->n, r);
typecheck(&n, Etop);
goto ret;
case OAS2MAPR:
*init = concat(*init, n->ninit);
n->ninit = nil;
r = n->rlist->n;
walkexprlistsafe(n->list, init);
walkexpr(&r->left, init);
walkexpr(&r->right, init);
t = r->left->type;
p = nil;
if(t->type->width <= 128) {
switch(simsimtype(t->down)) {
case TINT32:
case TUINT32:
p = "mapaccess2_fast32";
break;
case TINT64:
case TUINT64:
p = "mapaccess2_fast64";
break;
case TSTRING:
p = "mapaccess2_faststr";
break;
}
}
if(p != nil) {
key = r->right;
} else {
key = nod(OADDR, r->right, N);
p = "mapaccess2";
}
a = n->list->n;
var = temp(ptrto(t->type));
var->typecheck = 1;
fn = mapfn(p, t);
r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, key);
n->rlist = list1(r);
n->op = OAS2FUNC;
n->list->n = var;
walkexpr(&n, init);
*init = list(*init, n);
n = nod(OAS, a, nod(OIND, var, N));
typecheck(&n, Etop);
walkexpr(&n, init);
if(zerosize < t->type->width)
zerosize = t->type->width;
goto ret;
case ODELETE:
*init = concat(*init, n->ninit);
n->ninit = nil;
map = n->list->n;
key = n->list->next->n;
walkexpr(&map, init);
walkexpr(&key, init);
key = nod(OADDR, key, N);
t = map->type;
n = mkcall1(mapfndel("mapdelete", t), T, init, typename(t), map, key);
goto ret;
case OAS2DOTTYPE:
*init = concat(*init, n->ninit);
n->ninit = nil;
r = n->rlist->n;
walkexprlistsafe(n->list, init);
if(isblank(n->list->n) && !isinter(r->type)) {
strcpy(buf, "assert");
p = buf+strlen(buf);
if(isnilinter(r->left->type))
*p++ = 'E';
else
*p++ = 'I';
*p++ = '2';
*p++ = 'T';
*p++ = 'O';
*p++ = 'K';
*p = '\0';
fn = syslook(buf, 1);
ll = list1(typename(r->type));
ll = list(ll, r->left);
argtype(fn, r->left->type);
n1 = nod(OCALL, fn, N);
n1->list = ll;
n = nod(OAS, n->list->next->n, n1);
typecheck(&n, Etop);
walkexpr(&n, init);
goto ret;
}
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:
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:
walkexpr(&n->left, init);
if(!isinter(n->left->type) && isnilinter(n->type) &&
(n->left->type->width == widthptr) &&
isint[simsimtype(n->left->type)]) {
l = nod(OEFACE, typename(n->left->type), n->left);
l->type = n->type;
l->typecheck = n->typecheck;
n = l;
goto ret;
}
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));
if(!isinter(n->left->type) && !isnilinter(n->type)){
sym = pkglookup(smprint("%-T.%-T", n->left->type, n->type), itabpkg);
if(sym->def == N) {
l = nod(ONAME, N, N);
l->sym = sym;
l->type = ptrto(types[TUINT8]);
l->addable = 1;
l->class = PEXTERN;
l->xoffset = 0;
sym->def = l;
ggloblsym(sym, widthptr, 1, 0);
}
l = nod(OADDR, sym->def, N);
l->addable = 1;
ll = list(ll, l);
if(n->left->type->width == widthptr &&
isint[simsimtype(n->left->type)]) {
l = temp(ptrto(types[TUINT8]));
n1 = nod(OAS, l, sym->def);
typecheck(&n1, Etop);
*init = list(*init, n1);
fn = syslook("typ2Itab", 1);
n1 = nod(OCALL, fn, N);
n1->list = ll;
typecheck(&n1, Erv);
walkexpr(&n1, init);
n2 = nod(OIF, N, N);
n2->ntest = nod(OEQ, l, nodnil());
n2->nbody = list1(nod(OAS, l, n1));
n2->likely = -1;
typecheck(&n2, Etop);
*init = list(*init, n2);
l = nod(OEFACE, l, n->left);
l->typecheck = n->typecheck;
l->type = n->type;
n = l;
goto ret;
}
}
if(isinter(n->left->type)) {
ll = list(ll, n->left);
} else {
if(islvalue(n->left))
ll = list(ll, nod(OADDR, n->left, N));
else
ll = list(ll, nod(OADDR, copyexpr(n->left, n->left->type, init), N));
}
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 OANDNOT:
walkexpr(&n->left, init);
n->op = OAND;
n->right = nod(OCOM, n->right, N);
typecheck(&n->right, Erv);
walkexpr(&n->right, init);
goto ret;
case OMUL:
walkexpr(&n->left, init);
walkexpr(&n->right, init);
walkmul(&n, init);
goto ret;
case ODIV:
case OMOD:
walkexpr(&n->left, init);
walkexpr(&n->right, init);
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;
}
if(isfloat[et])
goto ret;
walkdiv(&n, init);
switch(n->op) {
case OMOD:
case ODIV:
if(widthreg >= 8 || (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]));
break;
default:
break;
}
goto ret;
case OINDEX:
walkexpr(&n->left, init);
r = n->right;
walkexpr(&n->right, init);
if(n->bounded)
goto ret;
t = n->left->type;
if(t != T && isptr[t->etype])
t = t->type;
if(isfixedarray(t)) {
n->bounded = bounded(r, t->bound);
if(debug['m'] && n->bounded && !isconst(n->right, CTINT))
warn("index bounds check elided");
if(smallintconst(n->right) && !n->bounded)
yyerror("index out of bounds");
} else if(isconst(n->left, CTSTR)) {
n->bounded = bounded(r, n->left->val.u.sval->len);
if(debug['m'] && n->bounded && !isconst(n->right, CTINT))
warn("index bounds check elided");
if(smallintconst(n->right)) {
if(!n->bounded)
yyerror("index out of bounds");
else {
v = mpgetfix(n->right->val.u.xval);
nodconst(n, n->type, n->left->val.u.sval->s[v]);
n->typecheck = 1;
}
}
}
if(isconst(n->right, CTINT))
if(mpcmpfixfix(n->right->val.u.xval, &mpzero) < 0 ||
mpcmpfixfix(n->right->val.u.xval, maxintval[TINT]) > 0)
yyerror("index out of bounds");
goto ret;
case OINDEXMAP:
if(n->etype == 1)
goto ret;
walkexpr(&n->left, init);
walkexpr(&n->right, init);
t = n->left->type;
p = nil;
if(t->type->width <= 128) {
switch(simsimtype(t->down)) {
case TINT32:
case TUINT32:
p = "mapaccess1_fast32";
break;
case TINT64:
case TUINT64:
p = "mapaccess1_fast64";
break;
case TSTRING:
p = "mapaccess1_faststr";
break;
}
}
if(p != nil) {
key = n->right;
} else {
key = nod(OADDR, n->right, N);
p = "mapaccess1";
}
n = mkcall1(mapfn(p, t), ptrto(t->type), init, typename(t), n->left, key);
n = nod(OIND, n, N);
n->type = t->type;
n->typecheck = 1;
if(zerosize < t->type->width)
zerosize = t->type->width;
goto ret;
case ORECV:
fatal("walkexpr ORECV");
case OSLICE:
if(n->right != N && n->right->left == N && n->right->right == N) {
walkexpr(&n->left, init);
n = n->left;
goto ret;
}
case OSLICEARR:
case OSLICESTR:
if(n->right == N)
goto ret;
walkexpr(&n->left, init);
if((n->op == OSLICESTR && n->left->op == OLITERAL) || (n->left->op == OINDEX))
n->left = copyexpr(n->left, n->left->type, init);
else
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);
n = sliceany(n, init);
goto ret;
case OSLICE3:
case OSLICE3ARR:
if(n->right == N)
goto ret;
walkexpr(&n->left, init);
if(n->left->op == OINDEX)
n->left = copyexpr(n->left, n->left->type, init);
else
n->left = safeexpr(n->left, init);
walkexpr(&n->right->left, init);
n->right->left = safeexpr(n->right->left, init);
walkexpr(&n->right->right->left, init);
n->right->right->left = safeexpr(n->right->right->left, init);
walkexpr(&n->right->right->right, init);
n->right->right->right = safeexpr(n->right->right->right, init);
n = sliceany(n, init);
goto ret;
case OADDR:
walkexpr(&n->left, init);
goto ret;
case ONEW:
if(n->esc == EscNone && n->type->type->width < (1<<16)) {
r = temp(n->type->type);
r = nod(OAS, r, N);
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:
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);
r->type = n->type;
n = r;
goto ret;
}
if((n->etype == OEQ || n->etype == ONE) &&
isconst(n->right, CTSTR) &&
n->left->op == OADDSTR && count(n->left->list) == 2 &&
isconst(n->left->list->next->n, CTSTR) &&
cmpslit(n->right, n->left->list->next->n) == 0) {
r = nod(n->etype, nod(OLEN, n->left->list->n, N), nodintconst(0));
typecheck(&r, Erv);
walkexpr(&r, init);
r->type = n->type;
n = r;
goto ret;
}
if(n->etype == OEQ || n->etype == ONE) {
n->left = cheapexpr(n->left, init);
n->right = cheapexpr(n->right, init);
r = mkcall("eqstring", types[TBOOL], init,
conv(n->left, types[TSTRING]),
conv(n->right, types[TSTRING]));
if(n->etype == OEQ) {
r = nod(OANDAND, nod(OEQ, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
} else {
r = nod(ONOT, r, N);
r = nod(OOROR, nod(ONE, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
}
typecheck(&r, Erv);
walkexpr(&r, nil);
} else {
r = mkcall("cmpstring", types[TINT], init,
conv(n->left, types[TSTRING]),
conv(n->right, types[TSTRING]));
r = nod(n->etype, r, nodintconst(0));
}
typecheck(&r, Erv);
if(n->type->etype != TBOOL) fatal("cmp %T", n->type);
r->type = n->type;
n = r;
goto ret;
case OADDSTR:
n = addstr(n, init);
goto ret;
case OAPPEND:
if(n->isddd)
n = appendslice(n, init);
else
n = append(n, init);
goto ret;
case OCOPY:
n = copyany(n, init, flag_race);
goto ret;
case OCLOSE:
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),
conv(n->left, types[TINT64]));
goto ret;
case OMAKEMAP:
t = n->type;
fn = syslook("makemap", 1);
argtype(fn, t->down);
argtype(fn, t->type);
n = mkcall1(fn, n->type, init,
typename(n->type),
conv(n->left, types[TINT64]));
goto ret;
case OMAKESLICE:
l = n->left;
r = n->right;
if(r == nil)
l = r = safeexpr(l, init);
t = n->type;
if(n->esc == EscNone
&& smallintconst(l) && smallintconst(r)
&& (t->type->width == 0 || mpgetfix(r->val.u.xval) < (1ULL<<16) / t->type->width)) {
t = aindex(r, t->type);
var = temp(t);
a = nod(OAS, var, N);
typecheck(&a, Etop);
*init = list(*init, a);
r = nod(OSLICE, var, nod(OKEY, N, l));
r = conv(r, n->type);
typecheck(&r, Erv);
walkexpr(&r, init);
n = r;
} else {
fn = syslook("makeslice", 1);
argtype(fn, t->type);
n = mkcall1(fn, n->type, init,
typename(n->type),
conv(l, types[TINT64]),
conv(r, types[TINT64]));
}
goto ret;
case ORUNESTR:
n = mkcall("intstring", n->type, init,
conv(n->left, types[TINT64]));
goto ret;
case OARRAYBYTESTR:
n = mkcall("slicebytetostring", n->type, init, n->left);
goto ret;
case OARRAYBYTESTRTMP:
n = mkcall("slicebytetostringtmp", n->type, init, n->left);
goto ret;
case OARRAYRUNESTR:
n = mkcall("slicerunetostring", n->type, init, n->left);
goto ret;
case OSTRARRAYBYTE:
n = mkcall("stringtoslicebyte", n->type, init, conv(n->left, types[TSTRING]));
goto ret;
case OSTRARRAYRUNE:
n = mkcall("stringtoslicerune", n->type, init, n->left);
goto ret;
case OCMPIFACE:
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);
n->right = cheapexpr(n->right, init);
n->left = cheapexpr(n->left, 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)
r = nod(ONOT, r, N);
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, init);
r->type = n->type;
n = r;
goto ret;
case OARRAYLIT:
case OMAPLIT:
case OSTRUCTLIT:
case OPTRLIT:
var = temp(n->type);
anylit(0, n, var, init);
n = var;
goto ret;
case OSEND:
n1 = n->right;
n1 = assignconv(n1, n->left->type->type, "chan send");
walkexpr(&n1, init);
n1 = nod(OADDR, n1, N);
n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, typename(n->left->type), n->left, n1);
goto ret;
case OCLOSURE:
n = walkclosure(n, init);
goto ret;
case OCALLPART:
n = walkpartialcall(n, init);
goto ret;
}
fatal("missing switch %O", n->op);
ret:
t = n->type;
evconst(n);
n->type = t;
if(n->op == OLITERAL)
typecheck(&n, Erv);
ullmancalc(n);
if(debug['w'] && n != N)
dump("walk", n);
lineno = lno;
*np = n;
}
static Node*
ascompatee1(int op, Node *l, Node *r, NodeList **init)
{
Node *n;
USED(op);
n = nod(OAS, l, r);
if(l->op == OINDEXMAP)
return n;
return convas(n, init);
}
static NodeList*
ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init)
{
NodeList *ll, *lr, *nn;
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) {
if(op == ORETURN && ll->n == lr->n)
continue;
nn = list(nn, ascompatee1(op, ll->n, lr->n, init));
}
if(ll || lr)
yyerror("error in shape across %+H %O %+H / %d %d [%s]", nl, op, nr, count(nl), count(nr), curfn->nname->sym->name);
return nn;
}
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;
USED(op);
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;
}
if(fncall(l, r->type)) {
tmp = temp(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("ascompatet: assignment count mismatch: %d = %d",
count(nl), structcount(*nr));
if(ucount)
fatal("ascompatet: too many function calls evaluating parameters");
return concat(nn, mm);
}
static NodeList*
mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, Node *ddd)
{
Node *a, *n;
Type *tslice;
int esc;
esc = EscUnknown;
if(ddd != nil)
esc = ddd->esc;
tslice = typ(TARRAY);
tslice->type = l->type->type;
tslice->bound = -1;
if(count(lr0) == 0) {
n = nodnil();
n->type = tslice;
} else {
n = nod(OCOMPLIT, N, typenod(tslice));
if(ddd != nil)
n->alloc = ddd->alloc;
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));
return nn;
}
static char*
dumptypes(Type **nl, char *what)
{
int first;
Type *l;
Iter savel;
Fmt fmt;
fmtstrinit(&fmt);
fmtprint(&fmt, "\t");
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);
}
static NodeList*
ascompatte(int op, Node *call, 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;
if(r != N && lr->next == nil && r->type->etype == TSTRUCT && r->type->funarg) {
if(eqtypenoname(r->type, *nl)) {
a = nodarg(*nl, fp);
r = nod(OCONVNOP, r, N);
r->type = a->type;
nn = list1(convas(nod(OAS, a, r), init));
goto ret;
}
alist = nil;
for(l=structfirst(&savel, &r->type); l; l=structnext(&savel)) {
a = temp(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) {
ll = structnext(&savel);
if(ll != T)
yyerror("... must be last argument");
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;
}
nn = mkdotargslice(lr, nn, l, fp, init, call->right);
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;
}
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) {
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 CTRUNE:
defaultlit(&n, runetype);
break;
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);
}
} 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);
}
} else if(isslice(n->type)) {
if(defer) {
fmtprint(&fmt, "%%a");
} else {
on = syslook("printslice", 1);
argtype(on, n->type);
}
} 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, typename(t));
}
static Node*
convas(Node *n, NodeList **init)
{
Type *lt, *rt;
Node *map, *key, *val;
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) {
map = n->left->left;
key = n->left->right;
val = n->right;
walkexpr(&map, init);
walkexpr(&key, init);
walkexpr(&val, init);
key = nod(OADDR, key, N);
val = nod(OADDR, val, N);
n = mkcall1(mapfn("mapassign1", map->type), T, init,
typename(map->type), map, key, val);
goto out;
}
if(eqtype(lt, rt))
goto out;
n->right = assignconv(n->right, lt, "assignment");
walkexpr(&n->right, init);
out:
ullmancalc(n);
return n;
}
static NodeList*
reorder1(NodeList *all)
{
Node *f, *a, *n;
NodeList *l, *r, *g;
int c, d, t;
c = 0;
t = 0;
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;
f = N;
r = nil;
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;
}
a = temp(n->right->type);
a = nod(OAS, a, n->right);
g = list(g, a);
n->right = a->left;
r = list(r, n);
}
if(f != N)
g = list(g, f);
return concat(g, r);
}
static void reorder3save(Node**, NodeList*, NodeList*, NodeList**);
static int aliased(Node*, NodeList*, NodeList*);
static NodeList*
reorder3(NodeList *all)
{
NodeList *list, *early, *mapinit;
Node *l;
early = nil;
mapinit = nil;
for(list=all; list; list=list->next) {
l = list->n->left;
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:
case OINDEXMAP:
reorder3save(&l->left, all, list, &early);
reorder3save(&l->right, all, list, &early);
if(l->op == OINDEXMAP)
list->n = convas(list->n, &mapinit);
break;
case OIND:
case ODOTPTR:
reorder3save(&l->left, all, list, &early);
}
reorder3save(&list->n->right, all, list, &early);
}
early = concat(mapinit, early);
return concat(early, all);
}
static int vmatch2(Node*, Node*);
static int varexpr(Node*);
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;
}
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;
}
static int
aliased(Node *n, NodeList *all, NodeList *stop)
{
int memwrite, varwrite;
Node *a;
NodeList *l;
if(n == N)
return 0;
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)) {
return 1;
}
}
}
if(!memwrite && !varwrite)
return 0;
if(varexpr(n))
return 0;
return 1;
}
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:
case OCONV:
case OCONVNOP:
case OCONVIFACE:
case ODOTTYPE:
return varexpr(n->left) && varexpr(n->right);
}
return 0;
}
static int
vmatch2(Node *l, Node *r)
{
NodeList *ll;
if(r == N)
return 0;
switch(r->op) {
case ONAME:
return l == r;
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;
if(l == N || r == N)
return 0;
switch(l->op) {
case ONAME:
switch(l->class) {
case PPARAM:
case PPARAMREF:
case PAUTO:
break;
default:
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;
}
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 && v->sym && v->sym->name[0] == '~' && v->sym->name[1] == 'r')
v = N;
if(out && (precisestack_enabled || (v == N && hasdefer))) {
nn = list(nn, nod(OAS, nodarg(t, 1), N));
}
if(v == N || !(v->class & PHEAP))
continue;
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;
}
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;
}
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;
}
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*
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, *slice;
NodeList *args, *l;
int c;
Type *t;
c = count(n->list);
if(c < 2)
yyerror("addstr count %d too small", c);
args = nil;
for(l=n->list; l != nil; l=l->next)
args = list(args, conv(l->n, types[TSTRING]));
if(c <= 5) {
snprint(namebuf, sizeof(namebuf), "concatstring%d", c);
} else {
strcpy(namebuf, "concatstrings");
t = typ(TARRAY);
t->type = types[TSTRING];
t->bound = -1;
slice = nod(OCOMPLIT, N, typenod(t));
slice->alloc = n->alloc;
slice->list = args;
slice->esc = EscNone;
args = list1(slice);
}
cat = syslook(namebuf, 1);
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)
{
NodeList *l;
Node *l1, *l2, *nt, *nif, *fn;
Node *nptr1, *nptr2, *nwid;
Node *s;
walkexprlistsafe(n->list, init);
for(l=n->list; l; l=l->next)
l->n = cheapexpr(l->n, init);
l1 = n->list->n;
l2 = n->list->next->n;
s = temp(l1->type);
l = nil;
l = list(l, nod(OAS, s, l1));
nt = temp(types[TINT]);
nif = nod(OIF, N, N);
nif->ninit = list1(nod(OAS, nt,
nod(OSUB, nod(OADD, nod(OLEN, s, N), nod(OLEN, l2, N)), nod(OCAP, s, N))));
nif->ntest = nod(OGT, nt, nodintconst(0));
fn = syslook("growslice", 1);
argtype(fn, s->type->type);
argtype(fn, s->type->type);
nif->nbody = list1(nod(OAS, s, mkcall1(fn, s->type, &nif->ninit,
typename(s->type),
s,
conv(nt, types[TINT64]))));
l = list(l, nif);
if(flag_race) {
nptr1 = nod(OSLICE, s, nod(OKEY,
nod(OLEN, l1, N),
nod(OADD, nod(OLEN, l1, N), nod(OLEN, l2, N))));
nptr1->etype = 1;
nptr2 = l2;
if(l2->type->etype == TSTRING)
fn = syslook("slicestringcopy", 1);
else
fn = syslook("copy", 1);
argtype(fn, l1->type);
argtype(fn, l2->type);
nt = mkcall1(fn, types[TINT], &l,
nptr1, nptr2,
nodintconst(s->type->type->width));
l = list(l, nt);
} else {
nptr1 = nod(OINDEX, s, nod(OLEN, l1, N));
nptr1->bounded = 1;
nptr1 = nod(OADDR, nptr1, N);
nptr2 = nod(OSPTR, l2, N);
fn = syslook("memmove", 1);
argtype(fn, s->type->type);
argtype(fn, s->type->type);
nwid = cheapexpr(conv(nod(OLEN, l2, N), types[TUINTPTR]), &l);
nwid = nod(OMUL, nwid, nodintconst(s->type->type->width));
nt = mkcall1(fn, T, &l, nptr1, nptr2, nwid);
l = list(l, nt);
}
nt = nod(OADD, nod(OLEN, l1, N), nod(OLEN, l2, N));
nt = nod(OSLICE, s, nod(OKEY, N, nt));
nt->etype = 1;
l = list(l, nod(OAS, s, nt));
typechecklist(l, Etop);
walkstmtlist(l);
*init = concat(*init, l);
return s;
}
static Node*
append(Node *n, NodeList **init)
{
NodeList *l, *a;
Node *nsrc, *ns, *nn, *na, *nx, *fn;
int argc;
walkexprlistsafe(n->list, init);
for(l=n->list; l; l=l->next)
l->n = cheapexpr(l->n, init);
nsrc = n->list->n;
if(istype(nsrc->type, TSTRUCT))
nsrc->type = nsrc->type->type->type;
argc = count(n->list) - 1;
if (argc < 1) {
return nsrc;
}
l = nil;
ns = temp(nsrc->type);
l = list(l, nod(OAS, ns, nsrc));
na = nodintconst(argc);
nx = nod(OIF, N, N);
nx->ntest = nod(OLT, nod(OSUB, nod(OCAP, ns, N), nod(OLEN, ns, N)), na);
fn = syslook("growslice", 1);
argtype(fn, ns->type->type);
argtype(fn, ns->type->type);
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 = temp(types[TINT]);
l = list(l, nod(OAS, nn, nod(OLEN, ns, N)));
nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na)));
nx->etype = 1;
l = list(l, nod(OAS, ns, nx));
for (a = n->list->next; a != nil; a = a->next) {
nx = nod(OINDEX, ns, nn);
nx->bounded = 1;
l = list(l, nod(OAS, nx, a->n));
if (a->next != nil)
l = list(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1))));
}
typechecklist(l, Etop);
walkstmtlist(l);
*init = concat(*init, l);
return ns;
}
static Node*
copyany(Node *n, NodeList **init, int runtimecall)
{
Node *nl, *nr, *nfrm, *nto, *nif, *nlen, *nwid, *fn;
NodeList *l;
if(runtimecall) {
if(n->right->type->etype == TSTRING)
fn = syslook("slicestringcopy", 1);
else
fn = syslook("copy", 1);
argtype(fn, n->left->type);
argtype(fn, n->right->type);
return mkcall1(fn, n->type, init,
n->left, n->right,
nodintconst(n->left->type->type->width));
}
walkexpr(&n->left, init);
walkexpr(&n->right, init);
nl = temp(n->left->type);
nr = temp(n->right->type);
l = nil;
l = list(l, nod(OAS, nl, n->left));
l = list(l, nod(OAS, nr, n->right));
nfrm = nod(OSPTR, nr, N);
nto = nod(OSPTR, nl, N);
nlen = temp(types[TINT]);
l = list(l, nod(OAS, nlen, nod(OLEN, nl, N)));
nif = nod(OIF, N, N);
nif->ntest = nod(OGT, nlen, nod(OLEN, nr, N));
nif->nbody = list(nif->nbody,
nod(OAS, nlen, nod(OLEN, nr, N)));
l = list(l, nif);
fn = syslook("memmove", 1);
argtype(fn, nl->type->type);
argtype(fn, nl->type->type);
nwid = temp(types[TUINTPTR]);
l = list(l, nod(OAS, nwid, conv(nlen, types[TUINTPTR])));
nwid = nod(OMUL, nwid, nodintconst(nl->type->type->width));
l = list(l, mkcall1(fn, T, init, nto, nfrm, nwid));
typechecklist(l, Etop);
walkstmtlist(l);
*init = concat(*init, l);
return nlen;
}
static Node*
sliceany(Node* n, NodeList **init)
{
int bounded, slice3;
Node *src, *lb, *hb, *cb, *bound, *chk, *chk0, *chk1, *chk2;
int64 lbv, hbv, cbv, bv, w;
Type *bt;
src = n->left;
lb = n->right->left;
slice3 = n->op == OSLICE3 || n->op == OSLICE3ARR;
if(slice3) {
hb = n->right->right->left;
cb = n->right->right->right;
} else {
hb = n->right->right;
cb = N;
}
bounded = n->etype;
if(n->op == OSLICESTR)
bound = nod(OLEN, src, N);
else
bound = nod(OCAP, src, N);
typecheck(&bound, Erv);
walkexpr(&bound, init);
bv = 1LL<<50;
if(isconst(bound, CTINT)) {
if(!smallintconst(bound))
yyerror("array len too large");
else
bv = mpgetfix(bound->val.u.xval);
}
if(isconst(cb, CTINT)) {
cbv = mpgetfix(cb->val.u.xval);
if(cbv < 0 || cbv > bv)
yyerror("slice index out of bounds");
}
if(isconst(hb, CTINT)) {
hbv = mpgetfix(hb->val.u.xval);
if(hbv < 0 || hbv > bv)
yyerror("slice index out of bounds");
}
if(isconst(lb, CTINT)) {
lbv = mpgetfix(lb->val.u.xval);
if(lbv < 0 || lbv > bv) {
yyerror("slice index out of bounds");
lbv = -1;
}
if(lbv == 0)
lb = N;
}
chk = N;
chk0 = N;
chk1 = N;
chk2 = N;
bt = types[simtype[TUINT]];
if(cb != N && cb->type->width > 4)
bt = types[TUINT64];
if(hb != N && hb->type->width > 4)
bt = types[TUINT64];
if(lb != N && lb->type->width > 4)
bt = types[TUINT64];
bound = cheapexpr(conv(bound, bt), init);
if(cb != N) {
cb = cheapexpr(conv(cb, bt), init);
if(!bounded)
chk0 = nod(OLT, bound, cb);
} else if(slice3) {
fatal("slice3 with cb == N");
}
if(hb != N) {
hb = cheapexpr(conv(hb, bt), init);
if(!bounded) {
if(cb != N)
chk1 = nod(OLT, cb, hb);
else
chk1 = nod(OLT, bound, hb);
}
} else if(slice3) {
fatal("slice3 with hb == N");
} else if(n->op == OSLICEARR) {
hb = bound;
} else {
hb = nod(OLEN, src, N);
typecheck(&hb, Erv);
walkexpr(&hb, init);
hb = cheapexpr(conv(hb, bt), init);
}
if(lb != N) {
lb = cheapexpr(conv(lb, bt), init);
if(!bounded)
chk2 = nod(OLT, hb, lb);
}
if(chk0 != N || chk1 != N || chk2 != N) {
chk = nod(OIF, N, N);
chk->nbody = list1(mkcall("panicslice", T, init));
chk->likely = -1;
if(chk0 != N)
chk->ntest = chk0;
if(chk1 != N) {
if(chk->ntest == N)
chk->ntest = chk1;
else
chk->ntest = nod(OOROR, chk->ntest, chk1);
}
if(chk2 != N) {
if(chk->ntest == N)
chk->ntest = chk2;
else
chk->ntest = nod(OOROR, chk->ntest, chk2);
}
typecheck(&chk, Etop);
walkstmt(&chk);
*init = concat(*init, chk->ninit);
chk->ninit = nil;
*init = list(*init, chk);
}
n->right = N;
n->list = nil;
if(!slice3)
cb = bound;
if(lb == N)
bound = conv(cb, types[simtype[TUINT]]);
else
bound = nod(OSUB, conv(cb, types[simtype[TUINT]]), conv(lb, types[simtype[TUINT]]));
typecheck(&bound, Erv);
walkexpr(&bound, init);
n->list = list(n->list, bound);
if(lb == N)
hb = conv(hb, types[simtype[TUINT]]);
else
hb = nod(OSUB, conv(hb, types[simtype[TUINT]]), conv(lb, types[simtype[TUINT]]));
typecheck(&hb, Erv);
walkexpr(&hb, init);
n->list = list(n->list, hb);
if(lb != N) {
if(n->op == OSLICESTR)
w = 1;
else
w = n->type->type->width;
lb = conv(lb, types[TUINTPTR]);
if(w > 1)
lb = nod(OMUL, nodintconst(w), lb);
typecheck(&lb, Erv);
walkexpr(&lb, init);
n->list = list(n->list, lb);
}
return n;
}
static Node*
eqfor(Type *t)
{
int a;
Node *n;
Node *ntype;
Sym *sym;
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;
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;
typecheck(&a, Etop);
*init = list(*init, a);
r = temp(ptrto(t));
a = nod(OAS, r, nod(OADDR, n->right, N));
a->right->etype = 1;
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]) {
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);
r = expr;
goto ret;
}
if(t->etype == TSTRUCT && countfield(t) <= 4) {
for(t1=t->type; t1; t1=t1->down) {
if(isblanksym(t1->sym))
continue;
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);
r = expr;
goto ret;
}
if(tempbool == N || tempbool->curfn != curfn)
tempbool = temp(types[TBOOL]);
call = nod(OCALL, eqfor(t), N);
a = nod(OADDR, tempbool, N);
a->etype = 1;
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);
r = temp(types[TBOOL]);
a = nod(OAS, r, tempbool);
typecheck(&a, Etop);
walkstmt(&a);
*init = list(*init, a);
if(n->op != OEQ)
r = nod(ONOT, r, N);
goto ret;
hard:
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);
}
goto ret;
ret:
typecheck(&r, Erv);
walkexpr(&r, init);
if(r->type != n->type) {
r = nod(OCONVNOP, r, N);
r->type = n->type;
r->typecheck = 1;
}
*np = r;
return;
}
static int
samecheap(Node *a, Node *b)
{
Node *ar, *br;
while(a != N && b != N && a->op == b->op) {
switch(a->op) {
default:
return 0;
case ONAME:
return a == b;
case ODOT:
case ODOTPTR:
ar = a->right;
br = b->right;
if(ar->op != ONAME || br->op != ONAME || ar->sym != br->sym)
return 0;
break;
case OINDEX:
ar = a->right;
br = b->right;
if(!isconst(ar, CTINT) || !isconst(br, CTINT) || mpcmpfixfix(ar->val.u.xval, br->val.u.xval) != 0)
return 0;
break;
}
a = a->left;
b = b->left;
}
return 0;
}
static void
walkrotate(Node **np)
{
int w, sl, sr, s;
Node *l, *r;
Node *n;
n = *np;
l = n->left;
r = n->right;
if((n->op != OOR && n->op != OXOR) ||
(l->op != OLSH && l->op != ORSH) ||
(r->op != OLSH && r->op != ORSH) ||
n->type == T || issigned[n->type->etype] ||
l->op == r->op) {
return;
}
if(!samecheap(l->left, r->left))
return;
w = l->type->width * 8;
if(smallintconst(l->right) && smallintconst(r->right)) {
if((sl=mpgetfix(l->right->val.u.xval)) >= 0 && (sr=mpgetfix(r->right->val.u.xval)) >= 0 && sl+sr == w)
goto yes;
return;
}
return;
yes:
if(l->op == OLSH)
n = l;
else
n = r;
n->op = OLROT;
s = mpgetfix(n->right->val.u.xval);
if(s == 0 || s == w)
n = n->left;
*np = n;
return;
}
static void
walkmul(Node **np, NodeList **init)
{
Node *n, *nl, *nr;
int pow, neg, w;
n = *np;
if(!isint[n->type->etype])
return;
if(n->right->op == OLITERAL) {
nl = n->left;
nr = n->right;
} else if(n->left->op == OLITERAL) {
nl = n->right;
nr = n->left;
} else
return;
neg = 0;
if(mpgetfix(nr->val.u.xval) == 0) {
cheapexpr(nl, init);
nodconst(n, n->type, 0);
goto ret;
}
pow = powtwo(nr);
if(pow < 0)
return;
if(pow >= 1000) {
neg = 1;
pow -= 1000;
}
w = nl->type->width*8;
if(pow+1 >= w)
return;
nl = cheapexpr(nl, init);
if(pow == 0) {
n = nl;
goto ret;
}
n = nod(OLSH, nl, nodintconst(pow));
ret:
if(neg)
n = nod(OMINUS, n, N);
typecheck(&n, Erv);
walkexpr(&n, init);
*np = n;
}
static void
walkdiv(Node **np, NodeList **init)
{
Node *n, *nl, *nr, *nc;
Node *n1, *n2, *n3, *n4;
int pow;
int s;
int w;
Type *twide;
Magic m;
n = *np;
if(n->right->op != OLITERAL)
return;
nl = cheapexpr(n->left, init);
nr = n->right;
w = nl->type->width*8;
s = 0;
pow = powtwo(nr);
if(pow >= 1000) {
s = 1;
pow -= 1000;
}
if(pow+1 >= w) {
return;
}
if(pow < 0) {
goto divbymul;
}
switch(pow) {
case 0:
if(n->op == OMOD) {
nodconst(n, n->type, 0);
} else if(s) {
n->op = OMINUS;
n->right = N;
} else {
n = nl;
}
break;
default:
if(issigned[n->type->etype]) {
if(n->op == OMOD) {
nc = nod(OXXX, N, N);
nodconst(nc, types[simtype[TUINT]], w-1);
n1 = nod(ORSH, nl, nc);
if(pow == 1) {
typecheck(&n1, Erv);
n1 = cheapexpr(n1, init);
n2 = nod(OSUB, nl, n1);
nc = nod(OXXX, N, N);
nodconst(nc, nl->type, 1);
n3 = nod(OAND, n2, nc);
n = nod(OADD, n3, n1);
} else {
nc = nod(OXXX, N, N);
nodconst(nc, nl->type, (1LL<<pow)-1);
n2 = nod(OAND, n1, nc);
typecheck(&n2, Erv);
n2 = cheapexpr(n2, init);
n3 = nod(OADD, nl, n2);
n4 = nod(OAND, n3, nc);
n = nod(OSUB, n4, n2);
}
break;
} else {
nc = nod(OXXX, N, N);
nodconst(nc, types[simtype[TUINT]], w-1);
n1 = nod(ORSH, nl, nc);
if(pow == 1) {
n->left = nod(OSUB, nl, n1);
} else {
nc = nod(OXXX, N, N);
nodconst(nc, types[simtype[TUINT]], w-pow);
n2 = nod(ORSH, conv(n1, tounsigned(nl->type)), nc);
n->left = nod(OADD, nl, conv(n2, nl->type));
}
n->op = ORSH;
nc = nod(OXXX, N, N);
nodconst(nc, types[simtype[TUINT]], pow);
n->right = nc;
n->typecheck = 0;
}
if(s)
n = nod(OMINUS, n, N);
break;
}
nc = nod(OXXX, N, N);
if(n->op == OMOD) {
n->op = OAND;
nodconst(nc, nl->type, mpgetfix(nr->val.u.xval)-1);
} else {
n->op = ORSH;
nodconst(nc, types[simtype[TUINT]], pow);
}
n->typecheck = 0;
n->right = nc;
break;
}
goto ret;
divbymul:
m.w = w;
if(issigned[nl->type->etype]) {
m.sd = mpgetfix(nr->val.u.xval);
smagic(&m);
} else {
m.ud = mpgetfix(nr->val.u.xval);
umagic(&m);
}
if(m.bad)
return;
if(n->op == OMOD)
goto longmod;
switch(simtype[nl->type->etype]) {
default:
return;
case TUINT8:
case TUINT16:
case TUINT32:
nc = nod(OXXX, N, N);
nodconst(nc, nl->type, m.um);
n1 = nod(OMUL, nl, nc);
typecheck(&n1, Erv);
n1->op = OHMUL;
if(m.ua) {
switch(simtype[nl->type->etype]) {
default:
return;
case TUINT8:
case TUINT16:
twide = types[TUINT32];
break;
case TUINT32:
twide = types[TUINT64];
break;
case TINT8:
case TINT16:
twide = types[TINT32];
break;
case TINT32:
twide = types[TINT64];
break;
}
n2 = nod(OADD, conv(n1, twide), conv(nl, twide));
nc = nod(OXXX, N, N);
nodconst(nc, types[TUINT], m.s);
n = conv(nod(ORSH, n2, nc), nl->type);
} else {
nc = nod(OXXX, N, N);
nodconst(nc, types[TUINT], m.s);
n = nod(ORSH, n1, nc);
}
break;
case TINT8:
case TINT16:
case TINT32:
nc = nod(OXXX, N, N);
nodconst(nc, nl->type, m.sm);
n1 = nod(OMUL, nl, nc);
typecheck(&n1, Erv);
n1->op = OHMUL;
if(m.sm < 0) {
n1 = nod(OADD, n1, nl);
}
nc = nod(OXXX, N, N);
nodconst(nc, types[TUINT], m.s);
n2 = conv(nod(ORSH, n1, nc), nl->type);
nc = nod(OXXX, N, N);
nodconst(nc, types[TUINT], w-1);
n3 = nod(ORSH, nl, nc);
n = nod(OSUB, n2, n3);
if(m.sd < 0)
n = nod(OMINUS, n, N);
break;
}
goto ret;
longmod:
n1 = nod(ODIV, nl, nr);
n2 = nod(OMUL, n1, nr);
n = nod(OSUB, nl, n2);
goto ret;
ret:
typecheck(&n, Erv);
walkexpr(&n, init);
*np = n;
}
static int
bounded(Node *n, int64 max)
{
int64 v;
int32 bits;
int sign;
if(n->type == T || !isint[n->type->etype])
return 0;
sign = issigned[n->type->etype];
bits = 8*n->type->width;
if(smallintconst(n)) {
v = mpgetfix(n->val.u.xval);
return 0 <= v && v < max;
}
switch(n->op) {
case OAND:
v = -1;
if(smallintconst(n->left)) {
v = mpgetfix(n->left->val.u.xval);
} else if(smallintconst(n->right)) {
v = mpgetfix(n->right->val.u.xval);
}
if(0 <= v && v < max)
return 1;
break;
case OMOD:
if(!sign && smallintconst(n->right)) {
v = mpgetfix(n->right->val.u.xval);
if(0 <= v && v <= max)
return 1;
}
break;
case ODIV:
if(!sign && smallintconst(n->right)) {
v = mpgetfix(n->right->val.u.xval);
while(bits > 0 && v >= 2) {
bits--;
v >>= 1;
}
}
break;
case ORSH:
if(!sign && smallintconst(n->right)) {
v = mpgetfix(n->right->val.u.xval);
if(v > bits)
return 1;
bits -= v;
}
break;
}
if(!sign && bits <= 62 && (1LL<<bits) <= max)
return 1;
return 0;
}
void
usefield(Node *n)
{
Type *field, *l;
if(!fieldtrack_enabled)
return;
switch(n->op) {
default:
fatal("usefield %O", n->op);
case ODOT:
case ODOTPTR:
break;
}
field = n->paramfld;
if(field == T)
fatal("usefield %T %S without paramfld", n->left->type, n->right->sym);
if(field->note == nil || strstr(field->note->s, "go:\"track\"") == nil)
return;
if(field->lastfn == curfn)
return;
field->lastfn = curfn;
field->outer = n->left->type;
if(isptr[field->outer->etype])
field->outer = field->outer->type;
if(field->outer->sym == S)
yyerror("tracked field must be in named struct type");
if(!exportname(field->sym->name))
yyerror("tracked field must be exported (upper case)");
l = typ(0);
l->type = field;
l->down = curfn->paramfld;
curfn->paramfld = l;
}
static int
candiscardlist(NodeList *l)
{
for(; l; l=l->next)
if(!candiscard(l->n))
return 0;
return 1;
}
int
candiscard(Node *n)
{
if(n == N)
return 1;
switch(n->op) {
default:
return 0;
case ONAME:
case ONONAME:
case OTYPE:
case OPACK:
case OLITERAL:
case OADD:
case OSUB:
case OOR:
case OXOR:
case OADDSTR:
case OADDR:
case OANDAND:
case OARRAYBYTESTR:
case OARRAYRUNESTR:
case OSTRARRAYBYTE:
case OSTRARRAYRUNE:
case OCAP:
case OCMPIFACE:
case OCMPSTR:
case OCOMPLIT:
case OMAPLIT:
case OSTRUCTLIT:
case OARRAYLIT:
case OPTRLIT:
case OCONV:
case OCONVIFACE:
case OCONVNOP:
case ODOT:
case OEQ:
case ONE:
case OLT:
case OLE:
case OGT:
case OGE:
case OKEY:
case OLEN:
case OMUL:
case OLSH:
case ORSH:
case OAND:
case OANDNOT:
case ONEW:
case ONOT:
case OCOM:
case OPLUS:
case OMINUS:
case OOROR:
case OPAREN:
case ORUNESTR:
case OREAL:
case OIMAG:
case OCOMPLEX:
break;
case ODIV:
case OMOD:
if(isconst(n->right, CTINT) && mpcmpfixc(n->right->val.u.xval, 0) != 0)
break;
if(isconst(n->right, CTFLT) && mpcmpfltc(n->right->val.u.fval, 0) != 0)
break;
return 0;
case OMAKECHAN:
case OMAKEMAP:
if(isconst(n->left, CTINT) && mpcmpfixc(n->left->val.u.xval, 0) == 0)
break;
return 0;
case OMAKESLICE:
return 0;
}
if(!candiscard(n->left) ||
!candiscard(n->right) ||
!candiscard(n->ntest) ||
!candiscard(n->nincr) ||
!candiscardlist(n->ninit) ||
!candiscardlist(n->nbody) ||
!candiscardlist(n->nelse) ||
!candiscardlist(n->list) ||
!candiscardlist(n->rlist)) {
return 0;
}
return 1;
}