github.com/fjballest/golang@v0.0.0-20151209143359-e4c5fe594ca8/src/cmd/compile/internal/gc/walk.go (about)

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