github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/src/cmd/compile/internal/ssa/prove.go (about)

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