github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/src/cmd/compile/internal/gc/order.go (about)

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