github.com/bir3/gocompiler@v0.3.205/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  	"github.com/bir3/gocompiler/src/cmd/internal/src"
     9  	"fmt"
    10  	"math"
    11  )
    12  
    13  type branch int
    14  
    15  const (
    16  	unknown branch = iota
    17  	positive
    18  	negative
    19  	// The outedges from a jump table are jumpTable0,
    20  	// jumpTable0+1, jumpTable0+2, etc. There could be an
    21  	// arbitrary number so we can't list them all here.
    22  	jumpTable0
    23  )
    24  
    25  // relation represents the set of possible relations between
    26  // pairs of variables (v, w). Without a priori knowledge the
    27  // mask is lt | eq | gt meaning v can be less than, equal to or
    28  // greater than w. When the execution path branches on the condition
    29  // `v op w` the set of relations is updated to exclude any
    30  // relation not possible due to `v op w` being true (or false).
    31  //
    32  // E.g.
    33  //
    34  //	r := relation(...)
    35  //
    36  //	if v < w {
    37  //	  newR := r & lt
    38  //	}
    39  //	if v >= w {
    40  //	  newR := r & (eq|gt)
    41  //	}
    42  //	if v != w {
    43  //	  newR := r & (lt|gt)
    44  //	}
    45  type relation uint
    46  
    47  const (
    48  	lt relation = 1 << iota
    49  	eq
    50  	gt
    51  )
    52  
    53  var relationStrings = [...]string{
    54  	0: "none", lt: "<", eq: "==", lt | eq: "<=",
    55  	gt: ">", gt | lt: "!=", gt | eq: ">=", gt | eq | lt: "any",
    56  }
    57  
    58  func (r relation) String() string {
    59  	if r < relation(len(relationStrings)) {
    60  		return relationStrings[r]
    61  	}
    62  	return fmt.Sprintf("relation(%d)", uint(r))
    63  }
    64  
    65  // domain represents the domain of a variable pair in which a set
    66  // of relations is known. For example, relations learned for unsigned
    67  // pairs cannot be transferred to signed pairs because the same bit
    68  // representation can mean something else.
    69  type domain uint
    70  
    71  const (
    72  	signed domain = 1 << iota
    73  	unsigned
    74  	pointer
    75  	boolean
    76  )
    77  
    78  var domainStrings = [...]string{
    79  	"signed", "unsigned", "pointer", "boolean",
    80  }
    81  
    82  func (d domain) String() string {
    83  	s := ""
    84  	for i, ds := range domainStrings {
    85  		if d&(1<<uint(i)) != 0 {
    86  			if len(s) != 0 {
    87  				s += "|"
    88  			}
    89  			s += ds
    90  			d &^= 1 << uint(i)
    91  		}
    92  	}
    93  	if d != 0 {
    94  		if len(s) != 0 {
    95  			s += "|"
    96  		}
    97  		s += fmt.Sprintf("0x%x", uint(d))
    98  	}
    99  	return s
   100  }
   101  
   102  type pair struct {
   103  	v, w *Value // a pair of values, ordered by ID.
   104  	// v can be nil, to mean the zero value.
   105  	// for booleans the zero value (v == nil) is false.
   106  	d domain
   107  }
   108  
   109  // fact is a pair plus a relation for that pair.
   110  type fact struct {
   111  	p pair
   112  	r relation
   113  }
   114  
   115  // a limit records known upper and lower bounds for a value.
   116  type limit struct {
   117  	min, max   int64  // min <= value <= max, signed
   118  	umin, umax uint64 // umin <= value <= umax, unsigned
   119  }
   120  
   121  func (l limit) String() string {
   122  	return fmt.Sprintf("sm,SM,um,UM=%d,%d,%d,%d", l.min, l.max, l.umin, l.umax)
   123  }
   124  
   125  func (l limit) intersect(l2 limit) limit {
   126  	if l.min < l2.min {
   127  		l.min = l2.min
   128  	}
   129  	if l.umin < l2.umin {
   130  		l.umin = l2.umin
   131  	}
   132  	if l.max > l2.max {
   133  		l.max = l2.max
   134  	}
   135  	if l.umax > l2.umax {
   136  		l.umax = l2.umax
   137  	}
   138  	return l
   139  }
   140  
   141  var noLimit = limit{math.MinInt64, math.MaxInt64, 0, math.MaxUint64}
   142  
   143  // a limitFact is a limit known for a particular value.
   144  type limitFact struct {
   145  	vid   ID
   146  	limit limit
   147  }
   148  
   149  // factsTable keeps track of relations between pairs of values.
   150  //
   151  // The fact table logic is sound, but incomplete. Outside of a few
   152  // special cases, it performs no deduction or arithmetic. While there
   153  // are known decision procedures for this, the ad hoc approach taken
   154  // by the facts table is effective for real code while remaining very
   155  // efficient.
   156  type factsTable struct {
   157  	// unsat is true if facts contains a contradiction.
   158  	//
   159  	// Note that the factsTable logic is incomplete, so if unsat
   160  	// is false, the assertions in factsTable could be satisfiable
   161  	// *or* unsatisfiable.
   162  	unsat      bool // true if facts contains a contradiction
   163  	unsatDepth int  // number of unsat checkpoints
   164  
   165  	facts map[pair]relation // current known set of relation
   166  	stack []fact            // previous sets of relations
   167  
   168  	// order is a couple of partial order sets that record information
   169  	// about relations between SSA values in the signed and unsigned
   170  	// domain.
   171  	orderS *poset
   172  	orderU *poset
   173  
   174  	// known lower and upper bounds on individual values.
   175  	limits     map[ID]limit
   176  	limitStack []limitFact // previous entries
   177  
   178  	// For each slice s, a map from s to a len(s)/cap(s) value (if any)
   179  	// TODO: check if there are cases that matter where we have
   180  	// more than one len(s) for a slice. We could keep a list if necessary.
   181  	lens map[ID]*Value
   182  	caps map[ID]*Value
   183  
   184  	// zero is a zero-valued constant
   185  	zero *Value
   186  }
   187  
   188  // checkpointFact is an invalid value used for checkpointing
   189  // and restoring factsTable.
   190  var checkpointFact = fact{}
   191  var checkpointBound = limitFact{}
   192  
   193  func newFactsTable(f *Func) *factsTable {
   194  	ft := &factsTable{}
   195  	ft.orderS = f.newPoset()
   196  	ft.orderU = f.newPoset()
   197  	ft.orderS.SetUnsigned(false)
   198  	ft.orderU.SetUnsigned(true)
   199  	ft.facts = make(map[pair]relation)
   200  	ft.stack = make([]fact, 4)
   201  	ft.limits = make(map[ID]limit)
   202  	ft.limitStack = make([]limitFact, 4)
   203  	ft.zero = f.ConstInt64(f.Config.Types.Int64, 0)
   204  	return ft
   205  }
   206  
   207  // update updates the set of relations between v and w in domain d
   208  // restricting it to r.
   209  func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
   210  	if parent.Func.pass.debug > 2 {
   211  		parent.Func.Warnl(parent.Pos, "parent=%s, update %s %s %s", parent, v, w, r)
   212  	}
   213  	// No need to do anything else if we already found unsat.
   214  	if ft.unsat {
   215  		return
   216  	}
   217  
   218  	// Self-fact. It's wasteful to register it into the facts
   219  	// table, so just note whether it's satisfiable
   220  	if v == w {
   221  		if r&eq == 0 {
   222  			ft.unsat = true
   223  		}
   224  		return
   225  	}
   226  
   227  	if d == signed || d == unsigned {
   228  		var ok bool
   229  		order := ft.orderS
   230  		if d == unsigned {
   231  			order = ft.orderU
   232  		}
   233  		switch r {
   234  		case lt:
   235  			ok = order.SetOrder(v, w)
   236  		case gt:
   237  			ok = order.SetOrder(w, v)
   238  		case lt | eq:
   239  			ok = order.SetOrderOrEqual(v, w)
   240  		case gt | eq:
   241  			ok = order.SetOrderOrEqual(w, v)
   242  		case eq:
   243  			ok = order.SetEqual(v, w)
   244  		case lt | gt:
   245  			ok = order.SetNonEqual(v, w)
   246  		default:
   247  			panic("unknown relation")
   248  		}
   249  		if !ok {
   250  			if parent.Func.pass.debug > 2 {
   251  				parent.Func.Warnl(parent.Pos, "unsat %s %s %s", v, w, r)
   252  			}
   253  			ft.unsat = true
   254  			return
   255  		}
   256  	} else {
   257  		if lessByID(w, v) {
   258  			v, w = w, v
   259  			r = reverseBits[r]
   260  		}
   261  
   262  		p := pair{v, w, d}
   263  		oldR, ok := ft.facts[p]
   264  		if !ok {
   265  			if v == w {
   266  				oldR = eq
   267  			} else {
   268  				oldR = lt | eq | gt
   269  			}
   270  		}
   271  		// No changes compared to information already in facts table.
   272  		if oldR == r {
   273  			return
   274  		}
   275  		ft.stack = append(ft.stack, fact{p, oldR})
   276  		ft.facts[p] = oldR & r
   277  		// If this relation is not satisfiable, mark it and exit right away
   278  		if oldR&r == 0 {
   279  			if parent.Func.pass.debug > 2 {
   280  				parent.Func.Warnl(parent.Pos, "unsat %s %s %s", v, w, r)
   281  			}
   282  			ft.unsat = true
   283  			return
   284  		}
   285  	}
   286  
   287  	// Extract bounds when comparing against constants
   288  	if v.isGenericIntConst() {
   289  		v, w = w, v
   290  		r = reverseBits[r]
   291  	}
   292  	if v != nil && w.isGenericIntConst() {
   293  		// Note: all the +1/-1 below could overflow/underflow. Either will
   294  		// still generate correct results, it will just lead to imprecision.
   295  		// In fact if there is overflow/underflow, the corresponding
   296  		// code is unreachable because the known range is outside the range
   297  		// of the value's type.
   298  		old, ok := ft.limits[v.ID]
   299  		if !ok {
   300  			old = noLimit
   301  			if v.isGenericIntConst() {
   302  				switch d {
   303  				case signed:
   304  					old.min, old.max = v.AuxInt, v.AuxInt
   305  					if v.AuxInt >= 0 {
   306  						old.umin, old.umax = uint64(v.AuxInt), uint64(v.AuxInt)
   307  					}
   308  				case unsigned:
   309  					old.umin = v.AuxUnsigned()
   310  					old.umax = old.umin
   311  					if int64(old.umin) >= 0 {
   312  						old.min, old.max = int64(old.umin), int64(old.umin)
   313  					}
   314  				}
   315  			}
   316  		}
   317  		lim := noLimit
   318  		switch d {
   319  		case signed:
   320  			c := w.AuxInt
   321  			switch r {
   322  			case lt:
   323  				lim.max = c - 1
   324  			case lt | eq:
   325  				lim.max = c
   326  			case gt | eq:
   327  				lim.min = c
   328  			case gt:
   329  				lim.min = c + 1
   330  			case lt | gt:
   331  				lim = old
   332  				if c == lim.min {
   333  					lim.min++
   334  				}
   335  				if c == lim.max {
   336  					lim.max--
   337  				}
   338  			case eq:
   339  				lim.min = c
   340  				lim.max = c
   341  			}
   342  			if lim.min >= 0 {
   343  				// int(x) >= 0 && int(x) >= N  ⇒  uint(x) >= N
   344  				lim.umin = uint64(lim.min)
   345  			}
   346  			if lim.max != noLimit.max && old.min >= 0 && lim.max >= 0 {
   347  				// 0 <= int(x) <= N  ⇒  0 <= uint(x) <= N
   348  				// This is for a max update, so the lower bound
   349  				// comes from what we already know (old).
   350  				lim.umax = uint64(lim.max)
   351  			}
   352  		case unsigned:
   353  			uc := w.AuxUnsigned()
   354  			switch r {
   355  			case lt:
   356  				lim.umax = uc - 1
   357  			case lt | eq:
   358  				lim.umax = uc
   359  			case gt | eq:
   360  				lim.umin = uc
   361  			case gt:
   362  				lim.umin = uc + 1
   363  			case lt | gt:
   364  				lim = old
   365  				if uc == lim.umin {
   366  					lim.umin++
   367  				}
   368  				if uc == lim.umax {
   369  					lim.umax--
   370  				}
   371  			case eq:
   372  				lim.umin = uc
   373  				lim.umax = uc
   374  			}
   375  			// We could use the contrapositives of the
   376  			// signed implications to derive signed facts,
   377  			// but it turns out not to matter.
   378  		}
   379  		ft.limitStack = append(ft.limitStack, limitFact{v.ID, old})
   380  		lim = old.intersect(lim)
   381  		ft.limits[v.ID] = lim
   382  		if v.Block.Func.pass.debug > 2 {
   383  			v.Block.Func.Warnl(parent.Pos, "parent=%s, new limits %s %s %s %s", parent, v, w, r, lim.String())
   384  		}
   385  		if lim.min > lim.max || lim.umin > lim.umax {
   386  			ft.unsat = true
   387  			return
   388  		}
   389  	}
   390  
   391  	// Derived facts below here are only about numbers.
   392  	if d != signed && d != unsigned {
   393  		return
   394  	}
   395  
   396  	// Additional facts we know given the relationship between len and cap.
   397  	//
   398  	// TODO: Since prove now derives transitive relations, it
   399  	// should be sufficient to learn that len(w) <= cap(w) at the
   400  	// beginning of prove where we look for all len/cap ops.
   401  	if v.Op == OpSliceLen && r&lt == 0 && ft.caps[v.Args[0].ID] != nil {
   402  		// len(s) > w implies cap(s) > w
   403  		// len(s) >= w implies cap(s) >= w
   404  		// len(s) == w implies cap(s) >= w
   405  		ft.update(parent, ft.caps[v.Args[0].ID], w, d, r|gt)
   406  	}
   407  	if w.Op == OpSliceLen && r&gt == 0 && ft.caps[w.Args[0].ID] != nil {
   408  		// same, length on the RHS.
   409  		ft.update(parent, v, ft.caps[w.Args[0].ID], d, r|lt)
   410  	}
   411  	if v.Op == OpSliceCap && r&gt == 0 && ft.lens[v.Args[0].ID] != nil {
   412  		// cap(s) < w implies len(s) < w
   413  		// cap(s) <= w implies len(s) <= w
   414  		// cap(s) == w implies len(s) <= w
   415  		ft.update(parent, ft.lens[v.Args[0].ID], w, d, r|lt)
   416  	}
   417  	if w.Op == OpSliceCap && r&lt == 0 && ft.lens[w.Args[0].ID] != nil {
   418  		// same, capacity on the RHS.
   419  		ft.update(parent, v, ft.lens[w.Args[0].ID], d, r|gt)
   420  	}
   421  
   422  	// Process fence-post implications.
   423  	//
   424  	// First, make the condition > or >=.
   425  	if r == lt || r == lt|eq {
   426  		v, w = w, v
   427  		r = reverseBits[r]
   428  	}
   429  	switch r {
   430  	case gt:
   431  		if x, delta := isConstDelta(v); x != nil && delta == 1 {
   432  			// x+1 > w  ⇒  x >= w
   433  			//
   434  			// This is useful for eliminating the
   435  			// growslice branch of append.
   436  			ft.update(parent, x, w, d, gt|eq)
   437  		} else if x, delta := isConstDelta(w); x != nil && delta == -1 {
   438  			// v > x-1  ⇒  v >= x
   439  			ft.update(parent, v, x, d, gt|eq)
   440  		}
   441  	case gt | eq:
   442  		if x, delta := isConstDelta(v); x != nil && delta == -1 {
   443  			// x-1 >= w && x > min  ⇒  x > w
   444  			//
   445  			// Useful for i > 0; s[i-1].
   446  			lim, ok := ft.limits[x.ID]
   447  			if ok && ((d == signed && lim.min > opMin[v.Op]) || (d == unsigned && lim.umin > 0)) {
   448  				ft.update(parent, x, w, d, gt)
   449  			}
   450  		} else if x, delta := isConstDelta(w); x != nil && delta == 1 {
   451  			// v >= x+1 && x < max  ⇒  v > x
   452  			lim, ok := ft.limits[x.ID]
   453  			if ok && ((d == signed && lim.max < opMax[w.Op]) || (d == unsigned && lim.umax < opUMax[w.Op])) {
   454  				ft.update(parent, v, x, d, gt)
   455  			}
   456  		}
   457  	}
   458  
   459  	// Process: x+delta > w (with delta constant)
   460  	// Only signed domain for now (useful for accesses to slices in loops).
   461  	if r == gt || r == gt|eq {
   462  		if x, delta := isConstDelta(v); x != nil && d == signed {
   463  			if parent.Func.pass.debug > 1 {
   464  				parent.Func.Warnl(parent.Pos, "x+d %s w; x:%v %v delta:%v w:%v d:%v", r, x, parent.String(), delta, w.AuxInt, d)
   465  			}
   466  			underflow := true
   467  			if l, has := ft.limits[x.ID]; has && delta < 0 {
   468  				if (x.Type.Size() == 8 && l.min >= math.MinInt64-delta) ||
   469  					(x.Type.Size() == 4 && l.min >= math.MinInt32-delta) {
   470  					underflow = false
   471  				}
   472  			}
   473  			if delta < 0 && !underflow {
   474  				// If delta < 0 and x+delta cannot underflow then x > x+delta (that is, x > v)
   475  				ft.update(parent, x, v, signed, gt)
   476  			}
   477  			if !w.isGenericIntConst() {
   478  				// If we know that x+delta > w but w is not constant, we can derive:
   479  				//    if delta < 0 and x+delta cannot underflow, then x > w
   480  				// This is useful for loops with bounds "len(slice)-K" (delta = -K)
   481  				if delta < 0 && !underflow {
   482  					ft.update(parent, x, w, signed, r)
   483  				}
   484  			} else {
   485  				// With w,delta constants, we want to derive: x+delta > w  ⇒  x > w-delta
   486  				//
   487  				// We compute (using integers of the correct size):
   488  				//    min = w - delta
   489  				//    max = MaxInt - delta
   490  				//
   491  				// And we prove that:
   492  				//    if min<max: min < x AND x <= max
   493  				//    if min>max: min < x OR  x <= max
   494  				//
   495  				// This is always correct, even in case of overflow.
   496  				//
   497  				// If the initial fact is x+delta >= w instead, the derived conditions are:
   498  				//    if min<max: min <= x AND x <= max
   499  				//    if min>max: min <= x OR  x <= max
   500  				//
   501  				// Notice the conditions for max are still <=, as they handle overflows.
   502  				var min, max int64
   503  				var vmin, vmax *Value
   504  				switch x.Type.Size() {
   505  				case 8:
   506  					min = w.AuxInt - delta
   507  					max = int64(^uint64(0)>>1) - delta
   508  
   509  					vmin = parent.NewValue0I(parent.Pos, OpConst64, parent.Func.Config.Types.Int64, min)
   510  					vmax = parent.NewValue0I(parent.Pos, OpConst64, parent.Func.Config.Types.Int64, max)
   511  
   512  				case 4:
   513  					min = int64(int32(w.AuxInt) - int32(delta))
   514  					max = int64(int32(^uint32(0)>>1) - int32(delta))
   515  
   516  					vmin = parent.NewValue0I(parent.Pos, OpConst32, parent.Func.Config.Types.Int32, min)
   517  					vmax = parent.NewValue0I(parent.Pos, OpConst32, parent.Func.Config.Types.Int32, max)
   518  
   519  				case 2:
   520  					min = int64(int16(w.AuxInt) - int16(delta))
   521  					max = int64(int16(^uint16(0)>>1) - int16(delta))
   522  
   523  					vmin = parent.NewValue0I(parent.Pos, OpConst16, parent.Func.Config.Types.Int16, min)
   524  					vmax = parent.NewValue0I(parent.Pos, OpConst16, parent.Func.Config.Types.Int16, max)
   525  
   526  				case 1:
   527  					min = int64(int8(w.AuxInt) - int8(delta))
   528  					max = int64(int8(^uint8(0)>>1) - int8(delta))
   529  
   530  					vmin = parent.NewValue0I(parent.Pos, OpConst8, parent.Func.Config.Types.Int8, min)
   531  					vmax = parent.NewValue0I(parent.Pos, OpConst8, parent.Func.Config.Types.Int8, max)
   532  
   533  				default:
   534  					panic("unimplemented")
   535  				}
   536  
   537  				if min < max {
   538  					// Record that x > min and max >= x
   539  					ft.update(parent, x, vmin, d, r)
   540  					ft.update(parent, vmax, x, d, r|eq)
   541  				} else {
   542  					// We know that either x>min OR x<=max. factsTable cannot record OR conditions,
   543  					// so let's see if we can already prove that one of them is false, in which case
   544  					// the other must be true
   545  					if l, has := ft.limits[x.ID]; has {
   546  						if l.max <= min {
   547  							if r&eq == 0 || l.max < min {
   548  								// x>min (x>=min) is impossible, so it must be x<=max
   549  								ft.update(parent, vmax, x, d, r|eq)
   550  							}
   551  						} else if l.min > max {
   552  							// x<=max is impossible, so it must be x>min
   553  							ft.update(parent, x, vmin, d, r)
   554  						}
   555  					}
   556  				}
   557  			}
   558  		}
   559  	}
   560  
   561  	// Look through value-preserving extensions.
   562  	// If the domain is appropriate for the pre-extension Type,
   563  	// repeat the update with the pre-extension Value.
   564  	if isCleanExt(v) {
   565  		switch {
   566  		case d == signed && v.Args[0].Type.IsSigned():
   567  			fallthrough
   568  		case d == unsigned && !v.Args[0].Type.IsSigned():
   569  			ft.update(parent, v.Args[0], w, d, r)
   570  		}
   571  	}
   572  	if isCleanExt(w) {
   573  		switch {
   574  		case d == signed && w.Args[0].Type.IsSigned():
   575  			fallthrough
   576  		case d == unsigned && !w.Args[0].Type.IsSigned():
   577  			ft.update(parent, v, w.Args[0], d, r)
   578  		}
   579  	}
   580  }
   581  
   582  var opMin = map[Op]int64{
   583  	OpAdd64: math.MinInt64, OpSub64: math.MinInt64,
   584  	OpAdd32: math.MinInt32, OpSub32: math.MinInt32,
   585  }
   586  
   587  var opMax = map[Op]int64{
   588  	OpAdd64: math.MaxInt64, OpSub64: math.MaxInt64,
   589  	OpAdd32: math.MaxInt32, OpSub32: math.MaxInt32,
   590  }
   591  
   592  var opUMax = map[Op]uint64{
   593  	OpAdd64: math.MaxUint64, OpSub64: math.MaxUint64,
   594  	OpAdd32: math.MaxUint32, OpSub32: math.MaxUint32,
   595  }
   596  
   597  // isNonNegative reports whether v is known to be non-negative.
   598  func (ft *factsTable) isNonNegative(v *Value) bool {
   599  	if isNonNegative(v) {
   600  		return true
   601  	}
   602  
   603  	var max int64
   604  	switch v.Type.Size() {
   605  	case 1:
   606  		max = math.MaxInt8
   607  	case 2:
   608  		max = math.MaxInt16
   609  	case 4:
   610  		max = math.MaxInt32
   611  	case 8:
   612  		max = math.MaxInt64
   613  	default:
   614  		panic("unexpected integer size")
   615  	}
   616  
   617  	// Check if the recorded limits can prove that the value is positive
   618  
   619  	if l, has := ft.limits[v.ID]; has && (l.min >= 0 || l.umax <= uint64(max)) {
   620  		return true
   621  	}
   622  
   623  	// Check if v = x+delta, and we can use x's limits to prove that it's positive
   624  	if x, delta := isConstDelta(v); x != nil {
   625  		if l, has := ft.limits[x.ID]; has {
   626  			if delta > 0 && l.min >= -delta && l.max <= max-delta {
   627  				return true
   628  			}
   629  			if delta < 0 && l.min >= -delta {
   630  				return true
   631  			}
   632  		}
   633  	}
   634  
   635  	// Check if v is a value-preserving extension of a non-negative value.
   636  	if isCleanExt(v) && ft.isNonNegative(v.Args[0]) {
   637  		return true
   638  	}
   639  
   640  	// Check if the signed poset can prove that the value is >= 0
   641  	return ft.orderS.OrderedOrEqual(ft.zero, v)
   642  }
   643  
   644  // checkpoint saves the current state of known relations.
   645  // Called when descending on a branch.
   646  func (ft *factsTable) checkpoint() {
   647  	if ft.unsat {
   648  		ft.unsatDepth++
   649  	}
   650  	ft.stack = append(ft.stack, checkpointFact)
   651  	ft.limitStack = append(ft.limitStack, checkpointBound)
   652  	ft.orderS.Checkpoint()
   653  	ft.orderU.Checkpoint()
   654  }
   655  
   656  // restore restores known relation to the state just
   657  // before the previous checkpoint.
   658  // Called when backing up on a branch.
   659  func (ft *factsTable) restore() {
   660  	if ft.unsatDepth > 0 {
   661  		ft.unsatDepth--
   662  	} else {
   663  		ft.unsat = false
   664  	}
   665  	for {
   666  		old := ft.stack[len(ft.stack)-1]
   667  		ft.stack = ft.stack[:len(ft.stack)-1]
   668  		if old == checkpointFact {
   669  			break
   670  		}
   671  		if old.r == lt|eq|gt {
   672  			delete(ft.facts, old.p)
   673  		} else {
   674  			ft.facts[old.p] = old.r
   675  		}
   676  	}
   677  	for {
   678  		old := ft.limitStack[len(ft.limitStack)-1]
   679  		ft.limitStack = ft.limitStack[:len(ft.limitStack)-1]
   680  		if old.vid == 0 { // checkpointBound
   681  			break
   682  		}
   683  		if old.limit == noLimit {
   684  			delete(ft.limits, old.vid)
   685  		} else {
   686  			ft.limits[old.vid] = old.limit
   687  		}
   688  	}
   689  	ft.orderS.Undo()
   690  	ft.orderU.Undo()
   691  }
   692  
   693  func lessByID(v, w *Value) bool {
   694  	if v == nil && w == nil {
   695  		// Should not happen, but just in case.
   696  		return false
   697  	}
   698  	if v == nil {
   699  		return true
   700  	}
   701  	return w != nil && v.ID < w.ID
   702  }
   703  
   704  var (
   705  	reverseBits = [...]relation{0, 4, 2, 6, 1, 5, 3, 7}
   706  
   707  	// maps what we learn when the positive branch is taken.
   708  	// For example:
   709  	//      OpLess8:   {signed, lt},
   710  	//	v1 = (OpLess8 v2 v3).
   711  	// If v1 branch is taken then we learn that the rangeMask
   712  	// can be at most lt.
   713  	domainRelationTable = map[Op]struct {
   714  		d domain
   715  		r relation
   716  	}{
   717  		OpEq8:   {signed | unsigned, eq},
   718  		OpEq16:  {signed | unsigned, eq},
   719  		OpEq32:  {signed | unsigned, eq},
   720  		OpEq64:  {signed | unsigned, eq},
   721  		OpEqPtr: {pointer, eq},
   722  
   723  		OpNeq8:   {signed | unsigned, lt | gt},
   724  		OpNeq16:  {signed | unsigned, lt | gt},
   725  		OpNeq32:  {signed | unsigned, lt | gt},
   726  		OpNeq64:  {signed | unsigned, lt | gt},
   727  		OpNeqPtr: {pointer, lt | gt},
   728  
   729  		OpLess8:   {signed, lt},
   730  		OpLess8U:  {unsigned, lt},
   731  		OpLess16:  {signed, lt},
   732  		OpLess16U: {unsigned, lt},
   733  		OpLess32:  {signed, lt},
   734  		OpLess32U: {unsigned, lt},
   735  		OpLess64:  {signed, lt},
   736  		OpLess64U: {unsigned, lt},
   737  
   738  		OpLeq8:   {signed, lt | eq},
   739  		OpLeq8U:  {unsigned, lt | eq},
   740  		OpLeq16:  {signed, lt | eq},
   741  		OpLeq16U: {unsigned, lt | eq},
   742  		OpLeq32:  {signed, lt | eq},
   743  		OpLeq32U: {unsigned, lt | eq},
   744  		OpLeq64:  {signed, lt | eq},
   745  		OpLeq64U: {unsigned, lt | eq},
   746  
   747  		// For these ops, the negative branch is different: we can only
   748  		// prove signed/GE (signed/GT) if we can prove that arg0 is non-negative.
   749  		// See the special case in addBranchRestrictions.
   750  		OpIsInBounds:      {signed | unsigned, lt},      // 0 <= arg0 < arg1
   751  		OpIsSliceInBounds: {signed | unsigned, lt | eq}, // 0 <= arg0 <= arg1
   752  	}
   753  )
   754  
   755  // cleanup returns the posets to the free list
   756  func (ft *factsTable) cleanup(f *Func) {
   757  	for _, po := range []*poset{ft.orderS, ft.orderU} {
   758  		// Make sure it's empty as it should be. A non-empty poset
   759  		// might cause errors and miscompilations if reused.
   760  		if checkEnabled {
   761  			if err := po.CheckEmpty(); err != nil {
   762  				f.Fatalf("poset not empty after function %s: %v", f.Name, err)
   763  			}
   764  		}
   765  		f.retPoset(po)
   766  	}
   767  }
   768  
   769  // prove removes redundant BlockIf branches that can be inferred
   770  // from previous dominating comparisons.
   771  //
   772  // By far, the most common redundant pair are generated by bounds checking.
   773  // For example for the code:
   774  //
   775  //	a[i] = 4
   776  //	foo(a[i])
   777  //
   778  // The compiler will generate the following code:
   779  //
   780  //	if i >= len(a) {
   781  //	    panic("not in bounds")
   782  //	}
   783  //	a[i] = 4
   784  //	if i >= len(a) {
   785  //	    panic("not in bounds")
   786  //	}
   787  //	foo(a[i])
   788  //
   789  // The second comparison i >= len(a) is clearly redundant because if the
   790  // else branch of the first comparison is executed, we already know that i < len(a).
   791  // The code for the second panic can be removed.
   792  //
   793  // prove works by finding contradictions and trimming branches whose
   794  // conditions are unsatisfiable given the branches leading up to them.
   795  // It tracks a "fact table" of branch conditions. For each branching
   796  // block, it asserts the branch conditions that uniquely dominate that
   797  // block, and then separately asserts the block's branch condition and
   798  // its negation. If either leads to a contradiction, it can trim that
   799  // successor.
   800  func prove(f *Func) {
   801  	ft := newFactsTable(f)
   802  	ft.checkpoint()
   803  
   804  	var lensVars map[*Block][]*Value
   805  
   806  	// Find length and capacity ops.
   807  	for _, b := range f.Blocks {
   808  		for _, v := range b.Values {
   809  			if v.Uses == 0 {
   810  				// We don't care about dead values.
   811  				// (There can be some that are CSEd but not removed yet.)
   812  				continue
   813  			}
   814  			switch v.Op {
   815  			case OpStringLen:
   816  				ft.update(b, v, ft.zero, signed, gt|eq)
   817  			case OpSliceLen:
   818  				if ft.lens == nil {
   819  					ft.lens = map[ID]*Value{}
   820  				}
   821  				// Set all len Values for the same slice as equal in the poset.
   822  				// The poset handles transitive relations, so Values related to
   823  				// any OpSliceLen for this slice will be correctly related to others.
   824  				if l, ok := ft.lens[v.Args[0].ID]; ok {
   825  					ft.update(b, v, l, signed, eq)
   826  				} else {
   827  					ft.lens[v.Args[0].ID] = v
   828  				}
   829  				ft.update(b, v, ft.zero, signed, gt|eq)
   830  				if v.Args[0].Op == OpSliceMake {
   831  					if lensVars == nil {
   832  						lensVars = make(map[*Block][]*Value)
   833  					}
   834  					lensVars[b] = append(lensVars[b], v)
   835  				}
   836  			case OpSliceCap:
   837  				if ft.caps == nil {
   838  					ft.caps = map[ID]*Value{}
   839  				}
   840  				// Same as case OpSliceLen above, but for slice cap.
   841  				if c, ok := ft.caps[v.Args[0].ID]; ok {
   842  					ft.update(b, v, c, signed, eq)
   843  				} else {
   844  					ft.caps[v.Args[0].ID] = v
   845  				}
   846  				ft.update(b, v, ft.zero, signed, gt|eq)
   847  				if v.Args[0].Op == OpSliceMake {
   848  					if lensVars == nil {
   849  						lensVars = make(map[*Block][]*Value)
   850  					}
   851  					lensVars[b] = append(lensVars[b], v)
   852  				}
   853  			case OpCtz64, OpCtz32, OpCtz16, OpCtz8, OpBitLen64, OpBitLen32, OpBitLen16, OpBitLen8:
   854  				ft.update(b, v, ft.zero, signed, gt|eq)
   855  				// TODO: we could also do <= 64/32/16/8, if that helped.
   856  			case OpAnd64, OpAnd32, OpAnd16, OpAnd8:
   857  				ft.update(b, v, v.Args[1], unsigned, lt|eq)
   858  				ft.update(b, v, v.Args[0], unsigned, lt|eq)
   859  			case OpPhi:
   860  				// Determine the min and max value of OpPhi composed entirely of integer constants.
   861  				//
   862  				// For example, for an OpPhi:
   863  				//
   864  				// v1 = OpConst64 [13]
   865  				// v2 = OpConst64 [7]
   866  				// v3 = OpConst64 [42]
   867  				//
   868  				// v4 = OpPhi(v1, v2, v3)
   869  				//
   870  				// We can prove:
   871  				//
   872  				// v4 >= 7 && v4 <= 42
   873  				//
   874  				// TODO(jake-ciolek): Handle nested constant OpPhi's
   875  				sameConstOp := true
   876  				min := 0
   877  				max := 0
   878  
   879  				if !v.Args[min].isGenericIntConst() {
   880  					break
   881  				}
   882  
   883  				for k := range v.Args {
   884  					if v.Args[k].Op != v.Args[min].Op {
   885  						sameConstOp = false
   886  						break
   887  					}
   888  					if v.Args[k].AuxInt < v.Args[min].AuxInt {
   889  						min = k
   890  					}
   891  					if v.Args[k].AuxInt > v.Args[max].AuxInt {
   892  						max = k
   893  					}
   894  				}
   895  
   896  				if sameConstOp {
   897  					ft.update(b, v, v.Args[min], signed, gt|eq)
   898  					ft.update(b, v, v.Args[max], signed, lt|eq)
   899  				}
   900  				// One might be tempted to create a v >= ft.zero relation for
   901  				// all OpPhi's composed of only provably-positive values
   902  				// but that bloats up the facts table for a very neglible gain.
   903  				// In Go itself, very few functions get improved (< 5) at a cost of 5-7% total increase
   904  				// of compile time.
   905  			}
   906  		}
   907  	}
   908  	// Find induction variables. Currently, findIndVars
   909  	// is limited to one induction variable per block.
   910  	var indVars map[*Block]indVar
   911  	for _, v := range findIndVar(f) {
   912  		if indVars == nil {
   913  			indVars = make(map[*Block]indVar)
   914  		}
   915  		indVars[v.entry] = v
   916  	}
   917  
   918  	// current node state
   919  	type walkState int
   920  	const (
   921  		descend walkState = iota
   922  		simplify
   923  	)
   924  	// work maintains the DFS stack.
   925  	type bp struct {
   926  		block *Block    // current handled block
   927  		state walkState // what's to do
   928  	}
   929  	work := make([]bp, 0, 256)
   930  	work = append(work, bp{
   931  		block: f.Entry,
   932  		state: descend,
   933  	})
   934  
   935  	idom := f.Idom()
   936  	sdom := f.Sdom()
   937  
   938  	// DFS on the dominator tree.
   939  	//
   940  	// For efficiency, we consider only the dominator tree rather
   941  	// than the entire flow graph. On the way down, we consider
   942  	// incoming branches and accumulate conditions that uniquely
   943  	// dominate the current block. If we discover a contradiction,
   944  	// we can eliminate the entire block and all of its children.
   945  	// On the way back up, we consider outgoing branches that
   946  	// haven't already been considered. This way we consider each
   947  	// branch condition only once.
   948  	for len(work) > 0 {
   949  		node := work[len(work)-1]
   950  		work = work[:len(work)-1]
   951  		parent := idom[node.block.ID]
   952  		branch := getBranch(sdom, parent, node.block)
   953  
   954  		switch node.state {
   955  		case descend:
   956  			ft.checkpoint()
   957  
   958  			// Entering the block, add the block-depending facts that we collected
   959  			// at the beginning: induction variables and lens/caps of slices.
   960  			if iv, ok := indVars[node.block]; ok {
   961  				addIndVarRestrictions(ft, parent, iv)
   962  			}
   963  			if lens, ok := lensVars[node.block]; ok {
   964  				for _, v := range lens {
   965  					switch v.Op {
   966  					case OpSliceLen:
   967  						ft.update(node.block, v, v.Args[0].Args[1], signed, eq)
   968  					case OpSliceCap:
   969  						ft.update(node.block, v, v.Args[0].Args[2], signed, eq)
   970  					}
   971  				}
   972  			}
   973  
   974  			if branch != unknown {
   975  				addBranchRestrictions(ft, parent, branch)
   976  				if ft.unsat {
   977  					// node.block is unreachable.
   978  					// Remove it and don't visit
   979  					// its children.
   980  					removeBranch(parent, branch)
   981  					ft.restore()
   982  					break
   983  				}
   984  				// Otherwise, we can now commit to
   985  				// taking this branch. We'll restore
   986  				// ft when we unwind.
   987  			}
   988  
   989  			// Add inductive facts for phis in this block.
   990  			addLocalInductiveFacts(ft, node.block)
   991  
   992  			work = append(work, bp{
   993  				block: node.block,
   994  				state: simplify,
   995  			})
   996  			for s := sdom.Child(node.block); s != nil; s = sdom.Sibling(s) {
   997  				work = append(work, bp{
   998  					block: s,
   999  					state: descend,
  1000  				})
  1001  			}
  1002  
  1003  		case simplify:
  1004  			simplifyBlock(sdom, ft, node.block)
  1005  			ft.restore()
  1006  		}
  1007  	}
  1008  
  1009  	ft.restore()
  1010  
  1011  	ft.cleanup(f)
  1012  }
  1013  
  1014  // getBranch returns the range restrictions added by p
  1015  // when reaching b. p is the immediate dominator of b.
  1016  func getBranch(sdom SparseTree, p *Block, b *Block) branch {
  1017  	if p == nil {
  1018  		return unknown
  1019  	}
  1020  	switch p.Kind {
  1021  	case BlockIf:
  1022  		// If p and p.Succs[0] are dominators it means that every path
  1023  		// from entry to b passes through p and p.Succs[0]. We care that
  1024  		// no path from entry to b passes through p.Succs[1]. If p.Succs[0]
  1025  		// has one predecessor then (apart from the degenerate case),
  1026  		// there is no path from entry that can reach b through p.Succs[1].
  1027  		// TODO: how about p->yes->b->yes, i.e. a loop in yes.
  1028  		if sdom.IsAncestorEq(p.Succs[0].b, b) && len(p.Succs[0].b.Preds) == 1 {
  1029  			return positive
  1030  		}
  1031  		if sdom.IsAncestorEq(p.Succs[1].b, b) && len(p.Succs[1].b.Preds) == 1 {
  1032  			return negative
  1033  		}
  1034  	case BlockJumpTable:
  1035  		// TODO: this loop can lead to quadratic behavior, as
  1036  		// getBranch can be called len(p.Succs) times.
  1037  		for i, e := range p.Succs {
  1038  			if sdom.IsAncestorEq(e.b, b) && len(e.b.Preds) == 1 {
  1039  				return jumpTable0 + branch(i)
  1040  			}
  1041  		}
  1042  	}
  1043  	return unknown
  1044  }
  1045  
  1046  // addIndVarRestrictions updates the factsTables ft with the facts
  1047  // learned from the induction variable indVar which drives the loop
  1048  // starting in Block b.
  1049  func addIndVarRestrictions(ft *factsTable, b *Block, iv indVar) {
  1050  	d := signed
  1051  	if ft.isNonNegative(iv.min) && ft.isNonNegative(iv.max) {
  1052  		d |= unsigned
  1053  	}
  1054  
  1055  	if iv.flags&indVarMinExc == 0 {
  1056  		addRestrictions(b, ft, d, iv.min, iv.ind, lt|eq)
  1057  	} else {
  1058  		addRestrictions(b, ft, d, iv.min, iv.ind, lt)
  1059  	}
  1060  
  1061  	if iv.flags&indVarMaxInc == 0 {
  1062  		addRestrictions(b, ft, d, iv.ind, iv.max, lt)
  1063  	} else {
  1064  		addRestrictions(b, ft, d, iv.ind, iv.max, lt|eq)
  1065  	}
  1066  }
  1067  
  1068  // addBranchRestrictions updates the factsTables ft with the facts learned when
  1069  // branching from Block b in direction br.
  1070  func addBranchRestrictions(ft *factsTable, b *Block, br branch) {
  1071  	c := b.Controls[0]
  1072  	switch {
  1073  	case br == negative:
  1074  		addRestrictions(b, ft, boolean, nil, c, eq)
  1075  	case br == positive:
  1076  		addRestrictions(b, ft, boolean, nil, c, lt|gt)
  1077  	case br >= jumpTable0:
  1078  		idx := br - jumpTable0
  1079  		val := int64(idx)
  1080  		if v, off := isConstDelta(c); v != nil {
  1081  			// Establish the bound on the underlying value we're switching on,
  1082  			// not on the offset-ed value used as the jump table index.
  1083  			c = v
  1084  			val -= off
  1085  		}
  1086  		old, ok := ft.limits[c.ID]
  1087  		if !ok {
  1088  			old = noLimit
  1089  		}
  1090  		ft.limitStack = append(ft.limitStack, limitFact{c.ID, old})
  1091  		if val < old.min || val > old.max || uint64(val) < old.umin || uint64(val) > old.umax {
  1092  			ft.unsat = true
  1093  			if b.Func.pass.debug > 2 {
  1094  				b.Func.Warnl(b.Pos, "block=%s outedge=%d %s=%d unsat", b, idx, c, val)
  1095  			}
  1096  		} else {
  1097  			ft.limits[c.ID] = limit{val, val, uint64(val), uint64(val)}
  1098  			if b.Func.pass.debug > 2 {
  1099  				b.Func.Warnl(b.Pos, "block=%s outedge=%d %s=%d", b, idx, c, val)
  1100  			}
  1101  		}
  1102  	default:
  1103  		panic("unknown branch")
  1104  	}
  1105  	if tr, has := domainRelationTable[c.Op]; has {
  1106  		// When we branched from parent we learned a new set of
  1107  		// restrictions. Update the factsTable accordingly.
  1108  		d := tr.d
  1109  		if d == signed && ft.isNonNegative(c.Args[0]) && ft.isNonNegative(c.Args[1]) {
  1110  			d |= unsigned
  1111  		}
  1112  		switch c.Op {
  1113  		case OpIsInBounds, OpIsSliceInBounds:
  1114  			// 0 <= a0 < a1 (or 0 <= a0 <= a1)
  1115  			//
  1116  			// On the positive branch, we learn:
  1117  			//   signed: 0 <= a0 < a1 (or 0 <= a0 <= a1)
  1118  			//   unsigned:    a0 < a1 (or a0 <= a1)
  1119  			//
  1120  			// On the negative branch, we learn (0 > a0 ||
  1121  			// a0 >= a1). In the unsigned domain, this is
  1122  			// simply a0 >= a1 (which is the reverse of the
  1123  			// positive branch, so nothing surprising).
  1124  			// But in the signed domain, we can't express the ||
  1125  			// condition, so check if a0 is non-negative instead,
  1126  			// to be able to learn something.
  1127  			switch br {
  1128  			case negative:
  1129  				d = unsigned
  1130  				if ft.isNonNegative(c.Args[0]) {
  1131  					d |= signed
  1132  				}
  1133  				addRestrictions(b, ft, d, c.Args[0], c.Args[1], tr.r^(lt|gt|eq))
  1134  			case positive:
  1135  				addRestrictions(b, ft, signed, ft.zero, c.Args[0], lt|eq)
  1136  				addRestrictions(b, ft, d, c.Args[0], c.Args[1], tr.r)
  1137  			}
  1138  		default:
  1139  			switch br {
  1140  			case negative:
  1141  				addRestrictions(b, ft, d, c.Args[0], c.Args[1], tr.r^(lt|gt|eq))
  1142  			case positive:
  1143  				addRestrictions(b, ft, d, c.Args[0], c.Args[1], tr.r)
  1144  			}
  1145  		}
  1146  
  1147  	}
  1148  }
  1149  
  1150  // addRestrictions updates restrictions from the immediate
  1151  // dominating block (p) using r.
  1152  func addRestrictions(parent *Block, ft *factsTable, t domain, v, w *Value, r relation) {
  1153  	if t == 0 {
  1154  		// Trivial case: nothing to do.
  1155  		// Shoult not happen, but just in case.
  1156  		return
  1157  	}
  1158  	for i := domain(1); i <= t; i <<= 1 {
  1159  		if t&i == 0 {
  1160  			continue
  1161  		}
  1162  		ft.update(parent, v, w, i, r)
  1163  	}
  1164  }
  1165  
  1166  // addLocalInductiveFacts adds inductive facts when visiting b, where
  1167  // b is a join point in a loop. In contrast with findIndVar, this
  1168  // depends on facts established for b, which is why it happens when
  1169  // visiting b.
  1170  //
  1171  // TODO: It would be nice to combine this with findIndVar.
  1172  func addLocalInductiveFacts(ft *factsTable, b *Block) {
  1173  	// This looks for a specific pattern of induction:
  1174  	//
  1175  	// 1. i1 = OpPhi(min, i2) in b
  1176  	// 2. i2 = i1 + 1
  1177  	// 3. i2 < max at exit from b.Preds[1]
  1178  	// 4. min < max
  1179  	//
  1180  	// If all of these conditions are true, then i1 < max and i1 >= min.
  1181  
  1182  	// To ensure this is a loop header node.
  1183  	if len(b.Preds) != 2 {
  1184  		return
  1185  	}
  1186  
  1187  	for _, i1 := range b.Values {
  1188  		if i1.Op != OpPhi {
  1189  			continue
  1190  		}
  1191  
  1192  		// Check for conditions 1 and 2. This is easy to do
  1193  		// and will throw out most phis.
  1194  		min, i2 := i1.Args[0], i1.Args[1]
  1195  		if i1q, delta := isConstDelta(i2); i1q != i1 || delta != 1 {
  1196  			continue
  1197  		}
  1198  
  1199  		// Try to prove condition 3. We can't just query the
  1200  		// fact table for this because we don't know what the
  1201  		// facts of b.Preds[1] are (in general, b.Preds[1] is
  1202  		// a loop-back edge, so we haven't even been there
  1203  		// yet). As a conservative approximation, we look for
  1204  		// this condition in the predecessor chain until we
  1205  		// hit a join point.
  1206  		uniquePred := func(b *Block) *Block {
  1207  			if len(b.Preds) == 1 {
  1208  				return b.Preds[0].b
  1209  			}
  1210  			return nil
  1211  		}
  1212  		pred, child := b.Preds[1].b, b
  1213  		for ; pred != nil; pred, child = uniquePred(pred), pred {
  1214  			if pred.Kind != BlockIf {
  1215  				continue
  1216  			}
  1217  			control := pred.Controls[0]
  1218  
  1219  			br := unknown
  1220  			if pred.Succs[0].b == child {
  1221  				br = positive
  1222  			}
  1223  			if pred.Succs[1].b == child {
  1224  				if br != unknown {
  1225  					continue
  1226  				}
  1227  				br = negative
  1228  			}
  1229  			if br == unknown {
  1230  				continue
  1231  			}
  1232  
  1233  			tr, has := domainRelationTable[control.Op]
  1234  			if !has {
  1235  				continue
  1236  			}
  1237  			r := tr.r
  1238  			if br == negative {
  1239  				// Negative branch taken to reach b.
  1240  				// Complement the relations.
  1241  				r = (lt | eq | gt) ^ r
  1242  			}
  1243  
  1244  			// Check for i2 < max or max > i2.
  1245  			var max *Value
  1246  			if r == lt && control.Args[0] == i2 {
  1247  				max = control.Args[1]
  1248  			} else if r == gt && control.Args[1] == i2 {
  1249  				max = control.Args[0]
  1250  			} else {
  1251  				continue
  1252  			}
  1253  
  1254  			// Check condition 4 now that we have a
  1255  			// candidate max. For this we can query the
  1256  			// fact table. We "prove" min < max by showing
  1257  			// that min >= max is unsat. (This may simply
  1258  			// compare two constants; that's fine.)
  1259  			ft.checkpoint()
  1260  			ft.update(b, min, max, tr.d, gt|eq)
  1261  			proved := ft.unsat
  1262  			ft.restore()
  1263  
  1264  			if proved {
  1265  				// We know that min <= i1 < max.
  1266  				if b.Func.pass.debug > 0 {
  1267  					printIndVar(b, i1, min, max, 1, 0)
  1268  				}
  1269  				ft.update(b, min, i1, tr.d, lt|eq)
  1270  				ft.update(b, i1, max, tr.d, lt)
  1271  			}
  1272  		}
  1273  	}
  1274  }
  1275  
  1276  var ctzNonZeroOp = map[Op]Op{OpCtz8: OpCtz8NonZero, OpCtz16: OpCtz16NonZero, OpCtz32: OpCtz32NonZero, OpCtz64: OpCtz64NonZero}
  1277  var mostNegativeDividend = map[Op]int64{
  1278  	OpDiv16: -1 << 15,
  1279  	OpMod16: -1 << 15,
  1280  	OpDiv32: -1 << 31,
  1281  	OpMod32: -1 << 31,
  1282  	OpDiv64: -1 << 63,
  1283  	OpMod64: -1 << 63}
  1284  
  1285  // simplifyBlock simplifies some constant values in b and evaluates
  1286  // branches to non-uniquely dominated successors of b.
  1287  func simplifyBlock(sdom SparseTree, ft *factsTable, b *Block) {
  1288  	for _, v := range b.Values {
  1289  		switch v.Op {
  1290  		case OpSlicemask:
  1291  			// Replace OpSlicemask operations in b with constants where possible.
  1292  			x, delta := isConstDelta(v.Args[0])
  1293  			if x == nil {
  1294  				break
  1295  			}
  1296  			// slicemask(x + y)
  1297  			// if x is larger than -y (y is negative), then slicemask is -1.
  1298  			lim, ok := ft.limits[x.ID]
  1299  			if !ok {
  1300  				break
  1301  			}
  1302  			if lim.umin > uint64(-delta) {
  1303  				if v.Args[0].Op == OpAdd64 {
  1304  					v.reset(OpConst64)
  1305  				} else {
  1306  					v.reset(OpConst32)
  1307  				}
  1308  				if b.Func.pass.debug > 0 {
  1309  					b.Func.Warnl(v.Pos, "Proved slicemask not needed")
  1310  				}
  1311  				v.AuxInt = -1
  1312  			}
  1313  		case OpCtz8, OpCtz16, OpCtz32, OpCtz64:
  1314  			// On some architectures, notably amd64, we can generate much better
  1315  			// code for CtzNN if we know that the argument is non-zero.
  1316  			// Capture that information here for use in arch-specific optimizations.
  1317  			x := v.Args[0]
  1318  			lim, ok := ft.limits[x.ID]
  1319  			if !ok {
  1320  				break
  1321  			}
  1322  			if lim.umin > 0 || lim.min > 0 || lim.max < 0 {
  1323  				if b.Func.pass.debug > 0 {
  1324  					b.Func.Warnl(v.Pos, "Proved %v non-zero", v.Op)
  1325  				}
  1326  				v.Op = ctzNonZeroOp[v.Op]
  1327  			}
  1328  		case OpRsh8x8, OpRsh8x16, OpRsh8x32, OpRsh8x64,
  1329  			OpRsh16x8, OpRsh16x16, OpRsh16x32, OpRsh16x64,
  1330  			OpRsh32x8, OpRsh32x16, OpRsh32x32, OpRsh32x64,
  1331  			OpRsh64x8, OpRsh64x16, OpRsh64x32, OpRsh64x64:
  1332  			// Check whether, for a >> b, we know that a is non-negative
  1333  			// and b is all of a's bits except the MSB. If so, a is shifted to zero.
  1334  			bits := 8 * v.Type.Size()
  1335  			if v.Args[1].isGenericIntConst() && v.Args[1].AuxInt >= bits-1 && ft.isNonNegative(v.Args[0]) {
  1336  				if b.Func.pass.debug > 0 {
  1337  					b.Func.Warnl(v.Pos, "Proved %v shifts to zero", v.Op)
  1338  				}
  1339  				switch bits {
  1340  				case 64:
  1341  					v.reset(OpConst64)
  1342  				case 32:
  1343  					v.reset(OpConst32)
  1344  				case 16:
  1345  					v.reset(OpConst16)
  1346  				case 8:
  1347  					v.reset(OpConst8)
  1348  				default:
  1349  					panic("unexpected integer size")
  1350  				}
  1351  				v.AuxInt = 0
  1352  				break // Be sure not to fallthrough - this is no longer OpRsh.
  1353  			}
  1354  			// If the Rsh hasn't been replaced with 0, still check if it is bounded.
  1355  			fallthrough
  1356  		case OpLsh8x8, OpLsh8x16, OpLsh8x32, OpLsh8x64,
  1357  			OpLsh16x8, OpLsh16x16, OpLsh16x32, OpLsh16x64,
  1358  			OpLsh32x8, OpLsh32x16, OpLsh32x32, OpLsh32x64,
  1359  			OpLsh64x8, OpLsh64x16, OpLsh64x32, OpLsh64x64,
  1360  			OpRsh8Ux8, OpRsh8Ux16, OpRsh8Ux32, OpRsh8Ux64,
  1361  			OpRsh16Ux8, OpRsh16Ux16, OpRsh16Ux32, OpRsh16Ux64,
  1362  			OpRsh32Ux8, OpRsh32Ux16, OpRsh32Ux32, OpRsh32Ux64,
  1363  			OpRsh64Ux8, OpRsh64Ux16, OpRsh64Ux32, OpRsh64Ux64:
  1364  			// Check whether, for a << b, we know that b
  1365  			// is strictly less than the number of bits in a.
  1366  			by := v.Args[1]
  1367  			lim, ok := ft.limits[by.ID]
  1368  			if !ok {
  1369  				break
  1370  			}
  1371  			bits := 8 * v.Args[0].Type.Size()
  1372  			if lim.umax < uint64(bits) || (lim.max < bits && ft.isNonNegative(by)) {
  1373  				v.AuxInt = 1 // see shiftIsBounded
  1374  				if b.Func.pass.debug > 0 {
  1375  					b.Func.Warnl(v.Pos, "Proved %v bounded", v.Op)
  1376  				}
  1377  			}
  1378  		case OpDiv16, OpDiv32, OpDiv64, OpMod16, OpMod32, OpMod64:
  1379  			// On amd64 and 386 fix-up code can be avoided if we know
  1380  			//  the divisor is not -1 or the dividend > MinIntNN.
  1381  			// Don't modify AuxInt on other architectures,
  1382  			// as that can interfere with CSE.
  1383  			// TODO: add other architectures?
  1384  			if b.Func.Config.arch != "386" && b.Func.Config.arch != "amd64" {
  1385  				break
  1386  			}
  1387  			divr := v.Args[1]
  1388  			divrLim, divrLimok := ft.limits[divr.ID]
  1389  			divd := v.Args[0]
  1390  			divdLim, divdLimok := ft.limits[divd.ID]
  1391  			if (divrLimok && (divrLim.max < -1 || divrLim.min > -1)) ||
  1392  				(divdLimok && divdLim.min > mostNegativeDividend[v.Op]) {
  1393  				// See DivisionNeedsFixUp in rewrite.go.
  1394  				// v.AuxInt = 1 means we have proved both that the divisor is not -1
  1395  				// and that the dividend is not the most negative integer,
  1396  				// so we do not need to add fix-up code.
  1397  				v.AuxInt = 1
  1398  				if b.Func.pass.debug > 0 {
  1399  					b.Func.Warnl(v.Pos, "Proved %v does not need fix-up", v.Op)
  1400  				}
  1401  			}
  1402  		}
  1403  		// Fold provable constant results.
  1404  		// Helps in cases where we reuse a value after branching on its equality.
  1405  		for i, arg := range v.Args {
  1406  			switch arg.Op {
  1407  			case OpConst64, OpConst32, OpConst16, OpConst8:
  1408  				continue
  1409  			}
  1410  			lim, ok := ft.limits[arg.ID]
  1411  			if !ok {
  1412  				continue
  1413  			}
  1414  
  1415  			var constValue int64
  1416  			typ := arg.Type
  1417  			bits := 8 * typ.Size()
  1418  			switch {
  1419  			case lim.min == lim.max:
  1420  				constValue = lim.min
  1421  			case lim.umin == lim.umax:
  1422  				// truncate then sign extand
  1423  				switch bits {
  1424  				case 64:
  1425  					constValue = int64(lim.umin)
  1426  				case 32:
  1427  					constValue = int64(int32(lim.umin))
  1428  				case 16:
  1429  					constValue = int64(int16(lim.umin))
  1430  				case 8:
  1431  					constValue = int64(int8(lim.umin))
  1432  				default:
  1433  					panic("unexpected integer size")
  1434  				}
  1435  			default:
  1436  				continue
  1437  			}
  1438  			var c *Value
  1439  			f := b.Func
  1440  			switch bits {
  1441  			case 64:
  1442  				c = f.ConstInt64(typ, constValue)
  1443  			case 32:
  1444  				c = f.ConstInt32(typ, int32(constValue))
  1445  			case 16:
  1446  				c = f.ConstInt16(typ, int16(constValue))
  1447  			case 8:
  1448  				c = f.ConstInt8(typ, int8(constValue))
  1449  			default:
  1450  				panic("unexpected integer size")
  1451  			}
  1452  			v.SetArg(i, c)
  1453  			if b.Func.pass.debug > 1 {
  1454  				b.Func.Warnl(v.Pos, "Proved %v's arg %d (%v) is constant %d", v, i, arg, constValue)
  1455  			}
  1456  		}
  1457  	}
  1458  
  1459  	if b.Kind != BlockIf {
  1460  		return
  1461  	}
  1462  
  1463  	// Consider outgoing edges from this block.
  1464  	parent := b
  1465  	for i, branch := range [...]branch{positive, negative} {
  1466  		child := parent.Succs[i].b
  1467  		if getBranch(sdom, parent, child) != unknown {
  1468  			// For edges to uniquely dominated blocks, we
  1469  			// already did this when we visited the child.
  1470  			continue
  1471  		}
  1472  		// For edges to other blocks, this can trim a branch
  1473  		// even if we couldn't get rid of the child itself.
  1474  		ft.checkpoint()
  1475  		addBranchRestrictions(ft, parent, branch)
  1476  		unsat := ft.unsat
  1477  		ft.restore()
  1478  		if unsat {
  1479  			// This branch is impossible, so remove it
  1480  			// from the block.
  1481  			removeBranch(parent, branch)
  1482  			// No point in considering the other branch.
  1483  			// (It *is* possible for both to be
  1484  			// unsatisfiable since the fact table is
  1485  			// incomplete. We could turn this into a
  1486  			// BlockExit, but it doesn't seem worth it.)
  1487  			break
  1488  		}
  1489  	}
  1490  }
  1491  
  1492  func removeBranch(b *Block, branch branch) {
  1493  	c := b.Controls[0]
  1494  	if b.Func.pass.debug > 0 {
  1495  		verb := "Proved"
  1496  		if branch == positive {
  1497  			verb = "Disproved"
  1498  		}
  1499  		if b.Func.pass.debug > 1 {
  1500  			b.Func.Warnl(b.Pos, "%s %s (%s)", verb, c.Op, c)
  1501  		} else {
  1502  			b.Func.Warnl(b.Pos, "%s %s", verb, c.Op)
  1503  		}
  1504  	}
  1505  	if c != nil && c.Pos.IsStmt() == src.PosIsStmt && c.Pos.SameFileAndLine(b.Pos) {
  1506  		// attempt to preserve statement marker.
  1507  		b.Pos = b.Pos.WithIsStmt()
  1508  	}
  1509  	if branch == positive || branch == negative {
  1510  		b.Kind = BlockFirst
  1511  		b.ResetControls()
  1512  		if branch == positive {
  1513  			b.swapSuccessors()
  1514  		}
  1515  	} else {
  1516  		// TODO: figure out how to remove an entry from a jump table
  1517  	}
  1518  }
  1519  
  1520  // isNonNegative reports whether v is known to be greater or equal to zero.
  1521  func isNonNegative(v *Value) bool {
  1522  	if !v.Type.IsInteger() {
  1523  		v.Fatalf("isNonNegative bad type: %v", v.Type)
  1524  	}
  1525  	// TODO: return true if !v.Type.IsSigned()
  1526  	// SSA isn't type-safe enough to do that now (issue 37753).
  1527  	// The checks below depend only on the pattern of bits.
  1528  
  1529  	switch v.Op {
  1530  	case OpConst64:
  1531  		return v.AuxInt >= 0
  1532  
  1533  	case OpConst32:
  1534  		return int32(v.AuxInt) >= 0
  1535  
  1536  	case OpConst16:
  1537  		return int16(v.AuxInt) >= 0
  1538  
  1539  	case OpConst8:
  1540  		return int8(v.AuxInt) >= 0
  1541  
  1542  	case OpStringLen, OpSliceLen, OpSliceCap,
  1543  		OpZeroExt8to64, OpZeroExt16to64, OpZeroExt32to64,
  1544  		OpZeroExt8to32, OpZeroExt16to32, OpZeroExt8to16,
  1545  		OpCtz64, OpCtz32, OpCtz16, OpCtz8,
  1546  		OpCtz64NonZero, OpCtz32NonZero, OpCtz16NonZero, OpCtz8NonZero,
  1547  		OpBitLen64, OpBitLen32, OpBitLen16, OpBitLen8:
  1548  		return true
  1549  
  1550  	case OpRsh64Ux64, OpRsh32Ux64:
  1551  		by := v.Args[1]
  1552  		return by.Op == OpConst64 && by.AuxInt > 0
  1553  
  1554  	case OpRsh64x64, OpRsh32x64, OpRsh8x64, OpRsh16x64, OpRsh32x32, OpRsh64x32,
  1555  		OpSignExt32to64, OpSignExt16to64, OpSignExt8to64, OpSignExt16to32, OpSignExt8to32:
  1556  		return isNonNegative(v.Args[0])
  1557  
  1558  	case OpAnd64, OpAnd32, OpAnd16, OpAnd8:
  1559  		return isNonNegative(v.Args[0]) || isNonNegative(v.Args[1])
  1560  
  1561  	case OpMod64, OpMod32, OpMod16, OpMod8,
  1562  		OpDiv64, OpDiv32, OpDiv16, OpDiv8,
  1563  		OpOr64, OpOr32, OpOr16, OpOr8,
  1564  		OpXor64, OpXor32, OpXor16, OpXor8:
  1565  		return isNonNegative(v.Args[0]) && isNonNegative(v.Args[1])
  1566  
  1567  		// We could handle OpPhi here, but the improvements from doing
  1568  		// so are very minor, and it is neither simple nor cheap.
  1569  	}
  1570  	return false
  1571  }
  1572  
  1573  // isConstDelta returns non-nil if v is equivalent to w+delta (signed).
  1574  func isConstDelta(v *Value) (w *Value, delta int64) {
  1575  	cop := OpConst64
  1576  	switch v.Op {
  1577  	case OpAdd32, OpSub32:
  1578  		cop = OpConst32
  1579  	case OpAdd16, OpSub16:
  1580  		cop = OpConst16
  1581  	case OpAdd8, OpSub8:
  1582  		cop = OpConst8
  1583  	}
  1584  	switch v.Op {
  1585  	case OpAdd64, OpAdd32, OpAdd16, OpAdd8:
  1586  		if v.Args[0].Op == cop {
  1587  			return v.Args[1], v.Args[0].AuxInt
  1588  		}
  1589  		if v.Args[1].Op == cop {
  1590  			return v.Args[0], v.Args[1].AuxInt
  1591  		}
  1592  	case OpSub64, OpSub32, OpSub16, OpSub8:
  1593  		if v.Args[1].Op == cop {
  1594  			aux := v.Args[1].AuxInt
  1595  			if aux != -aux { // Overflow; too bad
  1596  				return v.Args[0], -aux
  1597  			}
  1598  		}
  1599  	}
  1600  	return nil, 0
  1601  }
  1602  
  1603  // isCleanExt reports whether v is the result of a value-preserving
  1604  // sign or zero extension.
  1605  func isCleanExt(v *Value) bool {
  1606  	switch v.Op {
  1607  	case OpSignExt8to16, OpSignExt8to32, OpSignExt8to64,
  1608  		OpSignExt16to32, OpSignExt16to64, OpSignExt32to64:
  1609  		// signed -> signed is the only value-preserving sign extension
  1610  		return v.Args[0].Type.IsSigned() && v.Type.IsSigned()
  1611  
  1612  	case OpZeroExt8to16, OpZeroExt8to32, OpZeroExt8to64,
  1613  		OpZeroExt16to32, OpZeroExt16to64, OpZeroExt32to64:
  1614  		// unsigned -> signed/unsigned are value-preserving zero extensions
  1615  		return !v.Args[0].Type.IsSigned()
  1616  	}
  1617  	return false
  1618  }