...

Source file src/pkg/cmd/compile/internal/gc/order.go

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

View as plain text