Home | History | Annotate | Download | only in gc
      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 }
   1219