Commits

Anonymous committed 8161bcb Draft

checkpoint; still plenty to clean up

R=ken
OCL=32576
CL=32580

  • Participants
  • Parent commits 0fb8806

Comments (0)

Files changed (11)

File src/cmd/gc/Makefile

 	./mkbuiltin >builtin.c || \
 	(echo 'mkbuiltin failed; using bootstrap copy of builtin.c'; cp builtin.c.boot builtin.c)
 
+subr.$O: opnames.h
+
+opnames.h:	mkopnames go.h
+	./mkopnames go.h >opnames.h
+
 clean:
 	rm -f $(OFILES) *.6 enam.c 6.out a.out y.tab.h y.tab.c $(LIB) mkbuiltin1 builtin.c _builtin.c
 

File src/cmd/gc/builtin.c.boot

 	"func sys.throwindex ()\n"
 	"func sys.throwreturn ()\n"
 	"func sys.throwinit ()\n"
-	"func sys.panicl (? int32)\n"
+	"func sys.panicl ()\n"
 	"func sys.printbool (? bool)\n"
 	"func sys.printfloat (? float64)\n"
 	"func sys.printint (? int64)\n"

File src/cmd/gc/dcl.c

 		v = vl->n;
 		tv = t;
 		if(t == T) {
-			gettype(&e, &r);
+			typecheck(&e, Erv);
 			defaultlit(&e, T);
 			tv = e->type;
 		}

File src/cmd/gc/go.h

 {
 	OXXX,
 
-	ONAME, ONONAME, OTYPE, OPACK, OLITERAL,
-	ODCL,
+	// names
+	ONAME,
+	ONONAME,
+	OTYPE,
+	OPACK,
+	OLITERAL,
+
+	// exprs
+	OADD, OSUB, OOR, OXOR,
+	OADDR,
+	OANDAND,
+	OARRAY,
+	OAS, OAS2, OASOP,
+	OBAD,
+	OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
+	OCAP,
+	OCLOSE,
+	OCLOSED,
+	OCOMPOS, OCOMPSLICE, OCOMPMAP,
+	OCONV, OCONVNOP, OCONVRUNE, OCONVSTRB, OCONVSTRI, OCONVA2S,
+	ODCL, ODCLFUNC, ODCLFIELD, ODCLARG,
 	ODOT, ODOTPTR, ODOTMETH, ODOTINTER,
-	ODCLFUNC, ODCLFIELD, ODCLARG,
-	OCMP, OPTR, OARRAY, ORANGE,
-	ORETURN, OFOR, OIF, OSWITCH, ODEFER,
-	OAS, OAS2, OASOP, OCASE, OXCASE, OFALL, OXFALL,
-	OGOTO, OPROC, OMAKE, ONEW, OEMPTY, OSELECT,
-	OLEN, OCAP, OPANIC, OPANICN, OPRINT, OPRINTN, OTYPEOF,
-	OCLOSE, OCLOSED, OBLOCK,
+	ODOTTYPE,
+	OEQ, ONE, OLT, OLE, OGE, OGT,
+	OFUNC,
+	OIND,
+	OINDEX, OINDEXSTR, OINDEXMAP, OINDEXARR,
+	OKEY, OPARAM,
+	OLEN,
+	OMAKE,
+	OMUL, ODIV, OMOD, OLSH, ORSH, OAND, OANDNOT,
+	ONEW,
+	ONOT, OCOM, OPLUS, OMINUS,
+	OOROR,
+	OPANIC, OPANICN, OPRINT, OPRINTN,
+	OSEND,
+	OSLICE, OSLICESTR, OSLICEARR,
+	ORECV,
 
-	OOROR,
-	OANDAND,
-	OEQ, ONE, OLT, OLE, OGE, OGT,
-	OADD, OSUB, OOR, OXOR,
-	OMUL, ODIV, OMOD, OLSH, ORSH, OAND, OANDNOT,
-	OINC, ODEC,
-	OFUNC,
+	// stmts
+	OBLOCK,
+	OBREAK,
+	OCASE, OXCASE,
+	OCONTINUE,
+	ODEFER,
+	OEMPTY,
+	OFALL, OXFALL,
+	OFOR,
+	OGOTO,
+	OIF,
 	OLABEL,
-	OBREAK,
-	OCONTINUE,
-	OADDR,
-	OIND,
-	OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
-	OINDEX, OSLICE,
-	ONOT, OCOM, OPLUS, OMINUS, OSEND, ORECV,
-	OREGISTER, OINDREG,
-	OKEY, OPARAM,
-	OCOMPOS, OCOMPSLICE, OCOMPMAP,
-	OCONV, OCONVNOP, OCONVRUNE, OCONVSTRB, OCONVSTRI,
-	OCONVA2S,
-	ODOTTYPE, OTYPESW, OTYPECASE,
-	OBAD,
+	OPROC,
+	ORANGE,
+	ORETURN,
+	OSELECT,
+	OSWITCH,
+	OTYPECASE,
+	OTYPESW,
 
-	OTCHAN, OTMAP, OTSTRUCT, OTINTER, OTFUNC, OTARRAY,
+	// types
+	OTCHAN,
+	OTMAP,
+	OTSTRUCT,
+	OTINTER,
+	OTFUNC,
+	OTARRAY,
 
-	OEXTEND,	// 6g internal
+	// for back ends
+	OCMP, ODEC, OEXTEND, OINC, OREGISTER, OINDREG,
 
 	OEND,
 };
 /*
  *	walk.c
  */
-void	gettype(Node**, NodeList**);
 void	walk(Node*);
 void	walkstmt(Node**);
 void	walkstmtlist(NodeList*);
-void	walkexpr(Node**, int, NodeList**);
-void	walkexprlist(NodeList*, int, NodeList**);
+void	walkexprlist(NodeList*, NodeList**);
 void	walkconv(Node**, NodeList**);
 void	walkdottype(Node*, NodeList**);
 void	walkas(Node*);
 void	walkswitch(Node*);
 void	walkselect(Node*);
 void	walkdot(Node*, NodeList**);
+void	walkexpr(Node**, NodeList**);
 Node*	ascompatee1(int, Node*, Node*, NodeList**);
 NodeList*	ascompatee(int, NodeList*, NodeList*, NodeList**);
 NodeList*	ascompatet(int, NodeList*, Type**, int, NodeList**);
 NodeList*	ascompatte(int, Type**, NodeList*, int, NodeList**);
 int	ascompat(Type*, Type*);
-Node*	prcompat(NodeList*, int, int);
-Node*	nodpanic(int32);
 Node*	newcompat(Node*);
 Node*	makecompat(Node*);
-Node*	stringop(Node*, int, NodeList**);
+Node*	stringop(Node*, NodeList**);
 Type*	fixmap(Type*);
-Node*	mapop(Node*, int, NodeList**);
+Node*	mapop(Node*, NodeList**);
 Type*	fixchan(Type*);
-Node*	chanop(Node*, int, NodeList**);
-Node*	arrayop(Node*, int);
+Node*	chanop(Node*, NodeList**);
+Node*	arrayop(Node*);
 Node*	ifacecvt(Type*, Node*, int);
 Node*	ifaceop(Node*);
 int	ifaceas(Type*, Type*, int);

File src/cmd/gc/mkbuiltin

 for i in sys unsafe
 do
 	$GC -A $i.go
-	./mkbuiltin1 $i >>_builtin.c
+	O=$O ./mkbuiltin1 $i >>_builtin.c
 done
 
 # If _builtin.c has changed vs builtin.c.boot,

File src/cmd/gc/mkbuiltin1.c

 	name = argv[1];
 	snprintf(initfunc, sizeof(initfunc), "init_%s_function", name);
 
-	snprintf(buf, sizeof(buf), "%s.6", name);
+	snprintf(buf, sizeof(buf), "%s.%s", name, getenv("O"));
 	if((fin = fopen(buf, "r")) == NULL) {
 		fprintf(stderr, "open %s: %s\n", buf, strerror(errno));
 		exit(1);

File src/cmd/gc/subr.c

 
 #include	"go.h"
 #include	"y.tab.h"
+#include	"opnames.h"
 
 void
 errorexit(void)
 	dodump(n, 1);
 }
 
-/*
-s%,%,\n%g
-s%\n+%\n%g
-s%^[ 	]*O%%g
-s%,.*%%g
-s%.+%	[O&]		= "&",%g
-s%^	........*\]%&~%g
-s%~	%%g
-|sort
-*/
-
-static char*
-opnames[] =
-{
-	[OADDR]		= "ADDR",
-	[OADD]		= "ADD",
-	[OANDAND]	= "ANDAND",
-	[OANDNOT]	= "ANDNOT",
-	[OAND]		= "AND",
-	[OARRAY]	= "ARRAY",
-	[OASOP]		= "ASOP",
-	[OAS]		= "AS",
-	[OAS2]		= "AS2",
-	[OBAD]		= "BAD",
-	[OBLOCK]		= "BLOCK",
-	[OBREAK]	= "BREAK",
-	[OCALLFUNC]	= "CALLFUNC",
-	[OCALLINTER]	= "CALLINTER",
-	[OCALLMETH]	= "CALLMETH",
-	[OCALL]		= "CALL",
-	[OCAP]		= "CAP",
-	[OCASE]		= "CASE",
-	[OCLOSED]	= "CLOSED",
-	[OCLOSE]	= "CLOSE",
-	[OCMP]		= "CMP",
-	[OCOMPMAP]	= "COMPMAP",
-	[OCOMPOS]	= "COMPOS",
-	[OCOMPSLICE]	= "COMPSLICE",
-	[OCOM]		= "COM",
-	[OCONTINUE]	= "CONTINUE",
-	[OCONV]		= "CONV",
-	[OCONVNOP]		= "CONVNOP",
-	[ODCLARG]	= "DCLARG",
-	[ODCLFIELD]	= "DCLFIELD",
-	[ODCLFUNC]	= "DCLFUNC",
-	[ODCL]		= "DCL",
-	[ODEC]		= "DEC",
-	[ODEFER]	= "DEFER",
-	[ODIV]		= "DIV",
-	[ODOTINTER]	= "DOTINTER",
-	[ODOTMETH]	= "DOTMETH",
-	[ODOTPTR]	= "DOTPTR",
-	[ODOTTYPE]	= "DOTTYPE",
-	[ODOT]		= "DOT",
-	[OEMPTY]	= "EMPTY",
-	[OEND]		= "END",
-	[OEQ]		= "EQ",
-	[OEXTEND]	= "EXTEND",
-	[OFALL]		= "FALL",
-	[OFOR]		= "FOR",
-	[OFUNC]		= "FUNC",
-	[OGE]		= "GE",
-	[OGOTO]		= "GOTO",
-	[OGT]		= "GT",
-	[OIF]		= "IF",
-	[OINC]		= "INC",
-	[OINDEX]	= "INDEX",
-	[OINDREG]	= "INDREG",
-	[OIND]		= "IND",
-	[OKEY]		= "KEY",
-	[OLABEL]	= "LABEL",
-	[OLEN]		= "LEN",
-	[OLE]		= "LE",
-	[OLITERAL]	= "LITERAL",
-	[OLSH]		= "LSH",
-	[OLT]		= "LT",
-	[OMAKE]		= "MAKE",
-	[OMINUS]	= "MINUS",
-	[OMOD]		= "MOD",
-	[OMUL]		= "MUL",
-	[ONAME]		= "NAME",
-	[ONEW]		= "NEW",
-	[ONE]		= "NE",
-	[ONONAME]	= "NONAME",
-	[ONOT]		= "NOT",
-	[OOROR]		= "OROR",
-	[OOR]		= "OR",
-	[OPANICN]	= "PANICN",
-	[OPANIC]	= "PANIC",
-	[OPACK]		= "PACK",
-	[OPARAM]	= "PARAM",
-	[OPLUS]		= "PLUS",
-	[OPRINTN]	= "PRINTN",
-	[OPRINT]	= "PRINT",
-	[OPROC]		= "PROC",
-	[OPTR]		= "PTR",
-	[ORANGE]	= "RANGE",
-	[ORECV]		= "RECV",
-	[OREGISTER]	= "REGISTER",
-	[ORETURN]	= "RETURN",
-	[ORSH]		= "RSH",
-	[OSELECT]	= "SELECT",
-	[OSEND]		= "SEND",
-	[OSLICE]	= "SLICE",
-	[OSUB]		= "SUB",
-	[OSWITCH]	= "SWITCH",
-	[OTCHAN]	= "TCHAN",
-	[OTMAP]	= "TMAP",
-	[OTSTRUCT]	= "TSTRUCT",
-	[OTINTER]	= "TINTER",
-	[OTFUNC]	= "TFUNC",
-	[OTARRAY]	= "TARRAY",
-	[OTYPEOF]	= "TYPEOF",
-	[OTYPESW]	= "TYPESW",
-	[OTYPE]		= "TYPE",
-	[OXCASE]	= "XCASE",
-	[OXFALL]	= "XFALL",
-	[OXOR]		= "XOR",
-	[OXXX]		= "XXX",
-};
-
 static char*
 goopnames[] =
 {
 		*r = *n;
 		r->left = l;
 		typecheck(&r, Elv);
-		walkexpr(&r, Elv, init);
+		walkexpr(&r, init);
 		return r;
 
 	case OINDEX:
 		tempname(l, ptrto(n->type));
 		a = nod(OAS, l, nod(OADDR, n, N));
 		typecheck(&a, Etop);
-		walkexpr(&a, Etop, init);
+		walkexpr(&a, init);
 		*init = list(*init, a);
 		r = nod(OIND, l, N);
 		typecheck(&r, Elv);
-		walkexpr(&r, Elv, init);
+		walkexpr(&r, init);
 		return r;
 	}
 	fatal("saferef %N", n);

File src/cmd/gc/swt.c

 			yyerror("expression case in a type switch");
 			return T;
 		}
-		walkexpr(cp, Erv, nil);
+		walkexpr(cp, nil);
 		break;
 	case OTYPESW:
 	case OTYPECASE:
 		if(sw->ntest->val.u.bval == 0)
 			arg = Sfalse;
 	}
-	walkexpr(&sw->ntest, Erv, &sw->ninit);
+	walkexpr(&sw->ntest, &sw->ninit);
 
 	/*
 	 * pass 0,1,2,3
 		yyerror("type switch must have an assignment");
 		return;
 	}
-	walkexpr(&sw->ntest->right, Erv, &sw->ninit);
+	walkexpr(&sw->ntest->right, &sw->ninit);
 	if(!istype(sw->ntest->right->type, TINTER)) {
 		yyerror("type switch must be on an interface");
 		return;

File src/cmd/gc/sys.go

 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-
 package PACKAGE
 
 // emitted by compiler, not referred to by go programs
 func	throwindex();
 func	throwreturn();
 func	throwinit();
-func	panicl(int32);
+func	panicl();
 
 func	printbool(bool);
 func	printfloat(float64);

File src/cmd/gc/typecheck.c

 	 * exprs
 	 */
 	case OADDR:
-		l = typecheck(&n->left, Elv);
+		typecheck(&n->left, Elv);
+		defaultlit(&n->left, T);
+		l = n->left;
 		if((t = l->type) == T)
 			goto error;
 		n->type = ptrto(t);
 			break;
 
 		case TMAP:
+			n->etype = 0;
+			if(top & Elv)
+				n->etype = 1;	// clumsy hack
 			ok |= Erv | Elv;
 			defaultlit(&n->right, t->down);
 			n->type = t->type;
 		if((t = r->type) == T)
 			goto error;
 		// TODO: more aggressive
+		n->etype = 0;
+		if(top & Erv)
+			n->etype = 1;	// clumsy hack
 		ok |= Etop | Erv;
 		n->type = types[TBOOL];
 		goto ret;
 			goto error;
 
 		case TARRAY:
-			ok |= Elv;
-			n = arrayop(n, Erv);
+			n->type = typ(TARRAY);
+			n->type->type = t;
+			n->type->bound = -1;
+			n = arrayop(n);
 			break;
 
 		case TSTRING:
-			n = stringop(n, Erv, nil);
+			n->type = t;
+			n = stringop(n, nil);
 			break;
 		}
 		goto ret;

File src/cmd/gc/walk.c

 
 static	Node*	curfn;
 
+static	Node*	prcompat(Node*);
+static	Node*	mkcall(char*, Type*, NodeList**, ...);
+static	Node*	mkcall1(Node*, Type*, NodeList**, ...);
+static	Node*	conv(Node*, Type*);
+static	Node*	chanfn(char*, int, Type*);
+static	Node*	mapfn(char*, Type*);
+
 enum
 {
 	Inone,
 walk(Node *fn)
 {
 	char s[50];
+	// int nerr;
 
 	curfn = fn;
 	if(debug['W']) {
 	if(curfn->type->outtuple)
 		if(walkret(curfn->nbody))
 			yyerror("function ends without a return statement");
+	// nerr = nerrors;
 	typechecklist(curfn->nbody, Etop);
+	/* TODO(rsc)
+	if(nerrors != nerr)
+		return;
+	*/
 	walkstmtlist(curfn->nbody);
 	if(debug['W']) {
 		snprint(s, sizeof(s), "after walk %S", curfn->nname->sym);
 	case OEMPTY:
 		init = n->ninit;
 		n->ninit = nil;
-		walkexpr(&n, Etop, &init);
+		walkexpr(&n, &init);
 		n->ninit = concat(init, n->ninit);
 		break;
 
 
 	case ODEFER:
 		hasdefer = 1;
-		walkexpr(&n->left, Etop, &n->ninit);
+		walkexpr(&n->left, &n->ninit);
 		break;
 
 	case OFOR:
 		break;
 
 	case OPROC:
-		walkexpr(&n->left, Etop, &n->ninit);
+		walkexpr(&n->left, &n->ninit);
 		break;
 
 	case ORETURN:
-		walkexprlist(n->list, Erv, &n->ninit);
+		walkexprlist(n->list, &n->ninit);
 		if(curfn->type->outnamed && n->list == nil) {
 			// print("special return\n");
 			break;
  */
 
 void
-walkexprlist(NodeList *l, int top, NodeList **init)
+walkexprlist(NodeList *l, NodeList **init)
 {
 	for(; l; l=l->next)
-		walkexpr(&l->n, top, init);
+		walkexpr(&l->n, init);
 }
 
 void
-walkexpr(Node **np, int top, NodeList **init)
+walkexpr(Node **np, NodeList **init)
 {
 	Node *r, *l;
 	NodeList *ll, *lr;
 	Type *t;
 	Sym *s;
-	int et, cl, cr, typeok, op;
+	int et, cl, cr;
 	int32 lno;
 	Node *n;
 
 		return;
 
 	lno = setlineno(n);
-	typeok = top & Etype;
-	top &= ~Etype;
-
-	if(debug['w'] > 1 && top == Etop)
+
+	if(debug['w'] > 1)
 		dump("walk-before", n);
 
 	if(n->typecheck != 1) {
 	case ODOTPTR:
 	case ODOTMETH:
 	case ODOTINTER:
-		walkexpr(&n->left, Erv, init);
+	case OIND:
+		walkexpr(&n->left, init);
 		goto ret;
 
-	case OIND:
-		walkexpr(&n->left, Erv | Etype, init);
+	case OLSH:
+	case ORSH:
+	case OAND:
+	case OOR:
+	case OXOR:
+	case OANDAND:
+	case OOROR:
+	case OSUB:
+	case OMUL:
+		walkexpr(&n->left, init);
+		walkexpr(&n->right, init);
 		goto ret;
 
 	case OPRINT:
-		if(top != Etop)
-			goto nottop;
-		walkexprlist(n->list, Erv, init);
-		n = prcompat(n->list, 0, 0);
-//dump("prcompat", n);
+	case OPRINTN:
+	case OPANIC:
+	case OPANICN:
+		walkexprlist(n->list, init);
+		n = prcompat(n);
 		goto ret;
 
-	case OPRINTN:
-		if(top != Etop)
-			goto nottop;
-		walkexprlist(n->list, Erv, init);
-		n = prcompat(n->list, 1, 0);
-		goto ret;
-
-	case OPANIC:
-		if(top != Etop)
-			goto nottop;
-		walkexprlist(n->list, Erv, init);
-		n = prcompat(n->list, 0, 1);
-		goto ret;
-
-	case OPANICN:
-		if(top != Etop)
-			goto nottop;
-		walkexprlist(n->list, Erv, init);
-		n = prcompat(n->list, 2, 1);
-		goto ret;
-
 	case OLITERAL:
-		if(!(top & Erv))
-			goto nottop;
 		n->addable = 1;
 		goto ret;
 
 	case ONAME:
-		if(top == Etop)
-			goto nottop;
 		if(!(n->class & PHEAP) && n->class != PPARAMREF)
 			n->addable = 1;
 		if(n->type == T) {
 		goto ret;
 
 	case OCALL:
-		if(top == Elv)
-			goto nottop;
-
 		if(n->left == N)
 			goto ret;
 
 			goto reswitch;
 		}
 
-		walkexpr(&n->left, Erv | Etype | Ecall, init);
+		walkexpr(&n->left, init);
 		defaultlit(&n->left, T);
 
 		t = n->left->type;
 			break;
 		case OTYPE:
 			n->op = OCONV;
-			if(!(top & Erv))
-				goto nottop;
 			// turn CALL(type, arg) into CONV(arg) w/ type.
 			n->type = n->left->type;
 			if(n->list == nil) {
 		}
 
 		dowidth(t);
-		n->type = *getoutarg(t);
-		switch(t->outtuple) {
-		case 0:
-			if(top == Erv) {
-				yyerror("function requires a return type");
-				n->type = types[TINT];
-			}
-			break;
-
-		case 1:
-			if(n->type != T && n->type->type != T && n->type->type->type != T)
-				n->type = n->type->type->type;
-			break;
-		}
-
-		walkexprlist(n->list, Erv, init);
+		walkexprlist(n->list, init);
 
 		switch(n->op) {
 		default:
 		goto ret;
 
 	case OAS:
-		if(top != Etop)
-			goto nottop;
 		*init = concat(*init, n->ninit);
 		n->ninit = nil;
-		walkexpr(&n->left, Elv, init);
-		walkexpr(&n->right, Erv, init);
+		walkexpr(&n->left, init);
+		walkexpr(&n->right, init);
 		l = n->left;
 		r = n->right;
 		if(l == N || r == N)
 		goto ret;
 
 	case OAS2:
-		if(top != Etop)
-			goto nottop;
 		*init = concat(*init, n->ninit);
 		n->ninit = nil;
 
-		walkexprlist(n->list, Elv, init);
+		walkexprlist(n->list, init);
 
 		cl = count(n->list);
 		cr = count(n->rlist);
 		if(cl == cr) {
 		multias:
-			walkexprlist(n->rlist, Erv, init);
+			walkexprlist(n->rlist, init);
 			ll = ascompatee(OAS, n->list, n->rlist, init);
 			ll = reorder3(ll);
 			n = liststmt(ll);
 		case OCALL:
 			if(cr == 1) {
 				// a,b,... = fn()
-				walkexpr(&r, Erv, init);
+				walkexpr(&r, init);
 				if(r->type == T || r->type->etype != TSTRUCT)
 					break;
 				ll = ascompatet(n->op, n->list, &r->type, 0, init);
 		case OINDEX:
 			if(cl == 2 && cr == 1) {
 				// a,b = map[] - mapaccess2
-				walkexpr(&r->left, Erv, init);
+				walkexpr(&r->left, init);
 				if(!istype(r->left->type, TMAP))
 					break;
-				l = mapop(n, top, init);
+				l = mapop(n, init);
 				if(l == N)
 					break;
 				n = l;
 		case ORECV:
 			if(cl == 2 && cr == 1) {
 				// a,b = <chan - chanrecv2
-				walkexpr(&r->left, Erv, init);
+				walkexpr(&r->left, init);
 				if(!istype(r->left->type, TCHAN))
 					break;
-				l = chanop(n, top, init);
+				l = chanop(n, init);
 				if(l == N)
 					break;
 				n = l;
 				// map[] = a,b - mapassign2
 				if(!istype(l->left->type, TMAP))
 					break;
-				l = mapop(n, top, init);
+				l = mapop(n, init);
 				if(l == N)
 					break;
 				n = l;
 		walkdottype(n, init);
 		// fall through
 	case OCONV:
-		if(!(top & Erv))
-			goto nottop;
 		walkconv(&n, init);
 		goto ret;
 
 	case OCOMPOS:
-		walkexpr(&n->right, Etype, init);
+		walkexpr(&n->right, init);
 		t = n->right->type;
 		n->type = t;
 		if(t == T)
 		goto ret;
 
 	case OASOP:
-		if(top != Etop)
-			goto nottop;
-		walkexpr(&n->left, Elv, init);
+		walkexpr(&n->left, init);
 		l = n->left;
 		if(l->op == OINDEX && istype(l->left->type, TMAP))
-			n = mapop(n, top, init);
-		if(n->etype == OLSH || n->etype == ORSH)
-			goto shft;
-		goto com;
-
-	case OLSH:
-	case ORSH:
-		if(!(top & Erv))
-			goto nottop;
-		walkexpr(&n->left, Erv, init);
-
-	shft:
-		walkexpr(&n->right, Erv, init);
-		if(n->left == N || n->right == N)
+			n = mapop(n, init);
+		walkexpr(&n->right, init);
+		if(n->etype == OANDNOT) {
+			n->etype = OAND;
+			n->right = nod(OCOM, n->right, N);
+			n->right->type = n->right->left->type;
 			goto ret;
-		evconst(n);
-		if(n->op == OLITERAL)
+		}
+		if(istype(n->left->type, TSTRING)) {
+			n = stringop(n, init);
 			goto ret;
-		// do NOT defaultlit n->left.
-		// let parent defaultlit or convlit instead.
-		defaultlit(&n->right, types[TUINT]);
-		if(n->left->type == T || n->right->type == T)
-			goto ret;
-		et = n->right->type->etype;
-		if(issigned[et] || !isint[et])
-			goto badt;
-		// check of n->left->type happens in second switch.
+		}
+		
+		/*
+		 * on 32-bit arch, rewrite 64-bit ops into l = l op r
+		 */
+		et = n->left->type->etype;
+		if(widthptr == 4 && (et == TUINT64 || et == TINT64)) {
+			l = saferef(n->left, init);
+			r = nod(OAS, l, nod(n->etype, l, n->right));
+			typecheck(&r, Etop);
+			walkexpr(&r, init);
+			n = r;
+		}
 		goto ret;
 
-	case OMOD:
-	case OAND:
 	case OANDNOT:
-	case OOR:
-	case OXOR:
-	case OANDAND:
-	case OOROR:
+		walkexpr(&n->left, init);
+		walkexpr(&n->right, init);
+		n->op = OAND;
+		n->right = nod(OCOM, n->right, N);
+		n->right->type = n->right->left->type;
+		goto ret;
+
 	case OEQ:
 	case ONE:
 	case OLT:
 	case OGE:
 	case OGT:
 	case OADD:
-	case OSUB:
-	case OMUL:
+		walkexpr(&n->left, init);
+		walkexpr(&n->right, init);
+		if(istype(n->left->type, TSTRING)) {
+			n = stringop(n, nil);
+			goto ret;
+		}
+		if(isinter(n->left->type)) {
+			n = ifaceop(n);
+			goto ret;
+		}
+		goto ret;
+
 	case ODIV:
-		if(!(top & Erv))
-			goto nottop;
-		walkexpr(&n->left, Erv, init);
-
-	com:
-		walkexpr(&n->right, Erv, init);
-		if(n->left == N || n->right == N)
-			goto ret;
-		if(n->left->type == T || n->right->type == T)
-			goto ret;
-
-		switch(n->op) {
-		case OANDNOT:
-			n->op = OAND;
-			n->right = nod(OCOM, n->right, N);
-			n->right->type = n->right->left->type;
-			break;
-
-		case OASOP:
-			if(n->etype == OANDNOT) {
-				n->etype = OAND;
-				n->right = nod(OCOM, n->right, N);
-				n->right->type = n->right->left->type;
-				break;
-			}
-			if(istype(n->left->type, TSTRING)) {
-				n = stringop(n, top, init);
-				goto ret;
-			}
-			break;
-
-		case OEQ:
-		case ONE:
-		case OLT:
-		case OLE:
-		case OGE:
-		case OGT:
-		case OADD:
-			if(istype(n->left->type, TSTRING)) {
-				n = stringop(n, top, nil);
-				goto ret;
-			}
-			break;
-		}
-		
-		switch(n->op) {
-		case OEQ:
-		case ONE:
-			if(isinter(n->left->type)) {
-				n = ifaceop(n);
-				goto ret;
-			}
-			break;
-		}
-		
+	case OMOD:
 		/*
 		 * rewrite div and mod into function calls
 		 * on 32-bit architectures.
 		 */
-		switch(n->op) {
-		case ODIV:
-		case OMOD:
-			et = n->left->type->etype;
-			if(widthptr > 4 || (et != TUINT64 && et != TINT64))
-				break;
-			if(et == TINT64)
-				strcpy(namebuf, "int64");
-			else
-				strcpy(namebuf, "uint64");
-			if(n->op == ODIV)
-				strcat(namebuf, "div");
-			else
-				strcat(namebuf, "mod");
-			l = syslook(namebuf, 0);
-			n->left = nod(OCONV, n->left, N);
-			n->left->type = types[et];
-			n->right = nod(OCONV, n->right, N);
-			n->right->type = types[et];
-			r = nod(OCALL, l, N);
-			r->list = list(list1(n->left), n->right);
-			r = nod(OCONV, r, N);
-			r->type = n->left->left->type;
-			typecheck(&r, Erv);
-			walkexpr(&r, Erv, init);
-			n = r;
+		walkexpr(&n->left, init);
+		walkexpr(&n->right, init);
+		et = n->left->type->etype;
+		if(widthptr > 4 || (et != TUINT64 && et != TINT64))
+			goto ret;
+		if(et == TINT64)
+			strcpy(namebuf, "int64");
+		else
+			strcpy(namebuf, "uint64");
+		if(n->op == ODIV)
+			strcat(namebuf, "div");
+		else
+			strcat(namebuf, "mod");
+		n = mkcall(namebuf, n->type, init,
+			conv(n->left, types[et]), conv(n->right, types[et]));
+		goto ret;
+
+	case OINDEX:
+		walkexpr(&n->left, init);
+		walkexpr(&n->right, init);
+		if(n->left == N || n->right == N)
+			goto ret;
+		t = n->left->type;
+		if(t == T)
+			goto ret;
+
+		switch(t->etype) {
+		case TSTRING:
+			n = stringop(n, nil);
 			break;
-	
-		case OASOP:
-			et = n->left->type->etype;
-			if(widthptr > 4 || (et != TUINT64 && et != TINT64))
-				break;
-			l = saferef(n->left, init);
-			r = nod(OAS, l, nod(n->etype, l, n->right));
-			typecheck(&r, Etop);
-			walkexpr(&r, Etop, init);
-			n = r;
+
+		case TMAP:
+			if(n->etype != 1)	// clumsy hack
+				n = mapop(n, nil);
 			break;
 		}
 		goto ret;
 
-	case OINDEX:
-		if(top == Etop)
-			goto nottop;
-
-		walkexpr(&n->left, Erv, init);
-		walkexpr(&n->right, Erv, init);
-
+	case OCLOSE:
+	case OCLOSED:
+	case OSEND:
+	case ORECV:
+		walkexpr(&n->left, init);
+		walkexpr(&n->right, init);
+		n = chanop(n, init);
+		goto ret;
+
+	case OSLICE:
+		walkexpr(&n->left, init);
+		walkexpr(&n->right->left, init);
+		walkexpr(&n->right->right, init);
 		if(n->left == N || n->right == N)
 			goto ret;
-
-		defaultlit(&n->left, T);
-
-		t = n->left->type;
-		if(t == T)
-			goto ret;
-
-		switch(t->etype) {
-		default:
-			defaultlit(&n->right, T);
-			goto badt;
-
-		case TSTRING:
-			// right side must be an int
-			if(!(top & Erv))
-				goto nottop;
-			defaultlit(&n->right, types[TINT]);
-			if(n->right->type == T)
-				break;
-			if(!isint[n->right->type->etype])
-				goto badt;
-			n = stringop(n, top, nil);
-			break;
-
-		case TMAP:
-			// right side must be map type
-			defaultlit(&n->right, t->down);
-			if(n->right->type == T)
-				break;
-			if(!eqtype(n->right->type, t->down))
-				goto badt;
-			n->type = t->type;
-			if(top == Erv)
-				n = mapop(n, top, nil);
-			break;
-
-		case TARRAY:
-			// right side must be an int
-			defaultlit(&n->right, types[TINT]);
-			if(n->right->type == T)
-				break;
-			if(!isint[n->right->type->etype])
-				goto badt;
-			n->type = t->type;
-			break;
-		}
-		goto ret;
-
-	case OCLOSE:
-		if(top != Etop)
-			goto nottop;
-		walkexpr(&n->left, Erv, init);		// chan
-		n = chanop(n, top, nil);
-		goto ret;
-
-	case OCLOSED:
-		if(top == Elv)
-			goto nottop;
-		walkexpr(&n->left, Erv, init);		// chan
-		n = chanop(n, top, nil);
-		goto ret;
-
-	case OSEND:
-		if(top == Elv)
-			goto nottop;
-		walkexpr(&n->left, Erv, init);	// chan
-		walkexpr(&n->right, Erv, init);	// e
-		n = chanop(n, top, nil);
-		goto ret;
-
-	case ORECV:
-		if(top == Elv)
-			goto nottop;
-		if(n->right == N) {
-			walkexpr(&n->left, Erv, init);		// chan
-			n = chanop(n, top, init);	// returns e blocking
-			goto ret;
-		}
-		walkexpr(&n->left, Elv, init);		// e
-		walkexpr(&n->right, Erv, init);	// chan
-		n = chanop(n, top, nil);	// returns bool non-blocking
-		goto ret;
-
-	case OSLICE:
-		if(top == Etop)
-			goto nottop;
-
-		walkexpr(&n->left, top, init);
-		walkexpr(&n->right->left, Erv, init);
-		walkexpr(&n->right->right, Erv, init);
-		if(n->left == N || n->right == N)
-			goto ret;
-		defaultlit(&n->left, T);
-		defaultlit(&n->right->left, types[TUINT]);
-		defaultlit(&n->right->right, types[TUINT]);
 		t = n->left->type;
 		if(t == T)
 			goto ret;
 		if(t->etype == TSTRING) {
-			n = stringop(n, top, nil);
+			n = stringop(n, nil);
 			goto ret;
 		}
 		if(t->etype == TARRAY) {
-			n = arrayop(n, top);
+			n = arrayop(n);
 			goto ret;
 		}
-		badtype(OSLICE, n->left->type, T);
 		goto ret;
 
 	case OADDR:
-		if(!(top & Erv))
-			goto nottop;
-		defaultlit(&n->left, T);
 		if(n->left->op == OCOMPOS) {
-			walkexpr(&n->left->right, Etype, init);
+			walkexpr(&n->left->right, init);
 			n->left->type = n->left->right->type;
 			if(n->left->type == T)
 				goto ret;
 
 			nas = nod(OAS, nvar, callnew(n->left->type));
 			typecheck(&nas, Etop);
-			walkexpr(&nas, Etop, init);
+			walkexpr(&nas, init);
 			*init = list(*init, nas);
 
 			nstar = nod(OIND, nvar, N);
 				goto badlit;
 			}
 
-//			walkexpr(&n->left->left, Erv, init);
+//			walkexpr(&n->left->left, init);
 			n = nvar;
 			goto ret;
 		}
 		}
 		if(n->left == N)
 			goto ret;
-		walkexpr(&n->left, Elv, init);
+		walkexpr(&n->left, init);
 		t = n->left->type;
 		if(t == T)
 			goto ret;
 		goto ret;
 
 	case OMAKE:
-		if(!(top & Erv))
-			goto nottop;
 		n = makecompat(n);
 		goto ret;
 
 	case ONEW:
-		if(!(top & Erv))
-			goto nottop;
 		if(n->list == nil) {
 			yyerror("missing argument to new");
 			goto ret;
 		}
 		if(n->list->next)
 			yyerror("too many arguments to new");
-		walkexpr(&n->list->n, Etype, init);
+		walkexpr(&n->list->n, init);
 		l = n->list->n;
 		if((t = l->type) == T)
 			;
 			n = callnew(t);
 		goto ret;
 	}
-	fatal("missing switch %#O", n->op);
-
-nottop:
-	if(n->diag)
-		goto ret;
-	n->diag = 1;
-	switch(top | typeok) {
-	default:
-		yyerror("didn't expect %O here [top=%d]", n->op, top);
-		break;
-	case Etype:
-		yyerror("operation %O not allowed in type context", n->op);
-		break;
-	case Etop:
-		yyerror("operation %O not allowed in statement context", n->op);
-		break;
-	case Elv:
-		yyerror("operation %O not allowed in assignment context", n->op);
-		break;
-	case Erv:
-	case Erv | Etype:
-		yyerror("operation %O not allowed in expression context", n->op);
-		break;
-	}
-	goto ret;
-
-badt:
-	if(n->diag)
-		goto ret;
-	n->diag = 1;
-	if(n->right == N) {
-		if(n->left == N) {
-			badtype(n->op, T, T);
-			goto ret;
-		}
-		badtype(n->op, n->left->type, T);
-		goto ret;
-	}
-	op = n->op;
-	if(op == OASOP)
-		op = n->etype;
-	badtype(op, n->left->type, n->right->type);
-	goto ret;
+	fatal("missing switch %O", n->op);
 
 ret:
-	if(debug['w'] && top == Etop && n != N)
+	if(debug['w'] && n != N)
 		dump("walk", n);
 
-	if(typeok && top == 0) {	// must be type
-		if(n->op != OTYPE) {
-			if(n->sym) {
-				if(!n->sym->undef)
-					yyerror("%S is not a type", n->sym);
-			} else {
-				yyerror("expr %O is not type", n->op);
-				n->op = OTYPE;	// leads to fewer errors later
-				n->type = T;
-			}
-		}
-	}
-	if(!typeok && n->op == OTYPE)
-		yyerror("cannot use type %T as expr", n->type);
-
 	ullmancalc(n);
 	lineno = lno;
 	*np = n;
 	n = *np;
 	if(n == N)
 		return;
-	walkexpr(np, Erv, &n->ninit);
+	walkexpr(np, &n->ninit);
 	defaultlit(np, T);
 	n = *np;
 	if(n->type != T && !eqtype(n->type, types[TBOOL]))
 void
 walkdottype(Node *n, NodeList **init)
 {
-	walkexpr(&n->left, Erv, init);
+	walkexpr(&n->left, init);
 	if(n->left == N)
 		return;
-	defaultlit(&n->left, T);
-	if(!isinter(n->left->type))
-		yyerror("type assertion requires interface on left, have %T", n->left->type);
 	if(n->right != N) {
-		walkexpr(&n->right, Etype, init);
+		walkexpr(&n->right, init);
 		n->type = n->right->type;
 		n->right = N;
 	}
 	if(t == T)
 		return;
 	typecheck(&n->left, Erv);
-	walkexpr(&n->left, Erv, init);
+	walkexpr(&n->left, init);
 	l = n->left;
 	if(l == N)
 		return;
 	if(istype(t, TSTRING)) {
 		et = l->type->etype;
 		if(isint[et]) {
-			n = stringop(n, Erv, nil);
+			n = stringop(n, nil);
 			*np = n;
 			return;
 		}
 		if((isptr[et] && isfixedarray(l->type->type) && istype(l->type->type->type, TUINT8))
 		|| (isslice(l->type) && istype(l->type->type, TUINT8))) {
 			n->op = OARRAY;
-			n = stringop(n, Erv, nil);
+			n = stringop(n, nil);
 			*np = n;
 			return;
 		}
 		if((isptr[et] && isfixedarray(l->type->type) && istype(l->type->type->type, TINT))
 		|| (isslice(l->type) && istype(l->type->type, TINT))) {
 			n->op = OARRAY;
-			n = stringop(n, Erv, nil);
+			n = stringop(n, nil);
 			*np = n;
 			return;
 		}
 	// convert static array to dynamic array
 	if(isslice(t) && isptr[l->type->etype] && isfixedarray(l->type->type)) {
 		if(eqtype(t->type->type, l->type->type->type->type)) {
-			n = arrayop(n, Erv);
+			n = arrayop(n);
 			*np = n;
 			return;
 		}
 Node*
 selcase(Node *n, Node *var, NodeList **init)
 {
-	Node *a, *r, *on, *c;
+	Node *a, *r, *c;
 	Type *t;
-	NodeList *args;
 
 	if(n->list == nil)
 		goto dflt;
 	if(c->op == ORECV)
 		goto recv;
 
-	walkexpr(&c->left, Erv, init);		// chan
-	walkexpr(&c->right, Erv, init);	// elem
+	walkexpr(&c->left, init);		// chan
+	walkexpr(&c->right, init);	// elem
 
 	t = fixchan(c->left->type);
 	if(t == T)
 	}
 
 	// selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
-	on = syslook("selectsend", 1);
-	argtype(on, t->type);
-	argtype(on, t->type);
-
-	a = var;			// sel-var
-	args = list1(a);
-	a = c->left;			// chan
-	args = list(args, a);
-	a = c->right;			// elem
-	args = list(args, a);
+	a = mkcall1(chanfn("selectsend", 2, t), types[TBOOL], init, var, c->left, c->right);
 	goto out;
 
 recv:
 	if(c->right != N)
 		goto recv2;
 
-	walkexpr(&c->left, Erv, init);		// chan
+	walkexpr(&c->left, init);		// chan
 
 	t = fixchan(c->left->type);
 	if(t == T)
 	}
 
 	// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
-	on = syslook("selectrecv", 1);
-	argtype(on, t->type);
-	argtype(on, t->type);
-
-	a = var;			// sel-var
-	args = list1(a);
-
-	a = c->left;			// chan
-	args = list(args, a);
-
-	a = c->left;			// nil elem
-	a = nod(OLITERAL, N, N);
-	a->val.ctype = CTNIL;
-	a->type = types[TNIL];
-	args = list(args, a);
+	a = mkcall1(chanfn("selectrecv", 2, t), types[TBOOL], init, var, c->left, nodnil());
 	goto out;
 
 recv2:
-	walkexpr(&c->right, Erv, init);	// chan
+	walkexpr(&c->right, init);	// chan
 
 	t = fixchan(c->right->type);
 	if(t == T)
 		return N;
 	}
 
-	walkexpr(&c->left, Elv, init);	// check elem
-	convlit(&c->left, t->type);
-	if(!ascompat(t->type, c->left->type)) {
-		badtype(c->op, t->type, c->left->type);
-		return N;
-	}
+	walkexpr(&c->left, init);
 
 	// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
-	on = syslook("selectrecv", 1);
-	argtype(on, t->type);
-	argtype(on, t->type);
-
-	a = var;			// sel-var
-	args = list1(a);
-
-	a = c->right;			// chan
-	args = list(args, a);
-
-	a = c->left;			// elem
-	a = nod(OADDR, a, N);
-	args = list(args, a);
+	a = mkcall1(chanfn("selectrecv", 2, t), types[TBOOL], init, var, c->right, nod(OADDR, c->left, N));
 	goto out;
 
 dflt:
 	// selectdefault(sel *byte);
-	on = syslook("selectdefault", 0);
-	a = var;
-	args = list1(a);
+	a = mkcall("selectdefault", types[TBOOL], init, var);
 	goto out;
 
 out:
-	a = nod(OCALL, on, N);
-	a->list = args;
 	r = nod(OIF, N, N);
 	r->ntest = a;
 
 	if(expr == N || expr->op != ORECV)
 		goto bad;
 
-	walkexpr(&expr->left, Erv, init);
+	walkexpr(&expr->left, init);
 	t = expr->left->type;
 	if(t == T)
 		goto bad;
 {
 	Node *n, *l, *oc, *on, *r;
 	Node *var, *def;
-	NodeList *args, *res, *bod, *nbod, *init, *ln;
+	NodeList *res, *bod, *nbod, *init, *ln;
 	int count, op;
 	int32 lno;
 
 	setlineno(sel);
 
 	// selectgo(sel *byte);
-	on = syslook("selectgo", 0);
-	r = nod(OCALL, on, N);
-	r->list = list1(var);		// sel-var
-	res = list(res, r);
+	res = list(res, mkcall("selectgo", T, nil, var));
 
 	// newselect(size uint32) (sel *byte);
-	on = syslook("newselect", 0);
-
-	r = nod(OXXX, N, N);
-	nodconst(r, types[TINT], count);	// count
-	args = list1(r);
-	r = nod(OCALL, on, N);
-	r->list = args;
-	r = nod(OAS, var, r);
+	r = nod(OAS, var, mkcall("newselect", var->type, nil, nodintconst(count)));
 	typecheck(&r, Etop);
 	typechecklist(res, Etop);
 
 		r->left->type = r->right->type;
 		r->left->xoffset += t->width;
 		typecheck(&r, Etop);
-		walkexpr(&r, Etop, init);
+		walkexpr(&r, init);
 		lr->n = r;
 		t = t->down;
 	}
 }
 
 // generate code for print
-//	fmt = 0: print
-//	fmt = 1: println
-Node*
-prcompat(NodeList *all, int fmt, int dopanic)
+static Node*
+prcompat(Node *nn)
 {
 	Node *r;
 	Node *n;
-	NodeList *l;
+	NodeList *l, *all;
 	Node *on;
 	Type *t;
-	int notfirst, et;
+	int notfirst, et, op;
 	NodeList *calls;
 
+	op = nn->op;
+	all = nn->list;
 	calls = nil;
 	notfirst = 0;
 
 	for(l=all; l; l=l->next) {
-		if(notfirst) {
-			on = syslook("printsp", 0);
-			calls = list(calls, nod(OCALL, on, N));
-		}
-		notfirst = fmt;
+		if(notfirst)
+			calls = list(calls, mkcall("printsp", T, nil));
+		notfirst = op == OPRINTN || op == OPANICN;
 
 		typecheck(&l->n, Erv);
 		n = l->n;
 		calls = list(calls, r);
 	}
 
-	if(fmt == 1 && !dopanic) {
-		on = syslook("printnl", 0);
-		calls = list(calls, nod(OCALL, on, N));
-	}
+	if(op == OPRINTN)
+		calls = list(calls, mkcall("printnl", T, nil));
 	typechecklist(calls, Etop);
-	walkexprlist(calls, Etop, nil);
-
-	if(dopanic)
-		r = nodpanic(0);
+	walkexprlist(calls, nil);
+
+	if(op == OPANIC || op == OPANICN)
+		r = mkcall("panicl", T, nil);
 	else
 		r = nod(OEMPTY, N, N);
 	typecheck(&r, Etop);
-	walkexpr(&r, Etop, nil);
+	walkexpr(&r, nil);
 	r->ninit = calls;
 	return r;
 }
 
 Node*
-nodpanic(int32 lineno)
-{
-	Node *n, *on;
-	NodeList *args;
-
-	on = syslook("panicl", 0);
-	n = nodintconst(lineno);
-	args = list1(n);
-	n = nod(OCALL, on, N);
-	n->list = args;
-	typecheck(&n, Etop);
-	walkexpr(&n, Etop, nil);
-	return n;
-}
-
-Node*
 makecompat(Node *n)
 {
 	Type *t;
 	l = args->n;
 	args = args->next;
 	init = nil;
-	walkexpr(&l, Etype, &init);
+	walkexpr(&l, &init);
 	if(l->op != OTYPE) {
 		yyerror("cannot make(expr)");
 		return n;
 	case TARRAY:
 		if(!isslice(t))
 			goto bad;
-		return arrayop(n, Erv);
+		return arrayop(n);
 	case TMAP:
-		return mapop(n, Erv, nil);
+		return mapop(n, nil);
 	case TCHAN:
-		return chanop(n, Erv, nil);
+		return chanop(n, nil);
 	}
 
 bad:
 Node*
 callnew(Type *t)
 {
-	Node *r, *on;
-	NodeList *args;
+	Node *fn;
 
 	dowidth(t);
-	on = syslook("mal", 1);
-	argtype(on, t);
-	r = nodintconst(t->width);
-	args = list1(r);
-	r = nod(OCALL, on, N);
-	r->list = args;
-	typecheck(&r, Erv);
-	walkexpr(&r, Erv, nil);
-	return r;
+	fn = syslook("mal", 1);
+	argtype(fn, t);
+	return mkcall1(fn, ptrto(t), nil, nodintconst(t->width));
 }
 
 Node*
-stringop(Node *n, int top, NodeList **init)
+stringop(Node *n, NodeList **init)
 {
-	Node *r, *c, *on;
-	NodeList *args;
+	Node *r, *fn;
 
 	switch(n->op) {
 	default:
 	case OLE:
 	case OLT:
 		// sys_cmpstring(s1, s2) :: 0
-		on = syslook("cmpstring", 0);
-		r = nod(OCONV, n->left, N);
-		r->type = types[TSTRING];
-		args = list1(r);
-		c = nod(OCONV, n->right, N);
-		c->type = types[TSTRING];
-		args = list(args, c);
-		r = nod(OCALL, on, N);
-		r->list = args;
-		c = nodintconst(0);
-		r = nod(n->op, r, c);
+		r = mkcall("cmpstring", types[TINT], init,
+			conv(n->left, types[TSTRING]),
+			conv(n->right, types[TSTRING]));
+		r = nod(n->op, r, nodintconst(0));
+		typecheck(&r, Erv);
 		break;
 
 	case OADD:
 		// sys_catstring(s1, s2)
-		on = syslook("catstring", 0);
-		r = nod(OCONV, n->left, N);
-		r->type = types[TSTRING];
-		args = list1(r);
-		c = nod(OCONV, n->right, N);
-		c->type = types[TSTRING];
-		args = list(args, c);
-		r = nod(OCALL, on, N);
-		r->list = args;
+		r = mkcall("catstring", n->type, init,
+			conv(n->left, types[TSTRING]),
+			conv(n->right, types[TSTRING]));
 		break;
 
 	case OASOP:
 			// s1 = sys_catstring(s1, s2)
 			if(n->etype != OADD)
 				fatal("stringop: not cat");
-			on = syslook("catstring", 0);
-			r = nod(OCONV, n->left, N);
-			r->type = types[TSTRING];
-			args = list1(r);
-			c = nod(OCONV, n->right, N);
-			c->type = types[TSTRING];
-			args = list(args, c);
-			r = nod(OCALL, on, N);
-			r->list = args;
+			r = mkcall("catstring", n->left->type, init,
+				conv(n->left, types[TSTRING]),
+				conv(n->right, types[TSTRING]));
 			r = nod(OAS, n->left, r);
 			break;
 		}
 		break;
 
+
 	case OSLICE:
-		r = nod(OCONV, n->left, N);
-		r->type = types[TSTRING];
-		args = list1(r);
-
 		// sys_slicestring(s, lb, hb)
-		r = nod(OCONV, n->right->left, N);
-		r->type = types[TINT];
-		args = list(args, r);
-
-		c = nod(OCONV, n->right->right, N);
-		c->type = types[TINT];
-		args = list(args, c);
-
-		on = syslook("slicestring", 0);
-		r = nod(OCALL, on, N);
-		r->list = args;
+		r = mkcall("slicestring", n->type, init,
+			conv(n->left, types[TSTRING]),
+			conv(n->right->left, types[TINT]),
+			conv(n->right->right, types[TINT]));
 		break;
 
 	case OINDEX:
+		// TODO(rsc): should be done in back end
 		// sys_indexstring(s, i)
-		r = nod(OCONV, n->left, N);
-		r->type = types[TSTRING];
-		args = list1(r);
-
-		r = nod(OCONV, n->right, N);
-		r->type = types[TINT];
-		args = list(args, r);
-		on = syslook("indexstring", 0);
-		r = nod(OCALL, on, N);
-		r->list = args;
+		r = mkcall("indexstring", n->type, init,
+			conv(n->left, types[TSTRING]),
+			conv(n->right, types[TINT]));
 		break;
 
 	case OCONV:
 		// sys_intstring(v)
-		r = nod(OCONV, n->left, N);
-		r->type = types[TINT64];
-		args = list1(r);
-		on = syslook("intstring", 0);
-		r = nod(OCALL, on, N);
-		r->list = args;
+		r = mkcall("intstring", n->type, init,
+			conv(n->left, types[TINT64]));	// TODO(rsc): int64?!
 		break;
 
 	case OARRAY:
 		// arraystring([]byte) string;
-		on = syslook("arraystring", 0);
 		r = n->left;
-
+		fn = syslook("arraystring", 0);
 		if(r->type != T && r->type->type != T) {
 			if(istype(r->type->type, TINT) || istype(r->type->type->type, TINT)) {
 				// arraystring([]byte) string;
-				on = syslook("arraystringi", 0);
+				fn = syslook("arraystringi", 0);
 			}
 		}
-		args = list1(r);
-		r = nod(OCALL, on, N);
-		r->list = args;
+		r = mkcall1(fn, n->type, init, r);
 		break;
 	}
-
-	typecheck(&r, top);
-	walkexpr(&r, top, init);
 	return r;
 }
 
 }
 
 Node*
-mapop(Node *n, int top, NodeList **init)
+mapop(Node *n, NodeList **init)
 {
 	Node *r, *a, *l;
 	Type *t;
-	Node *on;
+	Node *fn, *hint;
 	int cl, cr;
 	NodeList *args;
 
 		if(cl > 1)
 			yyerror("too many arguments to make map");
 
-		if(!(top & Erv))
-			goto nottop;
-
 		// newmap(keysize int, valsize int,
 		//	keyalg int, valalg int,
 		//	hint int) (hmap map[any-1]any-2);
 		if(t == T)
 			break;
 
-		a = nodintconst(t->down->width);	// key width
-		args = list1(a);
-		a = nodintconst(t->type->width);	// val width
-		args = list(args, a);
-		a = nodintconst(algtype(t->down));	// key algorithm
-		args = list(args, a);
-		a = nodintconst(algtype(t->type));	// val algorithm
-		args = list(args, a);
-
+		fn = syslook("newmap", 1);
+		argtype(fn, t->down);	// any-1
+		argtype(fn, t->type);	// any-2
+		
 		if(cl == 1)
-			a = n->list->n;				// hint
+			hint = n->list->n;
 		else
-			a = nodintconst(0);
-		args = list(args, a);
-
-		on = syslook("newmap", 1);
-
-		argtype(on, t->down);	// any-1
-		argtype(on, t->type);	// any-2
-
-		r = nod(OCALL, on, N);
-		r->list = args;
-		typecheck(&r, Erv);
-		walkexpr(&r, top, nil);
-		r->type = n->type;
+			hint = nodintconst(0);
+
+		r = mkcall1(fn, n->type, init,
+			nodintconst(t->down->width),	// key width
+			nodintconst(t->type->width),		// val width
+			nodintconst(algtype(t->down)),	// key algorithm
+			nodintconst(algtype(t->type)),		// val algorithm
+			hint);
 		break;
 
 	case OINDEX:
-		if(!(top & Erv))
-			goto nottop;
 		// mapaccess1(hmap map[any]any, key any) (val any);
 
 		t = fixmap(n->left->type);
 		if(t == T)
 			break;
 
-		convlit(&n->right, t->down);
-
-		if(!eqtype(n->right->type, t->down)) {
-			badtype(n->op, n->right->type, t->down);
-			break;
-		}
-
-		a = n->left;				// map
-		args = list1(a);
-		a = n->right;				// key
-		args = list(args, a);
-
-		on = syslook("mapaccess1", 1);
-
-		argtype(on, t->down);	// any-1
-		argtype(on, t->type);	// any-2
-		argtype(on, t->down);	// any-3
-		argtype(on, t->type);	// any-4
-
-		r = nod(OCALL, on, N);
-		r->list = args;
-		typecheck(&r, Erv);
-		walkexpr(&r, Erv, nil);
-		r->type = t->type;
+		r = mkcall1(mapfn("mapaccess1", t), t->type, init, n->left, n->right);
 		break;
 
 	case OAS:
 		if(t == T)
 			break;
 
-		a = n->left->left;			// map
-		args = list1(a);
-		a = n->left->right;			// key
-		args = list(args, a);
-		a = n->right;				// val
-		args = list(args, a);
-
-		on = syslook("mapassign1", 1);
-
-		argtype(on, t->down);	// any-1
-		argtype(on, t->type);	// any-2
-		argtype(on, t->down);	// any-3
-		argtype(on, t->type);	// any-4
-
-		r = nod(OCALL, on, N);
-		r->list = args;
-		typecheck(&r, Etop);
-		walkexpr(&r, Etop, init);
+		r = mkcall1(mapfn("mapassign1", t), T, init, n->left->left, n->left->right, n->right);
 		break;
 
 	case OAS2:
 		if(t == T)
 			break;
 
-		args = list1(l->left);			// map
-		args = list(args, l->right);		// key
-		args = list(args, n->rlist->n);		// val
-		args = list(args, n->rlist->next->n);	// pres
-
-		on = syslook("mapassign2", 1);
-
-		argtype(on, t->down);	// any-1
-		argtype(on, t->type);	// any-2
-		argtype(on, t->down);	// any-3
-		argtype(on, t->type);	// any-4
-
-		r = nod(OCALL, on, N);
-		r->list = args;
-		typecheck(&r, Etop);
-		walkexpr(&r, Etop, init);
+		r = mkcall1(mapfn("mapassign2", t), T, init, l->left, l->right, n->rlist->n, n->rlist->next->n);
 		break;
 
 	access2:
 		args = list1(r->left);		// map
 		args = list(args, r->right);		// key
 
-		on = syslook("mapaccess2", 1);
-
-		argtype(on, t->down);	// any-1
-		argtype(on, t->type);	// any-2
-		argtype(on, t->down);	// any-3
-		argtype(on, t->type);	// any-4
-
-		a = nod(OCALL, on, N);
-		a->list = args;
-		typecheck(&a, Erv);
+		fn = mapfn("mapaccess2", t);
+		a = mkcall1(fn, getoutargx(fn->type), init, r->left, r->right);
 		n->rlist = list1(a);
 		typecheck(&n, Etop);
-		walkexpr(&n, Etop, init);
+		walkexpr(&n, init);
 		r = n;
 		break;
 
 		r = nod(OAS, a, n->left->right);	// tmpi := index
 		n->left->right = a;			// m[tmpi]
 		typecheck(&r, Etop);
-		walkexpr(&r, Etop, init);
+		walkexpr(&r, init);
 		*init = list(*init, r);
 
 		a = nod(OXXX, N, N);
 		*a = *n->left;		// copy of map[tmpi]
+		a->typecheck = 0;
+		a->type = T;
 		a = nod(n->etype, a, n->right);		// m[tmpi] op right
 		r = nod(OAS, n->left, a);		// map[tmpi] = map[tmpi] op right
 		typecheck(&r, Etop);
-		walkexpr(&r, Etop, init);
+		walkexpr(&r, init);
 		break;
 	}
 	return r;
 
 shape:
 	dump("shape", n);
-	fatal("mapop: cl=%d cr=%d, %O", top, n->op);
-	return N;
-
-nottop:
-	yyerror("didn't expect %O here", n->op);
+	fatal("mapop: %O", n->op);
 	return N;
 }
 
 Node*
-chanop(Node *n, int top, NodeList **init)
+chanop(Node *n, NodeList **init)
 {
-	Node *r, *a, *on;
-	NodeList *args;
+	Node *r, *a, *fn;
 	Type *t;
 	int cl, cr;
 
 		t = fixchan(n->left->type);
 		if(t == T)
 			break;
-
-		a = n->left;			// chan
-		args = list1(a);
-
-		on = syslook("closechan", 1);
-		argtype(on, t);	// any-1
-
-		r = nod(OCALL, on, N);
-		r->list = args;
-		typecheck(&r, Etop);
-		walkexpr(&r, top, nil);
-		r->type = n->type;
+		fn = syslook("closechan", 1);
+		argtype(fn, t);
+		r = mkcall1(fn, T, init, n->left);
 		break;
 
 	case OCLOSED:
 		t = fixchan(n->left->type);
 		if(t == T)
 			break;
-
-		a = n->left;			// chan
-		args = list1(a);
-
-		on = syslook("closedchan", 1);
-		argtype(on, t);	// any-1
-
-		r = nod(OCALL, on, N);
-		r->list = args;
-		typecheck(&r, Erv);
-		walkexpr(&r, top, nil);
-		n->type = r->type;
+		fn = syslook("closedchan", 1);
+		argtype(fn, t);
+		r = mkcall1(fn, n->type, init, n->left);
 		break;
 
 	case OMAKE:
 		if(t == T)
 			break;
 
-		a = nodintconst(t->type->width);	// elem width
-		args = list1(a);
-		a = nodintconst(algtype(t->type));	// elem algorithm
-		args = list(args, a);
-		a = nodintconst(0);
-		if(cl == 1) {
-			// async buf size
-			a = nod(OCONV, n->list->n, N);
-			a->type = types[TINT];
-		}
-		args = list(args, a);
-
-		on = syslook("newchan", 1);
-		argtype(on, t->type);	// any-1
-
-		r = nod(OCALL, on, N);
-		r->list = args;
-		typecheck(&r, Erv);
-		walkexpr(&r, top, nil);
-		r->type = n->type;
+		if(cl == 1)
+			a = conv(n->list->n, types[TINT]);
+		else
+			a = nodintconst(0);
+		r = mkcall1(chanfn("newchan", 1, t), n->type, init,
+			nodintconst(t->type->width),
+			nodintconst(algtype(t->type)),
+			a);
 		break;
 
 	case OAS2:
 		t = fixchan(r->left->type);
 		if(t == T)
 			break;
-
 		if(!(t->chan & Crecv)) {
 			yyerror("cannot receive from %T", t);
 			break;
 		}
 
-		a = r->left;			// chan
-		args = list1(a);
-
-		on = syslook("chanrecv2", 1);
-
-		argtype(on, t->type);	// any-1
-		argtype(on, t->type);	// any-2
-		r = nod(OCALL, on, N);
-		r->list = args;
-		typecheck(&r, Etop);
+		fn = chanfn("chanrecv2", 2, t);
+		r = mkcall1(fn, getoutargx(fn->type), init, r->left);
 		n->rlist->n = r;
 		r = n;
-		walkexpr(&r, Etop, init);
+		walkexpr(&r, init);
 		break;
 
 	case ORECV:
 		}
 
 		// chanrecv1(hchan *chan any) (elem any);
-		defaultlit(&n->left, T);
 		t = fixchan(n->left->type);
 		if(t == T)
 			break;
-
 		if(!(t->chan & Crecv)) {
 			yyerror("cannot receive from %T", t);
 			break;
 		}
 
-		a = n->left;			// chan
-		args = list1(a);
-
-		on = syslook("chanrecv1", 1);
-
-		argtype(on, t->type);	// any-1
-		argtype(on, t->type);	// any-2
-		r = nod(OCALL, on, N);
-		r->list = args;
-		typecheck(&r, Erv);
-		walkexpr(&r, Erv, nil);
+		r = mkcall1(chanfn("chanrecv1", 2, t), n->type, init, n->left);
 		break;
 
 	case OSEND:
 			yyerror("cannot send to %T", t);
 			break;
 		}
-
-		if(top != Etop)
+		if(n->etype == 1)	// clumsy hack
 			goto send2;
 
 		// chansend1(hchan *chan any, elem any);
-		a = n->left;			// chan
-		args = list1(a);
-		a = n->right;			// e
-		args = list(args, a);
-
-		on = syslook("chansend1", 1);
-		argtype(on, t->type);	// any-1
-		argtype(on, t->type);	// any-2
-		r = nod(OCALL, on, N);
-		r->list = args;
-		typecheck(&r, Etop);
-		walkexpr(&r, Etop, nil);
+		r = mkcall1(chanfn("chansend1", 2, t), T, init, n->left, n->right);
 		break;
 
 	send2:
 		// chansend2(hchan *chan any, val any) (pres bool);
-		a = n->left;			// chan
-		args = list1(a);
-		a = n->right;			// e