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.c543
1 files changed, 349 insertions, 194 deletions
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 1cb25512e..ff9b36208 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -5,8 +5,11 @@
#include <u.h>
#include <libc.h>
#include "go.h"
+#include "../ld/textflag.h"
-static Node* walkprint(Node*, NodeList**, int);
+static Node* walkprint(Node*, NodeList**);
+static Node* writebarrierfn(char*, Type*, Type*);
+static Node* applywritebarrier(Node*, NodeList**);
static Node* mapfn(char*, Type*);
static Node* mapfndel(char*, Type*);
static Node* ascompatee1(int, Node*, Node*, NodeList**);
@@ -29,6 +32,7 @@ static void walkmul(Node**, NodeList**);
static void walkdiv(Node**, NodeList**);
static int bounded(Node*, int64);
static Mpint mpzero;
+static void walkprintfunc(Node**, NodeList**);
void
walk(Node *fn)
@@ -134,6 +138,8 @@ walkstmt(Node **np)
n = *np;
if(n == N)
return;
+ if(n->dodata == 2) // don't walk, generated by anylit.
+ return;
setlineno(n);
@@ -221,8 +227,7 @@ walkstmt(Node **np)
switch(n->left->op) {
case OPRINT:
case OPRINTN:
- walkexprlist(n->left->list, &n->ninit);
- n->left = walkprint(n->left, &n->ninit, 1);
+ walkprintfunc(&n->left, &n->ninit);
break;
case OCOPY:
n->left = copyany(n->left, &n->ninit, 1);
@@ -255,8 +260,7 @@ walkstmt(Node **np)
switch(n->left->op) {
case OPRINT:
case OPRINTN:
- walkexprlist(n->left->list, &n->ninit);
- n->left = walkprint(n->left, &n->ninit, 1);
+ walkprintfunc(&n->left, &n->ninit);
break;
case OCOPY:
n->left = copyany(n->left, &n->ninit, 1);
@@ -538,15 +542,15 @@ walkexpr(Node **np, NodeList **init)
case OPRINT:
case OPRINTN:
walkexprlist(n->list, init);
- n = walkprint(n, init, 0);
+ n = walkprint(n, init);
goto ret;
case OPANIC:
- n = mkcall("panic", T, init, n->left);
+ n = mkcall("gopanic", T, init, n->left);
goto ret;
case ORECOVER:
- n = mkcall("recover", n->type, init, nod(OADDR, nodfp, N));
+ n = mkcall("gorecover", n->type, init, nod(OADDR, nodfp, N));
goto ret;
case OLITERAL:
@@ -609,7 +613,7 @@ walkexpr(Node **np, NodeList **init)
if(oaslit(n, init))
goto ret;
- if(n->right == N)
+ if(n->right == N || iszero(n->right) && !flag_race)
goto ret;
switch(n->right->op) {
@@ -632,6 +636,7 @@ walkexpr(Node **np, NodeList **init)
r = convas(nod(OAS, n->left, n->right), init);
r->dodata = n->dodata;
n = r;
+ n = applywritebarrier(n, init);
}
goto ret;
@@ -643,6 +648,8 @@ walkexpr(Node **np, NodeList **init)
walkexprlistsafe(n->rlist, init);
ll = ascompatee(OAS, n->list, n->rlist, init);
ll = reorder3(ll);
+ for(lr = ll; lr != nil; lr = lr->next)
+ lr->n = applywritebarrier(lr->n, init);
n = liststmt(ll);
goto ret;
@@ -655,6 +662,8 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&r, init);
ll = ascompatet(n->op, n->list, &r->type, 0, init);
+ for(lr = ll; lr != nil; lr = lr->next)
+ lr->n = applywritebarrier(lr->n, init);
n = liststmt(concat(list1(r), ll));
goto ret;
@@ -672,7 +681,7 @@ walkexpr(Node **np, NodeList **init)
n1 = nod(OADDR, n->list->n, N);
n1->etype = 1; // addr does not escape
fn = chanfn("chanrecv2", 2, r->left->type);
- r = mkcall1(fn, types[TBOOL], init, typename(r->left->type), r->left, n1);
+ r = mkcall1(fn, n->list->next->n->type, init, typename(r->left->type), r->left, n1);
n = nod(OAS, n->list->next->n, r);
typecheck(&n, Etop);
goto ret;
@@ -687,7 +696,7 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&r->right, init);
t = r->left->type;
p = nil;
- if(t->type->width <= 128) { // Check ../../pkg/runtime/hashmap.c:MAXVALUESIZE before changing.
+ if(t->type->width <= 128) { // Check ../../runtime/hashmap.c:MAXVALUESIZE before changing.
switch(simsimtype(t->down)) {
case TINT32:
case TUINT32:
@@ -722,6 +731,12 @@ walkexpr(Node **np, NodeList **init)
var->typecheck = 1;
fn = mapfn(p, t);
r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, key);
+
+ // mapaccess2* returns a typed bool, but due to spec changes,
+ // the boolean result of i.(T) is now untyped so we make it the
+ // same type as the variable on the lhs.
+ if(!isblank(n->list->next->n))
+ r->type->type->down->type = n->list->next->n->type;
n->rlist = list1(r);
n->op = OAS2FUNC;
n->list->n = var;
@@ -769,6 +784,12 @@ walkexpr(Node **np, NodeList **init)
*p = '\0';
fn = syslook(buf, 1);
+
+ // runtime.assert(E|I)2TOK returns a typed bool, but due
+ // to spec changes, the boolean result of i.(T) is now untyped
+ // so we make it the same type as the variable on the lhs.
+ if(!isblank(n->list->next->n))
+ fn->type->type->down->type->type = n->list->next->n->type;
ll = list1(typename(r->type));
ll = list(ll, r->left);
argtype(fn, r->left->type);
@@ -821,9 +842,7 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&n->left, init);
// Optimize convT2E as a two-word copy when T is uintptr-shaped.
- if(!isinter(n->left->type) && isnilinter(n->type) &&
- (n->left->type->width == widthptr) &&
- isint[simsimtype(n->left->type)]) {
+ if(isnilinter(n->type) && isdirectiface(n->left->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;
@@ -865,14 +884,13 @@ walkexpr(Node **np, NodeList **init)
l->class = PEXTERN;
l->xoffset = 0;
sym->def = l;
- ggloblsym(sym, widthptr, 1, 0);
+ ggloblsym(sym, widthptr, DUPOK|NOPTR);
}
l = nod(OADDR, sym->def, N);
l->addable = 1;
ll = list(ll, l);
- if(n->left->type->width == widthptr &&
- isint[simsimtype(n->left->type)]) {
+ if(isdirectiface(n->left->type) && n->left->type->width == widthptr && isint[simsimtype(n->left->type)]) {
/* For pointer types, we can make a special form of optimization
*
* These statements are put onto the expression init list:
@@ -1073,7 +1091,7 @@ walkexpr(Node **np, NodeList **init)
t = n->left->type;
p = nil;
- if(t->type->width <= 128) { // Check ../../pkg/runtime/hashmap.c:MAXVALUESIZE before changing.
+ if(t->type->width <= 128) { // Check ../../runtime/hashmap.c:MAXVALUESIZE before changing.
switch(simsimtype(t->down)) {
case TINT32:
case TUINT32:
@@ -1371,7 +1389,6 @@ walkexpr(Node **np, NodeList **init)
case OMAPLIT:
case OSTRUCTLIT:
case OPTRLIT:
- // XXX TODO do we need to clear var?
var = temp(n->type);
anylit(0, n, var, init);
n = var;
@@ -1471,8 +1488,13 @@ ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init)
static int
fncall(Node *l, Type *rt)
{
+ Node r;
+
if(l->ullman >= UINF || l->op == OINDEXMAP)
return 1;
+ memset(&r, 0, sizeof r);
+ if(needwritebarrier(l, &r))
+ return 1;
if(eqtype(l->type, rt))
return 0;
return 1;
@@ -1523,8 +1545,10 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
a = nod(OAS, l, nodarg(r, fp));
a = convas(a, init);
ullmancalc(a);
- if(a->ullman >= UINF)
+ if(a->ullman >= UINF) {
+ dump("ascompatet ucount", a);
ucount++;
+ }
nn = list(nn, a);
r = structnext(&saver);
}
@@ -1732,7 +1756,7 @@ ret:
// generate code for print
static Node*
-walkprint(Node *nn, NodeList **init, int defer)
+walkprint(Node *nn, NodeList **init)
{
Node *r;
Node *n;
@@ -1740,31 +1764,17 @@ walkprint(Node *nn, NodeList **init, int defer)
Node *on;
Type *t;
int notfirst, et, op;
- NodeList *calls, *intypes, *args;
- Fmt fmt;
+ NodeList *calls;
on = nil;
op = nn->op;
all = nn->list;
calls = nil;
notfirst = 0;
- intypes = nil;
- args = nil;
-
- memset(&fmt, 0, sizeof fmt);
- if(defer) {
- // defer print turns into defer printf with format string
- fmtstrinit(&fmt);
- intypes = list(intypes, nod(ODCLFIELD, N, typenod(types[TSTRING])));
- args = list1(nod(OXXX, N, N));
- }
for(l=all; l; l=l->next) {
if(notfirst) {
- if(defer)
- fmtprint(&fmt, " ");
- else
- calls = list(calls, mkcall("printsp", T, init));
+ calls = list(calls, mkcall("printsp", T, init));
}
notfirst = op == OPRINTN;
@@ -1792,119 +1802,63 @@ walkprint(Node *nn, NodeList **init, int defer)
t = n->type;
et = n->type->etype;
if(isinter(n->type)) {
- if(defer) {
- if(isnilinter(n->type))
- fmtprint(&fmt, "%%e");
- else
- fmtprint(&fmt, "%%i");
- } else {
- if(isnilinter(n->type))
- on = syslook("printeface", 1);
- else
- on = syslook("printiface", 1);
- argtype(on, n->type); // any-1
- }
+ if(isnilinter(n->type))
+ on = syslook("printeface", 1);
+ else
+ on = syslook("printiface", 1);
+ argtype(on, n->type); // any-1
} else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR) {
- if(defer) {
- fmtprint(&fmt, "%%p");
- } else {
- on = syslook("printpointer", 1);
- argtype(on, n->type); // any-1
- }
+ on = syslook("printpointer", 1);
+ argtype(on, n->type); // any-1
} else if(isslice(n->type)) {
- if(defer) {
- fmtprint(&fmt, "%%a");
- } else {
- on = syslook("printslice", 1);
- argtype(on, n->type); // any-1
- }
+ on = syslook("printslice", 1);
+ argtype(on, n->type); // any-1
} else if(isint[et]) {
- if(defer) {
- if(et == TUINT64)
- fmtprint(&fmt, "%%U");
- else {
- fmtprint(&fmt, "%%D");
- t = types[TINT64];
- }
- } else {
- if(et == TUINT64)
- on = syslook("printuint", 0);
+ if(et == TUINT64) {
+ if((t->sym->pkg == runtimepkg || compiling_runtime) && strcmp(t->sym->name, "hex") == 0)
+ on = syslook("printhex", 0);
else
- on = syslook("printint", 0);
- }
- } else if(isfloat[et]) {
- if(defer) {
- fmtprint(&fmt, "%%f");
- t = types[TFLOAT64];
+ on = syslook("printuint", 0);
} else
- on = syslook("printfloat", 0);
+ on = syslook("printint", 0);
+ } else if(isfloat[et]) {
+ on = syslook("printfloat", 0);
} else if(iscomplex[et]) {
- if(defer) {
- fmtprint(&fmt, "%%C");
- t = types[TCOMPLEX128];
- } else
- on = syslook("printcomplex", 0);
+ on = syslook("printcomplex", 0);
} else if(et == TBOOL) {
- if(defer)
- fmtprint(&fmt, "%%t");
- else
- on = syslook("printbool", 0);
+ on = syslook("printbool", 0);
} else if(et == TSTRING) {
- if(defer)
- fmtprint(&fmt, "%%S");
- else
- on = syslook("printstring", 0);
+ 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;
- }
+ 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);
- }
+ 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);
+ 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;
- }
+ r = nod(OEMPTY, N, N);
+ typecheck(&r, Etop);
+ walkexpr(&r, init);
+ r->ninit = calls;
return r;
}
@@ -1914,11 +1868,166 @@ callnew(Type *t)
Node *fn;
dowidth(t);
- fn = syslook("new", 1);
+ fn = syslook("newobject", 1);
argtype(fn, t);
return mkcall1(fn, ptrto(t), nil, typename(t));
}
+static int
+isstack(Node *n)
+{
+ while(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP || n->op == OINDEX && isfixedarray(n->left->type))
+ n = n->left;
+
+ switch(n->op) {
+ case OINDREG:
+ // OINDREG only ends up in walk if it's indirect of SP.
+ return 1;
+
+ case ONAME:
+ switch(n->class) {
+ case PAUTO:
+ case PPARAM:
+ case PPARAMOUT:
+ return 1;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static int
+isglobal(Node *n)
+{
+ while(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP || n->op == OINDEX && isfixedarray(n->left->type))
+ n = n->left;
+
+ switch(n->op) {
+ case ONAME:
+ switch(n->class) {
+ case PEXTERN:
+ return 1;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Do we need a write barrier for the assignment l = r?
+int
+needwritebarrier(Node *l, Node *r)
+{
+ if(!use_writebarrier)
+ return 0;
+
+ if(l == N || isblank(l))
+ return 0;
+
+ // No write barrier for write of non-pointers.
+ dowidth(l->type);
+ if(!haspointers(l->type))
+ return 0;
+
+ // No write barrier for write to stack.
+ if(isstack(l))
+ return 0;
+
+ // No write barrier for implicit or explicit zeroing.
+ if(r == N || iszero(r))
+ return 0;
+
+ // No write barrier for initialization to constant.
+ if(r->op == OLITERAL)
+ return 0;
+
+ // No write barrier for storing static (read-only) data.
+ if(r->op == ONAME && strncmp(r->sym->name, "statictmp_", 10) == 0)
+ return 0;
+
+ // No write barrier for storing address of stack values,
+ // which are guaranteed only to be written to the stack.
+ if(r->op == OADDR && isstack(r->left))
+ return 0;
+
+ // No write barrier for storing address of global, which
+ // is live no matter what.
+ if(r->op == OADDR && isglobal(r->left))
+ return 0;
+
+ // No write barrier for reslice: x = x[0:y] or x = append(x, ...).
+ // Both are compiled to modify x directly.
+ // In the case of append, a write barrier may still be needed
+ // if the underlying array grows, but the append code can
+ // generate the write barrier directly in that case.
+ // (It does not yet, but the cost of the write barrier will be
+ // small compared to the cost of the allocation.)
+ if(r->reslice) {
+ switch(r->op) {
+ case OSLICE:
+ case OSLICE3:
+ case OSLICESTR:
+ case OAPPEND:
+ break;
+ default:
+ dump("bad reslice-l", l);
+ dump("bad reslice-r", r);
+ break;
+ }
+ return 0;
+ }
+
+ // Otherwise, be conservative and use write barrier.
+ return 1;
+}
+
+// TODO(rsc): Perhaps componentgen should run before this.
+static Node*
+applywritebarrier(Node *n, NodeList **init)
+{
+ Node *l, *r;
+ Type *t;
+
+ if(n->left && n->right && needwritebarrier(n->left, n->right)) {
+ t = n->left->type;
+ l = nod(OADDR, n->left, N);
+ l->etype = 1; // addr does not escape
+ if(t->width == widthptr) {
+ n = mkcall1(writebarrierfn("writebarrierptr", t, n->right->type), T, init,
+ l, n->right);
+ } else if(t->etype == TSTRING) {
+ n = mkcall1(writebarrierfn("writebarrierstring", t, n->right->type), T, init,
+ l, n->right);
+ } else if(isslice(t)) {
+ n = mkcall1(writebarrierfn("writebarrierslice", t, n->right->type), T, init,
+ l, n->right);
+ } else if(isinter(t)) {
+ n = mkcall1(writebarrierfn("writebarrieriface", t, n->right->type), T, init,
+ l, n->right);
+ } else if(t->width == 2*widthptr) {
+ n = mkcall1(writebarrierfn("writebarrierfat2", t, n->right->type), T, init,
+ l, nodnil(), n->right);
+ } else if(t->width == 3*widthptr) {
+ n = mkcall1(writebarrierfn("writebarrierfat3", t, n->right->type), T, init,
+ l, nodnil(), n->right);
+ } else if(t->width == 4*widthptr) {
+ n = mkcall1(writebarrierfn("writebarrierfat4", t, n->right->type), T, init,
+ l, nodnil(), n->right);
+ } else {
+ r = n->right;
+ while(r->op == OCONVNOP)
+ r = r->left;
+ r = nod(OADDR, r, N);
+ r->etype = 1; // addr does not escape
+ //warnl(n->lineno, "writebarrierfat %T %N", t, r);
+ n = mkcall1(writebarrierfn("writebarrierfat", t, r->left->type), T, init,
+ typename(t), l, r);
+ }
+ }
+ return n;
+}
+
static Node*
convas(Node *n, NodeList **init)
{
@@ -1958,11 +2067,10 @@ convas(Node *n, NodeList **init)
goto out;
}
- if(eqtype(lt, rt))
- goto out;
-
- n->right = assignconv(n->right, lt, "assignment");
- walkexpr(&n->right, init);
+ if(!eqtype(lt, rt)) {
+ n->right = assignconv(n->right, lt, "assignment");
+ walkexpr(&n->right, init);
+ }
out:
ullmancalc(n);
@@ -2355,6 +2463,8 @@ paramstoheap(Type **argin, int out)
continue;
// generate allocation & copying code
+ if(compiling_runtime)
+ yyerror("%N escapes to heap, not allowed in runtime.", v);
if(v->alloc == nil)
v->alloc = callnew(v->type);
nn = list(nn, nod(OAS, v->heapaddr, v->alloc));
@@ -2512,6 +2622,17 @@ mapfndel(char *name, Type *t)
}
static Node*
+writebarrierfn(char *name, Type *l, Type *r)
+{
+ Node *fn;
+
+ fn = syslook(name, 1);
+ argtype(fn, l);
+ argtype(fn, r);
+ return fn;
+}
+
+static Node*
addstr(Node *n, NodeList **init)
{
Node *r, *cat, *slice;
@@ -2620,7 +2741,7 @@ appendslice(Node *n, NodeList **init)
if(l2->type->etype == TSTRING)
fn = syslook("slicestringcopy", 1);
else
- fn = syslook("copy", 1);
+ fn = syslook("slicecopy", 1);
argtype(fn, l1->type);
argtype(fn, l2->type);
nt = mkcall1(fn, types[TINT], &l,
@@ -2758,7 +2879,7 @@ copyany(Node *n, NodeList **init, int runtimecall)
if(n->right->type->etype == TSTRING)
fn = syslook("slicestringcopy", 1);
else
- fn = syslook("copy", 1);
+ fn = syslook("slicecopy", 1);
argtype(fn, n->left->type);
argtype(fn, n->right->type);
return mkcall1(fn, n->type, init,
@@ -2863,14 +2984,14 @@ sliceany(Node* n, NodeList **init)
lb = N;
}
- // dynamic checks convert all bounds to unsigned to save us the bound < 0 comparison
- // generate
- // if hb > bound || lb > hb { panicslice() }
+ // Checking src[lb:hb:cb] or src[lb:hb].
+ // if chk0 || chk1 || chk2 { panicslice() }
chk = N;
- chk0 = N;
- chk1 = N;
- chk2 = N;
+ chk0 = N; // cap(src) < cb
+ chk1 = N; // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb]
+ chk2 = N; // hb < lb
+ // All comparisons are unsigned to avoid testing < 0.
bt = types[simtype[TUINT]];
if(cb != N && cb->type->width > 4)
bt = types[TUINT64];
@@ -3010,10 +3131,10 @@ eqfor(Type *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))));
+ ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+ ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, N, typenod(types[TBOOL])));
typecheck(&ntype, Etype);
n->type = ntype->type;
return n;
@@ -3034,10 +3155,9 @@ countfield(Type *t)
static void
walkcompare(Node **np, NodeList **init)
{
- Node *n, *l, *r, *fn, *call, *a, *li, *ri, *expr;
+ Node *n, *l, *r, *call, *a, *li, *ri, *expr, *cmpl, *cmpr;
int andor, i;
Type *t, *t1;
- static Node *tempbool;
n = *np;
@@ -3055,17 +3175,25 @@ walkcompare(Node **np, NodeList **init)
break;
}
- if(!islvalue(n->left) || !islvalue(n->right))
- goto hard;
+ cmpl = n->left;
+ while(cmpl != N && cmpl->op == OCONVNOP)
+ cmpl = cmpl->left;
+ cmpr = n->right;
+ while(cmpr != N && cmpr->op == OCONVNOP)
+ cmpr = cmpr->left;
+
+ if(!islvalue(cmpl) || !islvalue(cmpr)) {
+ fatal("arguments of comparison must be lvalues - %N %N", cmpl, cmpr);
+ }
l = temp(ptrto(t));
- a = nod(OAS, l, nod(OADDR, n->left, N));
+ a = nod(OAS, l, nod(OADDR, cmpl, 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 = nod(OAS, r, nod(OADDR, cmpr, N));
a->right->etype = 1; // addr does not escape
typecheck(&a, Etop);
*init = list(*init, a);
@@ -3115,57 +3243,16 @@ walkcompare(Node **np, NodeList **init)
goto ret;
}
- // 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]);
-
+ // Chose not to inline. Call equality function directly.
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);
-
- // tempbool cannot be used directly as multiple comparison
- // expressions may exist in the same statement. Create another
- // temporary to hold the value (its address is not taken so it can
- // be optimized away).
- r = temp(types[TBOOL]);
- a = nod(OAS, r, tempbool);
- typecheck(&a, Etop);
- walkstmt(&a);
- *init = list(*init, a);
-
+ call->list = list(call->list, nodintconst(t->width));
+ r = call;
if(n->op != OEQ)
r = nod(ONOT, r, N);
goto ret;
-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);
- }
- goto ret;
-
ret:
typecheck(&r, Erv);
walkexpr(&r, init);
@@ -3780,3 +3867,71 @@ candiscard(Node *n)
return 1;
}
+
+// rewrite
+// print(x, y, z)
+// into
+// func(a1, a2, a3) {
+// print(a1, a2, a3)
+// }(x, y, z)
+// and same for println.
+static void
+walkprintfunc(Node **np, NodeList **init)
+{
+ Node *n;
+ Node *a, *fn, *t, *oldfn;
+ NodeList *l, *printargs;
+ int num;
+ char buf[100];
+ static int prgen;
+
+ n = *np;
+
+ if(n->ninit != nil) {
+ walkstmtlist(n->ninit);
+ *init = concat(*init, n->ninit);
+ n->ninit = nil;
+ }
+
+ t = nod(OTFUNC, N, N);
+ num = 0;
+ printargs = nil;
+ for(l=n->list; l != nil; l=l->next) {
+ snprint(buf, sizeof buf, "a%d", num++);
+ a = nod(ODCLFIELD, newname(lookup(buf)), typenod(l->n->type));
+ t->list = list(t->list, a);
+ printargs = list(printargs, a->left);
+ }
+
+ fn = nod(ODCLFUNC, N, N);
+ snprint(buf, sizeof buf, "print·%d", ++prgen);
+ fn->nname = newname(lookup(buf));
+ fn->nname->defn = fn;
+ fn->nname->ntype = t;
+ declare(fn->nname, PFUNC);
+
+ oldfn = curfn;
+ curfn = nil;
+ funchdr(fn);
+
+ a = nod(n->op, N, N);
+ a->list = printargs;
+ typecheck(&a, Etop);
+ walkstmt(&a);
+
+ fn->nbody = list1(a);
+
+ funcbody(fn);
+
+ typecheck(&fn, Etop);
+ typechecklist(fn->nbody, Etop);
+ xtop = list(xtop, fn);
+ curfn = oldfn;
+
+ a = nod(OCALL, N, N);
+ a->left = fn->nname;
+ a->list = n->list;
+ typecheck(&a, Etop);
+ walkexpr(&a, init);
+ *np = a;
+}