github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/src/cmd/compile/internal/gc/order.go (about)

     1  // Copyright 2012 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/compile/internal/types"
     9  	"cmd/internal/src"
    10  	"fmt"
    11  )
    12  
    13  // Rewrite tree to use separate statements to enforce
    14  // order of evaluation. Makes walk easier, because it
    15  // can (after this runs) reorder at will within an expression.
    16  //
    17  // Rewrite x op= y into x = x op y.
    18  //
    19  // Introduce temporaries as needed by runtime routines.
    20  // For example, the map runtime routines take the map key
    21  // by reference, so make sure all map keys are addressable
    22  // by copying them to temporaries as needed.
    23  // The same is true for channel operations.
    24  //
    25  // Arrange that map index expressions only appear in direct
    26  // assignments x = m[k] or m[k] = x, never in larger expressions.
    27  //
    28  // Arrange that receive expressions only appear in direct assignments
    29  // x = <-c or as standalone statements <-c, never in larger expressions.
    30  
    31  // TODO(rsc): The temporary introduction during multiple assignments
    32  // should be moved into this file, so that the temporaries can be cleaned
    33  // and so that conversions implicit in the OAS2FUNC and OAS2RECV
    34  // nodes can be made explicit and then have their temporaries cleaned.
    35  
    36  // TODO(rsc): Goto and multilevel break/continue can jump over
    37  // inserted VARKILL annotations. Work out a way to handle these.
    38  // The current implementation is safe, in that it will execute correctly.
    39  // But it won't reuse temporaries as aggressively as it might, and
    40  // it can result in unnecessary zeroing of those variables in the function
    41  // prologue.
    42  
    43  // Order holds state during the ordering process.
    44  type Order struct {
    45  	out  []*Node // list of generated statements
    46  	temp []*Node // stack of temporary variables
    47  }
    48  
    49  // Order rewrites fn->nbody to apply the ordering constraints
    50  // described in the comment at the top of the file.
    51  func order(fn *Node) {
    52  	if Debug['W'] > 1 {
    53  		s := fmt.Sprintf("\nbefore order %v", fn.Func.Nname.Sym)
    54  		dumplist(s, fn.Nbody)
    55  	}
    56  
    57  	orderblockNodes(&fn.Nbody)
    58  }
    59  
    60  // Ordertemp allocates a new temporary with the given type,
    61  // pushes it onto the temp stack, and returns it.
    62  // If clear is true, ordertemp emits code to zero the temporary.
    63  func ordertemp(t *types.Type, order *Order, clear bool) *Node {
    64  	var_ := temp(t)
    65  	if clear {
    66  		a := nod(OAS, var_, nil)
    67  		a = typecheck(a, Etop)
    68  		order.out = append(order.out, a)
    69  	}
    70  
    71  	order.temp = append(order.temp, var_)
    72  	return var_
    73  }
    74  
    75  // Ordercopyexpr behaves like ordertemp but also emits
    76  // code to initialize the temporary to the value n.
    77  //
    78  // The clear argument is provided for use when the evaluation
    79  // of tmp = n turns into a function call that is passed a pointer
    80  // to the temporary as the output space. If the call blocks before
    81  // tmp has been written, the garbage collector will still treat the
    82  // temporary as live, so we must zero it before entering that call.
    83  // Today, this only happens for channel receive operations.
    84  // (The other candidate would be map access, but map access
    85  // returns a pointer to the result data instead of taking a pointer
    86  // to be filled in.)
    87  func ordercopyexpr(n *Node, t *types.Type, order *Order, clear int) *Node {
    88  	var_ := ordertemp(t, order, clear != 0)
    89  	a := nod(OAS, var_, n)
    90  	a = typecheck(a, Etop)
    91  	order.out = append(order.out, a)
    92  	return var_
    93  }
    94  
    95  // Ordercheapexpr returns a cheap version of n.
    96  // The definition of cheap is that n is a variable or constant.
    97  // If not, ordercheapexpr allocates a new tmp, emits tmp = n,
    98  // and then returns tmp.
    99  func ordercheapexpr(n *Node, order *Order) *Node {
   100  	if n == nil {
   101  		return nil
   102  	}
   103  	switch n.Op {
   104  	case ONAME, OLITERAL:
   105  		return n
   106  	case OLEN, OCAP:
   107  		l := ordercheapexpr(n.Left, order)
   108  		if l == n.Left {
   109  			return n
   110  		}
   111  		a := *n
   112  		a.Orig = &a
   113  		a.Left = l
   114  		return typecheck(&a, Erv)
   115  	}
   116  
   117  	return ordercopyexpr(n, n.Type, order, 0)
   118  }
   119  
   120  // Ordersafeexpr returns a safe version of n.
   121  // The definition of safe is that n can appear multiple times
   122  // without violating the semantics of the original program,
   123  // and that assigning to the safe version has the same effect
   124  // as assigning to the original n.
   125  //
   126  // The intended use is to apply to x when rewriting x += y into x = x + y.
   127  func ordersafeexpr(n *Node, order *Order) *Node {
   128  	switch n.Op {
   129  	case ONAME, OLITERAL:
   130  		return n
   131  
   132  	case ODOT, OLEN, OCAP:
   133  		l := ordersafeexpr(n.Left, order)
   134  		if l == n.Left {
   135  			return n
   136  		}
   137  		a := *n
   138  		a.Orig = &a
   139  		a.Left = l
   140  		return typecheck(&a, Erv)
   141  
   142  	case ODOTPTR, OIND:
   143  		l := ordercheapexpr(n.Left, order)
   144  		if l == n.Left {
   145  			return n
   146  		}
   147  		a := *n
   148  		a.Orig = &a
   149  		a.Left = l
   150  		return typecheck(&a, Erv)
   151  
   152  	case OINDEX, OINDEXMAP:
   153  		var l *Node
   154  		if n.Left.Type.IsArray() {
   155  			l = ordersafeexpr(n.Left, order)
   156  		} else {
   157  			l = ordercheapexpr(n.Left, order)
   158  		}
   159  		r := ordercheapexpr(n.Right, order)
   160  		if l == n.Left && r == n.Right {
   161  			return n
   162  		}
   163  		a := *n
   164  		a.Orig = &a
   165  		a.Left = l
   166  		a.Right = r
   167  		return typecheck(&a, Erv)
   168  	default:
   169  		Fatalf("ordersafeexpr %v", n.Op)
   170  		return nil // not reached
   171  	}
   172  }
   173  
   174  // Isaddrokay reports whether it is okay to pass n's address to runtime routines.
   175  // Taking the address of a variable makes the liveness and optimization analyses
   176  // lose track of where the variable's lifetime ends. To avoid hurting the analyses
   177  // of ordinary stack variables, those are not 'isaddrokay'. Temporaries are okay,
   178  // because we emit explicit VARKILL instructions marking the end of those
   179  // temporaries' lifetimes.
   180  func isaddrokay(n *Node) bool {
   181  	return islvalue(n) && (n.Op != ONAME || n.Class() == PEXTERN || n.IsAutoTmp())
   182  }
   183  
   184  // Orderaddrtemp ensures that n is okay to pass by address to runtime routines.
   185  // If the original argument n is not okay, orderaddrtemp creates a tmp, emits
   186  // tmp = n, and then returns tmp.
   187  // The result of orderaddrtemp MUST be assigned back to n, e.g.
   188  // 	n.Left = orderaddrtemp(n.Left, order)
   189  func orderaddrtemp(n *Node, order *Order) *Node {
   190  	if consttype(n) > 0 {
   191  		// TODO: expand this to all static composite literal nodes?
   192  		n = defaultlit(n, nil)
   193  		dowidth(n.Type)
   194  		vstat := staticname(n.Type)
   195  		vstat.Name.SetReadonly(true)
   196  		var out []*Node
   197  		staticassign(vstat, n, &out)
   198  		if out != nil {
   199  			Fatalf("staticassign of const generated code: %+v", n)
   200  		}
   201  		vstat = typecheck(vstat, Erv)
   202  		return vstat
   203  	}
   204  	if isaddrokay(n) {
   205  		return n
   206  	}
   207  	return ordercopyexpr(n, n.Type, order, 0)
   208  }
   209  
   210  // ordermapkeytemp prepares n to be a key in a map runtime call and returns n.
   211  // It should only be used for map runtime calls which have *_fast* versions.
   212  func ordermapkeytemp(t *types.Type, n *Node, order *Order) *Node {
   213  	// Most map calls need to take the address of the key.
   214  	// Exception: map*_fast* calls. See golang.org/issue/19015.
   215  	if mapfast(t) == mapslow {
   216  		return orderaddrtemp(n, order)
   217  	}
   218  	return n
   219  }
   220  
   221  type ordermarker int
   222  
   223  // Marktemp returns the top of the temporary variable stack.
   224  func marktemp(order *Order) ordermarker {
   225  	return ordermarker(len(order.temp))
   226  }
   227  
   228  // Poptemp pops temporaries off the stack until reaching the mark,
   229  // which must have been returned by marktemp.
   230  func poptemp(mark ordermarker, order *Order) {
   231  	order.temp = order.temp[:mark]
   232  }
   233  
   234  // Cleantempnopop emits to *out VARKILL instructions for each temporary
   235  // above the mark on the temporary stack, but it does not pop them
   236  // from the stack.
   237  func cleantempnopop(mark ordermarker, order *Order, out *[]*Node) {
   238  	var kill *Node
   239  
   240  	for i := len(order.temp) - 1; i >= int(mark); i-- {
   241  		n := order.temp[i]
   242  		if n.Name.Keepalive() {
   243  			n.Name.SetKeepalive(false)
   244  			n.SetAddrtaken(true) // ensure SSA keeps the n variable
   245  			kill = nod(OVARLIVE, n, nil)
   246  			kill = typecheck(kill, Etop)
   247  			*out = append(*out, kill)
   248  		}
   249  		kill = nod(OVARKILL, n, nil)
   250  		kill = typecheck(kill, Etop)
   251  		*out = append(*out, kill)
   252  	}
   253  }
   254  
   255  // Cleantemp emits VARKILL instructions for each temporary above the
   256  // mark on the temporary stack and removes them from the stack.
   257  func cleantemp(top ordermarker, order *Order) {
   258  	cleantempnopop(top, order, &order.out)
   259  	poptemp(top, order)
   260  }
   261  
   262  // Orderstmtlist orders each of the statements in the list.
   263  func orderstmtlist(l Nodes, order *Order) {
   264  	for _, n := range l.Slice() {
   265  		orderstmt(n, order)
   266  	}
   267  }
   268  
   269  // Orderblock orders the block of statements l onto a new list,
   270  // and returns the ordered list.
   271  func orderblock(l Nodes) []*Node {
   272  	var order Order
   273  	mark := marktemp(&order)
   274  	orderstmtlist(l, &order)
   275  	cleantemp(mark, &order)
   276  	return order.out
   277  }
   278  
   279  // OrderblockNodes orders the block of statements in n into a new slice,
   280  // and then replaces the old slice in n with the new slice.
   281  func orderblockNodes(n *Nodes) {
   282  	var order Order
   283  	mark := marktemp(&order)
   284  	orderstmtlist(*n, &order)
   285  	cleantemp(mark, &order)
   286  	n.Set(order.out)
   287  }
   288  
   289  // Orderexprinplace orders the side effects in *np and
   290  // leaves them as the init list of the final *np.
   291  // The result of orderexprinplace MUST be assigned back to n, e.g.
   292  // 	n.Left = orderexprinplace(n.Left, outer)
   293  func orderexprinplace(n *Node, outer *Order) *Node {
   294  	var order Order
   295  	n = orderexpr(n, &order, nil)
   296  	n = addinit(n, order.out)
   297  
   298  	// insert new temporaries from order
   299  	// at head of outer list.
   300  	outer.temp = append(outer.temp, order.temp...)
   301  	return n
   302  }
   303  
   304  // Orderstmtinplace orders the side effects of the single statement *np
   305  // and replaces it with the resulting statement list.
   306  // The result of orderstmtinplace MUST be assigned back to n, e.g.
   307  // 	n.Left = orderstmtinplace(n.Left)
   308  func orderstmtinplace(n *Node) *Node {
   309  	var order Order
   310  	mark := marktemp(&order)
   311  	orderstmt(n, &order)
   312  	cleantemp(mark, &order)
   313  	return liststmt(order.out)
   314  }
   315  
   316  // Orderinit moves n's init list to order->out.
   317  func orderinit(n *Node, order *Order) {
   318  	if n.mayBeShared() {
   319  		// For concurrency safety, don't mutate potentially shared nodes.
   320  		// First, ensure that no work is required here.
   321  		if n.Ninit.Len() > 0 {
   322  			Fatalf("orderinit shared node with ninit")
   323  		}
   324  		return
   325  	}
   326  	orderstmtlist(n.Ninit, order)
   327  	n.Ninit.Set(nil)
   328  }
   329  
   330  // Ismulticall reports whether the list l is f() for a multi-value function.
   331  // Such an f() could appear as the lone argument to a multi-arg function.
   332  func ismulticall(l Nodes) bool {
   333  	// one arg only
   334  	if l.Len() != 1 {
   335  		return false
   336  	}
   337  	n := l.First()
   338  
   339  	// must be call
   340  	switch n.Op {
   341  	default:
   342  		return false
   343  
   344  	case OCALLFUNC, OCALLMETH, OCALLINTER:
   345  		break
   346  	}
   347  
   348  	// call must return multiple values
   349  	return n.Left.Type.NumResults() > 1
   350  }
   351  
   352  // Copyret emits t1, t2, ... = n, where n is a function call,
   353  // and then returns the list t1, t2, ....
   354  func copyret(n *Node, order *Order) []*Node {
   355  	if !n.Type.IsFuncArgStruct() {
   356  		Fatalf("copyret %v %d", n.Type, n.Left.Type.NumResults())
   357  	}
   358  
   359  	var l1 []*Node
   360  	var l2 []*Node
   361  	for _, t := range n.Type.Fields().Slice() {
   362  		tmp := temp(t.Type)
   363  		l1 = append(l1, tmp)
   364  		l2 = append(l2, tmp)
   365  	}
   366  
   367  	as := nod(OAS2, nil, nil)
   368  	as.List.Set(l1)
   369  	as.Rlist.Set1(n)
   370  	as = typecheck(as, Etop)
   371  	orderstmt(as, order)
   372  
   373  	return l2
   374  }
   375  
   376  // Ordercallargs orders the list of call arguments *l.
   377  func ordercallargs(l *Nodes, order *Order) {
   378  	if ismulticall(*l) {
   379  		// return f() where f() is multiple values.
   380  		l.Set(copyret(l.First(), order))
   381  	} else {
   382  		orderexprlist(*l, order)
   383  	}
   384  }
   385  
   386  // Ordercall orders the call expression n.
   387  // n->op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
   388  func ordercall(n *Node, order *Order) {
   389  	n.Left = orderexpr(n.Left, order, nil)
   390  	n.Right = orderexpr(n.Right, order, nil) // ODDDARG temp
   391  	ordercallargs(&n.List, order)
   392  
   393  	if n.Op == OCALLFUNC {
   394  		keepAlive := func(i int) {
   395  			// If the argument is really a pointer being converted to uintptr,
   396  			// arrange for the pointer to be kept alive until the call returns,
   397  			// by copying it into a temp and marking that temp
   398  			// still alive when we pop the temp stack.
   399  			xp := n.List.Addr(i)
   400  			for (*xp).Op == OCONVNOP && !(*xp).Type.IsPtr() {
   401  				xp = &(*xp).Left
   402  			}
   403  			x := *xp
   404  			if x.Type.IsPtr() {
   405  				x = ordercopyexpr(x, x.Type, order, 0)
   406  				x.Name.SetKeepalive(true)
   407  				*xp = x
   408  			}
   409  		}
   410  
   411  		for i, t := range n.Left.Type.Params().FieldSlice() {
   412  			// Check for "unsafe-uintptr" tag provided by escape analysis.
   413  			if t.Isddd() && !n.Isddd() {
   414  				if t.Note == uintptrEscapesTag {
   415  					for ; i < n.List.Len(); i++ {
   416  						keepAlive(i)
   417  					}
   418  				}
   419  			} else {
   420  				if t.Note == unsafeUintptrTag || t.Note == uintptrEscapesTag {
   421  					keepAlive(i)
   422  				}
   423  			}
   424  		}
   425  	}
   426  }
   427  
   428  // Ordermapassign appends n to order->out, introducing temporaries
   429  // to make sure that all map assignments have the form m[k] = x.
   430  // (Note: orderexpr has already been called on n, so we know k is addressable.)
   431  //
   432  // If n is the multiple assignment form ..., m[k], ... = ..., the rewrite is
   433  //	t1 = m
   434  //	t2 = k
   435  //	...., t3, ... = x
   436  //	t1[t2] = t3
   437  //
   438  // The temporaries t1, t2 are needed in case the ... being assigned
   439  // contain m or k. They are usually unnecessary, but in the unnecessary
   440  // cases they are also typically registerizable, so not much harm done.
   441  // And this only applies to the multiple-assignment form.
   442  // We could do a more precise analysis if needed, like in walk.go.
   443  func ordermapassign(n *Node, order *Order) {
   444  	switch n.Op {
   445  	default:
   446  		Fatalf("ordermapassign %v", n.Op)
   447  
   448  	case OAS:
   449  		order.out = append(order.out, n)
   450  
   451  	case OAS2, OAS2DOTTYPE, OAS2MAPR, OAS2FUNC:
   452  		var post []*Node
   453  		var m *Node
   454  		var a *Node
   455  		for i1, n1 := range n.List.Slice() {
   456  			if n1.Op == OINDEXMAP {
   457  				m = n1
   458  				if !m.Left.IsAutoTmp() {
   459  					m.Left = ordercopyexpr(m.Left, m.Left.Type, order, 0)
   460  				}
   461  				if !m.Right.IsAutoTmp() {
   462  					m.Right = ordercopyexpr(m.Right, m.Right.Type, order, 0)
   463  				}
   464  				n.List.SetIndex(i1, ordertemp(m.Type, order, false))
   465  				a = nod(OAS, m, n.List.Index(i1))
   466  				a = typecheck(a, Etop)
   467  				post = append(post, a)
   468  			} else if instrumenting && n.Op == OAS2FUNC && !isblank(n.List.Index(i1)) {
   469  				m = n.List.Index(i1)
   470  				t := ordertemp(m.Type, order, false)
   471  				n.List.SetIndex(i1, t)
   472  				a = nod(OAS, m, t)
   473  				a = typecheck(a, Etop)
   474  				post = append(post, a)
   475  			}
   476  		}
   477  
   478  		order.out = append(order.out, n)
   479  		order.out = append(order.out, post...)
   480  	}
   481  }
   482  
   483  // Orderstmt orders the statement n, appending to order->out.
   484  // Temporaries created during the statement are cleaned
   485  // up using VARKILL instructions as possible.
   486  func orderstmt(n *Node, order *Order) {
   487  	if n == nil {
   488  		return
   489  	}
   490  
   491  	lno := setlineno(n)
   492  
   493  	orderinit(n, order)
   494  
   495  	switch n.Op {
   496  	default:
   497  		Fatalf("orderstmt %v", n.Op)
   498  
   499  	case OVARKILL, OVARLIVE:
   500  		order.out = append(order.out, n)
   501  
   502  	case OAS:
   503  		t := marktemp(order)
   504  		n.Left = orderexpr(n.Left, order, nil)
   505  		n.Right = orderexpr(n.Right, order, n.Left)
   506  		ordermapassign(n, order)
   507  		cleantemp(t, order)
   508  
   509  	case OAS2,
   510  		OCLOSE,
   511  		OCOPY,
   512  		OPRINT,
   513  		OPRINTN,
   514  		ORECOVER,
   515  		ORECV:
   516  		t := marktemp(order)
   517  		n.Left = orderexpr(n.Left, order, nil)
   518  		n.Right = orderexpr(n.Right, order, nil)
   519  		orderexprlist(n.List, order)
   520  		orderexprlist(n.Rlist, order)
   521  		switch n.Op {
   522  		case OAS2:
   523  			ordermapassign(n, order)
   524  		default:
   525  			order.out = append(order.out, n)
   526  		}
   527  		cleantemp(t, order)
   528  
   529  	case OASOP:
   530  		// Special: rewrite l op= r into l = l op r.
   531  		// This simplifies quite a few operations;
   532  		// most important is that it lets us separate
   533  		// out map read from map write when l is
   534  		// a map index expression.
   535  		t := marktemp(order)
   536  		n.Left = orderexpr(n.Left, order, nil)
   537  		n.Right = orderexpr(n.Right, order, nil)
   538  
   539  		n.Left = ordersafeexpr(n.Left, order)
   540  		tmp1 := treecopy(n.Left, src.NoXPos)
   541  		if tmp1.Op == OINDEXMAP {
   542  			tmp1.Etype = 0 // now an rvalue not an lvalue
   543  		}
   544  		tmp1 = ordercopyexpr(tmp1, n.Left.Type, order, 0)
   545  		// TODO(marvin): Fix Node.EType type union.
   546  		n.Right = nod(Op(n.Etype), tmp1, n.Right)
   547  		n.Right = typecheck(n.Right, Erv)
   548  		n.Right = orderexpr(n.Right, order, nil)
   549  		n.Etype = 0
   550  		n.Op = OAS
   551  		ordermapassign(n, order)
   552  		cleantemp(t, order)
   553  
   554  	// Special: make sure key is addressable if needed,
   555  	// and make sure OINDEXMAP is not copied out.
   556  	case OAS2MAPR:
   557  		t := marktemp(order)
   558  
   559  		orderexprlist(n.List, order)
   560  		r := n.Rlist.First()
   561  		r.Left = orderexpr(r.Left, order, nil)
   562  		r.Right = orderexpr(r.Right, order, nil)
   563  
   564  		// See case OINDEXMAP below.
   565  		if r.Right.Op == OARRAYBYTESTR {
   566  			r.Right.Op = OARRAYBYTESTRTMP
   567  		}
   568  		r.Right = ordermapkeytemp(r.Left.Type, r.Right, order)
   569  		orderokas2(n, order)
   570  		cleantemp(t, order)
   571  
   572  	// Special: avoid copy of func call n->rlist->n.
   573  	case OAS2FUNC:
   574  		t := marktemp(order)
   575  
   576  		orderexprlist(n.List, order)
   577  		ordercall(n.Rlist.First(), order)
   578  		orderas2(n, order)
   579  		cleantemp(t, order)
   580  
   581  	// Special: use temporary variables to hold result,
   582  	// so that assertI2Tetc can take address of temporary.
   583  	// No temporary for blank assignment.
   584  	case OAS2DOTTYPE:
   585  		t := marktemp(order)
   586  
   587  		orderexprlist(n.List, order)
   588  		n.Rlist.First().Left = orderexpr(n.Rlist.First().Left, order, nil) // i in i.(T)
   589  		orderokas2(n, order)
   590  		cleantemp(t, order)
   591  
   592  	// Special: use temporary variables to hold result,
   593  	// so that chanrecv can take address of temporary.
   594  	case OAS2RECV:
   595  		t := marktemp(order)
   596  
   597  		orderexprlist(n.List, order)
   598  		n.Rlist.First().Left = orderexpr(n.Rlist.First().Left, order, nil) // arg to recv
   599  		ch := n.Rlist.First().Left.Type
   600  		tmp1 := ordertemp(ch.Elem(), order, types.Haspointers(ch.Elem()))
   601  		tmp2 := ordertemp(types.Types[TBOOL], order, false)
   602  		order.out = append(order.out, n)
   603  		r := nod(OAS, n.List.First(), tmp1)
   604  		r = typecheck(r, Etop)
   605  		ordermapassign(r, order)
   606  		r = okas(n.List.Second(), tmp2)
   607  		r = typecheck(r, Etop)
   608  		ordermapassign(r, order)
   609  		n.List.Set2(tmp1, tmp2)
   610  		cleantemp(t, order)
   611  
   612  	// Special: does not save n onto out.
   613  	case OBLOCK, OEMPTY:
   614  		orderstmtlist(n.List, order)
   615  
   616  	// Special: n->left is not an expression; save as is.
   617  	case OBREAK,
   618  		OCONTINUE,
   619  		ODCL,
   620  		ODCLCONST,
   621  		ODCLTYPE,
   622  		OFALL,
   623  		OGOTO,
   624  		OLABEL,
   625  		ORETJMP:
   626  		order.out = append(order.out, n)
   627  
   628  	// Special: handle call arguments.
   629  	case OCALLFUNC, OCALLINTER, OCALLMETH:
   630  		t := marktemp(order)
   631  
   632  		ordercall(n, order)
   633  		order.out = append(order.out, n)
   634  		cleantemp(t, order)
   635  
   636  	// Special: order arguments to inner call but not call itself.
   637  	case ODEFER, OPROC:
   638  		t := marktemp(order)
   639  
   640  		switch n.Left.Op {
   641  		// Delete will take the address of the key.
   642  		// Copy key into new temp and do not clean it
   643  		// (it persists beyond the statement).
   644  		case ODELETE:
   645  			orderexprlist(n.Left.List, order)
   646  
   647  			if mapfast(n.Left.List.First().Type) == mapslow {
   648  				t1 := marktemp(order)
   649  				np := n.Left.List.Addr(1) // map key
   650  				*np = ordercopyexpr(*np, (*np).Type, order, 0)
   651  				poptemp(t1, order)
   652  			}
   653  
   654  		default:
   655  			ordercall(n.Left, order)
   656  		}
   657  
   658  		order.out = append(order.out, n)
   659  		cleantemp(t, order)
   660  
   661  	case ODELETE:
   662  		t := marktemp(order)
   663  		n.List.SetFirst(orderexpr(n.List.First(), order, nil))
   664  		n.List.SetSecond(orderexpr(n.List.Second(), order, nil))
   665  		n.List.SetSecond(ordermapkeytemp(n.List.First().Type, n.List.Second(), order))
   666  		order.out = append(order.out, n)
   667  		cleantemp(t, order)
   668  
   669  	// Clean temporaries from condition evaluation at
   670  	// beginning of loop body and after for statement.
   671  	case OFOR:
   672  		t := marktemp(order)
   673  
   674  		n.Left = orderexprinplace(n.Left, order)
   675  		var l []*Node
   676  		cleantempnopop(t, order, &l)
   677  		n.Nbody.Prepend(l...)
   678  		orderblockNodes(&n.Nbody)
   679  		n.Right = orderstmtinplace(n.Right)
   680  		order.out = append(order.out, n)
   681  		cleantemp(t, order)
   682  
   683  	// Clean temporaries from condition at
   684  	// beginning of both branches.
   685  	case OIF:
   686  		t := marktemp(order)
   687  
   688  		n.Left = orderexprinplace(n.Left, order)
   689  		var l []*Node
   690  		cleantempnopop(t, order, &l)
   691  		n.Nbody.Prepend(l...)
   692  		l = nil
   693  		cleantempnopop(t, order, &l)
   694  		n.Rlist.Prepend(l...)
   695  		poptemp(t, order)
   696  		orderblockNodes(&n.Nbody)
   697  		n.Rlist.Set(orderblock(n.Rlist))
   698  		order.out = append(order.out, n)
   699  
   700  	// Special: argument will be converted to interface using convT2E
   701  	// so make sure it is an addressable temporary.
   702  	case OPANIC:
   703  		t := marktemp(order)
   704  
   705  		n.Left = orderexpr(n.Left, order, nil)
   706  		if !n.Left.Type.IsInterface() {
   707  			n.Left = orderaddrtemp(n.Left, order)
   708  		}
   709  		order.out = append(order.out, n)
   710  		cleantemp(t, order)
   711  
   712  	case ORANGE:
   713  		// n.Right is the expression being ranged over.
   714  		// order it, and then make a copy if we need one.
   715  		// We almost always do, to ensure that we don't
   716  		// see any value changes made during the loop.
   717  		// Usually the copy is cheap (e.g., array pointer,
   718  		// chan, slice, string are all tiny).
   719  		// The exception is ranging over an array value
   720  		// (not a slice, not a pointer to array),
   721  		// which must make a copy to avoid seeing updates made during
   722  		// the range body. Ranging over an array value is uncommon though.
   723  
   724  		// Mark []byte(str) range expression to reuse string backing storage.
   725  		// It is safe because the storage cannot be mutated.
   726  		if n.Right.Op == OSTRARRAYBYTE {
   727  			n.Right.Op = OSTRARRAYBYTETMP
   728  		}
   729  
   730  		t := marktemp(order)
   731  		n.Right = orderexpr(n.Right, order, nil)
   732  		switch n.Type.Etype {
   733  		default:
   734  			Fatalf("orderstmt range %v", n.Type)
   735  
   736  		case TARRAY, TSLICE:
   737  			if n.List.Len() < 2 || isblank(n.List.Second()) {
   738  				// for i := range x will only use x once, to compute len(x).
   739  				// No need to copy it.
   740  				break
   741  			}
   742  			fallthrough
   743  
   744  		case TCHAN, TSTRING:
   745  			// chan, string, slice, array ranges use value multiple times.
   746  			// make copy.
   747  			r := n.Right
   748  
   749  			if r.Type.IsString() && r.Type != types.Types[TSTRING] {
   750  				r = nod(OCONV, r, nil)
   751  				r.Type = types.Types[TSTRING]
   752  				r = typecheck(r, Erv)
   753  			}
   754  
   755  			n.Right = ordercopyexpr(r, r.Type, order, 0)
   756  
   757  		case TMAP:
   758  			// copy the map value in case it is a map literal.
   759  			// TODO(rsc): Make tmp = literal expressions reuse tmp.
   760  			// For maps tmp is just one word so it hardly matters.
   761  			r := n.Right
   762  			n.Right = ordercopyexpr(r, r.Type, order, 0)
   763  
   764  			// prealloc[n] is the temp for the iterator.
   765  			// hiter contains pointers and needs to be zeroed.
   766  			prealloc[n] = ordertemp(hiter(n.Type), order, true)
   767  		}
   768  		for i := range n.List.Slice() {
   769  			n.List.SetIndex(i, orderexprinplace(n.List.Index(i), order))
   770  		}
   771  		orderblockNodes(&n.Nbody)
   772  		order.out = append(order.out, n)
   773  		cleantemp(t, order)
   774  
   775  	case ORETURN:
   776  		ordercallargs(&n.List, order)
   777  		order.out = append(order.out, n)
   778  
   779  	// Special: clean case temporaries in each block entry.
   780  	// Select must enter one of its blocks, so there is no
   781  	// need for a cleaning at the end.
   782  	// Doubly special: evaluation order for select is stricter
   783  	// than ordinary expressions. Even something like p.c
   784  	// has to be hoisted into a temporary, so that it cannot be
   785  	// reordered after the channel evaluation for a different
   786  	// case (if p were nil, then the timing of the fault would
   787  	// give this away).
   788  	case OSELECT:
   789  		t := marktemp(order)
   790  
   791  		var tmp1 *Node
   792  		var tmp2 *Node
   793  		var r *Node
   794  		for _, n2 := range n.List.Slice() {
   795  			if n2.Op != OXCASE {
   796  				Fatalf("order select case %v", n2.Op)
   797  			}
   798  			r = n2.Left
   799  			setlineno(n2)
   800  
   801  			// Append any new body prologue to ninit.
   802  			// The next loop will insert ninit into nbody.
   803  			if n2.Ninit.Len() != 0 {
   804  				Fatalf("order select ninit")
   805  			}
   806  			if r != nil {
   807  				switch r.Op {
   808  				default:
   809  					Dump("select case", r)
   810  					Fatalf("unknown op in select %v", r.Op)
   811  
   812  				// If this is case x := <-ch or case x, y := <-ch, the case has
   813  				// the ODCL nodes to declare x and y. We want to delay that
   814  				// declaration (and possible allocation) until inside the case body.
   815  				// Delete the ODCL nodes here and recreate them inside the body below.
   816  				case OSELRECV, OSELRECV2:
   817  					if r.Colas() {
   818  						i := 0
   819  						if r.Ninit.Len() != 0 && r.Ninit.First().Op == ODCL && r.Ninit.First().Left == r.Left {
   820  							i++
   821  						}
   822  						if i < r.Ninit.Len() && r.Ninit.Index(i).Op == ODCL && r.List.Len() != 0 && r.Ninit.Index(i).Left == r.List.First() {
   823  							i++
   824  						}
   825  						if i >= r.Ninit.Len() {
   826  							r.Ninit.Set(nil)
   827  						}
   828  					}
   829  
   830  					if r.Ninit.Len() != 0 {
   831  						dumplist("ninit", r.Ninit)
   832  						Fatalf("ninit on select recv")
   833  					}
   834  
   835  					// case x = <-c
   836  					// case x, ok = <-c
   837  					// r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c.
   838  					// r->left == N means 'case <-c'.
   839  					// c is always evaluated; x and ok are only evaluated when assigned.
   840  					r.Right.Left = orderexpr(r.Right.Left, order, nil)
   841  
   842  					if r.Right.Left.Op != ONAME {
   843  						r.Right.Left = ordercopyexpr(r.Right.Left, r.Right.Left.Type, order, 0)
   844  					}
   845  
   846  					// Introduce temporary for receive and move actual copy into case body.
   847  					// avoids problems with target being addressed, as usual.
   848  					// NOTE: If we wanted to be clever, we could arrange for just one
   849  					// temporary per distinct type, sharing the temp among all receives
   850  					// with that temp. Similarly one ok bool could be shared among all
   851  					// the x,ok receives. Not worth doing until there's a clear need.
   852  					if r.Left != nil && isblank(r.Left) {
   853  						r.Left = nil
   854  					}
   855  					if r.Left != nil {
   856  						// use channel element type for temporary to avoid conversions,
   857  						// such as in case interfacevalue = <-intchan.
   858  						// the conversion happens in the OAS instead.
   859  						tmp1 = r.Left
   860  
   861  						if r.Colas() {
   862  							tmp2 = nod(ODCL, tmp1, nil)
   863  							tmp2 = typecheck(tmp2, Etop)
   864  							n2.Ninit.Append(tmp2)
   865  						}
   866  
   867  						r.Left = ordertemp(r.Right.Left.Type.Elem(), order, types.Haspointers(r.Right.Left.Type.Elem()))
   868  						tmp2 = nod(OAS, tmp1, r.Left)
   869  						tmp2 = typecheck(tmp2, Etop)
   870  						n2.Ninit.Append(tmp2)
   871  					}
   872  
   873  					if r.List.Len() != 0 && isblank(r.List.First()) {
   874  						r.List.Set(nil)
   875  					}
   876  					if r.List.Len() != 0 {
   877  						tmp1 = r.List.First()
   878  						if r.Colas() {
   879  							tmp2 = nod(ODCL, tmp1, nil)
   880  							tmp2 = typecheck(tmp2, Etop)
   881  							n2.Ninit.Append(tmp2)
   882  						}
   883  
   884  						r.List.Set1(ordertemp(types.Types[TBOOL], order, false))
   885  						tmp2 = okas(tmp1, r.List.First())
   886  						tmp2 = typecheck(tmp2, Etop)
   887  						n2.Ninit.Append(tmp2)
   888  					}
   889  					n2.Ninit.Set(orderblock(n2.Ninit))
   890  
   891  				case OSEND:
   892  					if r.Ninit.Len() != 0 {
   893  						dumplist("ninit", r.Ninit)
   894  						Fatalf("ninit on select send")
   895  					}
   896  
   897  					// case c <- x
   898  					// r->left is c, r->right is x, both are always evaluated.
   899  					r.Left = orderexpr(r.Left, order, nil)
   900  
   901  					if !r.Left.IsAutoTmp() {
   902  						r.Left = ordercopyexpr(r.Left, r.Left.Type, order, 0)
   903  					}
   904  					r.Right = orderexpr(r.Right, order, nil)
   905  					if !r.Right.IsAutoTmp() {
   906  						r.Right = ordercopyexpr(r.Right, r.Right.Type, order, 0)
   907  					}
   908  				}
   909  			}
   910  
   911  			orderblockNodes(&n2.Nbody)
   912  		}
   913  		// Now that we have accumulated all the temporaries, clean them.
   914  		// Also insert any ninit queued during the previous loop.
   915  		// (The temporary cleaning must follow that ninit work.)
   916  		for _, n3 := range n.List.Slice() {
   917  			s := n3.Ninit.Slice()
   918  			cleantempnopop(t, order, &s)
   919  			n3.Nbody.Prepend(s...)
   920  			n3.Ninit.Set(nil)
   921  		}
   922  
   923  		order.out = append(order.out, n)
   924  		poptemp(t, order)
   925  
   926  	// Special: value being sent is passed as a pointer; make it addressable.
   927  	case OSEND:
   928  		t := marktemp(order)
   929  
   930  		n.Left = orderexpr(n.Left, order, nil)
   931  		n.Right = orderexpr(n.Right, order, nil)
   932  		if instrumenting {
   933  			// Force copying to the stack so that (chan T)(nil) <- x
   934  			// is still instrumented as a read of x.
   935  			n.Right = ordercopyexpr(n.Right, n.Right.Type, order, 0)
   936  		} else {
   937  			n.Right = orderaddrtemp(n.Right, order)
   938  		}
   939  		order.out = append(order.out, n)
   940  		cleantemp(t, order)
   941  
   942  	// TODO(rsc): Clean temporaries more aggressively.
   943  	// Note that because walkswitch will rewrite some of the
   944  	// switch into a binary search, this is not as easy as it looks.
   945  	// (If we ran that code here we could invoke orderstmt on
   946  	// the if-else chain instead.)
   947  	// For now just clean all the temporaries at the end.
   948  	// In practice that's fine.
   949  	case OSWITCH:
   950  		t := marktemp(order)
   951  
   952  		n.Left = orderexpr(n.Left, order, nil)
   953  		for _, n4 := range n.List.Slice() {
   954  			if n4.Op != OXCASE {
   955  				Fatalf("order switch case %v", n4.Op)
   956  			}
   957  			orderexprlistinplace(n4.List, order)
   958  			orderblockNodes(&n4.Nbody)
   959  		}
   960  
   961  		order.out = append(order.out, n)
   962  		cleantemp(t, order)
   963  	}
   964  
   965  	lineno = lno
   966  }
   967  
   968  // Orderexprlist orders the expression list l into order.
   969  func orderexprlist(l Nodes, order *Order) {
   970  	s := l.Slice()
   971  	for i := range s {
   972  		s[i] = orderexpr(s[i], order, nil)
   973  	}
   974  }
   975  
   976  // Orderexprlist orders the expression list l but saves
   977  // the side effects on the individual expression ninit lists.
   978  func orderexprlistinplace(l Nodes, order *Order) {
   979  	s := l.Slice()
   980  	for i := range s {
   981  		s[i] = orderexprinplace(s[i], order)
   982  	}
   983  }
   984  
   985  // prealloc[x] records the allocation to use for x.
   986  var prealloc = map[*Node]*Node{}
   987  
   988  // Orderexpr orders a single expression, appending side
   989  // effects to order->out as needed.
   990  // If this is part of an assignment lhs = *np, lhs is given.
   991  // Otherwise lhs == nil. (When lhs != nil it may be possible
   992  // to avoid copying the result of the expression to a temporary.)
   993  // The result of orderexpr MUST be assigned back to n, e.g.
   994  // 	n.Left = orderexpr(n.Left, order, lhs)
   995  func orderexpr(n *Node, order *Order, lhs *Node) *Node {
   996  	if n == nil {
   997  		return n
   998  	}
   999  
  1000  	lno := setlineno(n)
  1001  	orderinit(n, order)
  1002  
  1003  	switch n.Op {
  1004  	default:
  1005  		n.Left = orderexpr(n.Left, order, nil)
  1006  		n.Right = orderexpr(n.Right, order, nil)
  1007  		orderexprlist(n.List, order)
  1008  		orderexprlist(n.Rlist, order)
  1009  
  1010  	// Addition of strings turns into a function call.
  1011  	// Allocate a temporary to hold the strings.
  1012  	// Fewer than 5 strings use direct runtime helpers.
  1013  	case OADDSTR:
  1014  		orderexprlist(n.List, order)
  1015  
  1016  		if n.List.Len() > 5 {
  1017  			t := types.NewArray(types.Types[TSTRING], int64(n.List.Len()))
  1018  			prealloc[n] = ordertemp(t, order, false)
  1019  		}
  1020  
  1021  		// Mark string(byteSlice) arguments to reuse byteSlice backing
  1022  		// buffer during conversion. String concatenation does not
  1023  		// memorize the strings for later use, so it is safe.
  1024  		// However, we can do it only if there is at least one non-empty string literal.
  1025  		// Otherwise if all other arguments are empty strings,
  1026  		// concatstrings will return the reference to the temp string
  1027  		// to the caller.
  1028  		hasbyte := false
  1029  
  1030  		haslit := false
  1031  		for _, n1 := range n.List.Slice() {
  1032  			hasbyte = hasbyte || n1.Op == OARRAYBYTESTR
  1033  			haslit = haslit || n1.Op == OLITERAL && len(n1.Val().U.(string)) != 0
  1034  		}
  1035  
  1036  		if haslit && hasbyte {
  1037  			for _, n2 := range n.List.Slice() {
  1038  				if n2.Op == OARRAYBYTESTR {
  1039  					n2.Op = OARRAYBYTESTRTMP
  1040  				}
  1041  			}
  1042  		}
  1043  
  1044  	case OCMPSTR:
  1045  		n.Left = orderexpr(n.Left, order, nil)
  1046  		n.Right = orderexpr(n.Right, order, nil)
  1047  
  1048  		// Mark string(byteSlice) arguments to reuse byteSlice backing
  1049  		// buffer during conversion. String comparison does not
  1050  		// memorize the strings for later use, so it is safe.
  1051  		if n.Left.Op == OARRAYBYTESTR {
  1052  			n.Left.Op = OARRAYBYTESTRTMP
  1053  		}
  1054  		if n.Right.Op == OARRAYBYTESTR {
  1055  			n.Right.Op = OARRAYBYTESTRTMP
  1056  		}
  1057  
  1058  		// key must be addressable
  1059  	case OINDEXMAP:
  1060  		n.Left = orderexpr(n.Left, order, nil)
  1061  		n.Right = orderexpr(n.Right, order, nil)
  1062  		needCopy := false
  1063  
  1064  		if n.Etype == 0 && instrumenting {
  1065  			// Race detector needs the copy so it can
  1066  			// call treecopy on the result.
  1067  			needCopy = true
  1068  		}
  1069  
  1070  		// For x = m[string(k)] where k is []byte, the allocation of
  1071  		// backing bytes for the string can be avoided by reusing
  1072  		// the []byte backing array. This is a special case that it
  1073  		// would be nice to handle more generally, but because
  1074  		// there are no []byte-keyed maps, this specific case comes
  1075  		// up in important cases in practice. See issue 3512.
  1076  		// Nothing can change the []byte we are not copying before
  1077  		// the map index, because the map access is going to
  1078  		// be forced to happen immediately following this
  1079  		// conversion (by the ordercopyexpr a few lines below).
  1080  		if n.Etype == 0 && n.Right.Op == OARRAYBYTESTR {
  1081  			n.Right.Op = OARRAYBYTESTRTMP
  1082  			needCopy = true
  1083  		}
  1084  
  1085  		n.Right = ordermapkeytemp(n.Left.Type, n.Right, order)
  1086  		if needCopy {
  1087  			n = ordercopyexpr(n, n.Type, order, 0)
  1088  		}
  1089  
  1090  	// concrete type (not interface) argument must be addressable
  1091  	// temporary to pass to runtime.
  1092  	case OCONVIFACE:
  1093  		n.Left = orderexpr(n.Left, order, nil)
  1094  
  1095  		if !n.Left.Type.IsInterface() {
  1096  			n.Left = orderaddrtemp(n.Left, order)
  1097  		}
  1098  
  1099  	case OCONVNOP:
  1100  		if n.Type.IsKind(TUNSAFEPTR) && n.Left.Type.IsKind(TUINTPTR) && (n.Left.Op == OCALLFUNC || n.Left.Op == OCALLINTER || n.Left.Op == OCALLMETH) {
  1101  			// When reordering unsafe.Pointer(f()) into a separate
  1102  			// statement, the conversion and function call must stay
  1103  			// together. See golang.org/issue/15329.
  1104  			orderinit(n.Left, order)
  1105  			ordercall(n.Left, order)
  1106  			if lhs == nil || lhs.Op != ONAME || instrumenting {
  1107  				n = ordercopyexpr(n, n.Type, order, 0)
  1108  			}
  1109  		} else {
  1110  			n.Left = orderexpr(n.Left, order, nil)
  1111  		}
  1112  
  1113  	case OANDAND, OOROR:
  1114  		mark := marktemp(order)
  1115  		n.Left = orderexpr(n.Left, order, nil)
  1116  
  1117  		// Clean temporaries from first branch at beginning of second.
  1118  		// Leave them on the stack so that they can be killed in the outer
  1119  		// context in case the short circuit is taken.
  1120  		var s []*Node
  1121  
  1122  		cleantempnopop(mark, order, &s)
  1123  		n.Right = addinit(n.Right, s)
  1124  		n.Right = orderexprinplace(n.Right, order)
  1125  
  1126  	case OCALLFUNC,
  1127  		OCALLINTER,
  1128  		OCALLMETH,
  1129  		OCAP,
  1130  		OCOMPLEX,
  1131  		OCOPY,
  1132  		OIMAG,
  1133  		OLEN,
  1134  		OMAKECHAN,
  1135  		OMAKEMAP,
  1136  		OMAKESLICE,
  1137  		ONEW,
  1138  		OREAL,
  1139  		ORECOVER,
  1140  		OSTRARRAYBYTE,
  1141  		OSTRARRAYBYTETMP,
  1142  		OSTRARRAYRUNE:
  1143  		ordercall(n, order)
  1144  		if lhs == nil || lhs.Op != ONAME || instrumenting {
  1145  			n = ordercopyexpr(n, n.Type, order, 0)
  1146  		}
  1147  
  1148  	case OAPPEND:
  1149  		ordercallargs(&n.List, order)
  1150  		if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.First()) {
  1151  			n = ordercopyexpr(n, n.Type, order, 0)
  1152  		}
  1153  
  1154  	case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
  1155  		n.Left = orderexpr(n.Left, order, nil)
  1156  		low, high, max := n.SliceBounds()
  1157  		low = orderexpr(low, order, nil)
  1158  		low = ordercheapexpr(low, order)
  1159  		high = orderexpr(high, order, nil)
  1160  		high = ordercheapexpr(high, order)
  1161  		max = orderexpr(max, order, nil)
  1162  		max = ordercheapexpr(max, order)
  1163  		n.SetSliceBounds(low, high, max)
  1164  		if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) {
  1165  			n = ordercopyexpr(n, n.Type, order, 0)
  1166  		}
  1167  
  1168  	case OCLOSURE:
  1169  		if n.Noescape() && n.Func.Cvars.Len() > 0 {
  1170  			prealloc[n] = ordertemp(types.Types[TUINT8], order, false) // walk will fill in correct type
  1171  		}
  1172  
  1173  	case OARRAYLIT, OSLICELIT, OCALLPART:
  1174  		n.Left = orderexpr(n.Left, order, nil)
  1175  		n.Right = orderexpr(n.Right, order, nil)
  1176  		orderexprlist(n.List, order)
  1177  		orderexprlist(n.Rlist, order)
  1178  		if n.Noescape() {
  1179  			prealloc[n] = ordertemp(types.Types[TUINT8], order, false) // walk will fill in correct type
  1180  		}
  1181  
  1182  	case ODDDARG:
  1183  		if n.Noescape() {
  1184  			// The ddd argument does not live beyond the call it is created for.
  1185  			// Allocate a temporary that will be cleaned up when this statement
  1186  			// completes. We could be more aggressive and try to arrange for it
  1187  			// to be cleaned up when the call completes.
  1188  			prealloc[n] = ordertemp(n.Type.Elem(), order, false)
  1189  		}
  1190  
  1191  	case ODOTTYPE, ODOTTYPE2:
  1192  		n.Left = orderexpr(n.Left, order, nil)
  1193  		// TODO(rsc): The isfat is for consistency with componentgen and walkexpr.
  1194  		// It needs to be removed in all three places.
  1195  		// That would allow inlining x.(struct{*int}) the same as x.(*int).
  1196  		if !isdirectiface(n.Type) || isfat(n.Type) || instrumenting {
  1197  			n = ordercopyexpr(n, n.Type, order, 1)
  1198  		}
  1199  
  1200  	case ORECV:
  1201  		n.Left = orderexpr(n.Left, order, nil)
  1202  		n = ordercopyexpr(n, n.Type, order, 1)
  1203  
  1204  	case OEQ, ONE:
  1205  		n.Left = orderexpr(n.Left, order, nil)
  1206  		n.Right = orderexpr(n.Right, order, nil)
  1207  		t := n.Left.Type
  1208  		if t.IsStruct() || t.IsArray() {
  1209  			// for complex comparisons, we need both args to be
  1210  			// addressable so we can pass them to the runtime.
  1211  			n.Left = orderaddrtemp(n.Left, order)
  1212  			n.Right = orderaddrtemp(n.Right, order)
  1213  		}
  1214  	}
  1215  
  1216  	lineno = lno
  1217  	return n
  1218  }
  1219  
  1220  // okas creates and returns an assignment of val to ok,
  1221  // including an explicit conversion if necessary.
  1222  func okas(ok, val *Node) *Node {
  1223  	if !isblank(ok) {
  1224  		val = conv(val, ok.Type)
  1225  	}
  1226  	return nod(OAS, ok, val)
  1227  }
  1228  
  1229  // orderas2 orders OAS2XXXX nodes. It creates temporaries to ensure left-to-right assignment.
  1230  // The caller should order the right-hand side of the assignment before calling orderas2.
  1231  // It rewrites,
  1232  // 	a, b, a = ...
  1233  // as
  1234  //	tmp1, tmp2, tmp3 = ...
  1235  // 	a, b, a = tmp1, tmp2, tmp3
  1236  // This is necessary to ensure left to right assignment order.
  1237  func orderas2(n *Node, order *Order) {
  1238  	tmplist := []*Node{}
  1239  	left := []*Node{}
  1240  	for _, l := range n.List.Slice() {
  1241  		if !isblank(l) {
  1242  			tmp := ordertemp(l.Type, order, types.Haspointers(l.Type))
  1243  			tmplist = append(tmplist, tmp)
  1244  			left = append(left, l)
  1245  		}
  1246  	}
  1247  
  1248  	order.out = append(order.out, n)
  1249  
  1250  	as := nod(OAS2, nil, nil)
  1251  	as.List.Set(left)
  1252  	as.Rlist.Set(tmplist)
  1253  	as = typecheck(as, Etop)
  1254  	orderstmt(as, order)
  1255  
  1256  	ti := 0
  1257  	for ni, l := range n.List.Slice() {
  1258  		if !isblank(l) {
  1259  			n.List.SetIndex(ni, tmplist[ti])
  1260  			ti++
  1261  		}
  1262  	}
  1263  }
  1264  
  1265  // orderokas2 orders OAS2 with ok.
  1266  // Just like orderas2(), this also adds temporaries to ensure left-to-right assignment.
  1267  func orderokas2(n *Node, order *Order) {
  1268  	var tmp1, tmp2 *Node
  1269  	if !isblank(n.List.First()) {
  1270  		typ := n.Rlist.First().Type
  1271  		tmp1 = ordertemp(typ, order, types.Haspointers(typ))
  1272  	}
  1273  
  1274  	if !isblank(n.List.Second()) {
  1275  		tmp2 = ordertemp(types.Types[TBOOL], order, false)
  1276  	}
  1277  
  1278  	order.out = append(order.out, n)
  1279  
  1280  	if tmp1 != nil {
  1281  		r := nod(OAS, n.List.First(), tmp1)
  1282  		r = typecheck(r, Etop)
  1283  		ordermapassign(r, order)
  1284  		n.List.SetFirst(tmp1)
  1285  	}
  1286  	if tmp2 != nil {
  1287  		r := okas(n.List.Second(), tmp2)
  1288  		r = typecheck(r, Etop)
  1289  		ordermapassign(r, order)
  1290  		n.List.SetSecond(tmp2)
  1291  	}
  1292  }