github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/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  	"github.com/gagliardetto/golang-go/cmd/compile/internal/types"
     9  	"github.com/gagliardetto/golang-go/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 types.Identical.
    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 newTemp 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("order.safeExpr %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) != CTxxx {
   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 s InitSchedule
   212  		s.staticassign(vstat, n)
   213  		if s.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.Name.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  // edge inserts coverage instrumentation for libfuzzer.
   328  func (o *Order) edge() {
   329  	if Debug_libfuzzer == 0 {
   330  		return
   331  	}
   332  
   333  	// Create a new uint8 counter to be allocated in section
   334  	// __libfuzzer_extra_counters.
   335  	counter := staticname(types.Types[TUINT8])
   336  	counter.Name.SetLibfuzzerExtraCounter(true)
   337  
   338  	// counter += 1
   339  	incr := nod(OASOP, counter, nodintconst(1))
   340  	incr.SetSubOp(OADD)
   341  	incr = typecheck(incr, ctxStmt)
   342  
   343  	o.out = append(o.out, incr)
   344  }
   345  
   346  // orderBlock orders the block of statements in n into a new slice,
   347  // and then replaces the old slice in n with the new slice.
   348  // free is a map that can be used to obtain temporary variables by type.
   349  func orderBlock(n *Nodes, free map[string][]*Node) {
   350  	var order Order
   351  	order.free = free
   352  	mark := order.markTemp()
   353  	order.edge()
   354  	order.stmtList(*n)
   355  	order.cleanTemp(mark)
   356  	n.Set(order.out)
   357  }
   358  
   359  // exprInPlace orders the side effects in *np and
   360  // leaves them as the init list of the final *np.
   361  // The result of exprInPlace MUST be assigned back to n, e.g.
   362  // 	n.Left = o.exprInPlace(n.Left)
   363  func (o *Order) exprInPlace(n *Node) *Node {
   364  	var order Order
   365  	order.free = o.free
   366  	n = order.expr(n, nil)
   367  	n = addinit(n, order.out)
   368  
   369  	// insert new temporaries from order
   370  	// at head of outer list.
   371  	o.temp = append(o.temp, order.temp...)
   372  	return n
   373  }
   374  
   375  // orderStmtInPlace orders the side effects of the single statement *np
   376  // and replaces it with the resulting statement list.
   377  // The result of orderStmtInPlace MUST be assigned back to n, e.g.
   378  // 	n.Left = orderStmtInPlace(n.Left)
   379  // free is a map that can be used to obtain temporary variables by type.
   380  func orderStmtInPlace(n *Node, free map[string][]*Node) *Node {
   381  	var order Order
   382  	order.free = free
   383  	mark := order.markTemp()
   384  	order.stmt(n)
   385  	order.cleanTemp(mark)
   386  	return liststmt(order.out)
   387  }
   388  
   389  // init moves n's init list to o.out.
   390  func (o *Order) init(n *Node) {
   391  	if n.mayBeShared() {
   392  		// For concurrency safety, don't mutate potentially shared nodes.
   393  		// First, ensure that no work is required here.
   394  		if n.Ninit.Len() > 0 {
   395  			Fatalf("order.init shared node with ninit")
   396  		}
   397  		return
   398  	}
   399  	o.stmtList(n.Ninit)
   400  	n.Ninit.Set(nil)
   401  }
   402  
   403  // call orders the call expression n.
   404  // n.Op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
   405  func (o *Order) call(n *Node) {
   406  	if n.Ninit.Len() > 0 {
   407  		// Caller should have already called o.init(n).
   408  		Fatalf("%v with unexpected ninit", n.Op)
   409  	}
   410  	n.Left = o.expr(n.Left, nil)
   411  	n.Right = o.expr(n.Right, nil) // ODDDARG temp
   412  	o.exprList(n.List)
   413  
   414  	if n.Op != OCALLFUNC && n.Op != OCALLMETH {
   415  		return
   416  	}
   417  	keepAlive := func(i int) {
   418  		// If the argument is really a pointer being converted to uintptr,
   419  		// arrange for the pointer to be kept alive until the call returns,
   420  		// by copying it into a temp and marking that temp
   421  		// still alive when we pop the temp stack.
   422  		xp := n.List.Addr(i)
   423  		for (*xp).Op == OCONVNOP && !(*xp).Type.IsUnsafePtr() {
   424  			xp = &(*xp).Left
   425  		}
   426  		x := *xp
   427  		if x.Type.IsUnsafePtr() {
   428  			x = o.copyExpr(x, x.Type, false)
   429  			x.Name.SetKeepalive(true)
   430  			*xp = x
   431  		}
   432  	}
   433  
   434  	for i, t := range n.Left.Type.Params().FieldSlice() {
   435  		// Check for "unsafe-uintptr" tag provided by escape analysis.
   436  		if t.IsDDD() && !n.IsDDD() {
   437  			if t.Note == uintptrEscapesTag {
   438  				for ; i < n.List.Len(); i++ {
   439  					keepAlive(i)
   440  				}
   441  			}
   442  		} else {
   443  			if t.Note == unsafeUintptrTag || t.Note == uintptrEscapesTag {
   444  				keepAlive(i)
   445  			}
   446  		}
   447  	}
   448  }
   449  
   450  // mapAssign appends n to o.out, introducing temporaries
   451  // to make sure that all map assignments have the form m[k] = x.
   452  // (Note: expr has already been called on n, so we know k is addressable.)
   453  //
   454  // If n is the multiple assignment form ..., m[k], ... = ..., x, ..., the rewrite is
   455  //	t1 = m
   456  //	t2 = k
   457  //	...., t3, ... = ..., x, ...
   458  //	t1[t2] = t3
   459  //
   460  // The temporaries t1, t2 are needed in case the ... being assigned
   461  // contain m or k. They are usually unnecessary, but in the unnecessary
   462  // cases they are also typically registerizable, so not much harm done.
   463  // And this only applies to the multiple-assignment form.
   464  // We could do a more precise analysis if needed, like in walk.go.
   465  func (o *Order) mapAssign(n *Node) {
   466  	switch n.Op {
   467  	default:
   468  		Fatalf("order.mapAssign %v", n.Op)
   469  
   470  	case OAS, OASOP:
   471  		if n.Left.Op == OINDEXMAP {
   472  			// Make sure we evaluate the RHS before starting the map insert.
   473  			// We need to make sure the RHS won't panic.  See issue 22881.
   474  			if n.Right.Op == OAPPEND {
   475  				s := n.Right.List.Slice()[1:]
   476  				for i, n := range s {
   477  					s[i] = o.cheapExpr(n)
   478  				}
   479  			} else {
   480  				n.Right = o.cheapExpr(n.Right)
   481  			}
   482  		}
   483  		o.out = append(o.out, n)
   484  
   485  	case OAS2, OAS2DOTTYPE, OAS2MAPR, OAS2FUNC:
   486  		var post []*Node
   487  		for i, m := range n.List.Slice() {
   488  			switch {
   489  			case m.Op == OINDEXMAP:
   490  				if !m.Left.IsAutoTmp() {
   491  					m.Left = o.copyExpr(m.Left, m.Left.Type, false)
   492  				}
   493  				if !m.Right.IsAutoTmp() {
   494  					m.Right = o.copyExpr(m.Right, m.Right.Type, false)
   495  				}
   496  				fallthrough
   497  			case instrumenting && n.Op == OAS2FUNC && !m.isBlank():
   498  				t := o.newTemp(m.Type, false)
   499  				n.List.SetIndex(i, t)
   500  				a := nod(OAS, m, t)
   501  				a = typecheck(a, ctxStmt)
   502  				post = append(post, a)
   503  			}
   504  		}
   505  
   506  		o.out = append(o.out, n)
   507  		o.out = append(o.out, post...)
   508  	}
   509  }
   510  
   511  // stmt orders the statement n, appending to o.out.
   512  // Temporaries created during the statement are cleaned
   513  // up using VARKILL instructions as possible.
   514  func (o *Order) stmt(n *Node) {
   515  	if n == nil {
   516  		return
   517  	}
   518  
   519  	lno := setlineno(n)
   520  	o.init(n)
   521  
   522  	switch n.Op {
   523  	default:
   524  		Fatalf("order.stmt %v", n.Op)
   525  
   526  	case OVARKILL, OVARLIVE, OINLMARK:
   527  		o.out = append(o.out, n)
   528  
   529  	case OAS:
   530  		t := o.markTemp()
   531  		n.Left = o.expr(n.Left, nil)
   532  		n.Right = o.expr(n.Right, n.Left)
   533  		o.mapAssign(n)
   534  		o.cleanTemp(t)
   535  
   536  	case OASOP:
   537  		t := o.markTemp()
   538  		n.Left = o.expr(n.Left, nil)
   539  		n.Right = o.expr(n.Right, nil)
   540  
   541  		if instrumenting || n.Left.Op == OINDEXMAP && (n.SubOp() == ODIV || n.SubOp() == OMOD) {
   542  			// Rewrite m[k] op= r into m[k] = m[k] op r so
   543  			// that we can ensure that if op panics
   544  			// because r is zero, the panic happens before
   545  			// the map assignment.
   546  
   547  			n.Left = o.safeExpr(n.Left)
   548  
   549  			l := treecopy(n.Left, src.NoXPos)
   550  			if l.Op == OINDEXMAP {
   551  				l.SetIndexMapLValue(false)
   552  			}
   553  			l = o.copyExpr(l, n.Left.Type, false)
   554  			n.Right = nod(n.SubOp(), l, n.Right)
   555  			n.Right = typecheck(n.Right, ctxExpr)
   556  			n.Right = o.expr(n.Right, nil)
   557  
   558  			n.Op = OAS
   559  			n.ResetAux()
   560  		}
   561  
   562  		o.mapAssign(n)
   563  		o.cleanTemp(t)
   564  
   565  	case OAS2:
   566  		t := o.markTemp()
   567  		o.exprList(n.List)
   568  		o.exprList(n.Rlist)
   569  		o.mapAssign(n)
   570  		o.cleanTemp(t)
   571  
   572  	// Special: avoid copy of func call n.Right
   573  	case OAS2FUNC:
   574  		t := o.markTemp()
   575  		o.exprList(n.List)
   576  		o.init(n.Right)
   577  		o.call(n.Right)
   578  		o.as2(n)
   579  		o.cleanTemp(t)
   580  
   581  	// Special: use temporary variables to hold result,
   582  	// so that runtime can take address of temporary.
   583  	// No temporary for blank assignment.
   584  	//
   585  	// OAS2MAPR: make sure key is addressable if needed,
   586  	//           and make sure OINDEXMAP is not copied out.
   587  	case OAS2DOTTYPE, OAS2RECV, OAS2MAPR:
   588  		t := o.markTemp()
   589  		o.exprList(n.List)
   590  
   591  		switch r := n.Right; r.Op {
   592  		case ODOTTYPE2, ORECV:
   593  			r.Left = o.expr(r.Left, nil)
   594  		case OINDEXMAP:
   595  			r.Left = o.expr(r.Left, nil)
   596  			r.Right = o.expr(r.Right, nil)
   597  			// See similar conversion for OINDEXMAP below.
   598  			_ = mapKeyReplaceStrConv(r.Right)
   599  			r.Right = o.mapKeyTemp(r.Left.Type, r.Right)
   600  		default:
   601  			Fatalf("order.stmt: %v", r.Op)
   602  		}
   603  
   604  		o.okAs2(n)
   605  		o.cleanTemp(t)
   606  
   607  	// Special: does not save n onto out.
   608  	case OBLOCK, OEMPTY:
   609  		o.stmtList(n.List)
   610  
   611  	// Special: n->left is not an expression; save as is.
   612  	case OBREAK,
   613  		OCONTINUE,
   614  		ODCL,
   615  		ODCLCONST,
   616  		ODCLTYPE,
   617  		OFALL,
   618  		OGOTO,
   619  		OLABEL,
   620  		ORETJMP:
   621  		o.out = append(o.out, n)
   622  
   623  	// Special: handle call arguments.
   624  	case OCALLFUNC, OCALLINTER, OCALLMETH:
   625  		t := o.markTemp()
   626  		o.call(n)
   627  		o.out = append(o.out, n)
   628  		o.cleanTemp(t)
   629  
   630  	case OCLOSE,
   631  		OCOPY,
   632  		OPRINT,
   633  		OPRINTN,
   634  		ORECOVER,
   635  		ORECV:
   636  		t := o.markTemp()
   637  		n.Left = o.expr(n.Left, nil)
   638  		n.Right = o.expr(n.Right, nil)
   639  		o.exprList(n.List)
   640  		o.exprList(n.Rlist)
   641  		o.out = append(o.out, n)
   642  		o.cleanTemp(t)
   643  
   644  	// Special: order arguments to inner call but not call itself.
   645  	case ODEFER, OGO:
   646  		t := o.markTemp()
   647  		o.init(n.Left)
   648  		o.call(n.Left)
   649  		o.out = append(o.out, n)
   650  		o.cleanTemp(t)
   651  
   652  	case ODELETE:
   653  		t := o.markTemp()
   654  		n.List.SetFirst(o.expr(n.List.First(), nil))
   655  		n.List.SetSecond(o.expr(n.List.Second(), nil))
   656  		n.List.SetSecond(o.mapKeyTemp(n.List.First().Type, n.List.Second()))
   657  		o.out = append(o.out, n)
   658  		o.cleanTemp(t)
   659  
   660  	// Clean temporaries from condition evaluation at
   661  	// beginning of loop body and after for statement.
   662  	case OFOR:
   663  		t := o.markTemp()
   664  		n.Left = o.exprInPlace(n.Left)
   665  		n.Nbody.Prepend(o.cleanTempNoPop(t)...)
   666  		orderBlock(&n.Nbody, o.free)
   667  		n.Right = orderStmtInPlace(n.Right, o.free)
   668  		o.out = append(o.out, n)
   669  		o.cleanTemp(t)
   670  
   671  	// Clean temporaries from condition at
   672  	// beginning of both branches.
   673  	case OIF:
   674  		t := o.markTemp()
   675  		n.Left = o.exprInPlace(n.Left)
   676  		n.Nbody.Prepend(o.cleanTempNoPop(t)...)
   677  		n.Rlist.Prepend(o.cleanTempNoPop(t)...)
   678  		o.popTemp(t)
   679  		orderBlock(&n.Nbody, o.free)
   680  		orderBlock(&n.Rlist, o.free)
   681  		o.out = append(o.out, n)
   682  
   683  	// Special: argument will be converted to interface using convT2E
   684  	// so make sure it is an addressable temporary.
   685  	case OPANIC:
   686  		t := o.markTemp()
   687  		n.Left = o.expr(n.Left, nil)
   688  		if !n.Left.Type.IsInterface() {
   689  			n.Left = o.addrTemp(n.Left)
   690  		}
   691  		o.out = append(o.out, n)
   692  		o.cleanTemp(t)
   693  
   694  	case ORANGE:
   695  		// n.Right is the expression being ranged over.
   696  		// order it, and then make a copy if we need one.
   697  		// We almost always do, to ensure that we don't
   698  		// see any value changes made during the loop.
   699  		// Usually the copy is cheap (e.g., array pointer,
   700  		// chan, slice, string are all tiny).
   701  		// The exception is ranging over an array value
   702  		// (not a slice, not a pointer to array),
   703  		// which must make a copy to avoid seeing updates made during
   704  		// the range body. Ranging over an array value is uncommon though.
   705  
   706  		// Mark []byte(str) range expression to reuse string backing storage.
   707  		// It is safe because the storage cannot be mutated.
   708  		if n.Right.Op == OSTR2BYTES {
   709  			n.Right.Op = OSTR2BYTESTMP
   710  		}
   711  
   712  		t := o.markTemp()
   713  		n.Right = o.expr(n.Right, nil)
   714  
   715  		orderBody := true
   716  		switch n.Type.Etype {
   717  		default:
   718  			Fatalf("order.stmt range %v", n.Type)
   719  
   720  		case TARRAY, TSLICE:
   721  			if n.List.Len() < 2 || n.List.Second().isBlank() {
   722  				// for i := range x will only use x once, to compute len(x).
   723  				// No need to copy it.
   724  				break
   725  			}
   726  			fallthrough
   727  
   728  		case TCHAN, TSTRING:
   729  			// chan, string, slice, array ranges use value multiple times.
   730  			// make copy.
   731  			r := n.Right
   732  
   733  			if r.Type.IsString() && r.Type != types.Types[TSTRING] {
   734  				r = nod(OCONV, r, nil)
   735  				r.Type = types.Types[TSTRING]
   736  				r = typecheck(r, ctxExpr)
   737  			}
   738  
   739  			n.Right = o.copyExpr(r, r.Type, false)
   740  
   741  		case TMAP:
   742  			if isMapClear(n) {
   743  				// Preserve the body of the map clear pattern so it can
   744  				// be detected during walk. The loop body will not be used
   745  				// when optimizing away the range loop to a runtime call.
   746  				orderBody = false
   747  				break
   748  			}
   749  
   750  			// copy the map value in case it is a map literal.
   751  			// TODO(rsc): Make tmp = literal expressions reuse tmp.
   752  			// For maps tmp is just one word so it hardly matters.
   753  			r := n.Right
   754  			n.Right = o.copyExpr(r, r.Type, false)
   755  
   756  			// prealloc[n] is the temp for the iterator.
   757  			// hiter contains pointers and needs to be zeroed.
   758  			prealloc[n] = o.newTemp(hiter(n.Type), true)
   759  		}
   760  		o.exprListInPlace(n.List)
   761  		if orderBody {
   762  			orderBlock(&n.Nbody, o.free)
   763  		}
   764  		o.out = append(o.out, n)
   765  		o.cleanTemp(t)
   766  
   767  	case ORETURN:
   768  		o.exprList(n.List)
   769  		o.out = append(o.out, n)
   770  
   771  	// Special: clean case temporaries in each block entry.
   772  	// Select must enter one of its blocks, so there is no
   773  	// need for a cleaning at the end.
   774  	// Doubly special: evaluation order for select is stricter
   775  	// than ordinary expressions. Even something like p.c
   776  	// has to be hoisted into a temporary, so that it cannot be
   777  	// reordered after the channel evaluation for a different
   778  	// case (if p were nil, then the timing of the fault would
   779  	// give this away).
   780  	case OSELECT:
   781  		t := o.markTemp()
   782  
   783  		for _, n2 := range n.List.Slice() {
   784  			if n2.Op != OCASE {
   785  				Fatalf("order select case %v", n2.Op)
   786  			}
   787  			r := n2.Left
   788  			setlineno(n2)
   789  
   790  			// Append any new body prologue to ninit.
   791  			// The next loop will insert ninit into nbody.
   792  			if n2.Ninit.Len() != 0 {
   793  				Fatalf("order select ninit")
   794  			}
   795  			if r == nil {
   796  				continue
   797  			}
   798  			switch r.Op {
   799  			default:
   800  				Dump("select case", r)
   801  				Fatalf("unknown op in select %v", r.Op)
   802  
   803  			// If this is case x := <-ch or case x, y := <-ch, the case has
   804  			// the ODCL nodes to declare x and y. We want to delay that
   805  			// declaration (and possible allocation) until inside the case body.
   806  			// Delete the ODCL nodes here and recreate them inside the body below.
   807  			case OSELRECV, OSELRECV2:
   808  				if r.Colas() {
   809  					i := 0
   810  					if r.Ninit.Len() != 0 && r.Ninit.First().Op == ODCL && r.Ninit.First().Left == r.Left {
   811  						i++
   812  					}
   813  					if i < r.Ninit.Len() && r.Ninit.Index(i).Op == ODCL && r.List.Len() != 0 && r.Ninit.Index(i).Left == r.List.First() {
   814  						i++
   815  					}
   816  					if i >= r.Ninit.Len() {
   817  						r.Ninit.Set(nil)
   818  					}
   819  				}
   820  
   821  				if r.Ninit.Len() != 0 {
   822  					dumplist("ninit", r.Ninit)
   823  					Fatalf("ninit on select recv")
   824  				}
   825  
   826  				// case x = <-c
   827  				// case x, ok = <-c
   828  				// r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c.
   829  				// r->left == N means 'case <-c'.
   830  				// c is always evaluated; x and ok are only evaluated when assigned.
   831  				r.Right.Left = o.expr(r.Right.Left, nil)
   832  
   833  				if r.Right.Left.Op != ONAME {
   834  					r.Right.Left = o.copyExpr(r.Right.Left, r.Right.Left.Type, false)
   835  				}
   836  
   837  				// Introduce temporary for receive and move actual copy into case body.
   838  				// avoids problems with target being addressed, as usual.
   839  				// NOTE: If we wanted to be clever, we could arrange for just one
   840  				// temporary per distinct type, sharing the temp among all receives
   841  				// with that temp. Similarly one ok bool could be shared among all
   842  				// the x,ok receives. Not worth doing until there's a clear need.
   843  				if r.Left != nil && r.Left.isBlank() {
   844  					r.Left = nil
   845  				}
   846  				if r.Left != nil {
   847  					// use channel element type for temporary to avoid conversions,
   848  					// such as in case interfacevalue = <-intchan.
   849  					// the conversion happens in the OAS instead.
   850  					tmp1 := r.Left
   851  
   852  					if r.Colas() {
   853  						tmp2 := nod(ODCL, tmp1, nil)
   854  						tmp2 = typecheck(tmp2, ctxStmt)
   855  						n2.Ninit.Append(tmp2)
   856  					}
   857  
   858  					r.Left = o.newTemp(r.Right.Left.Type.Elem(), types.Haspointers(r.Right.Left.Type.Elem()))
   859  					tmp2 := nod(OAS, tmp1, r.Left)
   860  					tmp2 = typecheck(tmp2, ctxStmt)
   861  					n2.Ninit.Append(tmp2)
   862  				}
   863  
   864  				if r.List.Len() != 0 && r.List.First().isBlank() {
   865  					r.List.Set(nil)
   866  				}
   867  				if r.List.Len() != 0 {
   868  					tmp1 := r.List.First()
   869  					if r.Colas() {
   870  						tmp2 := nod(ODCL, tmp1, nil)
   871  						tmp2 = typecheck(tmp2, ctxStmt)
   872  						n2.Ninit.Append(tmp2)
   873  					}
   874  
   875  					r.List.Set1(o.newTemp(types.Types[TBOOL], false))
   876  					tmp2 := okas(tmp1, r.List.First())
   877  					tmp2 = typecheck(tmp2, ctxStmt)
   878  					n2.Ninit.Append(tmp2)
   879  				}
   880  				orderBlock(&n2.Ninit, o.free)
   881  
   882  			case OSEND:
   883  				if r.Ninit.Len() != 0 {
   884  					dumplist("ninit", r.Ninit)
   885  					Fatalf("ninit on select send")
   886  				}
   887  
   888  				// case c <- x
   889  				// r->left is c, r->right is x, both are always evaluated.
   890  				r.Left = o.expr(r.Left, nil)
   891  
   892  				if !r.Left.IsAutoTmp() {
   893  					r.Left = o.copyExpr(r.Left, r.Left.Type, false)
   894  				}
   895  				r.Right = o.expr(r.Right, nil)
   896  				if !r.Right.IsAutoTmp() {
   897  					r.Right = o.copyExpr(r.Right, r.Right.Type, false)
   898  				}
   899  			}
   900  		}
   901  		// Now that we have accumulated all the temporaries, clean them.
   902  		// Also insert any ninit queued during the previous loop.
   903  		// (The temporary cleaning must follow that ninit work.)
   904  		for _, n3 := range n.List.Slice() {
   905  			orderBlock(&n3.Nbody, o.free)
   906  			n3.Nbody.Prepend(o.cleanTempNoPop(t)...)
   907  
   908  			// TODO(mdempsky): Is this actually necessary?
   909  			// walkselect appears to walk Ninit.
   910  			n3.Nbody.Prepend(n3.Ninit.Slice()...)
   911  			n3.Ninit.Set(nil)
   912  		}
   913  
   914  		o.out = append(o.out, n)
   915  		o.popTemp(t)
   916  
   917  	// Special: value being sent is passed as a pointer; make it addressable.
   918  	case OSEND:
   919  		t := o.markTemp()
   920  		n.Left = o.expr(n.Left, nil)
   921  		n.Right = o.expr(n.Right, nil)
   922  		if instrumenting {
   923  			// Force copying to the stack so that (chan T)(nil) <- x
   924  			// is still instrumented as a read of x.
   925  			n.Right = o.copyExpr(n.Right, n.Right.Type, false)
   926  		} else {
   927  			n.Right = o.addrTemp(n.Right)
   928  		}
   929  		o.out = append(o.out, n)
   930  		o.cleanTemp(t)
   931  
   932  	// TODO(rsc): Clean temporaries more aggressively.
   933  	// Note that because walkswitch will rewrite some of the
   934  	// switch into a binary search, this is not as easy as it looks.
   935  	// (If we ran that code here we could invoke order.stmt on
   936  	// the if-else chain instead.)
   937  	// For now just clean all the temporaries at the end.
   938  	// In practice that's fine.
   939  	case OSWITCH:
   940  		if Debug_libfuzzer != 0 && !hasDefaultCase(n) {
   941  			// Add empty "default:" case for instrumentation.
   942  			n.List.Append(nod(OCASE, nil, nil))
   943  		}
   944  
   945  		t := o.markTemp()
   946  		n.Left = o.expr(n.Left, nil)
   947  		for _, ncas := range n.List.Slice() {
   948  			if ncas.Op != OCASE {
   949  				Fatalf("order switch case %v", ncas.Op)
   950  			}
   951  			o.exprListInPlace(ncas.List)
   952  			orderBlock(&ncas.Nbody, o.free)
   953  		}
   954  
   955  		o.out = append(o.out, n)
   956  		o.cleanTemp(t)
   957  	}
   958  
   959  	lineno = lno
   960  }
   961  
   962  func hasDefaultCase(n *Node) bool {
   963  	for _, ncas := range n.List.Slice() {
   964  		if ncas.Op != OCASE {
   965  			Fatalf("expected case, found %v", ncas.Op)
   966  		}
   967  		if ncas.List.Len() == 0 {
   968  			return true
   969  		}
   970  	}
   971  	return false
   972  }
   973  
   974  // exprList orders the expression list l into o.
   975  func (o *Order) exprList(l Nodes) {
   976  	s := l.Slice()
   977  	for i := range s {
   978  		s[i] = o.expr(s[i], nil)
   979  	}
   980  }
   981  
   982  // exprListInPlace orders the expression list l but saves
   983  // the side effects on the individual expression ninit lists.
   984  func (o *Order) exprListInPlace(l Nodes) {
   985  	s := l.Slice()
   986  	for i := range s {
   987  		s[i] = o.exprInPlace(s[i])
   988  	}
   989  }
   990  
   991  // prealloc[x] records the allocation to use for x.
   992  var prealloc = map[*Node]*Node{}
   993  
   994  // expr orders a single expression, appending side
   995  // effects to o.out as needed.
   996  // If this is part of an assignment lhs = *np, lhs is given.
   997  // Otherwise lhs == nil. (When lhs != nil it may be possible
   998  // to avoid copying the result of the expression to a temporary.)
   999  // The result of expr MUST be assigned back to n, e.g.
  1000  // 	n.Left = o.expr(n.Left, lhs)
  1001  func (o *Order) expr(n, lhs *Node) *Node {
  1002  	if n == nil {
  1003  		return n
  1004  	}
  1005  
  1006  	lno := setlineno(n)
  1007  	o.init(n)
  1008  
  1009  	switch n.Op {
  1010  	default:
  1011  		n.Left = o.expr(n.Left, nil)
  1012  		n.Right = o.expr(n.Right, nil)
  1013  		o.exprList(n.List)
  1014  		o.exprList(n.Rlist)
  1015  
  1016  	// Addition of strings turns into a function call.
  1017  	// Allocate a temporary to hold the strings.
  1018  	// Fewer than 5 strings use direct runtime helpers.
  1019  	case OADDSTR:
  1020  		o.exprList(n.List)
  1021  
  1022  		if n.List.Len() > 5 {
  1023  			t := types.NewArray(types.Types[TSTRING], int64(n.List.Len()))
  1024  			prealloc[n] = o.newTemp(t, false)
  1025  		}
  1026  
  1027  		// Mark string(byteSlice) arguments to reuse byteSlice backing
  1028  		// buffer during conversion. String concatenation does not
  1029  		// memorize the strings for later use, so it is safe.
  1030  		// However, we can do it only if there is at least one non-empty string literal.
  1031  		// Otherwise if all other arguments are empty strings,
  1032  		// concatstrings will return the reference to the temp string
  1033  		// to the caller.
  1034  		hasbyte := false
  1035  
  1036  		haslit := false
  1037  		for _, n1 := range n.List.Slice() {
  1038  			hasbyte = hasbyte || n1.Op == OBYTES2STR
  1039  			haslit = haslit || n1.Op == OLITERAL && len(strlit(n1)) != 0
  1040  		}
  1041  
  1042  		if haslit && hasbyte {
  1043  			for _, n2 := range n.List.Slice() {
  1044  				if n2.Op == OBYTES2STR {
  1045  					n2.Op = OBYTES2STRTMP
  1046  				}
  1047  			}
  1048  		}
  1049  
  1050  	case OINDEXMAP:
  1051  		n.Left = o.expr(n.Left, nil)
  1052  		n.Right = o.expr(n.Right, nil)
  1053  		needCopy := false
  1054  
  1055  		if !n.IndexMapLValue() {
  1056  			// Enforce that any []byte slices we are not copying
  1057  			// can not be changed before the map index by forcing
  1058  			// the map index to happen immediately following the
  1059  			// conversions. See copyExpr a few lines below.
  1060  			needCopy = mapKeyReplaceStrConv(n.Right)
  1061  
  1062  			if instrumenting {
  1063  				// Race detector needs the copy so it can
  1064  				// call treecopy on the result.
  1065  				needCopy = true
  1066  			}
  1067  		}
  1068  
  1069  		// key must be addressable
  1070  		n.Right = o.mapKeyTemp(n.Left.Type, n.Right)
  1071  		if needCopy {
  1072  			n = o.copyExpr(n, n.Type, false)
  1073  		}
  1074  
  1075  	// concrete type (not interface) argument might need an addressable
  1076  	// temporary to pass to the runtime conversion routine.
  1077  	case OCONVIFACE:
  1078  		n.Left = o.expr(n.Left, nil)
  1079  		if n.Left.Type.IsInterface() {
  1080  			break
  1081  		}
  1082  		if _, needsaddr := convFuncName(n.Left.Type, n.Type); needsaddr || isStaticCompositeLiteral(n.Left) {
  1083  			// Need a temp if we need to pass the address to the conversion function.
  1084  			// We also process static composite literal node here, making a named static global
  1085  			// whose address we can put directly in an interface (see OCONVIFACE case in walk).
  1086  			n.Left = o.addrTemp(n.Left)
  1087  		}
  1088  
  1089  	case OCONVNOP:
  1090  		if n.Type.IsKind(TUNSAFEPTR) && n.Left.Type.IsKind(TUINTPTR) && (n.Left.Op == OCALLFUNC || n.Left.Op == OCALLINTER || n.Left.Op == OCALLMETH) {
  1091  			// When reordering unsafe.Pointer(f()) into a separate
  1092  			// statement, the conversion and function call must stay
  1093  			// together. See golang.org/issue/15329.
  1094  			o.init(n.Left)
  1095  			o.call(n.Left)
  1096  			if lhs == nil || lhs.Op != ONAME || instrumenting {
  1097  				n = o.copyExpr(n, n.Type, false)
  1098  			}
  1099  		} else {
  1100  			n.Left = o.expr(n.Left, nil)
  1101  		}
  1102  
  1103  	case OANDAND, OOROR:
  1104  		// ... = LHS && RHS
  1105  		//
  1106  		// var r bool
  1107  		// r = LHS
  1108  		// if r {       // or !r, for OROR
  1109  		//     r = RHS
  1110  		// }
  1111  		// ... = r
  1112  
  1113  		r := o.newTemp(n.Type, false)
  1114  
  1115  		// Evaluate left-hand side.
  1116  		lhs := o.expr(n.Left, nil)
  1117  		o.out = append(o.out, typecheck(nod(OAS, r, lhs), ctxStmt))
  1118  
  1119  		// Evaluate right-hand side, save generated code.
  1120  		saveout := o.out
  1121  		o.out = nil
  1122  		t := o.markTemp()
  1123  		o.edge()
  1124  		rhs := o.expr(n.Right, nil)
  1125  		o.out = append(o.out, typecheck(nod(OAS, r, rhs), ctxStmt))
  1126  		o.cleanTemp(t)
  1127  		gen := o.out
  1128  		o.out = saveout
  1129  
  1130  		// If left-hand side doesn't cause a short-circuit, issue right-hand side.
  1131  		nif := nod(OIF, r, nil)
  1132  		if n.Op == OANDAND {
  1133  			nif.Nbody.Set(gen)
  1134  		} else {
  1135  			nif.Rlist.Set(gen)
  1136  		}
  1137  		o.out = append(o.out, nif)
  1138  		n = r
  1139  
  1140  	case OCALLFUNC,
  1141  		OCALLINTER,
  1142  		OCALLMETH,
  1143  		OCAP,
  1144  		OCOMPLEX,
  1145  		OCOPY,
  1146  		OIMAG,
  1147  		OLEN,
  1148  		OMAKECHAN,
  1149  		OMAKEMAP,
  1150  		OMAKESLICE,
  1151  		ONEW,
  1152  		OREAL,
  1153  		ORECOVER,
  1154  		OSTR2BYTES,
  1155  		OSTR2BYTESTMP,
  1156  		OSTR2RUNES:
  1157  
  1158  		if isRuneCount(n) {
  1159  			// len([]rune(s)) is rewritten to runtime.countrunes(s) later.
  1160  			n.Left.Left = o.expr(n.Left.Left, nil)
  1161  		} else {
  1162  			o.call(n)
  1163  		}
  1164  
  1165  		if lhs == nil || lhs.Op != ONAME || instrumenting {
  1166  			n = o.copyExpr(n, n.Type, false)
  1167  		}
  1168  
  1169  	case OAPPEND:
  1170  		// Check for append(x, make([]T, y)...) .
  1171  		if isAppendOfMake(n) {
  1172  			n.List.SetFirst(o.expr(n.List.First(), nil))             // order x
  1173  			n.List.Second().Left = o.expr(n.List.Second().Left, nil) // order y
  1174  		} else {
  1175  			o.exprList(n.List)
  1176  		}
  1177  
  1178  		if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.First()) {
  1179  			n = o.copyExpr(n, n.Type, false)
  1180  		}
  1181  
  1182  	case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
  1183  		n.Left = o.expr(n.Left, nil)
  1184  		low, high, max := n.SliceBounds()
  1185  		low = o.expr(low, nil)
  1186  		low = o.cheapExpr(low)
  1187  		high = o.expr(high, nil)
  1188  		high = o.cheapExpr(high)
  1189  		max = o.expr(max, nil)
  1190  		max = o.cheapExpr(max)
  1191  		n.SetSliceBounds(low, high, max)
  1192  		if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) {
  1193  			n = o.copyExpr(n, n.Type, false)
  1194  		}
  1195  
  1196  	case OCLOSURE:
  1197  		if n.Transient() && n.Func.Closure.Func.Cvars.Len() > 0 {
  1198  			prealloc[n] = o.newTemp(closureType(n), false)
  1199  		}
  1200  
  1201  	case OSLICELIT, OCALLPART:
  1202  		n.Left = o.expr(n.Left, nil)
  1203  		n.Right = o.expr(n.Right, nil)
  1204  		o.exprList(n.List)
  1205  		o.exprList(n.Rlist)
  1206  		if n.Transient() {
  1207  			var t *types.Type
  1208  			switch n.Op {
  1209  			case OSLICELIT:
  1210  				t = types.NewArray(n.Type.Elem(), n.Right.Int64())
  1211  			case OCALLPART:
  1212  				t = partialCallType(n)
  1213  			}
  1214  			prealloc[n] = o.newTemp(t, false)
  1215  		}
  1216  
  1217  	case ODDDARG:
  1218  		if n.Transient() {
  1219  			// The ddd argument does not live beyond the call it is created for.
  1220  			// Allocate a temporary that will be cleaned up when this statement
  1221  			// completes. We could be more aggressive and try to arrange for it
  1222  			// to be cleaned up when the call completes.
  1223  			prealloc[n] = o.newTemp(n.Type.Elem(), false)
  1224  		}
  1225  
  1226  	case ODOTTYPE, ODOTTYPE2:
  1227  		n.Left = o.expr(n.Left, nil)
  1228  		if !isdirectiface(n.Type) || instrumenting {
  1229  			n = o.copyExpr(n, n.Type, true)
  1230  		}
  1231  
  1232  	case ORECV:
  1233  		n.Left = o.expr(n.Left, nil)
  1234  		n = o.copyExpr(n, n.Type, true)
  1235  
  1236  	case OEQ, ONE, OLT, OLE, OGT, OGE:
  1237  		n.Left = o.expr(n.Left, nil)
  1238  		n.Right = o.expr(n.Right, nil)
  1239  
  1240  		t := n.Left.Type
  1241  		switch {
  1242  		case t.IsString():
  1243  			// Mark string(byteSlice) arguments to reuse byteSlice backing
  1244  			// buffer during conversion. String comparison does not
  1245  			// memorize the strings for later use, so it is safe.
  1246  			if n.Left.Op == OBYTES2STR {
  1247  				n.Left.Op = OBYTES2STRTMP
  1248  			}
  1249  			if n.Right.Op == OBYTES2STR {
  1250  				n.Right.Op = OBYTES2STRTMP
  1251  			}
  1252  
  1253  		case t.IsStruct() || t.IsArray():
  1254  			// for complex comparisons, we need both args to be
  1255  			// addressable so we can pass them to the runtime.
  1256  			n.Left = o.addrTemp(n.Left)
  1257  			n.Right = o.addrTemp(n.Right)
  1258  		}
  1259  	case OMAPLIT:
  1260  		// Order map by converting:
  1261  		//   map[int]int{
  1262  		//     a(): b(),
  1263  		//     c(): d(),
  1264  		//     e(): f(),
  1265  		//   }
  1266  		// to
  1267  		//   m := map[int]int{}
  1268  		//   m[a()] = b()
  1269  		//   m[c()] = d()
  1270  		//   m[e()] = f()
  1271  		// Then order the result.
  1272  		// Without this special case, order would otherwise compute all
  1273  		// the keys and values before storing any of them to the map.
  1274  		// See issue 26552.
  1275  		entries := n.List.Slice()
  1276  		statics := entries[:0]
  1277  		var dynamics []*Node
  1278  		for _, r := range entries {
  1279  			if r.Op != OKEY {
  1280  				Fatalf("OMAPLIT entry not OKEY: %v\n", r)
  1281  			}
  1282  
  1283  			if !isStaticCompositeLiteral(r.Left) || !isStaticCompositeLiteral(r.Right) {
  1284  				dynamics = append(dynamics, r)
  1285  				continue
  1286  			}
  1287  
  1288  			// Recursively ordering some static entries can change them to dynamic;
  1289  			// e.g., OCONVIFACE nodes. See #31777.
  1290  			r = o.expr(r, nil)
  1291  			if !isStaticCompositeLiteral(r.Left) || !isStaticCompositeLiteral(r.Right) {
  1292  				dynamics = append(dynamics, r)
  1293  				continue
  1294  			}
  1295  
  1296  			statics = append(statics, r)
  1297  		}
  1298  		n.List.Set(statics)
  1299  
  1300  		if len(dynamics) == 0 {
  1301  			break
  1302  		}
  1303  
  1304  		// Emit the creation of the map (with all its static entries).
  1305  		m := o.newTemp(n.Type, false)
  1306  		as := nod(OAS, m, n)
  1307  		typecheck(as, ctxStmt)
  1308  		o.stmt(as)
  1309  		n = m
  1310  
  1311  		// Emit eval+insert of dynamic entries, one at a time.
  1312  		for _, r := range dynamics {
  1313  			as := nod(OAS, nod(OINDEX, n, r.Left), r.Right)
  1314  			typecheck(as, ctxStmt) // Note: this converts the OINDEX to an OINDEXMAP
  1315  			o.stmt(as)
  1316  		}
  1317  	}
  1318  
  1319  	lineno = lno
  1320  	return n
  1321  }
  1322  
  1323  // okas creates and returns an assignment of val to ok,
  1324  // including an explicit conversion if necessary.
  1325  func okas(ok, val *Node) *Node {
  1326  	if !ok.isBlank() {
  1327  		val = conv(val, ok.Type)
  1328  	}
  1329  	return nod(OAS, ok, val)
  1330  }
  1331  
  1332  // as2 orders OAS2XXXX nodes. It creates temporaries to ensure left-to-right assignment.
  1333  // The caller should order the right-hand side of the assignment before calling order.as2.
  1334  // It rewrites,
  1335  // 	a, b, a = ...
  1336  // as
  1337  //	tmp1, tmp2, tmp3 = ...
  1338  // 	a, b, a = tmp1, tmp2, tmp3
  1339  // This is necessary to ensure left to right assignment order.
  1340  func (o *Order) as2(n *Node) {
  1341  	tmplist := []*Node{}
  1342  	left := []*Node{}
  1343  	for ni, l := range n.List.Slice() {
  1344  		if !l.isBlank() {
  1345  			tmp := o.newTemp(l.Type, types.Haspointers(l.Type))
  1346  			n.List.SetIndex(ni, tmp)
  1347  			tmplist = append(tmplist, tmp)
  1348  			left = append(left, l)
  1349  		}
  1350  	}
  1351  
  1352  	o.out = append(o.out, n)
  1353  
  1354  	as := nod(OAS2, nil, nil)
  1355  	as.List.Set(left)
  1356  	as.Rlist.Set(tmplist)
  1357  	as = typecheck(as, ctxStmt)
  1358  	o.stmt(as)
  1359  }
  1360  
  1361  // okAs2 orders OAS2XXX with ok.
  1362  // Just like as2, this also adds temporaries to ensure left-to-right assignment.
  1363  func (o *Order) okAs2(n *Node) {
  1364  	var tmp1, tmp2 *Node
  1365  	if !n.List.First().isBlank() {
  1366  		typ := n.Right.Type
  1367  		tmp1 = o.newTemp(typ, types.Haspointers(typ))
  1368  	}
  1369  
  1370  	if !n.List.Second().isBlank() {
  1371  		tmp2 = o.newTemp(types.Types[TBOOL], false)
  1372  	}
  1373  
  1374  	o.out = append(o.out, n)
  1375  
  1376  	if tmp1 != nil {
  1377  		r := nod(OAS, n.List.First(), tmp1)
  1378  		r = typecheck(r, ctxStmt)
  1379  		o.mapAssign(r)
  1380  		n.List.SetFirst(tmp1)
  1381  	}
  1382  	if tmp2 != nil {
  1383  		r := okas(n.List.Second(), tmp2)
  1384  		r = typecheck(r, ctxStmt)
  1385  		o.mapAssign(r)
  1386  		n.List.SetSecond(tmp2)
  1387  	}
  1388  }