Home | History | Annotate | Download | only in ssa
      1 // Copyright 2016 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 ssa
      6 
      7 import (
      8 	"fmt"
      9 	"math"
     10 )
     11 
     12 type branch int
     13 
     14 const (
     15 	unknown = iota
     16 	positive
     17 	negative
     18 )
     19 
     20 // relation represents the set of possible relations between
     21 // pairs of variables (v, w). Without a priori knowledge the
     22 // mask is lt | eq | gt meaning v can be less than, equal to or
     23 // greater than w. When the execution path branches on the condition
     24 // `v op w` the set of relations is updated to exclude any
     25 // relation not possible due to `v op w` being true (or false).
     26 //
     27 // E.g.
     28 //
     29 // r := relation(...)
     30 //
     31 // if v < w {
     32 //   newR := r & lt
     33 // }
     34 // if v >= w {
     35 //   newR := r & (eq|gt)
     36 // }
     37 // if v != w {
     38 //   newR := r & (lt|gt)
     39 // }
     40 type relation uint
     41 
     42 const (
     43 	lt relation = 1 << iota
     44 	eq
     45 	gt
     46 )
     47 
     48 // domain represents the domain of a variable pair in which a set
     49 // of relations is known.  For example, relations learned for unsigned
     50 // pairs cannot be transferred to signed pairs because the same bit
     51 // representation can mean something else.
     52 type domain uint
     53 
     54 const (
     55 	signed domain = 1 << iota
     56 	unsigned
     57 	pointer
     58 	boolean
     59 )
     60 
     61 type pair struct {
     62 	v, w *Value // a pair of values, ordered by ID.
     63 	// v can be nil, to mean the zero value.
     64 	// for booleans the zero value (v == nil) is false.
     65 	d domain
     66 }
     67 
     68 // fact is a pair plus a relation for that pair.
     69 type fact struct {
     70 	p pair
     71 	r relation
     72 }
     73 
     74 // a limit records known upper and lower bounds for a value.
     75 type limit struct {
     76 	min, max   int64  // min <= value <= max, signed
     77 	umin, umax uint64 // umin <= value <= umax, unsigned
     78 }
     79 
     80 func (l limit) String() string {
     81 	return fmt.Sprintf("sm,SM,um,UM=%d,%d,%d,%d", l.min, l.max, l.umin, l.umax)
     82 }
     83 
     84 var noLimit = limit{math.MinInt64, math.MaxInt64, 0, math.MaxUint64}
     85 
     86 // a limitFact is a limit known for a particular value.
     87 type limitFact struct {
     88 	vid   ID
     89 	limit limit
     90 }
     91 
     92 // factsTable keeps track of relations between pairs of values.
     93 type factsTable struct {
     94 	facts map[pair]relation // current known set of relation
     95 	stack []fact            // previous sets of relations
     96 
     97 	// known lower and upper bounds on individual values.
     98 	limits     map[ID]limit
     99 	limitStack []limitFact // previous entries
    100 }
    101 
    102 // checkpointFact is an invalid value used for checkpointing
    103 // and restoring factsTable.
    104 var checkpointFact = fact{}
    105 var checkpointBound = limitFact{}
    106 
    107 func newFactsTable() *factsTable {
    108 	ft := &factsTable{}
    109 	ft.facts = make(map[pair]relation)
    110 	ft.stack = make([]fact, 4)
    111 	ft.limits = make(map[ID]limit)
    112 	ft.limitStack = make([]limitFact, 4)
    113 	return ft
    114 }
    115 
    116 // get returns the known possible relations between v and w.
    117 // If v and w are not in the map it returns lt|eq|gt, i.e. any order.
    118 func (ft *factsTable) get(v, w *Value, d domain) relation {
    119 	if v.isGenericIntConst() || w.isGenericIntConst() {
    120 		reversed := false
    121 		if v.isGenericIntConst() {
    122 			v, w = w, v
    123 			reversed = true
    124 		}
    125 		r := lt | eq | gt
    126 		lim, ok := ft.limits[v.ID]
    127 		if !ok {
    128 			return r
    129 		}
    130 		c := w.AuxInt
    131 		switch d {
    132 		case signed:
    133 			switch {
    134 			case c < lim.min:
    135 				r = gt
    136 			case c > lim.max:
    137 				r = lt
    138 			case c == lim.min && c == lim.max:
    139 				r = eq
    140 			case c == lim.min:
    141 				r = gt | eq
    142 			case c == lim.max:
    143 				r = lt | eq
    144 			}
    145 		case unsigned:
    146 			// TODO: also use signed data if lim.min >= 0?
    147 			var uc uint64
    148 			switch w.Op {
    149 			case OpConst64:
    150 				uc = uint64(c)
    151 			case OpConst32:
    152 				uc = uint64(uint32(c))
    153 			case OpConst16:
    154 				uc = uint64(uint16(c))
    155 			case OpConst8:
    156 				uc = uint64(uint8(c))
    157 			}
    158 			switch {
    159 			case uc < lim.umin:
    160 				r = gt
    161 			case uc > lim.umax:
    162 				r = lt
    163 			case uc == lim.umin && uc == lim.umax:
    164 				r = eq
    165 			case uc == lim.umin:
    166 				r = gt | eq
    167 			case uc == lim.umax:
    168 				r = lt | eq
    169 			}
    170 		}
    171 		if reversed {
    172 			return reverseBits[r]
    173 		}
    174 		return r
    175 	}
    176 
    177 	reversed := false
    178 	if lessByID(w, v) {
    179 		v, w = w, v
    180 		reversed = !reversed
    181 	}
    182 
    183 	p := pair{v, w, d}
    184 	r, ok := ft.facts[p]
    185 	if !ok {
    186 		if p.v == p.w {
    187 			r = eq
    188 		} else {
    189 			r = lt | eq | gt
    190 		}
    191 	}
    192 
    193 	if reversed {
    194 		return reverseBits[r]
    195 	}
    196 	return r
    197 }
    198 
    199 // update updates the set of relations between v and w in domain d
    200 // restricting it to r.
    201 func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
    202 	if lessByID(w, v) {
    203 		v, w = w, v
    204 		r = reverseBits[r]
    205 	}
    206 
    207 	p := pair{v, w, d}
    208 	oldR := ft.get(v, w, d)
    209 	ft.stack = append(ft.stack, fact{p, oldR})
    210 	ft.facts[p] = oldR & r
    211 
    212 	// Extract bounds when comparing against constants
    213 	if v.isGenericIntConst() {
    214 		v, w = w, v
    215 		r = reverseBits[r]
    216 	}
    217 	if v != nil && w.isGenericIntConst() {
    218 		c := w.AuxInt
    219 		// Note: all the +1/-1 below could overflow/underflow. Either will
    220 		// still generate correct results, it will just lead to imprecision.
    221 		// In fact if there is overflow/underflow, the corresponding
    222 		// code is unreachable because the known range is outside the range
    223 		// of the value's type.
    224 		old, ok := ft.limits[v.ID]
    225 		if !ok {
    226 			old = noLimit
    227 		}
    228 		lim := old
    229 		// Update lim with the new information we know.
    230 		switch d {
    231 		case signed:
    232 			switch r {
    233 			case lt:
    234 				if c-1 < lim.max {
    235 					lim.max = c - 1
    236 				}
    237 			case lt | eq:
    238 				if c < lim.max {
    239 					lim.max = c
    240 				}
    241 			case gt | eq:
    242 				if c > lim.min {
    243 					lim.min = c
    244 				}
    245 			case gt:
    246 				if c+1 > lim.min {
    247 					lim.min = c + 1
    248 				}
    249 			case lt | gt:
    250 				if c == lim.min {
    251 					lim.min++
    252 				}
    253 				if c == lim.max {
    254 					lim.max--
    255 				}
    256 			case eq:
    257 				lim.min = c
    258 				lim.max = c
    259 			}
    260 		case unsigned:
    261 			var uc uint64
    262 			switch w.Op {
    263 			case OpConst64:
    264 				uc = uint64(c)
    265 			case OpConst32:
    266 				uc = uint64(uint32(c))
    267 			case OpConst16:
    268 				uc = uint64(uint16(c))
    269 			case OpConst8:
    270 				uc = uint64(uint8(c))
    271 			}
    272 			switch r {
    273 			case lt:
    274 				if uc-1 < lim.umax {
    275 					lim.umax = uc - 1
    276 				}
    277 			case lt | eq:
    278 				if uc < lim.umax {
    279 					lim.umax = uc
    280 				}
    281 			case gt | eq:
    282 				if uc > lim.umin {
    283 					lim.umin = uc
    284 				}
    285 			case gt:
    286 				if uc+1 > lim.umin {
    287 					lim.umin = uc + 1
    288 				}
    289 			case lt | gt:
    290 				if uc == lim.umin {
    291 					lim.umin++
    292 				}
    293 				if uc == lim.umax {
    294 					lim.umax--
    295 				}
    296 			case eq:
    297 				lim.umin = uc
    298 				lim.umax = uc
    299 			}
    300 		}
    301 		ft.limitStack = append(ft.limitStack, limitFact{v.ID, old})
    302 		ft.limits[v.ID] = lim
    303 		if v.Block.Func.pass.debug > 2 {
    304 			v.Block.Func.Config.Warnl(parent.Line, "parent=%s, new limits %s %s %s", parent, v, w, lim.String())
    305 		}
    306 	}
    307 }
    308 
    309 // isNonNegative returns true if v is known to be non-negative.
    310 func (ft *factsTable) isNonNegative(v *Value) bool {
    311 	if isNonNegative(v) {
    312 		return true
    313 	}
    314 	l, has := ft.limits[v.ID]
    315 	return has && (l.min >= 0 || l.umax <= math.MaxInt64)
    316 }
    317 
    318 // checkpoint saves the current state of known relations.
    319 // Called when descending on a branch.
    320 func (ft *factsTable) checkpoint() {
    321 	ft.stack = append(ft.stack, checkpointFact)
    322 	ft.limitStack = append(ft.limitStack, checkpointBound)
    323 }
    324 
    325 // restore restores known relation to the state just
    326 // before the previous checkpoint.
    327 // Called when backing up on a branch.
    328 func (ft *factsTable) restore() {
    329 	for {
    330 		old := ft.stack[len(ft.stack)-1]
    331 		ft.stack = ft.stack[:len(ft.stack)-1]
    332 		if old == checkpointFact {
    333 			break
    334 		}
    335 		if old.r == lt|eq|gt {
    336 			delete(ft.facts, old.p)
    337 		} else {
    338 			ft.facts[old.p] = old.r
    339 		}
    340 	}
    341 	for {
    342 		old := ft.limitStack[len(ft.limitStack)-1]
    343 		ft.limitStack = ft.limitStack[:len(ft.limitStack)-1]
    344 		if old.vid == 0 { // checkpointBound
    345 			break
    346 		}
    347 		if old.limit == noLimit {
    348 			delete(ft.limits, old.vid)
    349 		} else {
    350 			ft.limits[old.vid] = old.limit
    351 		}
    352 	}
    353 }
    354 
    355 func lessByID(v, w *Value) bool {
    356 	if v == nil && w == nil {
    357 		// Should not happen, but just in case.
    358 		return false
    359 	}
    360 	if v == nil {
    361 		return true
    362 	}
    363 	return w != nil && v.ID < w.ID
    364 }
    365 
    366 var (
    367 	reverseBits = [...]relation{0, 4, 2, 6, 1, 5, 3, 7}
    368 
    369 	// maps what we learn when the positive branch is taken.
    370 	// For example:
    371 	//      OpLess8:   {signed, lt},
    372 	//	v1 = (OpLess8 v2 v3).
    373 	// If v1 branch is taken than we learn that the rangeMaks
    374 	// can be at most lt.
    375 	domainRelationTable = map[Op]struct {
    376 		d domain
    377 		r relation
    378 	}{
    379 		OpEq8:   {signed | unsigned, eq},
    380 		OpEq16:  {signed | unsigned, eq},
    381 		OpEq32:  {signed | unsigned, eq},
    382 		OpEq64:  {signed | unsigned, eq},
    383 		OpEqPtr: {pointer, eq},
    384 
    385 		OpNeq8:   {signed | unsigned, lt | gt},
    386 		OpNeq16:  {signed | unsigned, lt | gt},
    387 		OpNeq32:  {signed | unsigned, lt | gt},
    388 		OpNeq64:  {signed | unsigned, lt | gt},
    389 		OpNeqPtr: {pointer, lt | gt},
    390 
    391 		OpLess8:   {signed, lt},
    392 		OpLess8U:  {unsigned, lt},
    393 		OpLess16:  {signed, lt},
    394 		OpLess16U: {unsigned, lt},
    395 		OpLess32:  {signed, lt},
    396 		OpLess32U: {unsigned, lt},
    397 		OpLess64:  {signed, lt},
    398 		OpLess64U: {unsigned, lt},
    399 
    400 		OpLeq8:   {signed, lt | eq},
    401 		OpLeq8U:  {unsigned, lt | eq},
    402 		OpLeq16:  {signed, lt | eq},
    403 		OpLeq16U: {unsigned, lt | eq},
    404 		OpLeq32:  {signed, lt | eq},
    405 		OpLeq32U: {unsigned, lt | eq},
    406 		OpLeq64:  {signed, lt | eq},
    407 		OpLeq64U: {unsigned, lt | eq},
    408 
    409 		OpGeq8:   {signed, eq | gt},
    410 		OpGeq8U:  {unsigned, eq | gt},
    411 		OpGeq16:  {signed, eq | gt},
    412 		OpGeq16U: {unsigned, eq | gt},
    413 		OpGeq32:  {signed, eq | gt},
    414 		OpGeq32U: {unsigned, eq | gt},
    415 		OpGeq64:  {signed, eq | gt},
    416 		OpGeq64U: {unsigned, eq | gt},
    417 
    418 		OpGreater8:   {signed, gt},
    419 		OpGreater8U:  {unsigned, gt},
    420 		OpGreater16:  {signed, gt},
    421 		OpGreater16U: {unsigned, gt},
    422 		OpGreater32:  {signed, gt},
    423 		OpGreater32U: {unsigned, gt},
    424 		OpGreater64:  {signed, gt},
    425 		OpGreater64U: {unsigned, gt},
    426 
    427 		// TODO: OpIsInBounds actually test 0 <= a < b. This means
    428 		// that the positive branch learns signed/LT and unsigned/LT
    429 		// but the negative branch only learns unsigned/GE.
    430 		OpIsInBounds:      {unsigned, lt},
    431 		OpIsSliceInBounds: {unsigned, lt | eq},
    432 	}
    433 )
    434 
    435 // prove removes redundant BlockIf controls that can be inferred in a straight line.
    436 //
    437 // By far, the most common redundant pair are generated by bounds checking.
    438 // For example for the code:
    439 //
    440 //    a[i] = 4
    441 //    foo(a[i])
    442 //
    443 // The compiler will generate the following code:
    444 //
    445 //    if i >= len(a) {
    446 //        panic("not in bounds")
    447 //    }
    448 //    a[i] = 4
    449 //    if i >= len(a) {
    450 //        panic("not in bounds")
    451 //    }
    452 //    foo(a[i])
    453 //
    454 // The second comparison i >= len(a) is clearly redundant because if the
    455 // else branch of the first comparison is executed, we already know that i < len(a).
    456 // The code for the second panic can be removed.
    457 func prove(f *Func) {
    458 	// current node state
    459 	type walkState int
    460 	const (
    461 		descend walkState = iota
    462 		simplify
    463 	)
    464 	// work maintains the DFS stack.
    465 	type bp struct {
    466 		block *Block    // current handled block
    467 		state walkState // what's to do
    468 	}
    469 	work := make([]bp, 0, 256)
    470 	work = append(work, bp{
    471 		block: f.Entry,
    472 		state: descend,
    473 	})
    474 
    475 	ft := newFactsTable()
    476 	idom := f.Idom()
    477 	sdom := f.sdom()
    478 
    479 	// DFS on the dominator tree.
    480 	for len(work) > 0 {
    481 		node := work[len(work)-1]
    482 		work = work[:len(work)-1]
    483 		parent := idom[node.block.ID]
    484 		branch := getBranch(sdom, parent, node.block)
    485 
    486 		switch node.state {
    487 		case descend:
    488 			if branch != unknown {
    489 				ft.checkpoint()
    490 				c := parent.Control
    491 				updateRestrictions(parent, ft, boolean, nil, c, lt|gt, branch)
    492 				if tr, has := domainRelationTable[parent.Control.Op]; has {
    493 					// When we branched from parent we learned a new set of
    494 					// restrictions. Update the factsTable accordingly.
    495 					updateRestrictions(parent, ft, tr.d, c.Args[0], c.Args[1], tr.r, branch)
    496 				}
    497 			}
    498 
    499 			work = append(work, bp{
    500 				block: node.block,
    501 				state: simplify,
    502 			})
    503 			for s := sdom.Child(node.block); s != nil; s = sdom.Sibling(s) {
    504 				work = append(work, bp{
    505 					block: s,
    506 					state: descend,
    507 				})
    508 			}
    509 
    510 		case simplify:
    511 			succ := simplifyBlock(ft, node.block)
    512 			if succ != unknown {
    513 				b := node.block
    514 				b.Kind = BlockFirst
    515 				b.SetControl(nil)
    516 				if succ == negative {
    517 					b.swapSuccessors()
    518 				}
    519 			}
    520 
    521 			if branch != unknown {
    522 				ft.restore()
    523 			}
    524 		}
    525 	}
    526 }
    527 
    528 // getBranch returns the range restrictions added by p
    529 // when reaching b. p is the immediate dominator of b.
    530 func getBranch(sdom SparseTree, p *Block, b *Block) branch {
    531 	if p == nil || p.Kind != BlockIf {
    532 		return unknown
    533 	}
    534 	// If p and p.Succs[0] are dominators it means that every path
    535 	// from entry to b passes through p and p.Succs[0]. We care that
    536 	// no path from entry to b passes through p.Succs[1]. If p.Succs[0]
    537 	// has one predecessor then (apart from the degenerate case),
    538 	// there is no path from entry that can reach b through p.Succs[1].
    539 	// TODO: how about p->yes->b->yes, i.e. a loop in yes.
    540 	if sdom.isAncestorEq(p.Succs[0].b, b) && len(p.Succs[0].b.Preds) == 1 {
    541 		return positive
    542 	}
    543 	if sdom.isAncestorEq(p.Succs[1].b, b) && len(p.Succs[1].b.Preds) == 1 {
    544 		return negative
    545 	}
    546 	return unknown
    547 }
    548 
    549 // updateRestrictions updates restrictions from the immediate
    550 // dominating block (p) using r. r is adjusted according to the branch taken.
    551 func updateRestrictions(parent *Block, ft *factsTable, t domain, v, w *Value, r relation, branch branch) {
    552 	if t == 0 || branch == unknown {
    553 		// Trivial case: nothing to do, or branch unknown.
    554 		// Shoult not happen, but just in case.
    555 		return
    556 	}
    557 	if branch == negative {
    558 		// Negative branch taken, complement the relations.
    559 		r = (lt | eq | gt) ^ r
    560 	}
    561 	for i := domain(1); i <= t; i <<= 1 {
    562 		if t&i != 0 {
    563 			ft.update(parent, v, w, i, r)
    564 		}
    565 	}
    566 }
    567 
    568 // simplifyBlock simplifies block known the restrictions in ft.
    569 // Returns which branch must always be taken.
    570 func simplifyBlock(ft *factsTable, b *Block) branch {
    571 	for _, v := range b.Values {
    572 		if v.Op != OpSlicemask {
    573 			continue
    574 		}
    575 		add := v.Args[0]
    576 		if add.Op != OpAdd64 && add.Op != OpAdd32 {
    577 			continue
    578 		}
    579 		// Note that the arg of slicemask was originally a sub, but
    580 		// was rewritten to an add by generic.rules (if the thing
    581 		// being subtracted was a constant).
    582 		x := add.Args[0]
    583 		y := add.Args[1]
    584 		if x.Op == OpConst64 || x.Op == OpConst32 {
    585 			x, y = y, x
    586 		}
    587 		if y.Op != OpConst64 && y.Op != OpConst32 {
    588 			continue
    589 		}
    590 		// slicemask(x + y)
    591 		// if x is larger than -y (y is negative), then slicemask is -1.
    592 		lim, ok := ft.limits[x.ID]
    593 		if !ok {
    594 			continue
    595 		}
    596 		if lim.umin > uint64(-y.AuxInt) {
    597 			if v.Args[0].Op == OpAdd64 {
    598 				v.reset(OpConst64)
    599 			} else {
    600 				v.reset(OpConst32)
    601 			}
    602 			if b.Func.pass.debug > 0 {
    603 				b.Func.Config.Warnl(v.Line, "Proved slicemask not needed")
    604 			}
    605 			v.AuxInt = -1
    606 		}
    607 	}
    608 
    609 	if b.Kind != BlockIf {
    610 		return unknown
    611 	}
    612 
    613 	// First, checks if the condition itself is redundant.
    614 	m := ft.get(nil, b.Control, boolean)
    615 	if m == lt|gt {
    616 		if b.Func.pass.debug > 0 {
    617 			if b.Func.pass.debug > 1 {
    618 				b.Func.Config.Warnl(b.Line, "Proved boolean %s (%s)", b.Control.Op, b.Control)
    619 			} else {
    620 				b.Func.Config.Warnl(b.Line, "Proved boolean %s", b.Control.Op)
    621 			}
    622 		}
    623 		return positive
    624 	}
    625 	if m == eq {
    626 		if b.Func.pass.debug > 0 {
    627 			if b.Func.pass.debug > 1 {
    628 				b.Func.Config.Warnl(b.Line, "Disproved boolean %s (%s)", b.Control.Op, b.Control)
    629 			} else {
    630 				b.Func.Config.Warnl(b.Line, "Disproved boolean %s", b.Control.Op)
    631 			}
    632 		}
    633 		return negative
    634 	}
    635 
    636 	// Next look check equalities.
    637 	c := b.Control
    638 	tr, has := domainRelationTable[c.Op]
    639 	if !has {
    640 		return unknown
    641 	}
    642 
    643 	a0, a1 := c.Args[0], c.Args[1]
    644 	for d := domain(1); d <= tr.d; d <<= 1 {
    645 		if d&tr.d == 0 {
    646 			continue
    647 		}
    648 
    649 		// tr.r represents in which case the positive branch is taken.
    650 		// m represents which cases are possible because of previous relations.
    651 		// If the set of possible relations m is included in the set of relations
    652 		// need to take the positive branch (or negative) then that branch will
    653 		// always be taken.
    654 		// For shortcut, if m == 0 then this block is dead code.
    655 		m := ft.get(a0, a1, d)
    656 		if m != 0 && tr.r&m == m {
    657 			if b.Func.pass.debug > 0 {
    658 				if b.Func.pass.debug > 1 {
    659 					b.Func.Config.Warnl(b.Line, "Proved %s (%s)", c.Op, c)
    660 				} else {
    661 					b.Func.Config.Warnl(b.Line, "Proved %s", c.Op)
    662 				}
    663 			}
    664 			return positive
    665 		}
    666 		if m != 0 && ((lt|eq|gt)^tr.r)&m == m {
    667 			if b.Func.pass.debug > 0 {
    668 				if b.Func.pass.debug > 1 {
    669 					b.Func.Config.Warnl(b.Line, "Disproved %s (%s)", c.Op, c)
    670 				} else {
    671 					b.Func.Config.Warnl(b.Line, "Disproved %s", c.Op)
    672 				}
    673 			}
    674 			return negative
    675 		}
    676 	}
    677 
    678 	// HACK: If the first argument of IsInBounds or IsSliceInBounds
    679 	// is a constant and we already know that constant is smaller (or equal)
    680 	// to the upper bound than this is proven. Most useful in cases such as:
    681 	// if len(a) <= 1 { return }
    682 	// do something with a[1]
    683 	if (c.Op == OpIsInBounds || c.Op == OpIsSliceInBounds) && ft.isNonNegative(c.Args[0]) {
    684 		m := ft.get(a0, a1, signed)
    685 		if m != 0 && tr.r&m == m {
    686 			if b.Func.pass.debug > 0 {
    687 				if b.Func.pass.debug > 1 {
    688 					b.Func.Config.Warnl(b.Line, "Proved non-negative bounds %s (%s)", c.Op, c)
    689 				} else {
    690 					b.Func.Config.Warnl(b.Line, "Proved non-negative bounds %s", c.Op)
    691 				}
    692 			}
    693 			return positive
    694 		}
    695 	}
    696 
    697 	return unknown
    698 }
    699 
    700 // isNonNegative returns true is v is known to be greater or equal to zero.
    701 func isNonNegative(v *Value) bool {
    702 	switch v.Op {
    703 	case OpConst64:
    704 		return v.AuxInt >= 0
    705 
    706 	case OpConst32:
    707 		return int32(v.AuxInt) >= 0
    708 
    709 	case OpStringLen, OpSliceLen, OpSliceCap,
    710 		OpZeroExt8to64, OpZeroExt16to64, OpZeroExt32to64:
    711 		return true
    712 
    713 	case OpRsh64x64:
    714 		return isNonNegative(v.Args[0])
    715 	}
    716 	return false
    717 }
    718