// known lower and upper bounds on individual values.
limits map[ID]limit
limitStack []limitFact // previous entries
+
+ // For each slice s, a map from s to a len(s)/cap(s) value (if any)
+ // TODO: check if there are cases that matter where we have
+ // more than one len(s) for a slice. We could keep a list if necessary.
+ lens map[ID]*Value
+ caps map[ID]*Value
}
// checkpointFact is an invalid value used for checkpointing
}
)
-// prove removes redundant BlockIf controls that can be inferred in a straight line.
+// prove removes redundant BlockIf branches that can be inferred
+// from previous dominating comparisons.
//
// By far, the most common redundant pair are generated by bounds checking.
// For example for the code:
// else branch of the first comparison is executed, we already know that i < len(a).
// The code for the second panic can be removed.
func prove(f *Func) {
+ ft := newFactsTable()
+
+ // Find length and capacity ops.
+ for _, b := range f.Blocks {
+ for _, v := range b.Values {
+ if v.Uses == 0 {
+ // We don't care about dead values.
+ // (There can be some that are CSEd but not removed yet.)
+ continue
+ }
+ switch v.Op {
+ case OpSliceLen:
+ if ft.lens == nil {
+ ft.lens = map[ID]*Value{}
+ }
+ ft.lens[v.Args[0].ID] = v
+ case OpSliceCap:
+ if ft.caps == nil {
+ ft.caps = map[ID]*Value{}
+ }
+ ft.caps[v.Args[0].ID] = v
+ }
+ }
+ }
+
// current node state
type walkState int
const (
state: descend,
})
- ft := newFactsTable()
idom := f.Idom()
sdom := f.sdom()
r = (lt | eq | gt) ^ r
}
for i := domain(1); i <= t; i <<= 1 {
- if t&i != 0 {
- ft.update(parent, v, w, i, r)
+ if t&i == 0 {
+ continue
+ }
+ ft.update(parent, v, w, i, r)
+
+ // Additional facts we know given the relationship between len and cap.
+ if i != signed && i != unsigned {
+ continue
+ }
+ if v.Op == OpSliceLen && r< == 0 && ft.caps[v.Args[0].ID] != nil {
+ // len(s) > w implies cap(s) > w
+ // len(s) >= w implies cap(s) >= w
+ // len(s) == w implies cap(s) >= w
+ ft.update(parent, ft.caps[v.Args[0].ID], w, i, r|gt)
+ }
+ if w.Op == OpSliceLen && r> == 0 && ft.caps[w.Args[0].ID] != nil {
+ // same, length on the RHS.
+ ft.update(parent, v, ft.caps[w.Args[0].ID], i, r|lt)
+ }
+ if v.Op == OpSliceCap && r> == 0 && ft.lens[v.Args[0].ID] != nil {
+ // cap(s) < w implies len(s) < w
+ // cap(s) <= w implies len(s) <= w
+ // cap(s) == w implies len(s) <= w
+ ft.update(parent, ft.lens[v.Args[0].ID], w, i, r|lt)
+ }
+ if w.Op == OpSliceCap && r< == 0 && ft.lens[w.Args[0].ID] != nil {
+ // same, capacity on the RHS.
+ ft.update(parent, v, ft.lens[w.Args[0].ID], i, r|gt)
}
}
}