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