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