Home | History | Annotate | Download | only in gc
      1 // Copyright 2009 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package gc
      6 
      7 import (
      8 	"cmd/internal/obj"
      9 	"fmt"
     10 	"strings"
     11 )
     12 
     13 var mpzero Mpint
     14 
     15 // The constant is known to runtime.
     16 const (
     17 	tmpstringbufsize = 32
     18 )
     19 
     20 func walk(fn *Node) {
     21 	Curfn = fn
     22 
     23 	if Debug['W'] != 0 {
     24 		s := fmt.Sprintf("\nbefore %v", Curfn.Func.Nname.Sym)
     25 		dumplist(s, Curfn.Nbody)
     26 	}
     27 
     28 	lno := int(lineno)
     29 
     30 	// Final typecheck for any unused variables.
     31 	// It's hard to be on the heap when not-used, but best to be consistent about &~PHEAP here and below.
     32 	for l := fn.Func.Dcl; l != nil; l = l.Next {
     33 		if l.N.Op == ONAME && l.N.Class&^PHEAP == PAUTO {
     34 			typecheck(&l.N, Erv|Easgn)
     35 		}
     36 	}
     37 
     38 	// Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
     39 	for l := fn.Func.Dcl; l != nil; l = l.Next {
     40 		if l.N.Op == ONAME && l.N.Class&^PHEAP == PAUTO && l.N.Name.Defn != nil && l.N.Name.Defn.Op == OTYPESW && l.N.Used {
     41 			l.N.Name.Defn.Left.Used = true
     42 		}
     43 	}
     44 
     45 	for l := fn.Func.Dcl; l != nil; l = l.Next {
     46 		if l.N.Op != ONAME || l.N.Class&^PHEAP != PAUTO || l.N.Sym.Name[0] == '&' || l.N.Used {
     47 			continue
     48 		}
     49 		if defn := l.N.Name.Defn; defn != nil && defn.Op == OTYPESW {
     50 			if defn.Left.Used {
     51 				continue
     52 			}
     53 			lineno = defn.Left.Lineno
     54 			Yyerror("%v declared and not used", l.N.Sym)
     55 			defn.Left.Used = true // suppress repeats
     56 		} else {
     57 			lineno = l.N.Lineno
     58 			Yyerror("%v declared and not used", l.N.Sym)
     59 		}
     60 	}
     61 
     62 	lineno = int32(lno)
     63 	if nerrors != 0 {
     64 		return
     65 	}
     66 	walkstmtlist(Curfn.Nbody)
     67 	if Debug['W'] != 0 {
     68 		s := fmt.Sprintf("after walk %v", Curfn.Func.Nname.Sym)
     69 		dumplist(s, Curfn.Nbody)
     70 	}
     71 
     72 	heapmoves()
     73 	if Debug['W'] != 0 && Curfn.Func.Enter != nil {
     74 		s := fmt.Sprintf("enter %v", Curfn.Func.Nname.Sym)
     75 		dumplist(s, Curfn.Func.Enter)
     76 	}
     77 }
     78 
     79 func walkstmtlist(l *NodeList) {
     80 	for ; l != nil; l = l.Next {
     81 		walkstmt(&l.N)
     82 	}
     83 }
     84 
     85 func samelist(a *NodeList, b *NodeList) bool {
     86 	for ; a != nil && b != nil; a, b = a.Next, b.Next {
     87 		if a.N != b.N {
     88 			return false
     89 		}
     90 	}
     91 	return a == b
     92 }
     93 
     94 func paramoutheap(fn *Node) bool {
     95 	for l := fn.Func.Dcl; l != nil; l = l.Next {
     96 		switch l.N.Class {
     97 		case PPARAMOUT,
     98 			PPARAMOUT | PHEAP:
     99 			return l.N.Addrtaken
    100 
    101 			// stop early - parameters are over
    102 		case PAUTO,
    103 			PAUTO | PHEAP:
    104 			return false
    105 		}
    106 	}
    107 
    108 	return false
    109 }
    110 
    111 // adds "adjust" to all the argument locations for the call n.
    112 // n must be a defer or go node that has already been walked.
    113 func adjustargs(n *Node, adjust int) {
    114 	var arg *Node
    115 	var lhs *Node
    116 
    117 	callfunc := n.Left
    118 	for args := callfunc.List; args != nil; args = args.Next {
    119 		arg = args.N
    120 		if arg.Op != OAS {
    121 			Yyerror("call arg not assignment")
    122 		}
    123 		lhs = arg.Left
    124 		if lhs.Op == ONAME {
    125 			// This is a temporary introduced by reorder1.
    126 			// The real store to the stack appears later in the arg list.
    127 			continue
    128 		}
    129 
    130 		if lhs.Op != OINDREG {
    131 			Yyerror("call argument store does not use OINDREG")
    132 		}
    133 
    134 		// can't really check this in machine-indep code.
    135 		//if(lhs->val.u.reg != D_SP)
    136 		//      yyerror("call arg assign not indreg(SP)");
    137 		lhs.Xoffset += int64(adjust)
    138 	}
    139 }
    140 
    141 func walkstmt(np **Node) {
    142 	n := *np
    143 	if n == nil {
    144 		return
    145 	}
    146 	if n.Dodata == 2 { // don't walk, generated by anylit.
    147 		return
    148 	}
    149 
    150 	setlineno(n)
    151 
    152 	walkstmtlist(n.Ninit)
    153 
    154 	switch n.Op {
    155 	default:
    156 		if n.Op == ONAME {
    157 			Yyerror("%v is not a top level statement", n.Sym)
    158 		} else {
    159 			Yyerror("%v is not a top level statement", Oconv(int(n.Op), 0))
    160 		}
    161 		Dump("nottop", n)
    162 
    163 	case OAS,
    164 		OASOP,
    165 		OAS2,
    166 		OAS2DOTTYPE,
    167 		OAS2RECV,
    168 		OAS2FUNC,
    169 		OAS2MAPR,
    170 		OCLOSE,
    171 		OCOPY,
    172 		OCALLMETH,
    173 		OCALLINTER,
    174 		OCALL,
    175 		OCALLFUNC,
    176 		ODELETE,
    177 		OSEND,
    178 		OPRINT,
    179 		OPRINTN,
    180 		OPANIC,
    181 		OEMPTY,
    182 		ORECOVER,
    183 		OGETG:
    184 		if n.Typecheck == 0 {
    185 			Fatal("missing typecheck: %v", Nconv(n, obj.FmtSign))
    186 		}
    187 		init := n.Ninit
    188 		n.Ninit = nil
    189 		walkexpr(&n, &init)
    190 		addinit(&n, init)
    191 		if (*np).Op == OCOPY && n.Op == OCONVNOP {
    192 			n.Op = OEMPTY // don't leave plain values as statements.
    193 		}
    194 
    195 		// special case for a receive where we throw away
    196 	// the value received.
    197 	case ORECV:
    198 		if n.Typecheck == 0 {
    199 			Fatal("missing typecheck: %v", Nconv(n, obj.FmtSign))
    200 		}
    201 		init := n.Ninit
    202 		n.Ninit = nil
    203 
    204 		walkexpr(&n.Left, &init)
    205 		n = mkcall1(chanfn("chanrecv1", 2, n.Left.Type), nil, &init, typename(n.Left.Type), n.Left, nodnil())
    206 		walkexpr(&n, &init)
    207 
    208 		addinit(&n, init)
    209 
    210 	case OBREAK,
    211 		ODCL,
    212 		OCONTINUE,
    213 		OFALL,
    214 		OGOTO,
    215 		OLABEL,
    216 		ODCLCONST,
    217 		ODCLTYPE,
    218 		OCHECKNIL,
    219 		OVARKILL:
    220 		break
    221 
    222 	case OBLOCK:
    223 		walkstmtlist(n.List)
    224 
    225 	case OXCASE:
    226 		Yyerror("case statement out of place")
    227 		n.Op = OCASE
    228 		fallthrough
    229 
    230 	case OCASE:
    231 		walkstmt(&n.Right)
    232 
    233 	case ODEFER:
    234 		Hasdefer = 1
    235 		switch n.Left.Op {
    236 		case OPRINT, OPRINTN:
    237 			walkprintfunc(&n.Left, &n.Ninit)
    238 
    239 		case OCOPY:
    240 			n.Left = copyany(n.Left, &n.Ninit, 1)
    241 
    242 		default:
    243 			walkexpr(&n.Left, &n.Ninit)
    244 		}
    245 
    246 		// make room for size & fn arguments.
    247 		adjustargs(n, 2*Widthptr)
    248 
    249 	case OFOR:
    250 		if n.Left != nil {
    251 			walkstmtlist(n.Left.Ninit)
    252 			init := n.Left.Ninit
    253 			n.Left.Ninit = nil
    254 			walkexpr(&n.Left, &init)
    255 			addinit(&n.Left, init)
    256 		}
    257 
    258 		walkstmt(&n.Right)
    259 		walkstmtlist(n.Nbody)
    260 
    261 	case OIF:
    262 		walkexpr(&n.Left, &n.Ninit)
    263 		walkstmtlist(n.Nbody)
    264 		walkstmtlist(n.Rlist)
    265 
    266 	case OPROC:
    267 		switch n.Left.Op {
    268 		case OPRINT, OPRINTN:
    269 			walkprintfunc(&n.Left, &n.Ninit)
    270 
    271 		case OCOPY:
    272 			n.Left = copyany(n.Left, &n.Ninit, 1)
    273 
    274 		default:
    275 			walkexpr(&n.Left, &n.Ninit)
    276 		}
    277 
    278 		// make room for size & fn arguments.
    279 		adjustargs(n, 2*Widthptr)
    280 
    281 	case ORETURN:
    282 		walkexprlist(n.List, &n.Ninit)
    283 		if n.List == nil {
    284 			break
    285 		}
    286 		if (Curfn.Type.Outnamed != 0 && count(n.List) > 1) || paramoutheap(Curfn) {
    287 			// assign to the function out parameters,
    288 			// so that reorder3 can fix up conflicts
    289 			var rl *NodeList
    290 
    291 			var cl uint8
    292 			for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
    293 				cl = ll.N.Class &^ PHEAP
    294 				if cl == PAUTO {
    295 					break
    296 				}
    297 				if cl == PPARAMOUT {
    298 					rl = list(rl, ll.N)
    299 				}
    300 			}
    301 
    302 			if samelist(rl, n.List) {
    303 				// special return in disguise
    304 				n.List = nil
    305 
    306 				break
    307 			}
    308 
    309 			if count(n.List) == 1 && count(rl) > 1 {
    310 				// OAS2FUNC in disguise
    311 				f := n.List.N
    312 
    313 				if f.Op != OCALLFUNC && f.Op != OCALLMETH && f.Op != OCALLINTER {
    314 					Fatal("expected return of call, have %v", f)
    315 				}
    316 				n.List = concat(list1(f), ascompatet(int(n.Op), rl, &f.Type, 0, &n.Ninit))
    317 				break
    318 			}
    319 
    320 			// move function calls out, to make reorder3's job easier.
    321 			walkexprlistsafe(n.List, &n.Ninit)
    322 
    323 			ll := ascompatee(int(n.Op), rl, n.List, &n.Ninit)
    324 			n.List = reorder3(ll)
    325 			break
    326 		}
    327 
    328 		ll := ascompatte(int(n.Op), nil, false, Getoutarg(Curfn.Type), n.List, 1, &n.Ninit)
    329 		n.List = ll
    330 
    331 	case ORETJMP:
    332 		break
    333 
    334 	case OSELECT:
    335 		walkselect(n)
    336 
    337 	case OSWITCH:
    338 		walkswitch(n)
    339 
    340 	case ORANGE:
    341 		walkrange(n)
    342 
    343 	case OXFALL:
    344 		Yyerror("fallthrough statement out of place")
    345 		n.Op = OFALL
    346 	}
    347 
    348 	if n.Op == ONAME {
    349 		Fatal("walkstmt ended up with name: %v", Nconv(n, obj.FmtSign))
    350 	}
    351 
    352 	*np = n
    353 }
    354 
    355 func isSmallMakeSlice(n *Node) bool {
    356 	if n.Op != OMAKESLICE {
    357 		return false
    358 	}
    359 	l := n.Left
    360 	r := n.Right
    361 	if r == nil {
    362 		r = l
    363 	}
    364 	t := n.Type
    365 
    366 	return Smallintconst(l) && Smallintconst(r) && (t.Type.Width == 0 || Mpgetfix(r.Val().U.(*Mpint)) < (1<<16)/t.Type.Width)
    367 }
    368 
    369 /*
    370  * walk the whole tree of the body of an
    371  * expression or simple statement.
    372  * the types expressions are calculated.
    373  * compile-time constants are evaluated.
    374  * complex side effects like statements are appended to init
    375  */
    376 func walkexprlist(l *NodeList, init **NodeList) {
    377 	for ; l != nil; l = l.Next {
    378 		walkexpr(&l.N, init)
    379 	}
    380 }
    381 
    382 func walkexprlistsafe(l *NodeList, init **NodeList) {
    383 	for ; l != nil; l = l.Next {
    384 		l.N = safeexpr(l.N, init)
    385 		walkexpr(&l.N, init)
    386 	}
    387 }
    388 
    389 func walkexprlistcheap(l *NodeList, init **NodeList) {
    390 	for ; l != nil; l = l.Next {
    391 		l.N = cheapexpr(l.N, init)
    392 		walkexpr(&l.N, init)
    393 	}
    394 }
    395 
    396 func walkexpr(np **Node, init **NodeList) {
    397 	n := *np
    398 
    399 	if n == nil {
    400 		return
    401 	}
    402 
    403 	if init == &n.Ninit {
    404 		// not okay to use n->ninit when walking n,
    405 		// because we might replace n with some other node
    406 		// and would lose the init list.
    407 		Fatal("walkexpr init == &n->ninit")
    408 	}
    409 
    410 	if n.Ninit != nil {
    411 		walkstmtlist(n.Ninit)
    412 		*init = concat(*init, n.Ninit)
    413 		n.Ninit = nil
    414 	}
    415 
    416 	// annoying case - not typechecked
    417 	if n.Op == OKEY {
    418 		walkexpr(&n.Left, init)
    419 		walkexpr(&n.Right, init)
    420 		return
    421 	}
    422 
    423 	lno := setlineno(n)
    424 
    425 	if Debug['w'] > 1 {
    426 		Dump("walk-before", n)
    427 	}
    428 
    429 	if n.Typecheck != 1 {
    430 		Fatal("missed typecheck: %v\n", Nconv(n, obj.FmtSign))
    431 	}
    432 
    433 	switch n.Op {
    434 	default:
    435 		Dump("walk", n)
    436 		Fatal("walkexpr: switch 1 unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
    437 
    438 	case OTYPE,
    439 		ONONAME,
    440 		OINDREG,
    441 		OEMPTY,
    442 		OPARAM,
    443 		OGETG:
    444 		goto ret
    445 
    446 	case ONOT,
    447 		OMINUS,
    448 		OPLUS,
    449 		OCOM,
    450 		OREAL,
    451 		OIMAG,
    452 		ODOTMETH,
    453 		ODOTINTER:
    454 		walkexpr(&n.Left, init)
    455 		goto ret
    456 
    457 	case OIND:
    458 		walkexpr(&n.Left, init)
    459 		goto ret
    460 
    461 	case ODOT:
    462 		usefield(n)
    463 		walkexpr(&n.Left, init)
    464 		goto ret
    465 
    466 	case ODOTPTR:
    467 		usefield(n)
    468 		if n.Op == ODOTPTR && n.Left.Type.Type.Width == 0 {
    469 			// No actual copy will be generated, so emit an explicit nil check.
    470 			n.Left = cheapexpr(n.Left, init)
    471 
    472 			checknil(n.Left, init)
    473 		}
    474 
    475 		walkexpr(&n.Left, init)
    476 		goto ret
    477 
    478 	case OEFACE:
    479 		walkexpr(&n.Left, init)
    480 		walkexpr(&n.Right, init)
    481 		goto ret
    482 
    483 	case OSPTR, OITAB:
    484 		walkexpr(&n.Left, init)
    485 		goto ret
    486 
    487 	case OLEN, OCAP:
    488 		walkexpr(&n.Left, init)
    489 
    490 		// replace len(*[10]int) with 10.
    491 		// delayed until now to preserve side effects.
    492 		t := n.Left.Type
    493 
    494 		if Isptr[t.Etype] {
    495 			t = t.Type
    496 		}
    497 		if Isfixedarray(t) {
    498 			safeexpr(n.Left, init)
    499 			Nodconst(n, n.Type, t.Bound)
    500 			n.Typecheck = 1
    501 		}
    502 
    503 		goto ret
    504 
    505 	case OLSH, ORSH:
    506 		walkexpr(&n.Left, init)
    507 		walkexpr(&n.Right, init)
    508 		t := n.Left.Type
    509 		n.Bounded = bounded(n.Right, 8*t.Width)
    510 		if Debug['m'] != 0 && n.Etype != 0 && !Isconst(n.Right, CTINT) {
    511 			Warn("shift bounds check elided")
    512 		}
    513 		goto ret
    514 
    515 		// Use results from call expression as arguments for complex.
    516 	case OAND,
    517 		OSUB,
    518 		OHMUL,
    519 		OLT,
    520 		OLE,
    521 		OGE,
    522 		OGT,
    523 		OADD,
    524 		OCOMPLEX,
    525 		OLROT:
    526 		if n.Op == OCOMPLEX && n.Left == nil && n.Right == nil {
    527 			n.Left = n.List.N
    528 			n.Right = n.List.Next.N
    529 		}
    530 
    531 		walkexpr(&n.Left, init)
    532 		walkexpr(&n.Right, init)
    533 		goto ret
    534 
    535 	case OOR, OXOR:
    536 		walkexpr(&n.Left, init)
    537 		walkexpr(&n.Right, init)
    538 		walkrotate(&n)
    539 		goto ret
    540 
    541 	case OEQ, ONE:
    542 		walkexpr(&n.Left, init)
    543 		walkexpr(&n.Right, init)
    544 
    545 		// Disable safemode while compiling this code: the code we
    546 		// generate internally can refer to unsafe.Pointer.
    547 		// In this case it can happen if we need to generate an ==
    548 		// for a struct containing a reflect.Value, which itself has
    549 		// an unexported field of type unsafe.Pointer.
    550 		old_safemode := safemode
    551 
    552 		safemode = 0
    553 		walkcompare(&n, init)
    554 		safemode = old_safemode
    555 		goto ret
    556 
    557 	case OANDAND, OOROR:
    558 		walkexpr(&n.Left, init)
    559 
    560 		// cannot put side effects from n.Right on init,
    561 		// because they cannot run before n.Left is checked.
    562 		// save elsewhere and store on the eventual n.Right.
    563 		var ll *NodeList
    564 
    565 		walkexpr(&n.Right, &ll)
    566 		addinit(&n.Right, ll)
    567 		goto ret
    568 
    569 	case OPRINT, OPRINTN:
    570 		walkexprlist(n.List, init)
    571 		n = walkprint(n, init)
    572 		goto ret
    573 
    574 	case OPANIC:
    575 		n = mkcall("gopanic", nil, init, n.Left)
    576 		goto ret
    577 
    578 	case ORECOVER:
    579 		n = mkcall("gorecover", n.Type, init, Nod(OADDR, nodfp, nil))
    580 		goto ret
    581 
    582 	case OLITERAL:
    583 		n.Addable = true
    584 		goto ret
    585 
    586 	case OCLOSUREVAR, OCFUNC:
    587 		n.Addable = true
    588 		goto ret
    589 
    590 	case ONAME:
    591 		if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
    592 			n.Addable = true
    593 		}
    594 		goto ret
    595 
    596 	case OCALLINTER:
    597 		t := n.Left.Type
    598 		if n.List != nil && n.List.N.Op == OAS {
    599 			goto ret
    600 		}
    601 		walkexpr(&n.Left, init)
    602 		walkexprlist(n.List, init)
    603 		ll := ascompatte(int(n.Op), n, n.Isddd, getinarg(t), n.List, 0, init)
    604 		n.List = reorder1(ll)
    605 		goto ret
    606 
    607 	case OCALLFUNC:
    608 		if n.Left.Op == OCLOSURE {
    609 			// Transform direct call of a closure to call of a normal function.
    610 			// transformclosure already did all preparation work.
    611 
    612 			// Prepend captured variables to argument list.
    613 			n.List = concat(n.Left.Func.Enter, n.List)
    614 
    615 			n.Left.Func.Enter = nil
    616 
    617 			// Replace OCLOSURE with ONAME/PFUNC.
    618 			n.Left = n.Left.Func.Closure.Func.Nname
    619 
    620 			// Update type of OCALLFUNC node.
    621 			// Output arguments had not changed, but their offsets could.
    622 			if n.Left.Type.Outtuple == 1 {
    623 				t := getoutargx(n.Left.Type).Type
    624 				if t.Etype == TFIELD {
    625 					t = t.Type
    626 				}
    627 				n.Type = t
    628 			} else {
    629 				n.Type = getoutargx(n.Left.Type)
    630 			}
    631 		}
    632 
    633 		t := n.Left.Type
    634 		if n.List != nil && n.List.N.Op == OAS {
    635 			goto ret
    636 		}
    637 
    638 		walkexpr(&n.Left, init)
    639 		walkexprlist(n.List, init)
    640 
    641 		if n.Left.Op == ONAME && n.Left.Sym.Name == "Sqrt" && n.Left.Sym.Pkg.Path == "math" {
    642 			switch Thearch.Thechar {
    643 			case '5', '6', '7':
    644 				n.Op = OSQRT
    645 				n.Left = n.List.N
    646 				n.List = nil
    647 				goto ret
    648 			}
    649 		}
    650 
    651 		ll := ascompatte(int(n.Op), n, n.Isddd, getinarg(t), n.List, 0, init)
    652 		n.List = reorder1(ll)
    653 		goto ret
    654 
    655 	case OCALLMETH:
    656 		t := n.Left.Type
    657 		if n.List != nil && n.List.N.Op == OAS {
    658 			goto ret
    659 		}
    660 		walkexpr(&n.Left, init)
    661 		walkexprlist(n.List, init)
    662 		ll := ascompatte(int(n.Op), n, false, getthis(t), list1(n.Left.Left), 0, init)
    663 		lr := ascompatte(int(n.Op), n, n.Isddd, getinarg(t), n.List, 0, init)
    664 		ll = concat(ll, lr)
    665 		n.Left.Left = nil
    666 		ullmancalc(n.Left)
    667 		n.List = reorder1(ll)
    668 		goto ret
    669 
    670 	case OAS:
    671 		*init = concat(*init, n.Ninit)
    672 		n.Ninit = nil
    673 
    674 		walkexpr(&n.Left, init)
    675 		n.Left = safeexpr(n.Left, init)
    676 
    677 		if oaslit(n, init) {
    678 			goto ret
    679 		}
    680 
    681 		if n.Right == nil || iszero(n.Right) && flag_race == 0 {
    682 			goto ret
    683 		}
    684 
    685 		switch n.Right.Op {
    686 		default:
    687 			walkexpr(&n.Right, init)
    688 
    689 		case ODOTTYPE:
    690 			// TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
    691 			// It needs to be removed in all three places.
    692 			// That would allow inlining x.(struct{*int}) the same as x.(*int).
    693 			if isdirectiface(n.Right.Type) && !Isfat(n.Right.Type) && flag_race == 0 {
    694 				// handled directly during cgen
    695 				walkexpr(&n.Right, init)
    696 				break
    697 			}
    698 
    699 			// x = i.(T); n.Left is x, n.Right.Left is i.
    700 			// orderstmt made sure x is addressable.
    701 			walkexpr(&n.Right.Left, init)
    702 
    703 			n1 := Nod(OADDR, n.Left, nil)
    704 			r := n.Right // i.(T)
    705 
    706 			if Debug_typeassert > 0 {
    707 				Warn("type assertion not inlined")
    708 			}
    709 
    710 			buf := "assert" + type2IET(r.Left.Type) + "2" + type2IET(r.Type)
    711 			fn := syslook(buf, 1)
    712 			substArgTypes(fn, r.Left.Type, r.Type)
    713 
    714 			n = mkcall1(fn, nil, init, typename(r.Type), r.Left, n1)
    715 			walkexpr(&n, init)
    716 			goto ret
    717 
    718 		case ORECV:
    719 			// x = <-c; n.Left is x, n.Right.Left is c.
    720 			// orderstmt made sure x is addressable.
    721 			walkexpr(&n.Right.Left, init)
    722 
    723 			n1 := Nod(OADDR, n.Left, nil)
    724 			r := n.Right.Left // the channel
    725 			n = mkcall1(chanfn("chanrecv1", 2, r.Type), nil, init, typename(r.Type), r, n1)
    726 			walkexpr(&n, init)
    727 			goto ret
    728 
    729 		case OAPPEND:
    730 			// x = append(...)
    731 			r := n.Right
    732 			if r.Isddd {
    733 				r = appendslice(r, init) // also works for append(slice, string).
    734 			} else {
    735 				r = walkappend(r, init, n)
    736 			}
    737 			n.Right = r
    738 			if r.Op == OAPPEND {
    739 				// Left in place for back end.
    740 				// Do not add a new write barrier.
    741 				goto ret
    742 			}
    743 			// Otherwise, lowered for race detector.
    744 			// Treat as ordinary assignment.
    745 		}
    746 
    747 		if n.Left != nil && n.Right != nil {
    748 			r := convas(Nod(OAS, n.Left, n.Right), init)
    749 			r.Dodata = n.Dodata
    750 			n = r
    751 			n = applywritebarrier(n, init)
    752 		}
    753 
    754 		goto ret
    755 
    756 	case OAS2:
    757 		*init = concat(*init, n.Ninit)
    758 		n.Ninit = nil
    759 		walkexprlistsafe(n.List, init)
    760 		walkexprlistsafe(n.Rlist, init)
    761 		ll := ascompatee(OAS, n.List, n.Rlist, init)
    762 		ll = reorder3(ll)
    763 		for lr := ll; lr != nil; lr = lr.Next {
    764 			lr.N = applywritebarrier(lr.N, init)
    765 		}
    766 		n = liststmt(ll)
    767 		goto ret
    768 
    769 		// a,b,... = fn()
    770 	case OAS2FUNC:
    771 		*init = concat(*init, n.Ninit)
    772 
    773 		n.Ninit = nil
    774 		r := n.Rlist.N
    775 		walkexprlistsafe(n.List, init)
    776 		walkexpr(&r, init)
    777 
    778 		ll := ascompatet(int(n.Op), n.List, &r.Type, 0, init)
    779 		for lr := ll; lr != nil; lr = lr.Next {
    780 			lr.N = applywritebarrier(lr.N, init)
    781 		}
    782 		n = liststmt(concat(list1(r), ll))
    783 		goto ret
    784 
    785 		// x, y = <-c
    786 	// orderstmt made sure x is addressable.
    787 	case OAS2RECV:
    788 		*init = concat(*init, n.Ninit)
    789 
    790 		n.Ninit = nil
    791 		r := n.Rlist.N
    792 		walkexprlistsafe(n.List, init)
    793 		walkexpr(&r.Left, init)
    794 		var n1 *Node
    795 		if isblank(n.List.N) {
    796 			n1 = nodnil()
    797 		} else {
    798 			n1 = Nod(OADDR, n.List.N, nil)
    799 		}
    800 		n1.Etype = 1 // addr does not escape
    801 		fn := chanfn("chanrecv2", 2, r.Left.Type)
    802 		r = mkcall1(fn, n.List.Next.N.Type, init, typename(r.Left.Type), r.Left, n1)
    803 		n = Nod(OAS, n.List.Next.N, r)
    804 		typecheck(&n, Etop)
    805 		goto ret
    806 
    807 		// a,b = m[i];
    808 	case OAS2MAPR:
    809 		*init = concat(*init, n.Ninit)
    810 
    811 		n.Ninit = nil
    812 		r := n.Rlist.N
    813 		walkexprlistsafe(n.List, init)
    814 		walkexpr(&r.Left, init)
    815 		walkexpr(&r.Right, init)
    816 		t := r.Left.Type
    817 		p := ""
    818 		if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
    819 			switch Simsimtype(t.Down) {
    820 			case TINT32, TUINT32:
    821 				p = "mapaccess2_fast32"
    822 
    823 			case TINT64, TUINT64:
    824 				p = "mapaccess2_fast64"
    825 
    826 			case TSTRING:
    827 				p = "mapaccess2_faststr"
    828 			}
    829 		}
    830 
    831 		var key *Node
    832 		if p != "" {
    833 			// fast versions take key by value
    834 			key = r.Right
    835 		} else {
    836 			// standard version takes key by reference
    837 			// orderexpr made sure key is addressable.
    838 			key = Nod(OADDR, r.Right, nil)
    839 
    840 			p = "mapaccess2"
    841 		}
    842 
    843 		// from:
    844 		//   a,b = m[i]
    845 		// to:
    846 		//   var,b = mapaccess2*(t, m, i)
    847 		//   a = *var
    848 		a := n.List.N
    849 
    850 		fn := mapfn(p, t)
    851 		r = mkcall1(fn, getoutargx(fn.Type), init, typename(t), r.Left, key)
    852 
    853 		// mapaccess2* returns a typed bool, but due to spec changes,
    854 		// the boolean result of i.(T) is now untyped so we make it the
    855 		// same type as the variable on the lhs.
    856 		if !isblank(n.List.Next.N) {
    857 			r.Type.Type.Down.Type = n.List.Next.N.Type
    858 		}
    859 		n.Rlist = list1(r)
    860 		n.Op = OAS2FUNC
    861 
    862 		// don't generate a = *var if a is _
    863 		if !isblank(a) {
    864 			var_ := temp(Ptrto(t.Type))
    865 			var_.Typecheck = 1
    866 			n.List.N = var_
    867 			walkexpr(&n, init)
    868 			*init = list(*init, n)
    869 			n = Nod(OAS, a, Nod(OIND, var_, nil))
    870 		}
    871 
    872 		typecheck(&n, Etop)
    873 		walkexpr(&n, init)
    874 
    875 		// mapaccess needs a zero value to be at least this big.
    876 		if zerosize < t.Type.Width {
    877 			zerosize = t.Type.Width
    878 		}
    879 
    880 		// TODO: ptr is always non-nil, so disable nil check for this OIND op.
    881 		goto ret
    882 
    883 	case ODELETE:
    884 		*init = concat(*init, n.Ninit)
    885 		n.Ninit = nil
    886 		map_ := n.List.N
    887 		key := n.List.Next.N
    888 		walkexpr(&map_, init)
    889 		walkexpr(&key, init)
    890 
    891 		// orderstmt made sure key is addressable.
    892 		key = Nod(OADDR, key, nil)
    893 
    894 		t := map_.Type
    895 		n = mkcall1(mapfndel("mapdelete", t), nil, init, typename(t), map_, key)
    896 		goto ret
    897 
    898 	case OAS2DOTTYPE:
    899 		e := n.Rlist.N // i.(T)
    900 		// TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
    901 		// It needs to be removed in all three places.
    902 		// That would allow inlining x.(struct{*int}) the same as x.(*int).
    903 		if isdirectiface(e.Type) && !Isfat(e.Type) && flag_race == 0 {
    904 			// handled directly during gen.
    905 			walkexprlistsafe(n.List, init)
    906 			walkexpr(&e.Left, init)
    907 			goto ret
    908 		}
    909 
    910 		// res, ok = i.(T)
    911 		// orderstmt made sure a is addressable.
    912 		*init = concat(*init, n.Ninit)
    913 		n.Ninit = nil
    914 
    915 		walkexprlistsafe(n.List, init)
    916 		walkexpr(&e.Left, init)
    917 		t := e.Type    // T
    918 		from := e.Left // i
    919 
    920 		oktype := Types[TBOOL]
    921 		ok := n.List.Next.N
    922 		if !isblank(ok) {
    923 			oktype = ok.Type
    924 		}
    925 
    926 		fromKind := type2IET(from.Type)
    927 		toKind := type2IET(t)
    928 
    929 		// Avoid runtime calls in a few cases of the form _, ok := i.(T).
    930 		// This is faster and shorter and allows the corresponding assertX2X2
    931 		// routines to skip nil checks on their last argument.
    932 		if isblank(n.List.N) {
    933 			var fast *Node
    934 			switch {
    935 			case fromKind == "E" && toKind == "T":
    936 				tab := Nod(OITAB, from, nil) // type:eface::tab:iface
    937 				typ := Nod(OCONVNOP, typename(t), nil)
    938 				typ.Type = Ptrto(Types[TUINTPTR])
    939 				fast = Nod(OEQ, tab, typ)
    940 			case fromKind == "I" && toKind == "E",
    941 				fromKind == "E" && toKind == "E":
    942 				tab := Nod(OITAB, from, nil)
    943 				fast = Nod(ONE, nodnil(), tab)
    944 			}
    945 			if fast != nil {
    946 				if Debug_typeassert > 0 {
    947 					Warn("type assertion (ok only) inlined")
    948 				}
    949 				n = Nod(OAS, ok, fast)
    950 				typecheck(&n, Etop)
    951 				goto ret
    952 			}
    953 		}
    954 
    955 		var resptr *Node // &res
    956 		if isblank(n.List.N) {
    957 			resptr = nodnil()
    958 		} else {
    959 			resptr = Nod(OADDR, n.List.N, nil)
    960 		}
    961 		resptr.Etype = 1 // addr does not escape
    962 
    963 		if Debug_typeassert > 0 {
    964 			Warn("type assertion not inlined")
    965 		}
    966 		buf := "assert" + fromKind + "2" + toKind + "2"
    967 		fn := syslook(buf, 1)
    968 		substArgTypes(fn, from.Type, t)
    969 		call := mkcall1(fn, oktype, init, typename(t), from, resptr)
    970 		n = Nod(OAS, ok, call)
    971 		typecheck(&n, Etop)
    972 		goto ret
    973 
    974 	case ODOTTYPE, ODOTTYPE2:
    975 		if !isdirectiface(n.Type) || Isfat(n.Type) {
    976 			Fatal("walkexpr ODOTTYPE") // should see inside OAS only
    977 		}
    978 		walkexpr(&n.Left, init)
    979 		goto ret
    980 
    981 	case OCONVIFACE:
    982 		walkexpr(&n.Left, init)
    983 
    984 		// Optimize convT2E as a two-word copy when T is pointer-shaped.
    985 		if isnilinter(n.Type) && isdirectiface(n.Left.Type) {
    986 			l := Nod(OEFACE, typename(n.Left.Type), n.Left)
    987 			l.Type = n.Type
    988 			l.Typecheck = n.Typecheck
    989 			n = l
    990 			goto ret
    991 		}
    992 
    993 		// Build name of function: convI2E etc.
    994 		// Not all names are possible
    995 		// (e.g., we'll never generate convE2E or convE2I).
    996 		buf := "conv" + type2IET(n.Left.Type) + "2" + type2IET(n.Type)
    997 		fn := syslook(buf, 1)
    998 		var ll *NodeList
    999 		if !Isinter(n.Left.Type) {
   1000 			ll = list(ll, typename(n.Left.Type))
   1001 		}
   1002 		if !isnilinter(n.Type) {
   1003 			ll = list(ll, typename(n.Type))
   1004 		}
   1005 		if !Isinter(n.Left.Type) && !isnilinter(n.Type) {
   1006 			sym := Pkglookup(Tconv(n.Left.Type, obj.FmtLeft)+"."+Tconv(n.Type, obj.FmtLeft), itabpkg)
   1007 			if sym.Def == nil {
   1008 				l := Nod(ONAME, nil, nil)
   1009 				l.Sym = sym
   1010 				l.Type = Ptrto(Types[TUINT8])
   1011 				l.Addable = true
   1012 				l.Class = PEXTERN
   1013 				l.Xoffset = 0
   1014 				sym.Def = l
   1015 				ggloblsym(sym, int32(Widthptr), obj.DUPOK|obj.NOPTR)
   1016 			}
   1017 
   1018 			l := Nod(OADDR, sym.Def, nil)
   1019 			l.Addable = true
   1020 			ll = list(ll, l)
   1021 
   1022 			if isdirectiface(n.Left.Type) {
   1023 				/* For pointer types, we can make a special form of optimization
   1024 				 *
   1025 				 * These statements are put onto the expression init list:
   1026 				 * 	Itab *tab = atomicloadtype(&cache);
   1027 				 * 	if(tab == nil)
   1028 				 * 		tab = typ2Itab(type, itype, &cache);
   1029 				 *
   1030 				 * The CONVIFACE expression is replaced with this:
   1031 				 * 	OEFACE{tab, ptr};
   1032 				 */
   1033 				l := temp(Ptrto(Types[TUINT8]))
   1034 
   1035 				n1 := Nod(OAS, l, sym.Def)
   1036 				typecheck(&n1, Etop)
   1037 				*init = list(*init, n1)
   1038 
   1039 				fn := syslook("typ2Itab", 1)
   1040 				n1 = Nod(OCALL, fn, nil)
   1041 				n1.List = ll
   1042 				typecheck(&n1, Erv)
   1043 				walkexpr(&n1, init)
   1044 
   1045 				n2 := Nod(OIF, nil, nil)
   1046 				n2.Left = Nod(OEQ, l, nodnil())
   1047 				n2.Nbody = list1(Nod(OAS, l, n1))
   1048 				n2.Likely = -1
   1049 				typecheck(&n2, Etop)
   1050 				*init = list(*init, n2)
   1051 
   1052 				l = Nod(OEFACE, l, n.Left)
   1053 				l.Typecheck = n.Typecheck
   1054 				l.Type = n.Type
   1055 				n = l
   1056 				goto ret
   1057 			}
   1058 		}
   1059 
   1060 		if Isinter(n.Left.Type) {
   1061 			ll = list(ll, n.Left)
   1062 		} else {
   1063 			// regular types are passed by reference to avoid C vararg calls
   1064 			// orderexpr arranged for n.Left to be a temporary for all
   1065 			// the conversions it could see. comparison of an interface
   1066 			// with a non-interface, especially in a switch on interface value
   1067 			// with non-interface cases, is not visible to orderstmt, so we
   1068 			// have to fall back on allocating a temp here.
   1069 			if islvalue(n.Left) {
   1070 				ll = list(ll, Nod(OADDR, n.Left, nil))
   1071 			} else {
   1072 				ll = list(ll, Nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
   1073 			}
   1074 			dowidth(n.Left.Type)
   1075 			r := nodnil()
   1076 			if n.Esc == EscNone && n.Left.Type.Width <= 1024 {
   1077 				// Allocate stack buffer for value stored in interface.
   1078 				r = temp(n.Left.Type)
   1079 				r = Nod(OAS, r, nil) // zero temp
   1080 				typecheck(&r, Etop)
   1081 				*init = list(*init, r)
   1082 				r = Nod(OADDR, r.Left, nil)
   1083 				typecheck(&r, Erv)
   1084 			}
   1085 			ll = list(ll, r)
   1086 		}
   1087 
   1088 		if !Isinter(n.Left.Type) {
   1089 			substArgTypes(fn, n.Left.Type, n.Left.Type, n.Type)
   1090 		} else {
   1091 			substArgTypes(fn, n.Left.Type, n.Type)
   1092 		}
   1093 		dowidth(fn.Type)
   1094 		n = Nod(OCALL, fn, nil)
   1095 		n.List = ll
   1096 		typecheck(&n, Erv)
   1097 		walkexpr(&n, init)
   1098 		goto ret
   1099 
   1100 	case OCONV, OCONVNOP:
   1101 		if Thearch.Thechar == '5' {
   1102 			if Isfloat[n.Left.Type.Etype] {
   1103 				if n.Type.Etype == TINT64 {
   1104 					n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
   1105 					goto ret
   1106 				}
   1107 
   1108 				if n.Type.Etype == TUINT64 {
   1109 					n = mkcall("float64touint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
   1110 					goto ret
   1111 				}
   1112 			}
   1113 
   1114 			if Isfloat[n.Type.Etype] {
   1115 				if n.Left.Type.Etype == TINT64 {
   1116 					n = mkcall("int64tofloat64", n.Type, init, conv(n.Left, Types[TINT64]))
   1117 					goto ret
   1118 				}
   1119 
   1120 				if n.Left.Type.Etype == TUINT64 {
   1121 					n = mkcall("uint64tofloat64", n.Type, init, conv(n.Left, Types[TUINT64]))
   1122 					goto ret
   1123 				}
   1124 			}
   1125 		}
   1126 
   1127 		walkexpr(&n.Left, init)
   1128 		goto ret
   1129 
   1130 	case OANDNOT:
   1131 		walkexpr(&n.Left, init)
   1132 		n.Op = OAND
   1133 		n.Right = Nod(OCOM, n.Right, nil)
   1134 		typecheck(&n.Right, Erv)
   1135 		walkexpr(&n.Right, init)
   1136 		goto ret
   1137 
   1138 	case OMUL:
   1139 		walkexpr(&n.Left, init)
   1140 		walkexpr(&n.Right, init)
   1141 		walkmul(&n, init)
   1142 		goto ret
   1143 
   1144 	case ODIV, OMOD:
   1145 		walkexpr(&n.Left, init)
   1146 		walkexpr(&n.Right, init)
   1147 
   1148 		/*
   1149 		 * rewrite complex div into function call.
   1150 		 */
   1151 		et := int(n.Left.Type.Etype)
   1152 
   1153 		if Iscomplex[et] && n.Op == ODIV {
   1154 			t := n.Type
   1155 			n = mkcall("complex128div", Types[TCOMPLEX128], init, conv(n.Left, Types[TCOMPLEX128]), conv(n.Right, Types[TCOMPLEX128]))
   1156 			n = conv(n, t)
   1157 			goto ret
   1158 		}
   1159 
   1160 		// Nothing to do for float divisions.
   1161 		if Isfloat[et] {
   1162 			goto ret
   1163 		}
   1164 
   1165 		// Try rewriting as shifts or magic multiplies.
   1166 		walkdiv(&n, init)
   1167 
   1168 		/*
   1169 		 * rewrite 64-bit div and mod into function calls
   1170 		 * on 32-bit architectures.
   1171 		 */
   1172 		switch n.Op {
   1173 		case OMOD, ODIV:
   1174 			if Widthreg >= 8 || (et != TUINT64 && et != TINT64) {
   1175 				goto ret
   1176 			}
   1177 			var fn string
   1178 			if et == TINT64 {
   1179 				fn = "int64"
   1180 			} else {
   1181 				fn = "uint64"
   1182 			}
   1183 			if n.Op == ODIV {
   1184 				fn += "div"
   1185 			} else {
   1186 				fn += "mod"
   1187 			}
   1188 			n = mkcall(fn, n.Type, init, conv(n.Left, Types[et]), conv(n.Right, Types[et]))
   1189 
   1190 		default:
   1191 			break
   1192 		}
   1193 
   1194 		goto ret
   1195 
   1196 	case OINDEX:
   1197 		walkexpr(&n.Left, init)
   1198 
   1199 		// save the original node for bounds checking elision.
   1200 		// If it was a ODIV/OMOD walk might rewrite it.
   1201 		r := n.Right
   1202 
   1203 		walkexpr(&n.Right, init)
   1204 
   1205 		// if range of type cannot exceed static array bound,
   1206 		// disable bounds check.
   1207 		if n.Bounded {
   1208 			goto ret
   1209 		}
   1210 		t := n.Left.Type
   1211 		if t != nil && Isptr[t.Etype] {
   1212 			t = t.Type
   1213 		}
   1214 		if Isfixedarray(t) {
   1215 			n.Bounded = bounded(r, t.Bound)
   1216 			if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
   1217 				Warn("index bounds check elided")
   1218 			}
   1219 			if Smallintconst(n.Right) && !n.Bounded {
   1220 				Yyerror("index out of bounds")
   1221 			}
   1222 		} else if Isconst(n.Left, CTSTR) {
   1223 			n.Bounded = bounded(r, int64(len(n.Left.Val().U.(string))))
   1224 			if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
   1225 				Warn("index bounds check elided")
   1226 			}
   1227 			if Smallintconst(n.Right) {
   1228 				if !n.Bounded {
   1229 					Yyerror("index out of bounds")
   1230 				} else {
   1231 					// replace "abc"[1] with 'b'.
   1232 					// delayed until now because "abc"[1] is not
   1233 					// an ideal constant.
   1234 					v := Mpgetfix(n.Right.Val().U.(*Mpint))
   1235 
   1236 					Nodconst(n, n.Type, int64(n.Left.Val().U.(string)[v]))
   1237 					n.Typecheck = 1
   1238 				}
   1239 			}
   1240 		}
   1241 
   1242 		if Isconst(n.Right, CTINT) {
   1243 			if Mpcmpfixfix(n.Right.Val().U.(*Mpint), &mpzero) < 0 || Mpcmpfixfix(n.Right.Val().U.(*Mpint), Maxintval[TINT]) > 0 {
   1244 				Yyerror("index out of bounds")
   1245 			}
   1246 		}
   1247 		goto ret
   1248 
   1249 	case OINDEXMAP:
   1250 		if n.Etype == 1 {
   1251 			goto ret
   1252 		}
   1253 		walkexpr(&n.Left, init)
   1254 		walkexpr(&n.Right, init)
   1255 
   1256 		t := n.Left.Type
   1257 		p := ""
   1258 		if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
   1259 			switch Simsimtype(t.Down) {
   1260 			case TINT32, TUINT32:
   1261 				p = "mapaccess1_fast32"
   1262 
   1263 			case TINT64, TUINT64:
   1264 				p = "mapaccess1_fast64"
   1265 
   1266 			case TSTRING:
   1267 				p = "mapaccess1_faststr"
   1268 			}
   1269 		}
   1270 
   1271 		var key *Node
   1272 		if p != "" {
   1273 			// fast versions take key by value
   1274 			key = n.Right
   1275 		} else {
   1276 			// standard version takes key by reference.
   1277 			// orderexpr made sure key is addressable.
   1278 			key = Nod(OADDR, n.Right, nil)
   1279 
   1280 			p = "mapaccess1"
   1281 		}
   1282 
   1283 		n = mkcall1(mapfn(p, t), Ptrto(t.Type), init, typename(t), n.Left, key)
   1284 		n = Nod(OIND, n, nil)
   1285 		n.Type = t.Type
   1286 		n.Typecheck = 1
   1287 
   1288 		// mapaccess needs a zero value to be at least this big.
   1289 		if zerosize < t.Type.Width {
   1290 			zerosize = t.Type.Width
   1291 		}
   1292 		goto ret
   1293 
   1294 	case ORECV:
   1295 		Fatal("walkexpr ORECV") // should see inside OAS only
   1296 
   1297 	case OSLICE, OSLICEARR, OSLICESTR:
   1298 		walkexpr(&n.Left, init)
   1299 		walkexpr(&n.Right.Left, init)
   1300 		if n.Right.Left != nil && iszero(n.Right.Left) {
   1301 			// Reduce x[0:j] to x[:j].
   1302 			n.Right.Left = nil
   1303 		}
   1304 		walkexpr(&n.Right.Right, init)
   1305 		n = reduceSlice(n)
   1306 		goto ret
   1307 
   1308 	case OSLICE3, OSLICE3ARR:
   1309 		walkexpr(&n.Left, init)
   1310 		walkexpr(&n.Right.Left, init)
   1311 		if n.Right.Left != nil && iszero(n.Right.Left) {
   1312 			// Reduce x[0:j:k] to x[:j:k].
   1313 			n.Right.Left = nil
   1314 		}
   1315 		walkexpr(&n.Right.Right.Left, init)
   1316 		walkexpr(&n.Right.Right.Right, init)
   1317 
   1318 		r := n.Right.Right.Right
   1319 		if r != nil && r.Op == OCAP && samesafeexpr(n.Left, r.Left) {
   1320 			// Reduce x[i:j:cap(x)] to x[i:j].
   1321 			n.Right.Right = n.Right.Right.Left
   1322 			if n.Op == OSLICE3 {
   1323 				n.Op = OSLICE
   1324 			} else {
   1325 				n.Op = OSLICEARR
   1326 			}
   1327 			n = reduceSlice(n)
   1328 			goto ret
   1329 		}
   1330 		goto ret
   1331 
   1332 	case OADDR:
   1333 		walkexpr(&n.Left, init)
   1334 		goto ret
   1335 
   1336 	case ONEW:
   1337 		if n.Esc == EscNone {
   1338 			if n.Type.Type.Width >= 1<<16 {
   1339 				Fatal("large ONEW with EscNone: %v", n)
   1340 			}
   1341 			r := temp(n.Type.Type)
   1342 			r = Nod(OAS, r, nil) // zero temp
   1343 			typecheck(&r, Etop)
   1344 			*init = list(*init, r)
   1345 			r = Nod(OADDR, r.Left, nil)
   1346 			typecheck(&r, Erv)
   1347 			n = r
   1348 		} else {
   1349 			n = callnew(n.Type.Type)
   1350 		}
   1351 
   1352 		goto ret
   1353 
   1354 		// If one argument to the comparison is an empty string,
   1355 	// comparing the lengths instead will yield the same result
   1356 	// without the function call.
   1357 	case OCMPSTR:
   1358 		if (Isconst(n.Left, CTSTR) && len(n.Left.Val().U.(string)) == 0) || (Isconst(n.Right, CTSTR) && len(n.Right.Val().U.(string)) == 0) {
   1359 			r := Nod(int(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil))
   1360 			typecheck(&r, Erv)
   1361 			walkexpr(&r, init)
   1362 			r.Type = n.Type
   1363 			n = r
   1364 			goto ret
   1365 		}
   1366 
   1367 		// s + "badgerbadgerbadger" == "badgerbadgerbadger"
   1368 		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 {
   1369 			r := Nod(int(n.Etype), Nod(OLEN, n.Left.List.N, nil), Nodintconst(0))
   1370 			typecheck(&r, Erv)
   1371 			walkexpr(&r, init)
   1372 			r.Type = n.Type
   1373 			n = r
   1374 			goto ret
   1375 		}
   1376 
   1377 		var r *Node
   1378 		if n.Etype == OEQ || n.Etype == ONE {
   1379 			// prepare for rewrite below
   1380 			n.Left = cheapexpr(n.Left, init)
   1381 
   1382 			n.Right = cheapexpr(n.Right, init)
   1383 
   1384 			r = mkcall("eqstring", Types[TBOOL], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
   1385 
   1386 			// quick check of len before full compare for == or !=
   1387 			// eqstring assumes that the lengths are equal
   1388 			if n.Etype == OEQ {
   1389 				// len(left) == len(right) && eqstring(left, right)
   1390 				r = Nod(OANDAND, Nod(OEQ, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
   1391 			} else {
   1392 				// len(left) != len(right) || !eqstring(left, right)
   1393 				r = Nod(ONOT, r, nil)
   1394 
   1395 				r = Nod(OOROR, Nod(ONE, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
   1396 			}
   1397 
   1398 			typecheck(&r, Erv)
   1399 			walkexpr(&r, nil)
   1400 		} else {
   1401 			// sys_cmpstring(s1, s2) :: 0
   1402 			r = mkcall("cmpstring", Types[TINT], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
   1403 
   1404 			r = Nod(int(n.Etype), r, Nodintconst(0))
   1405 		}
   1406 
   1407 		typecheck(&r, Erv)
   1408 		if n.Type.Etype != TBOOL {
   1409 			Fatal("cmp %v", n.Type)
   1410 		}
   1411 		r.Type = n.Type
   1412 		n = r
   1413 		goto ret
   1414 
   1415 	case OADDSTR:
   1416 		n = addstr(n, init)
   1417 		goto ret
   1418 
   1419 	case OAPPEND:
   1420 		// order should make sure we only see OAS(node, OAPPEND), which we handle above.
   1421 		Fatal("append outside assignment")
   1422 
   1423 	case OCOPY:
   1424 		n = copyany(n, init, flag_race)
   1425 		goto ret
   1426 
   1427 		// cannot use chanfn - closechan takes any, not chan any
   1428 	case OCLOSE:
   1429 		fn := syslook("closechan", 1)
   1430 
   1431 		substArgTypes(fn, n.Left.Type)
   1432 		n = mkcall1(fn, nil, init, n.Left)
   1433 		goto ret
   1434 
   1435 	case OMAKECHAN:
   1436 		n = mkcall1(chanfn("makechan", 1, n.Type), n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]))
   1437 		goto ret
   1438 
   1439 	case OMAKEMAP:
   1440 		t := n.Type
   1441 
   1442 		fn := syslook("makemap", 1)
   1443 
   1444 		a := nodnil() // hmap buffer
   1445 		r := nodnil() // bucket buffer
   1446 		if n.Esc == EscNone {
   1447 			// Allocate hmap buffer on stack.
   1448 			var_ := temp(hmap(t))
   1449 
   1450 			a = Nod(OAS, var_, nil) // zero temp
   1451 			typecheck(&a, Etop)
   1452 			*init = list(*init, a)
   1453 			a = Nod(OADDR, var_, nil)
   1454 
   1455 			// Allocate one bucket on stack.
   1456 			// Maximum key/value size is 128 bytes, larger objects
   1457 			// are stored with an indirection. So max bucket size is 2048+eps.
   1458 			var_ = temp(mapbucket(t))
   1459 
   1460 			r = Nod(OAS, var_, nil) // zero temp
   1461 			typecheck(&r, Etop)
   1462 			*init = list(*init, r)
   1463 			r = Nod(OADDR, var_, nil)
   1464 		}
   1465 
   1466 		substArgTypes(fn, hmap(t), mapbucket(t), t.Down, t.Type)
   1467 		n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r)
   1468 		goto ret
   1469 
   1470 	case OMAKESLICE:
   1471 		l := n.Left
   1472 		r := n.Right
   1473 		if r == nil {
   1474 			r = safeexpr(l, init)
   1475 			l = r
   1476 		}
   1477 		t := n.Type
   1478 		if n.Esc == EscNone {
   1479 			if !isSmallMakeSlice(n) {
   1480 				Fatal("non-small OMAKESLICE with EscNone: %v", n)
   1481 			}
   1482 			// var arr [r]T
   1483 			// n = arr[:l]
   1484 			t = aindex(r, t.Type) // [r]T
   1485 			var_ := temp(t)
   1486 			a := Nod(OAS, var_, nil) // zero temp
   1487 			typecheck(&a, Etop)
   1488 			*init = list(*init, a)
   1489 			r := Nod(OSLICE, var_, Nod(OKEY, nil, l)) // arr[:l]
   1490 			r = conv(r, n.Type)                       // in case n.Type is named.
   1491 			typecheck(&r, Erv)
   1492 			walkexpr(&r, init)
   1493 			n = r
   1494 		} else {
   1495 			// makeslice(t *Type, nel int64, max int64) (ary []any)
   1496 			fn := syslook("makeslice", 1)
   1497 
   1498 			substArgTypes(fn, t.Type) // any-1
   1499 			n = mkcall1(fn, n.Type, init, typename(n.Type), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
   1500 		}
   1501 
   1502 		goto ret
   1503 
   1504 	case ORUNESTR:
   1505 		a := nodnil()
   1506 		if n.Esc == EscNone {
   1507 			t := aindex(Nodintconst(4), Types[TUINT8])
   1508 			var_ := temp(t)
   1509 			a = Nod(OADDR, var_, nil)
   1510 		}
   1511 
   1512 		// intstring(*[4]byte, rune)
   1513 		n = mkcall("intstring", n.Type, init, a, conv(n.Left, Types[TINT64]))
   1514 
   1515 		goto ret
   1516 
   1517 	case OARRAYBYTESTR:
   1518 		a := nodnil()
   1519 		if n.Esc == EscNone {
   1520 			// Create temporary buffer for string on stack.
   1521 			t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
   1522 
   1523 			a = Nod(OADDR, temp(t), nil)
   1524 		}
   1525 
   1526 		// slicebytetostring(*[32]byte, []byte) string;
   1527 		n = mkcall("slicebytetostring", n.Type, init, a, n.Left)
   1528 
   1529 		goto ret
   1530 
   1531 		// slicebytetostringtmp([]byte) string;
   1532 	case OARRAYBYTESTRTMP:
   1533 		n = mkcall("slicebytetostringtmp", n.Type, init, n.Left)
   1534 
   1535 		goto ret
   1536 
   1537 		// slicerunetostring(*[32]byte, []rune) string;
   1538 	case OARRAYRUNESTR:
   1539 		a := nodnil()
   1540 
   1541 		if n.Esc == EscNone {
   1542 			// Create temporary buffer for string on stack.
   1543 			t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
   1544 
   1545 			a = Nod(OADDR, temp(t), nil)
   1546 		}
   1547 
   1548 		n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
   1549 		goto ret
   1550 
   1551 		// stringtoslicebyte(*32[byte], string) []byte;
   1552 	case OSTRARRAYBYTE:
   1553 		a := nodnil()
   1554 
   1555 		if n.Esc == EscNone {
   1556 			// Create temporary buffer for slice on stack.
   1557 			t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
   1558 
   1559 			a = Nod(OADDR, temp(t), nil)
   1560 		}
   1561 
   1562 		n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, Types[TSTRING]))
   1563 		goto ret
   1564 
   1565 		// stringtoslicebytetmp(string) []byte;
   1566 	case OSTRARRAYBYTETMP:
   1567 		n = mkcall("stringtoslicebytetmp", n.Type, init, conv(n.Left, Types[TSTRING]))
   1568 
   1569 		goto ret
   1570 
   1571 		// stringtoslicerune(*[32]rune, string) []rune
   1572 	case OSTRARRAYRUNE:
   1573 		a := nodnil()
   1574 
   1575 		if n.Esc == EscNone {
   1576 			// Create temporary buffer for slice on stack.
   1577 			t := aindex(Nodintconst(tmpstringbufsize), Types[TINT32])
   1578 
   1579 			a = Nod(OADDR, temp(t), nil)
   1580 		}
   1581 
   1582 		n = mkcall("stringtoslicerune", n.Type, init, a, n.Left)
   1583 		goto ret
   1584 
   1585 		// ifaceeq(i1 any-1, i2 any-2) (ret bool);
   1586 	case OCMPIFACE:
   1587 		if !Eqtype(n.Left.Type, n.Right.Type) {
   1588 			Fatal("ifaceeq %v %v %v", Oconv(int(n.Op), 0), n.Left.Type, n.Right.Type)
   1589 		}
   1590 		var fn *Node
   1591 		if isnilinter(n.Left.Type) {
   1592 			fn = syslook("efaceeq", 1)
   1593 		} else {
   1594 			fn = syslook("ifaceeq", 1)
   1595 		}
   1596 
   1597 		n.Right = cheapexpr(n.Right, init)
   1598 		n.Left = cheapexpr(n.Left, init)
   1599 		substArgTypes(fn, n.Right.Type, n.Left.Type)
   1600 		r := mkcall1(fn, n.Type, init, n.Left, n.Right)
   1601 		if n.Etype == ONE {
   1602 			r = Nod(ONOT, r, nil)
   1603 		}
   1604 
   1605 		// check itable/type before full compare.
   1606 		if n.Etype == OEQ {
   1607 			r = Nod(OANDAND, Nod(OEQ, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
   1608 		} else {
   1609 			r = Nod(OOROR, Nod(ONE, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
   1610 		}
   1611 		typecheck(&r, Erv)
   1612 		walkexpr(&r, init)
   1613 		r.Type = n.Type
   1614 		n = r
   1615 		goto ret
   1616 
   1617 	case OARRAYLIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
   1618 		var_ := temp(n.Type)
   1619 		anylit(0, n, var_, init)
   1620 		n = var_
   1621 		goto ret
   1622 
   1623 	case OSEND:
   1624 		n1 := n.Right
   1625 		n1 = assignconv(n1, n.Left.Type.Type, "chan send")
   1626 		walkexpr(&n1, init)
   1627 		n1 = Nod(OADDR, n1, nil)
   1628 		n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, typename(n.Left.Type), n.Left, n1)
   1629 		goto ret
   1630 
   1631 	case OCLOSURE:
   1632 		n = walkclosure(n, init)
   1633 		goto ret
   1634 
   1635 	case OCALLPART:
   1636 		n = walkpartialcall(n, init)
   1637 		goto ret
   1638 	}
   1639 
   1640 	Fatal("missing switch %v", Oconv(int(n.Op), 0))
   1641 
   1642 	// Expressions that are constant at run time but not
   1643 	// considered const by the language spec are not turned into
   1644 	// constants until walk. For example, if n is y%1 == 0, the
   1645 	// walk of y%1 may have replaced it by 0.
   1646 	// Check whether n with its updated args is itself now a constant.
   1647 ret:
   1648 	t := n.Type
   1649 
   1650 	evconst(n)
   1651 	n.Type = t
   1652 	if n.Op == OLITERAL {
   1653 		typecheck(&n, Erv)
   1654 	}
   1655 
   1656 	ullmancalc(n)
   1657 
   1658 	if Debug['w'] != 0 && n != nil {
   1659 		Dump("walk", n)
   1660 	}
   1661 
   1662 	lineno = lno
   1663 	*np = n
   1664 }
   1665 
   1666 func reduceSlice(n *Node) *Node {
   1667 	r := n.Right.Right
   1668 	if r != nil && r.Op == OLEN && samesafeexpr(n.Left, r.Left) {
   1669 		// Reduce x[i:len(x)] to x[i:].
   1670 		n.Right.Right = nil
   1671 	}
   1672 	if (n.Op == OSLICE || n.Op == OSLICESTR) && n.Right.Left == nil && n.Right.Right == nil {
   1673 		// Reduce x[:] to x.
   1674 		if Debug_slice > 0 {
   1675 			Warn("slice: omit slice operation")
   1676 		}
   1677 		return n.Left
   1678 	}
   1679 	return n
   1680 }
   1681 
   1682 func ascompatee1(op int, l *Node, r *Node, init **NodeList) *Node {
   1683 	// convas will turn map assigns into function calls,
   1684 	// making it impossible for reorder3 to work.
   1685 	n := Nod(OAS, l, r)
   1686 
   1687 	if l.Op == OINDEXMAP {
   1688 		return n
   1689 	}
   1690 
   1691 	return convas(n, init)
   1692 }
   1693 
   1694 func ascompatee(op int, nl *NodeList, nr *NodeList, init **NodeList) *NodeList {
   1695 	/*
   1696 	 * check assign expression list to
   1697 	 * a expression list. called in
   1698 	 *	expr-list = expr-list
   1699 	 */
   1700 
   1701 	// ensure order of evaluation for function calls
   1702 	for ll := nl; ll != nil; ll = ll.Next {
   1703 		ll.N = safeexpr(ll.N, init)
   1704 	}
   1705 	for lr := nr; lr != nil; lr = lr.Next {
   1706 		lr.N = safeexpr(lr.N, init)
   1707 	}
   1708 
   1709 	var nn *NodeList
   1710 	ll := nl
   1711 	lr := nr
   1712 	for ; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next {
   1713 		// Do not generate 'x = x' during return. See issue 4014.
   1714 		if op == ORETURN && ll.N == lr.N {
   1715 			continue
   1716 		}
   1717 		nn = list(nn, ascompatee1(op, ll.N, lr.N, init))
   1718 	}
   1719 
   1720 	// cannot happen: caller checked that lists had same length
   1721 	if ll != nil || lr != nil {
   1722 		Yyerror("error in shape across %v %v %v / %d %d [%s]", Hconv(nl, obj.FmtSign), Oconv(int(op), 0), Hconv(nr, obj.FmtSign), count(nl), count(nr), Curfn.Func.Nname.Sym.Name)
   1723 	}
   1724 	return nn
   1725 }
   1726 
   1727 /*
   1728  * l is an lv and rt is the type of an rv
   1729  * return 1 if this implies a function call
   1730  * evaluating the lv or a function call
   1731  * in the conversion of the types
   1732  */
   1733 func fncall(l *Node, rt *Type) bool {
   1734 	if l.Ullman >= UINF || l.Op == OINDEXMAP {
   1735 		return true
   1736 	}
   1737 	var r Node
   1738 	if needwritebarrier(l, &r) {
   1739 		return true
   1740 	}
   1741 	if Eqtype(l.Type, rt) {
   1742 		return false
   1743 	}
   1744 	return true
   1745 }
   1746 
   1747 func ascompatet(op int, nl *NodeList, nr **Type, fp int, init **NodeList) *NodeList {
   1748 	var l *Node
   1749 	var tmp *Node
   1750 	var a *Node
   1751 	var ll *NodeList
   1752 	var saver Iter
   1753 
   1754 	/*
   1755 	 * check assign type list to
   1756 	 * a expression list. called in
   1757 	 *	expr-list = func()
   1758 	 */
   1759 	r := Structfirst(&saver, nr)
   1760 
   1761 	var nn *NodeList
   1762 	var mm *NodeList
   1763 	ucount := 0
   1764 	for ll = nl; ll != nil; ll = ll.Next {
   1765 		if r == nil {
   1766 			break
   1767 		}
   1768 		l = ll.N
   1769 		if isblank(l) {
   1770 			r = structnext(&saver)
   1771 			continue
   1772 		}
   1773 
   1774 		// any lv that causes a fn call must be
   1775 		// deferred until all the return arguments
   1776 		// have been pulled from the output arguments
   1777 		if fncall(l, r.Type) {
   1778 			tmp = temp(r.Type)
   1779 			typecheck(&tmp, Erv)
   1780 			a = Nod(OAS, l, tmp)
   1781 			a = convas(a, init)
   1782 			mm = list(mm, a)
   1783 			l = tmp
   1784 		}
   1785 
   1786 		a = Nod(OAS, l, nodarg(r, fp))
   1787 		a = convas(a, init)
   1788 		ullmancalc(a)
   1789 		if a.Ullman >= UINF {
   1790 			Dump("ascompatet ucount", a)
   1791 			ucount++
   1792 		}
   1793 
   1794 		nn = list(nn, a)
   1795 		r = structnext(&saver)
   1796 	}
   1797 
   1798 	if ll != nil || r != nil {
   1799 		Yyerror("ascompatet: assignment count mismatch: %d = %d", count(nl), structcount(*nr))
   1800 	}
   1801 
   1802 	if ucount != 0 {
   1803 		Fatal("ascompatet: too many function calls evaluating parameters")
   1804 	}
   1805 	return concat(nn, mm)
   1806 }
   1807 
   1808 /*
   1809 * package all the arguments that match a ... T parameter into a []T.
   1810  */
   1811 func mkdotargslice(lr0 *NodeList, nn *NodeList, l *Type, fp int, init **NodeList, ddd *Node) *NodeList {
   1812 	esc := uint16(EscUnknown)
   1813 	if ddd != nil {
   1814 		esc = ddd.Esc
   1815 	}
   1816 
   1817 	tslice := typ(TARRAY)
   1818 	tslice.Type = l.Type.Type
   1819 	tslice.Bound = -1
   1820 
   1821 	var n *Node
   1822 	if count(lr0) == 0 {
   1823 		n = nodnil()
   1824 		n.Type = tslice
   1825 	} else {
   1826 		n = Nod(OCOMPLIT, nil, typenod(tslice))
   1827 		if ddd != nil && prealloc[ddd] != nil {
   1828 			prealloc[n] = prealloc[ddd] // temporary to use
   1829 		}
   1830 		n.List = lr0
   1831 		n.Esc = esc
   1832 		typecheck(&n, Erv)
   1833 		if n.Type == nil {
   1834 			Fatal("mkdotargslice: typecheck failed")
   1835 		}
   1836 		walkexpr(&n, init)
   1837 	}
   1838 
   1839 	a := Nod(OAS, nodarg(l, fp), n)
   1840 	nn = list(nn, convas(a, init))
   1841 	return nn
   1842 }
   1843 
   1844 /*
   1845  * helpers for shape errors
   1846  */
   1847 func dumptypes(nl **Type, what string) string {
   1848 	var savel Iter
   1849 
   1850 	fmt_ := ""
   1851 	fmt_ += "\t"
   1852 	first := 1
   1853 	for l := Structfirst(&savel, nl); l != nil; l = structnext(&savel) {
   1854 		if first != 0 {
   1855 			first = 0
   1856 		} else {
   1857 			fmt_ += ", "
   1858 		}
   1859 		fmt_ += Tconv(l, 0)
   1860 	}
   1861 
   1862 	if first != 0 {
   1863 		fmt_ += fmt.Sprintf("[no arguments %s]", what)
   1864 	}
   1865 	return fmt_
   1866 }
   1867 
   1868 func dumpnodetypes(l *NodeList, what string) string {
   1869 	var r *Node
   1870 
   1871 	fmt_ := ""
   1872 	fmt_ += "\t"
   1873 	first := 1
   1874 	for ; l != nil; l = l.Next {
   1875 		r = l.N
   1876 		if first != 0 {
   1877 			first = 0
   1878 		} else {
   1879 			fmt_ += ", "
   1880 		}
   1881 		fmt_ += Tconv(r.Type, 0)
   1882 	}
   1883 
   1884 	if first != 0 {
   1885 		fmt_ += fmt.Sprintf("[no arguments %s]", what)
   1886 	}
   1887 	return fmt_
   1888 }
   1889 
   1890 /*
   1891  * check assign expression list to
   1892  * a type list. called in
   1893  *	return expr-list
   1894  *	func(expr-list)
   1895  */
   1896 func ascompatte(op int, call *Node, isddd bool, nl **Type, lr *NodeList, fp int, init **NodeList) *NodeList {
   1897 	var savel Iter
   1898 
   1899 	lr0 := lr
   1900 	l := Structfirst(&savel, nl)
   1901 	var r *Node
   1902 	if lr != nil {
   1903 		r = lr.N
   1904 	}
   1905 	var nn *NodeList
   1906 
   1907 	// f(g()) where g has multiple return values
   1908 	var a *Node
   1909 	var l2 string
   1910 	var ll *Type
   1911 	var l1 string
   1912 	if r != nil && lr.Next == nil && r.Type.Etype == TSTRUCT && r.Type.Funarg != 0 {
   1913 		// optimization - can do block copy
   1914 		if eqtypenoname(r.Type, *nl) {
   1915 			a := nodarg(*nl, fp)
   1916 			r = Nod(OCONVNOP, r, nil)
   1917 			r.Type = a.Type
   1918 			nn = list1(convas(Nod(OAS, a, r), init))
   1919 			goto ret
   1920 		}
   1921 
   1922 		// conversions involved.
   1923 		// copy into temporaries.
   1924 		var alist *NodeList
   1925 
   1926 		for l := Structfirst(&savel, &r.Type); l != nil; l = structnext(&savel) {
   1927 			a = temp(l.Type)
   1928 			alist = list(alist, a)
   1929 		}
   1930 
   1931 		a = Nod(OAS2, nil, nil)
   1932 		a.List = alist
   1933 		a.Rlist = lr
   1934 		typecheck(&a, Etop)
   1935 		walkstmt(&a)
   1936 		*init = list(*init, a)
   1937 		lr = alist
   1938 		r = lr.N
   1939 		l = Structfirst(&savel, nl)
   1940 	}
   1941 
   1942 loop:
   1943 	if l != nil && l.Isddd {
   1944 		// the ddd parameter must be last
   1945 		ll = structnext(&savel)
   1946 
   1947 		if ll != nil {
   1948 			Yyerror("... must be last argument")
   1949 		}
   1950 
   1951 		// special case --
   1952 		// only if we are assigning a single ddd
   1953 		// argument to a ddd parameter then it is
   1954 		// passed thru unencapsulated
   1955 		if r != nil && lr.Next == nil && isddd && Eqtype(l.Type, r.Type) {
   1956 			a = Nod(OAS, nodarg(l, fp), r)
   1957 			a = convas(a, init)
   1958 			nn = list(nn, a)
   1959 			goto ret
   1960 		}
   1961 
   1962 		// normal case -- make a slice of all
   1963 		// remaining arguments and pass it to
   1964 		// the ddd parameter.
   1965 		nn = mkdotargslice(lr, nn, l, fp, init, call.Right)
   1966 
   1967 		goto ret
   1968 	}
   1969 
   1970 	if l == nil || r == nil {
   1971 		if l != nil || r != nil {
   1972 			l1 = dumptypes(nl, "expected")
   1973 			l2 = dumpnodetypes(lr0, "given")
   1974 			if l != nil {
   1975 				Yyerror("not enough arguments to %v\n%s\n%s", Oconv(int(op), 0), l1, l2)
   1976 			} else {
   1977 				Yyerror("too many arguments to %v\n%s\n%s", Oconv(int(op), 0), l1, l2)
   1978 			}
   1979 		}
   1980 
   1981 		goto ret
   1982 	}
   1983 
   1984 	a = Nod(OAS, nodarg(l, fp), r)
   1985 	a = convas(a, init)
   1986 	nn = list(nn, a)
   1987 
   1988 	l = structnext(&savel)
   1989 	r = nil
   1990 	lr = lr.Next
   1991 	if lr != nil {
   1992 		r = lr.N
   1993 	}
   1994 	goto loop
   1995 
   1996 ret:
   1997 	for lr = nn; lr != nil; lr = lr.Next {
   1998 		lr.N.Typecheck = 1
   1999 	}
   2000 	return nn
   2001 }
   2002 
   2003 // generate code for print
   2004 func walkprint(nn *Node, init **NodeList) *Node {
   2005 	var r *Node
   2006 	var n *Node
   2007 	var on *Node
   2008 	var t *Type
   2009 	var et int
   2010 
   2011 	op := int(nn.Op)
   2012 	all := nn.List
   2013 	var calls *NodeList
   2014 	notfirst := false
   2015 
   2016 	// Hoist all the argument evaluation up before the lock.
   2017 	walkexprlistcheap(all, init)
   2018 
   2019 	calls = list(calls, mkcall("printlock", nil, init))
   2020 
   2021 	for l := all; l != nil; l = l.Next {
   2022 		if notfirst {
   2023 			calls = list(calls, mkcall("printsp", nil, init))
   2024 		}
   2025 
   2026 		notfirst = op == OPRINTN
   2027 
   2028 		n = l.N
   2029 		if n.Op == OLITERAL {
   2030 			switch n.Val().Ctype() {
   2031 			case CTRUNE:
   2032 				defaultlit(&n, runetype)
   2033 
   2034 			case CTINT:
   2035 				defaultlit(&n, Types[TINT64])
   2036 
   2037 			case CTFLT:
   2038 				defaultlit(&n, Types[TFLOAT64])
   2039 			}
   2040 		}
   2041 
   2042 		if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL {
   2043 			defaultlit(&n, Types[TINT64])
   2044 		}
   2045 		defaultlit(&n, nil)
   2046 		l.N = n
   2047 		if n.Type == nil || n.Type.Etype == TFORW {
   2048 			continue
   2049 		}
   2050 
   2051 		t = n.Type
   2052 		et = int(n.Type.Etype)
   2053 		if Isinter(n.Type) {
   2054 			if isnilinter(n.Type) {
   2055 				on = syslook("printeface", 1)
   2056 			} else {
   2057 				on = syslook("printiface", 1)
   2058 			}
   2059 			substArgTypes(on, n.Type) // any-1
   2060 		} else if Isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR {
   2061 			on = syslook("printpointer", 1)
   2062 			substArgTypes(on, n.Type) // any-1
   2063 		} else if Isslice(n.Type) {
   2064 			on = syslook("printslice", 1)
   2065 			substArgTypes(on, n.Type) // any-1
   2066 		} else if Isint[et] {
   2067 			if et == TUINT64 {
   2068 				if (t.Sym.Pkg == Runtimepkg || compiling_runtime != 0) && t.Sym.Name == "hex" {
   2069 					on = syslook("printhex", 0)
   2070 				} else {
   2071 					on = syslook("printuint", 0)
   2072 				}
   2073 			} else {
   2074 				on = syslook("printint", 0)
   2075 			}
   2076 		} else if Isfloat[et] {
   2077 			on = syslook("printfloat", 0)
   2078 		} else if Iscomplex[et] {
   2079 			on = syslook("printcomplex", 0)
   2080 		} else if et == TBOOL {
   2081 			on = syslook("printbool", 0)
   2082 		} else if et == TSTRING {
   2083 			on = syslook("printstring", 0)
   2084 		} else {
   2085 			badtype(OPRINT, n.Type, nil)
   2086 			continue
   2087 		}
   2088 
   2089 		t = *getinarg(on.Type)
   2090 		if t != nil {
   2091 			t = t.Type
   2092 		}
   2093 		if t != nil {
   2094 			t = t.Type
   2095 		}
   2096 
   2097 		if !Eqtype(t, n.Type) {
   2098 			n = Nod(OCONV, n, nil)
   2099 			n.Type = t
   2100 		}
   2101 
   2102 		r = Nod(OCALL, on, nil)
   2103 		r.List = list1(n)
   2104 		calls = list(calls, r)
   2105 	}
   2106 
   2107 	if op == OPRINTN {
   2108 		calls = list(calls, mkcall("printnl", nil, nil))
   2109 	}
   2110 
   2111 	calls = list(calls, mkcall("printunlock", nil, init))
   2112 
   2113 	typechecklist(calls, Etop)
   2114 	walkexprlist(calls, init)
   2115 
   2116 	r = Nod(OEMPTY, nil, nil)
   2117 	typecheck(&r, Etop)
   2118 	walkexpr(&r, init)
   2119 	r.Ninit = calls
   2120 	return r
   2121 }
   2122 
   2123 func callnew(t *Type) *Node {
   2124 	dowidth(t)
   2125 	fn := syslook("newobject", 1)
   2126 	substArgTypes(fn, t)
   2127 	return mkcall1(fn, Ptrto(t), nil, typename(t))
   2128 }
   2129 
   2130 func iscallret(n *Node) bool {
   2131 	n = outervalue(n)
   2132 	return n.Op == OINDREG && n.Reg == int16(Thearch.REGSP)
   2133 }
   2134 
   2135 func isstack(n *Node) bool {
   2136 	n = outervalue(n)
   2137 
   2138 	// If n is *autotmp and autotmp = &foo, replace n with foo.
   2139 	// We introduce such temps when initializing struct literals.
   2140 	if n.Op == OIND && n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
   2141 		defn := n.Left.Name.Defn
   2142 		if defn != nil && defn.Op == OAS && defn.Right.Op == OADDR {
   2143 			n = defn.Right.Left
   2144 		}
   2145 	}
   2146 
   2147 	switch n.Op {
   2148 	case OINDREG:
   2149 		return n.Reg == int16(Thearch.REGSP)
   2150 
   2151 	case ONAME:
   2152 		switch n.Class {
   2153 		case PAUTO, PPARAM, PPARAMOUT:
   2154 			return true
   2155 		}
   2156 	}
   2157 
   2158 	return false
   2159 }
   2160 
   2161 func isglobal(n *Node) bool {
   2162 	n = outervalue(n)
   2163 
   2164 	switch n.Op {
   2165 	case ONAME:
   2166 		switch n.Class {
   2167 		case PEXTERN:
   2168 			return true
   2169 		}
   2170 	}
   2171 
   2172 	return false
   2173 }
   2174 
   2175 // Do we need a write barrier for the assignment l = r?
   2176 func needwritebarrier(l *Node, r *Node) bool {
   2177 	if use_writebarrier == 0 {
   2178 		return false
   2179 	}
   2180 
   2181 	if l == nil || isblank(l) {
   2182 		return false
   2183 	}
   2184 
   2185 	// No write barrier for write of non-pointers.
   2186 	dowidth(l.Type)
   2187 
   2188 	if !haspointers(l.Type) {
   2189 		return false
   2190 	}
   2191 
   2192 	// No write barrier for write to stack.
   2193 	if isstack(l) {
   2194 		return false
   2195 	}
   2196 
   2197 	// No write barrier for implicit zeroing.
   2198 	if r == nil {
   2199 		return false
   2200 	}
   2201 
   2202 	// Ignore no-op conversions when making decision.
   2203 	// Ensures that xp = unsafe.Pointer(&x) is treated
   2204 	// the same as xp = &x.
   2205 	for r.Op == OCONVNOP {
   2206 		r = r.Left
   2207 	}
   2208 
   2209 	// No write barrier for zeroing or initialization to constant.
   2210 	if iszero(r) || r.Op == OLITERAL {
   2211 		return false
   2212 	}
   2213 
   2214 	// No write barrier for storing static (read-only) data.
   2215 	if r.Op == ONAME && strings.HasPrefix(r.Sym.Name, "statictmp_") {
   2216 		return false
   2217 	}
   2218 
   2219 	// No write barrier for storing address of stack values,
   2220 	// which are guaranteed only to be written to the stack.
   2221 	if r.Op == OADDR && isstack(r.Left) {
   2222 		return false
   2223 	}
   2224 
   2225 	// No write barrier for storing address of global, which
   2226 	// is live no matter what.
   2227 	if r.Op == OADDR && isglobal(r.Left) {
   2228 		return false
   2229 	}
   2230 
   2231 	// Otherwise, be conservative and use write barrier.
   2232 	return true
   2233 }
   2234 
   2235 // TODO(rsc): Perhaps componentgen should run before this.
   2236 
   2237 var applywritebarrier_bv Bvec
   2238 
   2239 func applywritebarrier(n *Node, init **NodeList) *Node {
   2240 	if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
   2241 		if Debug_wb > 1 {
   2242 			Warnl(int(n.Lineno), "marking %v for barrier", Nconv(n.Left, 0))
   2243 		}
   2244 		n.Op = OASWB
   2245 		return n
   2246 	}
   2247 	return n
   2248 }
   2249 
   2250 func convas(n *Node, init **NodeList) *Node {
   2251 	if n.Op != OAS {
   2252 		Fatal("convas: not OAS %v", Oconv(int(n.Op), 0))
   2253 	}
   2254 
   2255 	n.Typecheck = 1
   2256 
   2257 	var lt *Type
   2258 	var rt *Type
   2259 	if n.Left == nil || n.Right == nil {
   2260 		goto out
   2261 	}
   2262 
   2263 	lt = n.Left.Type
   2264 	rt = n.Right.Type
   2265 	if lt == nil || rt == nil {
   2266 		goto out
   2267 	}
   2268 
   2269 	if isblank(n.Left) {
   2270 		defaultlit(&n.Right, nil)
   2271 		goto out
   2272 	}
   2273 
   2274 	if n.Left.Op == OINDEXMAP {
   2275 		map_ := n.Left.Left
   2276 		key := n.Left.Right
   2277 		val := n.Right
   2278 		walkexpr(&map_, init)
   2279 		walkexpr(&key, init)
   2280 		walkexpr(&val, init)
   2281 
   2282 		// orderexpr made sure key and val are addressable.
   2283 		key = Nod(OADDR, key, nil)
   2284 
   2285 		val = Nod(OADDR, val, nil)
   2286 		n = mkcall1(mapfn("mapassign1", map_.Type), nil, init, typename(map_.Type), map_, key, val)
   2287 		goto out
   2288 	}
   2289 
   2290 	if !Eqtype(lt, rt) {
   2291 		n.Right = assignconv(n.Right, lt, "assignment")
   2292 		walkexpr(&n.Right, init)
   2293 	}
   2294 
   2295 out:
   2296 	ullmancalc(n)
   2297 	return n
   2298 }
   2299 
   2300 /*
   2301  * from ascompat[te]
   2302  * evaluating actual function arguments.
   2303  *	f(a,b)
   2304  * if there is exactly one function expr,
   2305  * then it is done first. otherwise must
   2306  * make temp variables
   2307  */
   2308 func reorder1(all *NodeList) *NodeList {
   2309 	var n *Node
   2310 
   2311 	c := 0 // function calls
   2312 	t := 0 // total parameters
   2313 
   2314 	for l := all; l != nil; l = l.Next {
   2315 		n = l.N
   2316 		t++
   2317 		ullmancalc(n)
   2318 		if n.Ullman >= UINF {
   2319 			c++
   2320 		}
   2321 	}
   2322 
   2323 	if c == 0 || t == 1 {
   2324 		return all
   2325 	}
   2326 
   2327 	var g *NodeList // fncalls assigned to tempnames
   2328 	var f *Node     // last fncall assigned to stack
   2329 	var r *NodeList // non fncalls and tempnames assigned to stack
   2330 	d := 0
   2331 	var a *Node
   2332 	for l := all; l != nil; l = l.Next {
   2333 		n = l.N
   2334 		if n.Ullman < UINF {
   2335 			r = list(r, n)
   2336 			continue
   2337 		}
   2338 
   2339 		d++
   2340 		if d == c {
   2341 			f = n
   2342 			continue
   2343 		}
   2344 
   2345 		// make assignment of fncall to tempname
   2346 		a = temp(n.Right.Type)
   2347 
   2348 		a = Nod(OAS, a, n.Right)
   2349 		g = list(g, a)
   2350 
   2351 		// put normal arg assignment on list
   2352 		// with fncall replaced by tempname
   2353 		n.Right = a.Left
   2354 
   2355 		r = list(r, n)
   2356 	}
   2357 
   2358 	if f != nil {
   2359 		g = list(g, f)
   2360 	}
   2361 	return concat(g, r)
   2362 }
   2363 
   2364 /*
   2365  * from ascompat[ee]
   2366  *	a,b = c,d
   2367  * simultaneous assignment. there cannot
   2368  * be later use of an earlier lvalue.
   2369  *
   2370  * function calls have been removed.
   2371  */
   2372 func reorder3(all *NodeList) *NodeList {
   2373 	var l *Node
   2374 
   2375 	// If a needed expression may be affected by an
   2376 	// earlier assignment, make an early copy of that
   2377 	// expression and use the copy instead.
   2378 	var early *NodeList
   2379 
   2380 	var mapinit *NodeList
   2381 	for list := all; list != nil; list = list.Next {
   2382 		l = list.N.Left
   2383 
   2384 		// Save subexpressions needed on left side.
   2385 		// Drill through non-dereferences.
   2386 		for {
   2387 			if l.Op == ODOT || l.Op == OPAREN {
   2388 				l = l.Left
   2389 				continue
   2390 			}
   2391 
   2392 			if l.Op == OINDEX && Isfixedarray(l.Left.Type) {
   2393 				reorder3save(&l.Right, all, list, &early)
   2394 				l = l.Left
   2395 				continue
   2396 			}
   2397 
   2398 			break
   2399 		}
   2400 
   2401 		switch l.Op {
   2402 		default:
   2403 			Fatal("reorder3 unexpected lvalue %v", Oconv(int(l.Op), obj.FmtSharp))
   2404 
   2405 		case ONAME:
   2406 			break
   2407 
   2408 		case OINDEX, OINDEXMAP:
   2409 			reorder3save(&l.Left, all, list, &early)
   2410 			reorder3save(&l.Right, all, list, &early)
   2411 			if l.Op == OINDEXMAP {
   2412 				list.N = convas(list.N, &mapinit)
   2413 			}
   2414 
   2415 		case OIND, ODOTPTR:
   2416 			reorder3save(&l.Left, all, list, &early)
   2417 		}
   2418 
   2419 		// Save expression on right side.
   2420 		reorder3save(&list.N.Right, all, list, &early)
   2421 	}
   2422 
   2423 	early = concat(mapinit, early)
   2424 	return concat(early, all)
   2425 }
   2426 
   2427 /*
   2428  * if the evaluation of *np would be affected by the
   2429  * assignments in all up to but not including stop,
   2430  * copy into a temporary during *early and
   2431  * replace *np with that temp.
   2432  */
   2433 func reorder3save(np **Node, all *NodeList, stop *NodeList, early **NodeList) {
   2434 	n := *np
   2435 	if !aliased(n, all, stop) {
   2436 		return
   2437 	}
   2438 
   2439 	q := temp(n.Type)
   2440 	q = Nod(OAS, q, n)
   2441 	typecheck(&q, Etop)
   2442 	*early = list(*early, q)
   2443 	*np = q.Left
   2444 }
   2445 
   2446 /*
   2447  * what's the outer value that a write to n affects?
   2448  * outer value means containing struct or array.
   2449  */
   2450 func outervalue(n *Node) *Node {
   2451 	for {
   2452 		if n.Op == OXDOT {
   2453 			Fatal("OXDOT in walk")
   2454 		}
   2455 		if n.Op == ODOT || n.Op == OPAREN || n.Op == OCONVNOP {
   2456 			n = n.Left
   2457 			continue
   2458 		}
   2459 
   2460 		if n.Op == OINDEX && Isfixedarray(n.Left.Type) {
   2461 			n = n.Left
   2462 			continue
   2463 		}
   2464 
   2465 		break
   2466 	}
   2467 
   2468 	return n
   2469 }
   2470 
   2471 /*
   2472  * Is it possible that the computation of n might be
   2473  * affected by writes in as up to but not including stop?
   2474  */
   2475 func aliased(n *Node, all *NodeList, stop *NodeList) bool {
   2476 	if n == nil {
   2477 		return false
   2478 	}
   2479 
   2480 	// Look for obvious aliasing: a variable being assigned
   2481 	// during the all list and appearing in n.
   2482 	// Also record whether there are any writes to main memory.
   2483 	// Also record whether there are any writes to variables
   2484 	// whose addresses have been taken.
   2485 	memwrite := 0
   2486 
   2487 	varwrite := 0
   2488 	var a *Node
   2489 	for l := all; l != stop; l = l.Next {
   2490 		a = outervalue(l.N.Left)
   2491 		if a.Op != ONAME {
   2492 			memwrite = 1
   2493 			continue
   2494 		}
   2495 
   2496 		switch n.Class {
   2497 		default:
   2498 			varwrite = 1
   2499 			continue
   2500 
   2501 		case PAUTO, PPARAM, PPARAMOUT:
   2502 			if n.Addrtaken {
   2503 				varwrite = 1
   2504 				continue
   2505 			}
   2506 
   2507 			if vmatch2(a, n) {
   2508 				// Direct hit.
   2509 				return true
   2510 			}
   2511 		}
   2512 	}
   2513 
   2514 	// The variables being written do not appear in n.
   2515 	// However, n might refer to computed addresses
   2516 	// that are being written.
   2517 
   2518 	// If no computed addresses are affected by the writes, no aliasing.
   2519 	if memwrite == 0 && varwrite == 0 {
   2520 		return false
   2521 	}
   2522 
   2523 	// If n does not refer to computed addresses
   2524 	// (that is, if n only refers to variables whose addresses
   2525 	// have not been taken), no aliasing.
   2526 	if varexpr(n) {
   2527 		return false
   2528 	}
   2529 
   2530 	// Otherwise, both the writes and n refer to computed memory addresses.
   2531 	// Assume that they might conflict.
   2532 	return true
   2533 }
   2534 
   2535 /*
   2536  * does the evaluation of n only refer to variables
   2537  * whose addresses have not been taken?
   2538  * (and no other memory)
   2539  */
   2540 func varexpr(n *Node) bool {
   2541 	if n == nil {
   2542 		return true
   2543 	}
   2544 
   2545 	switch n.Op {
   2546 	case OLITERAL:
   2547 		return true
   2548 
   2549 	case ONAME:
   2550 		switch n.Class {
   2551 		case PAUTO, PPARAM, PPARAMOUT:
   2552 			if !n.Addrtaken {
   2553 				return true
   2554 			}
   2555 		}
   2556 
   2557 		return false
   2558 
   2559 	case OADD,
   2560 		OSUB,
   2561 		OOR,
   2562 		OXOR,
   2563 		OMUL,
   2564 		ODIV,
   2565 		OMOD,
   2566 		OLSH,
   2567 		ORSH,
   2568 		OAND,
   2569 		OANDNOT,
   2570 		OPLUS,
   2571 		OMINUS,
   2572 		OCOM,
   2573 		OPAREN,
   2574 		OANDAND,
   2575 		OOROR,
   2576 		ODOT, // but not ODOTPTR
   2577 		OCONV,
   2578 		OCONVNOP,
   2579 		OCONVIFACE,
   2580 		ODOTTYPE:
   2581 		return varexpr(n.Left) && varexpr(n.Right)
   2582 	}
   2583 
   2584 	// Be conservative.
   2585 	return false
   2586 }
   2587 
   2588 /*
   2589  * is the name l mentioned in r?
   2590  */
   2591 func vmatch2(l *Node, r *Node) bool {
   2592 	if r == nil {
   2593 		return false
   2594 	}
   2595 	switch r.Op {
   2596 	// match each right given left
   2597 	case ONAME:
   2598 		return l == r
   2599 
   2600 	case OLITERAL:
   2601 		return false
   2602 	}
   2603 
   2604 	if vmatch2(l, r.Left) {
   2605 		return true
   2606 	}
   2607 	if vmatch2(l, r.Right) {
   2608 		return true
   2609 	}
   2610 	for ll := r.List; ll != nil; ll = ll.Next {
   2611 		if vmatch2(l, ll.N) {
   2612 			return true
   2613 		}
   2614 	}
   2615 	return false
   2616 }
   2617 
   2618 /*
   2619  * is any name mentioned in l also mentioned in r?
   2620  * called by sinit.go
   2621  */
   2622 func vmatch1(l *Node, r *Node) bool {
   2623 	/*
   2624 	 * isolate all left sides
   2625 	 */
   2626 	if l == nil || r == nil {
   2627 		return false
   2628 	}
   2629 	switch l.Op {
   2630 	case ONAME:
   2631 		switch l.Class {
   2632 		case PPARAM, PPARAMREF, PAUTO:
   2633 			break
   2634 
   2635 			// assignment to non-stack variable
   2636 		// must be delayed if right has function calls.
   2637 		default:
   2638 			if r.Ullman >= UINF {
   2639 				return true
   2640 			}
   2641 		}
   2642 
   2643 		return vmatch2(l, r)
   2644 
   2645 	case OLITERAL:
   2646 		return false
   2647 	}
   2648 
   2649 	if vmatch1(l.Left, r) {
   2650 		return true
   2651 	}
   2652 	if vmatch1(l.Right, r) {
   2653 		return true
   2654 	}
   2655 	for ll := l.List; ll != nil; ll = ll.Next {
   2656 		if vmatch1(ll.N, r) {
   2657 			return true
   2658 		}
   2659 	}
   2660 	return false
   2661 }
   2662 
   2663 /*
   2664  * walk through argin parameters.
   2665  * generate and return code to allocate
   2666  * copies of escaped parameters to the heap.
   2667  */
   2668 func paramstoheap(argin **Type, out int) *NodeList {
   2669 	var savet Iter
   2670 	var v *Node
   2671 	var as *Node
   2672 
   2673 	var nn *NodeList
   2674 	for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
   2675 		v = t.Nname
   2676 		if v != nil && v.Sym != nil && v.Sym.Name[0] == '~' && v.Sym.Name[1] == 'r' { // unnamed result
   2677 			v = nil
   2678 		}
   2679 
   2680 		// For precise stacks, the garbage collector assumes results
   2681 		// are always live, so zero them always.
   2682 		if out != 0 {
   2683 			// Defer might stop a panic and show the
   2684 			// return values as they exist at the time of panic.
   2685 			// Make sure to zero them on entry to the function.
   2686 			nn = list(nn, Nod(OAS, nodarg(t, 1), nil))
   2687 		}
   2688 
   2689 		if v == nil || v.Class&PHEAP == 0 {
   2690 			continue
   2691 		}
   2692 
   2693 		// generate allocation & copying code
   2694 		if compiling_runtime != 0 {
   2695 			Yyerror("%v escapes to heap, not allowed in runtime.", v)
   2696 		}
   2697 		if prealloc[v] == nil {
   2698 			prealloc[v] = callnew(v.Type)
   2699 		}
   2700 		nn = list(nn, Nod(OAS, v.Name.Heapaddr, prealloc[v]))
   2701 		if v.Class&^PHEAP != PPARAMOUT {
   2702 			as = Nod(OAS, v, v.Name.Param.Stackparam)
   2703 			v.Name.Param.Stackparam.Typecheck = 1
   2704 			typecheck(&as, Etop)
   2705 			as = applywritebarrier(as, &nn)
   2706 			nn = list(nn, as)
   2707 		}
   2708 	}
   2709 
   2710 	return nn
   2711 }
   2712 
   2713 /*
   2714  * walk through argout parameters copying back to stack
   2715  */
   2716 func returnsfromheap(argin **Type) *NodeList {
   2717 	var savet Iter
   2718 	var v *Node
   2719 
   2720 	var nn *NodeList
   2721 	for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
   2722 		v = t.Nname
   2723 		if v == nil || v.Class != PHEAP|PPARAMOUT {
   2724 			continue
   2725 		}
   2726 		nn = list(nn, Nod(OAS, v.Name.Param.Stackparam, v))
   2727 	}
   2728 
   2729 	return nn
   2730 }
   2731 
   2732 /*
   2733  * take care of migrating any function in/out args
   2734  * between the stack and the heap.  adds code to
   2735  * curfn's before and after lists.
   2736  */
   2737 func heapmoves() {
   2738 	lno := lineno
   2739 	lineno = Curfn.Lineno
   2740 	nn := paramstoheap(getthis(Curfn.Type), 0)
   2741 	nn = concat(nn, paramstoheap(getinarg(Curfn.Type), 0))
   2742 	nn = concat(nn, paramstoheap(Getoutarg(Curfn.Type), 1))
   2743 	Curfn.Func.Enter = concat(Curfn.Func.Enter, nn)
   2744 	lineno = Curfn.Func.Endlineno
   2745 	Curfn.Func.Exit = returnsfromheap(Getoutarg(Curfn.Type))
   2746 	lineno = lno
   2747 }
   2748 
   2749 func vmkcall(fn *Node, t *Type, init **NodeList, va []*Node) *Node {
   2750 	if fn.Type == nil || fn.Type.Etype != TFUNC {
   2751 		Fatal("mkcall %v %v", fn, fn.Type)
   2752 	}
   2753 
   2754 	var args *NodeList
   2755 	n := fn.Type.Intuple
   2756 	for i := 0; i < n; i++ {
   2757 		args = list(args, va[i])
   2758 	}
   2759 
   2760 	r := Nod(OCALL, fn, nil)
   2761 	r.List = args
   2762 	if fn.Type.Outtuple > 0 {
   2763 		typecheck(&r, Erv|Efnstruct)
   2764 	} else {
   2765 		typecheck(&r, Etop)
   2766 	}
   2767 	walkexpr(&r, init)
   2768 	r.Type = t
   2769 	return r
   2770 }
   2771 
   2772 func mkcall(name string, t *Type, init **NodeList, args ...*Node) *Node {
   2773 	return vmkcall(syslook(name, 0), t, init, args)
   2774 }
   2775 
   2776 func mkcall1(fn *Node, t *Type, init **NodeList, args ...*Node) *Node {
   2777 	return vmkcall(fn, t, init, args)
   2778 }
   2779 
   2780 func conv(n *Node, t *Type) *Node {
   2781 	if Eqtype(n.Type, t) {
   2782 		return n
   2783 	}
   2784 	n = Nod(OCONV, n, nil)
   2785 	n.Type = t
   2786 	typecheck(&n, Erv)
   2787 	return n
   2788 }
   2789 
   2790 func chanfn(name string, n int, t *Type) *Node {
   2791 	if t.Etype != TCHAN {
   2792 		Fatal("chanfn %v", t)
   2793 	}
   2794 	fn := syslook(name, 1)
   2795 	switch n {
   2796 	default:
   2797 		Fatal("chanfn %d", n)
   2798 	case 1:
   2799 		substArgTypes(fn, t.Type)
   2800 	case 2:
   2801 		substArgTypes(fn, t.Type, t.Type)
   2802 	}
   2803 	return fn
   2804 }
   2805 
   2806 func mapfn(name string, t *Type) *Node {
   2807 	if t.Etype != TMAP {
   2808 		Fatal("mapfn %v", t)
   2809 	}
   2810 	fn := syslook(name, 1)
   2811 	substArgTypes(fn, t.Down, t.Type, t.Down, t.Type)
   2812 	return fn
   2813 }
   2814 
   2815 func mapfndel(name string, t *Type) *Node {
   2816 	if t.Etype != TMAP {
   2817 		Fatal("mapfn %v", t)
   2818 	}
   2819 	fn := syslook(name, 1)
   2820 	substArgTypes(fn, t.Down, t.Type, t.Down)
   2821 	return fn
   2822 }
   2823 
   2824 func writebarrierfn(name string, l *Type, r *Type) *Node {
   2825 	fn := syslook(name, 1)
   2826 	substArgTypes(fn, l, r)
   2827 	return fn
   2828 }
   2829 
   2830 func addstr(n *Node, init **NodeList) *Node {
   2831 	// orderexpr rewrote OADDSTR to have a list of strings.
   2832 	c := count(n.List)
   2833 
   2834 	if c < 2 {
   2835 		Yyerror("addstr count %d too small", c)
   2836 	}
   2837 
   2838 	buf := nodnil()
   2839 	if n.Esc == EscNone {
   2840 		sz := int64(0)
   2841 		for l := n.List; l != nil; l = l.Next {
   2842 			if n.Op == OLITERAL {
   2843 				sz += int64(len(n.Val().U.(string)))
   2844 			}
   2845 		}
   2846 
   2847 		// Don't allocate the buffer if the result won't fit.
   2848 		if sz < tmpstringbufsize {
   2849 			// Create temporary buffer for result string on stack.
   2850 			t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
   2851 
   2852 			buf = Nod(OADDR, temp(t), nil)
   2853 		}
   2854 	}
   2855 
   2856 	// build list of string arguments
   2857 	args := list1(buf)
   2858 
   2859 	for l := n.List; l != nil; l = l.Next {
   2860 		args = list(args, conv(l.N, Types[TSTRING]))
   2861 	}
   2862 
   2863 	var fn string
   2864 	if c <= 5 {
   2865 		// small numbers of strings use direct runtime helpers.
   2866 		// note: orderexpr knows this cutoff too.
   2867 		fn = fmt.Sprintf("concatstring%d", c)
   2868 	} else {
   2869 		// large numbers of strings are passed to the runtime as a slice.
   2870 		fn = "concatstrings"
   2871 
   2872 		t := typ(TARRAY)
   2873 		t.Type = Types[TSTRING]
   2874 		t.Bound = -1
   2875 		slice := Nod(OCOMPLIT, nil, typenod(t))
   2876 		if prealloc[n] != nil {
   2877 			prealloc[slice] = prealloc[n]
   2878 		}
   2879 		slice.List = args.Next // skip buf arg
   2880 		args = list1(buf)
   2881 		args = list(args, slice)
   2882 		slice.Esc = EscNone
   2883 	}
   2884 
   2885 	cat := syslook(fn, 1)
   2886 	r := Nod(OCALL, cat, nil)
   2887 	r.List = args
   2888 	typecheck(&r, Erv)
   2889 	walkexpr(&r, init)
   2890 	r.Type = n.Type
   2891 
   2892 	return r
   2893 }
   2894 
   2895 // expand append(l1, l2...) to
   2896 //   init {
   2897 //     s := l1
   2898 //     if n := len(l1) + len(l2) - cap(s); n > 0 {
   2899 //       s = growslice_n(s, n)
   2900 //     }
   2901 //     s = s[:len(l1)+len(l2)]
   2902 //     memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
   2903 //   }
   2904 //   s
   2905 //
   2906 // l2 is allowed to be a string.
   2907 func appendslice(n *Node, init **NodeList) *Node {
   2908 	walkexprlistsafe(n.List, init)
   2909 
   2910 	// walkexprlistsafe will leave OINDEX (s[n]) alone if both s
   2911 	// and n are name or literal, but those may index the slice we're
   2912 	// modifying here.  Fix explicitly.
   2913 	for l := n.List; l != nil; l = l.Next {
   2914 		l.N = cheapexpr(l.N, init)
   2915 	}
   2916 
   2917 	l1 := n.List.N
   2918 	l2 := n.List.Next.N
   2919 
   2920 	s := temp(l1.Type) // var s []T
   2921 	var l *NodeList
   2922 	l = list(l, Nod(OAS, s, l1)) // s = l1
   2923 
   2924 	nt := temp(Types[TINT])
   2925 
   2926 	nif := Nod(OIF, nil, nil)
   2927 
   2928 	// n := len(s) + len(l2) - cap(s)
   2929 	nif.Ninit = list1(Nod(OAS, nt, Nod(OSUB, Nod(OADD, Nod(OLEN, s, nil), Nod(OLEN, l2, nil)), Nod(OCAP, s, nil))))
   2930 
   2931 	nif.Left = Nod(OGT, nt, Nodintconst(0))
   2932 
   2933 	// instantiate growslice_n(Type*, []any, int) []any
   2934 	fn := syslook("growslice_n", 1) //   growslice_n(<type>, old []T, n int64) (ret []T)
   2935 	substArgTypes(fn, s.Type.Type, s.Type.Type)
   2936 
   2937 	// s = growslice_n(T, s, n)
   2938 	nif.Nbody = list1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type), s, nt)))
   2939 
   2940 	l = list(l, nif)
   2941 
   2942 	if haspointers(l1.Type.Type) {
   2943 		// copy(s[len(l1):len(l1)+len(l2)], l2)
   2944 		nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), Nod(OADD, Nod(OLEN, l1, nil), Nod(OLEN, l2, nil))))
   2945 
   2946 		nptr1.Etype = 1
   2947 		nptr2 := l2
   2948 		fn := syslook("typedslicecopy", 1)
   2949 		substArgTypes(fn, l1.Type, l2.Type)
   2950 		nt := mkcall1(fn, Types[TINT], &l, typename(l1.Type.Type), nptr1, nptr2)
   2951 		l = list(l, nt)
   2952 	} else if flag_race != 0 {
   2953 		// rely on runtime to instrument copy.
   2954 		// copy(s[len(l1):len(l1)+len(l2)], l2)
   2955 		nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), Nod(OADD, Nod(OLEN, l1, nil), Nod(OLEN, l2, nil))))
   2956 
   2957 		nptr1.Etype = 1
   2958 		nptr2 := l2
   2959 		var fn *Node
   2960 		if l2.Type.Etype == TSTRING {
   2961 			fn = syslook("slicestringcopy", 1)
   2962 		} else {
   2963 			fn = syslook("slicecopy", 1)
   2964 		}
   2965 		substArgTypes(fn, l1.Type, l2.Type)
   2966 		nt := mkcall1(fn, Types[TINT], &l, nptr1, nptr2, Nodintconst(s.Type.Type.Width))
   2967 		l = list(l, nt)
   2968 	} else {
   2969 		// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
   2970 		nptr1 := Nod(OINDEX, s, Nod(OLEN, l1, nil))
   2971 
   2972 		nptr1.Bounded = true
   2973 		nptr1 = Nod(OADDR, nptr1, nil)
   2974 
   2975 		nptr2 := Nod(OSPTR, l2, nil)
   2976 
   2977 		fn := syslook("memmove", 1)
   2978 		substArgTypes(fn, s.Type.Type, s.Type.Type)
   2979 
   2980 		nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &l)
   2981 
   2982 		nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Type.Width))
   2983 		nt := mkcall1(fn, nil, &l, nptr1, nptr2, nwid)
   2984 		l = list(l, nt)
   2985 	}
   2986 
   2987 	// s = s[:len(l1)+len(l2)]
   2988 	nt = Nod(OADD, Nod(OLEN, l1, nil), Nod(OLEN, l2, nil))
   2989 
   2990 	nt = Nod(OSLICE, s, Nod(OKEY, nil, nt))
   2991 	nt.Etype = 1
   2992 	l = list(l, Nod(OAS, s, nt))
   2993 
   2994 	typechecklist(l, Etop)
   2995 	walkstmtlist(l)
   2996 	*init = concat(*init, l)
   2997 	return s
   2998 }
   2999 
   3000 // Rewrite append(src, x, y, z) so that any side effects in
   3001 // x, y, z (including runtime panics) are evaluated in
   3002 // initialization statements before the append.
   3003 // For normal code generation, stop there and leave the
   3004 // rest to cgen_append.
   3005 //
   3006 // For race detector, expand append(src, a [, b]* ) to
   3007 //
   3008 //   init {
   3009 //     s := src
   3010 //     const argc = len(args) - 1
   3011 //     if cap(s) - len(s) < argc {
   3012 //	    s = growslice(s, len(s)+argc)
   3013 //     }
   3014 //     n := len(s)
   3015 //     s = s[:n+argc]
   3016 //     s[n] = a
   3017 //     s[n+1] = b
   3018 //     ...
   3019 //   }
   3020 //   s
   3021 func walkappend(n *Node, init **NodeList, dst *Node) *Node {
   3022 	if !samesafeexpr(dst, n.List.N) {
   3023 		l := n.List
   3024 		l.N = safeexpr(l.N, init)
   3025 		walkexpr(&l.N, init)
   3026 	}
   3027 	walkexprlistsafe(n.List.Next, init)
   3028 
   3029 	// walkexprlistsafe will leave OINDEX (s[n]) alone if both s
   3030 	// and n are name or literal, but those may index the slice we're
   3031 	// modifying here.  Fix explicitly.
   3032 	// Using cheapexpr also makes sure that the evaluation
   3033 	// of all arguments (and especially any panics) happen
   3034 	// before we begin to modify the slice in a visible way.
   3035 	for l := n.List.Next; l != nil; l = l.Next {
   3036 		l.N = cheapexpr(l.N, init)
   3037 	}
   3038 
   3039 	nsrc := n.List.N
   3040 
   3041 	// Resolve slice type of multi-valued return.
   3042 	if Istype(nsrc.Type, TSTRUCT) {
   3043 		nsrc.Type = nsrc.Type.Type.Type
   3044 	}
   3045 	argc := count(n.List) - 1
   3046 	if argc < 1 {
   3047 		return nsrc
   3048 	}
   3049 
   3050 	// General case, with no function calls left as arguments.
   3051 	// Leave for gen, except that race detector requires old form
   3052 	if flag_race == 0 {
   3053 		return n
   3054 	}
   3055 
   3056 	var l *NodeList
   3057 
   3058 	ns := temp(nsrc.Type)
   3059 	l = list(l, Nod(OAS, ns, nsrc)) // s = src
   3060 
   3061 	na := Nodintconst(int64(argc)) // const argc
   3062 	nx := Nod(OIF, nil, nil)       // if cap(s) - len(s) < argc
   3063 	nx.Left = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na)
   3064 
   3065 	fn := syslook("growslice", 1) //   growslice(<type>, old []T, mincap int) (ret []T)
   3066 	substArgTypes(fn, ns.Type.Type, ns.Type.Type)
   3067 
   3068 	nx.Nbody = list1(Nod(OAS, ns, mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type), ns, Nod(OADD, Nod(OLEN, ns, nil), na))))
   3069 
   3070 	l = list(l, nx)
   3071 
   3072 	nn := temp(Types[TINT])
   3073 	l = list(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s)
   3074 
   3075 	nx = Nod(OSLICE, ns, Nod(OKEY, nil, Nod(OADD, nn, na))) // ...s[:n+argc]
   3076 	nx.Etype = 1
   3077 	l = list(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
   3078 
   3079 	for a := n.List.Next; a != nil; a = a.Next {
   3080 		nx = Nod(OINDEX, ns, nn) // s[n] ...
   3081 		nx.Bounded = true
   3082 		l = list(l, Nod(OAS, nx, a.N)) // s[n] = arg
   3083 		if a.Next != nil {
   3084 			l = list(l, Nod(OAS, nn, Nod(OADD, nn, Nodintconst(1)))) // n = n + 1
   3085 		}
   3086 	}
   3087 
   3088 	typechecklist(l, Etop)
   3089 	walkstmtlist(l)
   3090 	*init = concat(*init, l)
   3091 	return ns
   3092 }
   3093 
   3094 // Lower copy(a, b) to a memmove call or a runtime call.
   3095 //
   3096 // init {
   3097 //   n := len(a)
   3098 //   if n > len(b) { n = len(b) }
   3099 //   memmove(a.ptr, b.ptr, n*sizeof(elem(a)))
   3100 // }
   3101 // n;
   3102 //
   3103 // Also works if b is a string.
   3104 //
   3105 func copyany(n *Node, init **NodeList, runtimecall int) *Node {
   3106 	if haspointers(n.Left.Type.Type) {
   3107 		fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type)
   3108 		return mkcall1(fn, n.Type, init, typename(n.Left.Type.Type), n.Left, n.Right)
   3109 	}
   3110 
   3111 	if runtimecall != 0 {
   3112 		var fn *Node
   3113 		if n.Right.Type.Etype == TSTRING {
   3114 			fn = syslook("slicestringcopy", 1)
   3115 		} else {
   3116 			fn = syslook("slicecopy", 1)
   3117 		}
   3118 		substArgTypes(fn, n.Left.Type, n.Right.Type)
   3119 		return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Type.Width))
   3120 	}
   3121 
   3122 	walkexpr(&n.Left, init)
   3123 	walkexpr(&n.Right, init)
   3124 	nl := temp(n.Left.Type)
   3125 	nr := temp(n.Right.Type)
   3126 	var l *NodeList
   3127 	l = list(l, Nod(OAS, nl, n.Left))
   3128 	l = list(l, Nod(OAS, nr, n.Right))
   3129 
   3130 	nfrm := Nod(OSPTR, nr, nil)
   3131 	nto := Nod(OSPTR, nl, nil)
   3132 
   3133 	nlen := temp(Types[TINT])
   3134 
   3135 	// n = len(to)
   3136 	l = list(l, Nod(OAS, nlen, Nod(OLEN, nl, nil)))
   3137 
   3138 	// if n > len(frm) { n = len(frm) }
   3139 	nif := Nod(OIF, nil, nil)
   3140 
   3141 	nif.Left = Nod(OGT, nlen, Nod(OLEN, nr, nil))
   3142 	nif.Nbody = list(nif.Nbody, Nod(OAS, nlen, Nod(OLEN, nr, nil)))
   3143 	l = list(l, nif)
   3144 
   3145 	// Call memmove.
   3146 	fn := syslook("memmove", 1)
   3147 
   3148 	substArgTypes(fn, nl.Type.Type, nl.Type.Type)
   3149 	nwid := temp(Types[TUINTPTR])
   3150 	l = list(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
   3151 	nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Type.Width))
   3152 	l = list(l, mkcall1(fn, nil, init, nto, nfrm, nwid))
   3153 
   3154 	typechecklist(l, Etop)
   3155 	walkstmtlist(l)
   3156 	*init = concat(*init, l)
   3157 	return nlen
   3158 }
   3159 
   3160 func eqfor(t *Type, needsize *int) *Node {
   3161 	// Should only arrive here with large memory or
   3162 	// a struct/array containing a non-memory field/element.
   3163 	// Small memory is handled inline, and single non-memory
   3164 	// is handled during type check (OCMPSTR etc).
   3165 	a := algtype1(t, nil)
   3166 
   3167 	if a != AMEM && a != -1 {
   3168 		Fatal("eqfor %v", t)
   3169 	}
   3170 
   3171 	if a == AMEM {
   3172 		n := syslook("memequal", 1)
   3173 		substArgTypes(n, t, t)
   3174 		*needsize = 1
   3175 		return n
   3176 	}
   3177 
   3178 	sym := typesymprefix(".eq", t)
   3179 	n := newname(sym)
   3180 	n.Class = PFUNC
   3181 	ntype := Nod(OTFUNC, nil, nil)
   3182 	ntype.List = list(ntype.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
   3183 	ntype.List = list(ntype.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
   3184 	ntype.Rlist = list(ntype.Rlist, Nod(ODCLFIELD, nil, typenod(Types[TBOOL])))
   3185 	typecheck(&ntype, Etype)
   3186 	n.Type = ntype.Type
   3187 	*needsize = 0
   3188 	return n
   3189 }
   3190 
   3191 func countfield(t *Type) int {
   3192 	n := 0
   3193 	for t1 := t.Type; t1 != nil; t1 = t1.Down {
   3194 		n++
   3195 	}
   3196 	return n
   3197 }
   3198 
   3199 func walkcompare(np **Node, init **NodeList) {
   3200 	n := *np
   3201 
   3202 	// Given interface value l and concrete value r, rewrite
   3203 	//   l == r
   3204 	// to
   3205 	//   x, ok := l.(type(r)); ok && x == r
   3206 	// Handle != similarly.
   3207 	// This avoids the allocation that would be required
   3208 	// to convert r to l for comparison.
   3209 	var l *Node
   3210 
   3211 	var r *Node
   3212 	if Isinter(n.Left.Type) && !Isinter(n.Right.Type) {
   3213 		l = n.Left
   3214 		r = n.Right
   3215 	} else if !Isinter(n.Left.Type) && Isinter(n.Right.Type) {
   3216 		l = n.Right
   3217 		r = n.Left
   3218 	}
   3219 
   3220 	if l != nil {
   3221 		x := temp(r.Type)
   3222 		if haspointers(r.Type) {
   3223 			a := Nod(OAS, x, nil)
   3224 			typecheck(&a, Etop)
   3225 			*init = list(*init, a)
   3226 		}
   3227 		ok := temp(Types[TBOOL])
   3228 
   3229 		// l.(type(r))
   3230 		a := Nod(ODOTTYPE, l, nil)
   3231 
   3232 		a.Type = r.Type
   3233 
   3234 		// x, ok := l.(type(r))
   3235 		expr := Nod(OAS2, nil, nil)
   3236 
   3237 		expr.List = list1(x)
   3238 		expr.List = list(expr.List, ok)
   3239 		expr.Rlist = list1(a)
   3240 		typecheck(&expr, Etop)
   3241 		walkexpr(&expr, init)
   3242 
   3243 		if n.Op == OEQ {
   3244 			r = Nod(OANDAND, ok, Nod(OEQ, x, r))
   3245 		} else {
   3246 			r = Nod(OOROR, Nod(ONOT, ok, nil), Nod(ONE, x, r))
   3247 		}
   3248 		*init = list(*init, expr)
   3249 		finishcompare(np, n, r, init)
   3250 		return
   3251 	}
   3252 
   3253 	// Must be comparison of array or struct.
   3254 	// Otherwise back end handles it.
   3255 	t := n.Left.Type
   3256 
   3257 	switch t.Etype {
   3258 	default:
   3259 		return
   3260 
   3261 	case TARRAY:
   3262 		if Isslice(t) {
   3263 			return
   3264 		}
   3265 
   3266 	case TSTRUCT:
   3267 		break
   3268 	}
   3269 
   3270 	cmpl := n.Left
   3271 	for cmpl != nil && cmpl.Op == OCONVNOP {
   3272 		cmpl = cmpl.Left
   3273 	}
   3274 	cmpr := n.Right
   3275 	for cmpr != nil && cmpr.Op == OCONVNOP {
   3276 		cmpr = cmpr.Left
   3277 	}
   3278 
   3279 	if !islvalue(cmpl) || !islvalue(cmpr) {
   3280 		Fatal("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
   3281 	}
   3282 
   3283 	l = temp(Ptrto(t))
   3284 	a := Nod(OAS, l, Nod(OADDR, cmpl, nil))
   3285 	a.Right.Etype = 1 // addr does not escape
   3286 	typecheck(&a, Etop)
   3287 	*init = list(*init, a)
   3288 
   3289 	r = temp(Ptrto(t))
   3290 	a = Nod(OAS, r, Nod(OADDR, cmpr, nil))
   3291 	a.Right.Etype = 1 // addr does not escape
   3292 	typecheck(&a, Etop)
   3293 	*init = list(*init, a)
   3294 
   3295 	andor := OANDAND
   3296 	if n.Op == ONE {
   3297 		andor = OOROR
   3298 	}
   3299 
   3300 	var expr *Node
   3301 	if t.Etype == TARRAY && t.Bound <= 4 && issimple[t.Type.Etype] {
   3302 		// Four or fewer elements of a basic type.
   3303 		// Unroll comparisons.
   3304 		var li *Node
   3305 		var ri *Node
   3306 		for i := 0; int64(i) < t.Bound; i++ {
   3307 			li = Nod(OINDEX, l, Nodintconst(int64(i)))
   3308 			ri = Nod(OINDEX, r, Nodintconst(int64(i)))
   3309 			a = Nod(int(n.Op), li, ri)
   3310 			if expr == nil {
   3311 				expr = a
   3312 			} else {
   3313 				expr = Nod(andor, expr, a)
   3314 			}
   3315 		}
   3316 
   3317 		if expr == nil {
   3318 			expr = Nodbool(n.Op == OEQ)
   3319 		}
   3320 		finishcompare(np, n, expr, init)
   3321 		return
   3322 	}
   3323 
   3324 	if t.Etype == TSTRUCT && countfield(t) <= 4 {
   3325 		// Struct of four or fewer fields.
   3326 		// Inline comparisons.
   3327 		var li *Node
   3328 		var ri *Node
   3329 		for t1 := t.Type; t1 != nil; t1 = t1.Down {
   3330 			if isblanksym(t1.Sym) {
   3331 				continue
   3332 			}
   3333 			li = Nod(OXDOT, l, newname(t1.Sym))
   3334 			ri = Nod(OXDOT, r, newname(t1.Sym))
   3335 			a = Nod(int(n.Op), li, ri)
   3336 			if expr == nil {
   3337 				expr = a
   3338 			} else {
   3339 				expr = Nod(andor, expr, a)
   3340 			}
   3341 		}
   3342 
   3343 		if expr == nil {
   3344 			expr = Nodbool(n.Op == OEQ)
   3345 		}
   3346 		finishcompare(np, n, expr, init)
   3347 		return
   3348 	}
   3349 
   3350 	// Chose not to inline.  Call equality function directly.
   3351 	var needsize int
   3352 	call := Nod(OCALL, eqfor(t, &needsize), nil)
   3353 
   3354 	call.List = list(call.List, l)
   3355 	call.List = list(call.List, r)
   3356 	if needsize != 0 {
   3357 		call.List = list(call.List, Nodintconst(t.Width))
   3358 	}
   3359 	r = call
   3360 	if n.Op != OEQ {
   3361 		r = Nod(ONOT, r, nil)
   3362 	}
   3363 
   3364 	finishcompare(np, n, r, init)
   3365 	return
   3366 }
   3367 
   3368 func finishcompare(np **Node, n, r *Node, init **NodeList) {
   3369 	// Using np here to avoid passing &r to typecheck.
   3370 	*np = r
   3371 	typecheck(np, Erv)
   3372 	walkexpr(np, init)
   3373 	r = *np
   3374 	if r.Type != n.Type {
   3375 		r = Nod(OCONVNOP, r, nil)
   3376 		r.Type = n.Type
   3377 		r.Typecheck = 1
   3378 		*np = r
   3379 	}
   3380 }
   3381 
   3382 func samecheap(a *Node, b *Node) bool {
   3383 	var ar *Node
   3384 	var br *Node
   3385 	for a != nil && b != nil && a.Op == b.Op {
   3386 		switch a.Op {
   3387 		default:
   3388 			return false
   3389 
   3390 		case ONAME:
   3391 			return a == b
   3392 
   3393 		case ODOT, ODOTPTR:
   3394 			ar = a.Right
   3395 			br = b.Right
   3396 			if ar.Op != ONAME || br.Op != ONAME || ar.Sym != br.Sym {
   3397 				return false
   3398 			}
   3399 
   3400 		case OINDEX:
   3401 			ar = a.Right
   3402 			br = b.Right
   3403 			if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || Mpcmpfixfix(ar.Val().U.(*Mpint), br.Val().U.(*Mpint)) != 0 {
   3404 				return false
   3405 			}
   3406 		}
   3407 
   3408 		a = a.Left
   3409 		b = b.Left
   3410 	}
   3411 
   3412 	return false
   3413 }
   3414 
   3415 func walkrotate(np **Node) {
   3416 	if Thearch.Thechar == '7' || Thearch.Thechar == '9' {
   3417 		return
   3418 	}
   3419 
   3420 	n := *np
   3421 
   3422 	// Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value.
   3423 	l := n.Left
   3424 
   3425 	r := n.Right
   3426 	if (n.Op != OOR && n.Op != OXOR) || (l.Op != OLSH && l.Op != ORSH) || (r.Op != OLSH && r.Op != ORSH) || n.Type == nil || Issigned[n.Type.Etype] || l.Op == r.Op {
   3427 		return
   3428 	}
   3429 
   3430 	// Want same, side effect-free expression on lhs of both shifts.
   3431 	if !samecheap(l.Left, r.Left) {
   3432 		return
   3433 	}
   3434 
   3435 	// Constants adding to width?
   3436 	w := int(l.Type.Width * 8)
   3437 
   3438 	if Smallintconst(l.Right) && Smallintconst(r.Right) {
   3439 		sl := int(Mpgetfix(l.Right.Val().U.(*Mpint)))
   3440 		if sl >= 0 {
   3441 			sr := int(Mpgetfix(r.Right.Val().U.(*Mpint)))
   3442 			if sr >= 0 && sl+sr == w {
   3443 				// Rewrite left shift half to left rotate.
   3444 				if l.Op == OLSH {
   3445 					n = l
   3446 				} else {
   3447 					n = r
   3448 				}
   3449 				n.Op = OLROT
   3450 
   3451 				// Remove rotate 0 and rotate w.
   3452 				s := int(Mpgetfix(n.Right.Val().U.(*Mpint)))
   3453 
   3454 				if s == 0 || s == w {
   3455 					n = n.Left
   3456 				}
   3457 
   3458 				*np = n
   3459 				return
   3460 			}
   3461 		}
   3462 		return
   3463 	}
   3464 
   3465 	// TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31).
   3466 	return
   3467 }
   3468 
   3469 /*
   3470  * walkmul rewrites integer multiplication by powers of two as shifts.
   3471  */
   3472 func walkmul(np **Node, init **NodeList) {
   3473 	n := *np
   3474 	if !Isint[n.Type.Etype] {
   3475 		return
   3476 	}
   3477 
   3478 	var nr *Node
   3479 	var nl *Node
   3480 	if n.Right.Op == OLITERAL {
   3481 		nl = n.Left
   3482 		nr = n.Right
   3483 	} else if n.Left.Op == OLITERAL {
   3484 		nl = n.Right
   3485 		nr = n.Left
   3486 	} else {
   3487 		return
   3488 	}
   3489 
   3490 	neg := 0
   3491 
   3492 	// x*0 is 0 (and side effects of x).
   3493 	var pow int
   3494 	var w int
   3495 	if Mpgetfix(nr.Val().U.(*Mpint)) == 0 {
   3496 		cheapexpr(nl, init)
   3497 		Nodconst(n, n.Type, 0)
   3498 		goto ret
   3499 	}
   3500 
   3501 	// nr is a constant.
   3502 	pow = powtwo(nr)
   3503 
   3504 	if pow < 0 {
   3505 		return
   3506 	}
   3507 	if pow >= 1000 {
   3508 		// negative power of 2, like -16
   3509 		neg = 1
   3510 
   3511 		pow -= 1000
   3512 	}
   3513 
   3514 	w = int(nl.Type.Width * 8)
   3515 	if pow+1 >= w { // too big, shouldn't happen
   3516 		return
   3517 	}
   3518 
   3519 	nl = cheapexpr(nl, init)
   3520 
   3521 	if pow == 0 {
   3522 		// x*1 is x
   3523 		n = nl
   3524 
   3525 		goto ret
   3526 	}
   3527 
   3528 	n = Nod(OLSH, nl, Nodintconst(int64(pow)))
   3529 
   3530 ret:
   3531 	if neg != 0 {
   3532 		n = Nod(OMINUS, n, nil)
   3533 	}
   3534 
   3535 	typecheck(&n, Erv)
   3536 	walkexpr(&n, init)
   3537 	*np = n
   3538 }
   3539 
   3540 /*
   3541  * walkdiv rewrites division by a constant as less expensive
   3542  * operations.
   3543  */
   3544 func walkdiv(np **Node, init **NodeList) {
   3545 	// if >= 0, nr is 1<<pow // 1 if nr is negative.
   3546 
   3547 	// TODO(minux)
   3548 	if Thearch.Thechar == '7' || Thearch.Thechar == '9' {
   3549 		return
   3550 	}
   3551 
   3552 	n := *np
   3553 	if n.Right.Op != OLITERAL {
   3554 		return
   3555 	}
   3556 
   3557 	// nr is a constant.
   3558 	nl := cheapexpr(n.Left, init)
   3559 
   3560 	nr := n.Right
   3561 
   3562 	// special cases of mod/div
   3563 	// by a constant
   3564 	w := int(nl.Type.Width * 8)
   3565 
   3566 	s := 0            // 1 if nr is negative.
   3567 	pow := powtwo(nr) // if >= 0, nr is 1<<pow
   3568 	if pow >= 1000 {
   3569 		// negative power of 2
   3570 		s = 1
   3571 
   3572 		pow -= 1000
   3573 	}
   3574 
   3575 	if pow+1 >= w {
   3576 		// divisor too large.
   3577 		return
   3578 	}
   3579 
   3580 	if pow < 0 {
   3581 		// try to do division by multiply by (2^w)/d
   3582 		// see hacker's delight chapter 10
   3583 		// TODO: support 64-bit magic multiply here.
   3584 		var m Magic
   3585 		m.W = w
   3586 
   3587 		if Issigned[nl.Type.Etype] {
   3588 			m.Sd = Mpgetfix(nr.Val().U.(*Mpint))
   3589 			Smagic(&m)
   3590 		} else {
   3591 			m.Ud = uint64(Mpgetfix(nr.Val().U.(*Mpint)))
   3592 			Umagic(&m)
   3593 		}
   3594 
   3595 		if m.Bad != 0 {
   3596 			return
   3597 		}
   3598 
   3599 		// We have a quick division method so use it
   3600 		// for modulo too.
   3601 		if n.Op == OMOD {
   3602 			// rewrite as A%B = A - (A/B*B).
   3603 			n1 := Nod(ODIV, nl, nr)
   3604 
   3605 			n2 := Nod(OMUL, n1, nr)
   3606 			n = Nod(OSUB, nl, n2)
   3607 			goto ret
   3608 		}
   3609 
   3610 		switch Simtype[nl.Type.Etype] {
   3611 		default:
   3612 			return
   3613 
   3614 			// n1 = nl * magic >> w (HMUL)
   3615 		case TUINT8, TUINT16, TUINT32:
   3616 			nc := Nod(OXXX, nil, nil)
   3617 
   3618 			Nodconst(nc, nl.Type, int64(m.Um))
   3619 			n1 := Nod(OHMUL, nl, nc)
   3620 			typecheck(&n1, Erv)
   3621 			if m.Ua != 0 {
   3622 				// Select a Go type with (at least) twice the width.
   3623 				var twide *Type
   3624 				switch Simtype[nl.Type.Etype] {
   3625 				default:
   3626 					return
   3627 
   3628 				case TUINT8, TUINT16:
   3629 					twide = Types[TUINT32]
   3630 
   3631 				case TUINT32:
   3632 					twide = Types[TUINT64]
   3633 
   3634 				case TINT8, TINT16:
   3635 					twide = Types[TINT32]
   3636 
   3637 				case TINT32:
   3638 					twide = Types[TINT64]
   3639 				}
   3640 
   3641 				// add numerator (might overflow).
   3642 				// n2 = (n1 + nl)
   3643 				n2 := Nod(OADD, conv(n1, twide), conv(nl, twide))
   3644 
   3645 				// shift by m.s
   3646 				nc := Nod(OXXX, nil, nil)
   3647 
   3648 				Nodconst(nc, Types[TUINT], int64(m.S))
   3649 				n = conv(Nod(ORSH, n2, nc), nl.Type)
   3650 			} else {
   3651 				// n = n1 >> m.s
   3652 				nc := Nod(OXXX, nil, nil)
   3653 
   3654 				Nodconst(nc, Types[TUINT], int64(m.S))
   3655 				n = Nod(ORSH, n1, nc)
   3656 			}
   3657 
   3658 			// n1 = nl * magic >> w
   3659 		case TINT8, TINT16, TINT32:
   3660 			nc := Nod(OXXX, nil, nil)
   3661 
   3662 			Nodconst(nc, nl.Type, m.Sm)
   3663 			n1 := Nod(OHMUL, nl, nc)
   3664 			typecheck(&n1, Erv)
   3665 			if m.Sm < 0 {
   3666 				// add the numerator.
   3667 				n1 = Nod(OADD, n1, nl)
   3668 			}
   3669 
   3670 			// shift by m.s
   3671 			nc = Nod(OXXX, nil, nil)
   3672 
   3673 			Nodconst(nc, Types[TUINT], int64(m.S))
   3674 			n2 := conv(Nod(ORSH, n1, nc), nl.Type)
   3675 
   3676 			// add 1 iff n1 is negative.
   3677 			nc = Nod(OXXX, nil, nil)
   3678 
   3679 			Nodconst(nc, Types[TUINT], int64(w)-1)
   3680 			n3 := Nod(ORSH, nl, nc) // n4 = -1 iff n1 is negative.
   3681 			n = Nod(OSUB, n2, n3)
   3682 
   3683 			// apply sign.
   3684 			if m.Sd < 0 {
   3685 				n = Nod(OMINUS, n, nil)
   3686 			}
   3687 		}
   3688 
   3689 		goto ret
   3690 	}
   3691 
   3692 	switch pow {
   3693 	case 0:
   3694 		if n.Op == OMOD {
   3695 			// nl % 1 is zero.
   3696 			Nodconst(n, n.Type, 0)
   3697 		} else if s != 0 {
   3698 			// divide by -1
   3699 			n.Op = OMINUS
   3700 
   3701 			n.Right = nil
   3702 		} else {
   3703 			// divide by 1
   3704 			n = nl
   3705 		}
   3706 
   3707 	default:
   3708 		if Issigned[n.Type.Etype] {
   3709 			if n.Op == OMOD {
   3710 				// signed modulo 2^pow is like ANDing
   3711 				// with the last pow bits, but if nl < 0,
   3712 				// nl & (2^pow-1) is (nl+1)%2^pow - 1.
   3713 				nc := Nod(OXXX, nil, nil)
   3714 
   3715 				Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
   3716 				n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
   3717 				if pow == 1 {
   3718 					typecheck(&n1, Erv)
   3719 					n1 = cheapexpr(n1, init)
   3720 
   3721 					// n = (nl+)&1 - where =1 iff nl<0.
   3722 					n2 := Nod(OSUB, nl, n1)
   3723 
   3724 					nc := Nod(OXXX, nil, nil)
   3725 					Nodconst(nc, nl.Type, 1)
   3726 					n3 := Nod(OAND, n2, nc)
   3727 					n = Nod(OADD, n3, n1)
   3728 				} else {
   3729 					// n = (nl+)&(nr-1) -  where =2^pow-1 iff nl<0.
   3730 					nc := Nod(OXXX, nil, nil)
   3731 
   3732 					Nodconst(nc, nl.Type, (1<<uint(pow))-1)
   3733 					n2 := Nod(OAND, n1, nc) // n2 = 2^pow-1 iff nl<0.
   3734 					typecheck(&n2, Erv)
   3735 					n2 = cheapexpr(n2, init)
   3736 
   3737 					n3 := Nod(OADD, nl, n2)
   3738 					n4 := Nod(OAND, n3, nc)
   3739 					n = Nod(OSUB, n4, n2)
   3740 				}
   3741 
   3742 				break
   3743 			} else {
   3744 				// arithmetic right shift does not give the correct rounding.
   3745 				// if nl >= 0, nl >> n == nl / nr
   3746 				// if nl < 0, we want to add 2^n-1 first.
   3747 				nc := Nod(OXXX, nil, nil)
   3748 
   3749 				Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
   3750 				n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
   3751 				if pow == 1 {
   3752 					// nl+1 is nl-(-1)
   3753 					n.Left = Nod(OSUB, nl, n1)
   3754 				} else {
   3755 					// Do a logical right right on -1 to keep pow bits.
   3756 					nc := Nod(OXXX, nil, nil)
   3757 
   3758 					Nodconst(nc, Types[Simtype[TUINT]], int64(w)-int64(pow))
   3759 					n2 := Nod(ORSH, conv(n1, tounsigned(nl.Type)), nc)
   3760 					n.Left = Nod(OADD, nl, conv(n2, nl.Type))
   3761 				}
   3762 
   3763 				// n = (nl + 2^pow-1) >> pow
   3764 				n.Op = ORSH
   3765 
   3766 				nc = Nod(OXXX, nil, nil)
   3767 				Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
   3768 				n.Right = nc
   3769 				n.Typecheck = 0
   3770 			}
   3771 
   3772 			if s != 0 {
   3773 				n = Nod(OMINUS, n, nil)
   3774 			}
   3775 			break
   3776 		}
   3777 
   3778 		nc := Nod(OXXX, nil, nil)
   3779 		if n.Op == OMOD {
   3780 			// n = nl & (nr-1)
   3781 			n.Op = OAND
   3782 
   3783 			Nodconst(nc, nl.Type, Mpgetfix(nr.Val().U.(*Mpint))-1)
   3784 		} else {
   3785 			// n = nl >> pow
   3786 			n.Op = ORSH
   3787 
   3788 			Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
   3789 		}
   3790 
   3791 		n.Typecheck = 0
   3792 		n.Right = nc
   3793 	}
   3794 
   3795 	goto ret
   3796 
   3797 ret:
   3798 	typecheck(&n, Erv)
   3799 	walkexpr(&n, init)
   3800 	*np = n
   3801 }
   3802 
   3803 // return 1 if integer n must be in range [0, max), 0 otherwise
   3804 func bounded(n *Node, max int64) bool {
   3805 	if n.Type == nil || !Isint[n.Type.Etype] {
   3806 		return false
   3807 	}
   3808 
   3809 	sign := Issigned[n.Type.Etype]
   3810 	bits := int32(8 * n.Type.Width)
   3811 
   3812 	if Smallintconst(n) {
   3813 		v := Mpgetfix(n.Val().U.(*Mpint))
   3814 		return 0 <= v && v < max
   3815 	}
   3816 
   3817 	switch n.Op {
   3818 	case OAND:
   3819 		v := int64(-1)
   3820 		if Smallintconst(n.Left) {
   3821 			v = Mpgetfix(n.Left.Val().U.(*Mpint))
   3822 		} else if Smallintconst(n.Right) {
   3823 			v = Mpgetfix(n.Right.Val().U.(*Mpint))
   3824 		}
   3825 
   3826 		if 0 <= v && v < max {
   3827 			return true
   3828 		}
   3829 
   3830 	case OMOD:
   3831 		if !sign && Smallintconst(n.Right) {
   3832 			v := Mpgetfix(n.Right.Val().U.(*Mpint))
   3833 			if 0 <= v && v <= max {
   3834 				return true
   3835 			}
   3836 		}
   3837 
   3838 	case ODIV:
   3839 		if !sign && Smallintconst(n.Right) {
   3840 			v := Mpgetfix(n.Right.Val().U.(*Mpint))
   3841 			for bits > 0 && v >= 2 {
   3842 				bits--
   3843 				v >>= 1
   3844 			}
   3845 		}
   3846 
   3847 	case ORSH:
   3848 		if !sign && Smallintconst(n.Right) {
   3849 			v := Mpgetfix(n.Right.Val().U.(*Mpint))
   3850 			if v > int64(bits) {
   3851 				return true
   3852 			}
   3853 			bits -= int32(v)
   3854 		}
   3855 	}
   3856 
   3857 	if !sign && bits <= 62 && 1<<uint(bits) <= max {
   3858 		return true
   3859 	}
   3860 
   3861 	return false
   3862 }
   3863 
   3864 func usefield(n *Node) {
   3865 	if obj.Fieldtrack_enabled == 0 {
   3866 		return
   3867 	}
   3868 
   3869 	switch n.Op {
   3870 	default:
   3871 		Fatal("usefield %v", Oconv(int(n.Op), 0))
   3872 
   3873 	case ODOT, ODOTPTR:
   3874 		break
   3875 	}
   3876 
   3877 	t := n.Left.Type
   3878 	if Isptr[t.Etype] {
   3879 		t = t.Type
   3880 	}
   3881 	field := dotField[typeSym{t.Orig, n.Right.Sym}]
   3882 	if field == nil {
   3883 		Fatal("usefield %v %v without paramfld", n.Left.Type, n.Right.Sym)
   3884 	}
   3885 	if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") {
   3886 		return
   3887 	}
   3888 
   3889 	// dedup on list
   3890 	if field.Lastfn == Curfn {
   3891 		return
   3892 	}
   3893 	field.Lastfn = Curfn
   3894 	field.Outer = n.Left.Type
   3895 	if Isptr[field.Outer.Etype] {
   3896 		field.Outer = field.Outer.Type
   3897 	}
   3898 	if field.Outer.Sym == nil {
   3899 		Yyerror("tracked field must be in named struct type")
   3900 	}
   3901 	if !exportname(field.Sym.Name) {
   3902 		Yyerror("tracked field must be exported (upper case)")
   3903 	}
   3904 
   3905 	Curfn.Func.Fieldtrack = append(Curfn.Func.Fieldtrack, field)
   3906 }
   3907 
   3908 func candiscardlist(l *NodeList) bool {
   3909 	for ; l != nil; l = l.Next {
   3910 		if !candiscard(l.N) {
   3911 			return false
   3912 		}
   3913 	}
   3914 	return true
   3915 }
   3916 
   3917 func candiscard(n *Node) bool {
   3918 	if n == nil {
   3919 		return true
   3920 	}
   3921 
   3922 	switch n.Op {
   3923 	default:
   3924 		return false
   3925 
   3926 		// Discardable as long as the subpieces are.
   3927 	case ONAME,
   3928 		ONONAME,
   3929 		OTYPE,
   3930 		OPACK,
   3931 		OLITERAL,
   3932 		OADD,
   3933 		OSUB,
   3934 		OOR,
   3935 		OXOR,
   3936 		OADDSTR,
   3937 		OADDR,
   3938 		OANDAND,
   3939 		OARRAYBYTESTR,
   3940 		OARRAYRUNESTR,
   3941 		OSTRARRAYBYTE,
   3942 		OSTRARRAYRUNE,
   3943 		OCAP,
   3944 		OCMPIFACE,
   3945 		OCMPSTR,
   3946 		OCOMPLIT,
   3947 		OMAPLIT,
   3948 		OSTRUCTLIT,
   3949 		OARRAYLIT,
   3950 		OPTRLIT,
   3951 		OCONV,
   3952 		OCONVIFACE,
   3953 		OCONVNOP,
   3954 		ODOT,
   3955 		OEQ,
   3956 		ONE,
   3957 		OLT,
   3958 		OLE,
   3959 		OGT,
   3960 		OGE,
   3961 		OKEY,
   3962 		OLEN,
   3963 		OMUL,
   3964 		OLSH,
   3965 		ORSH,
   3966 		OAND,
   3967 		OANDNOT,
   3968 		ONEW,
   3969 		ONOT,
   3970 		OCOM,
   3971 		OPLUS,
   3972 		OMINUS,
   3973 		OOROR,
   3974 		OPAREN,
   3975 		ORUNESTR,
   3976 		OREAL,
   3977 		OIMAG,
   3978 		OCOMPLEX:
   3979 		break
   3980 
   3981 		// Discardable as long as we know it's not division by zero.
   3982 	case ODIV, OMOD:
   3983 		if Isconst(n.Right, CTINT) && mpcmpfixc(n.Right.Val().U.(*Mpint), 0) != 0 {
   3984 			break
   3985 		}
   3986 		if Isconst(n.Right, CTFLT) && mpcmpfltc(n.Right.Val().U.(*Mpflt), 0) != 0 {
   3987 			break
   3988 		}
   3989 		return false
   3990 
   3991 		// Discardable as long as we know it won't fail because of a bad size.
   3992 	case OMAKECHAN, OMAKEMAP:
   3993 		if Isconst(n.Left, CTINT) && mpcmpfixc(n.Left.Val().U.(*Mpint), 0) == 0 {
   3994 			break
   3995 		}
   3996 		return false
   3997 
   3998 		// Difficult to tell what sizes are okay.
   3999 	case OMAKESLICE:
   4000 		return false
   4001 	}
   4002 
   4003 	if !candiscard(n.Left) || !candiscard(n.Right) || !candiscardlist(n.Ninit) || !candiscardlist(n.Nbody) || !candiscardlist(n.List) || !candiscardlist(n.Rlist) {
   4004 		return false
   4005 	}
   4006 
   4007 	return true
   4008 }
   4009 
   4010 // rewrite
   4011 //	print(x, y, z)
   4012 // into
   4013 //	func(a1, a2, a3) {
   4014 //		print(a1, a2, a3)
   4015 //	}(x, y, z)
   4016 // and same for println.
   4017 
   4018 var walkprintfunc_prgen int
   4019 
   4020 func walkprintfunc(np **Node, init **NodeList) {
   4021 	n := *np
   4022 
   4023 	if n.Ninit != nil {
   4024 		walkstmtlist(n.Ninit)
   4025 		*init = concat(*init, n.Ninit)
   4026 		n.Ninit = nil
   4027 	}
   4028 
   4029 	t := Nod(OTFUNC, nil, nil)
   4030 	num := 0
   4031 	var printargs *NodeList
   4032 	var a *Node
   4033 	var buf string
   4034 	for l := n.List; l != nil; l = l.Next {
   4035 		buf = fmt.Sprintf("a%d", num)
   4036 		num++
   4037 		a = Nod(ODCLFIELD, newname(Lookup(buf)), typenod(l.N.Type))
   4038 		t.List = list(t.List, a)
   4039 		printargs = list(printargs, a.Left)
   4040 	}
   4041 
   4042 	fn := Nod(ODCLFUNC, nil, nil)
   4043 	walkprintfunc_prgen++
   4044 	buf = fmt.Sprintf("print%d", walkprintfunc_prgen)
   4045 	fn.Func.Nname = newname(Lookup(buf))
   4046 	fn.Func.Nname.Name.Defn = fn
   4047 	fn.Func.Nname.Name.Param.Ntype = t
   4048 	declare(fn.Func.Nname, PFUNC)
   4049 
   4050 	oldfn := Curfn
   4051 	Curfn = nil
   4052 	funchdr(fn)
   4053 
   4054 	a = Nod(int(n.Op), nil, nil)
   4055 	a.List = printargs
   4056 	typecheck(&a, Etop)
   4057 	walkstmt(&a)
   4058 
   4059 	fn.Nbody = list1(a)
   4060 
   4061 	funcbody(fn)
   4062 
   4063 	typecheck(&fn, Etop)
   4064 	typechecklist(fn.Nbody, Etop)
   4065 	xtop = list(xtop, fn)
   4066 	Curfn = oldfn
   4067 
   4068 	a = Nod(OCALL, nil, nil)
   4069 	a.Left = fn.Func.Nname
   4070 	a.List = n.List
   4071 	typecheck(&a, Etop)
   4072 	walkexpr(&a, init)
   4073 	*np = a
   4074 }
   4075