github.com/alash3al/go@v0.0.0-20150827002835-d497eeb00540/src/cmd/compile/internal/gc/walk.go (about)

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