github.com/aloncn/graphics-go@v0.0.1/src/cmd/compile/internal/gc/walk.go (about)

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