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