github.com/huandu/go@v0.0.0-20151114150818-04e615e41150/src/cmd/compile/internal/gc/walk.go (about)

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