limits []limit // indexed by value ID
limitStack []limitFact // previous entries
recurseCheck []bool // recursion detector for limit propagation
+
+ // 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
}
// checkpointBound is an invalid value used for checkpointing
}
if !isTrue {
r ^= lt | gt | eq
- } else if d == unsigned && (r == lt || r == lt|eq) && ft.isNonNegative(v.Args[1]) {
- // Since every representation of a non-negative signed number is the same
- // as in the unsigned domain, we can transfer x <= y to the signed domain,
- // but only for the true branch.
- d |= signed
}
// TODO: v.Block is wrong?
addRestrictions(v.Block, ft, d, v.Args[0], v.Args[1], r)
// restricting it to r.
func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
if parent.Func.pass.debug > 2 {
- parent.Func.Warnl(parent.Pos, "parent=%s, update %s %s %s %s", parent, d, v, w, r)
+ parent.Func.Warnl(parent.Pos, "parent=%s, update %s %s %s", parent, v, w, r)
}
// No need to do anything else if we already found unsat.
if ft.unsat {
return
}
+ // Additional facts we know given the relationship between len and cap.
+ //
+ // TODO: Since prove now derives transitive relations, it
+ // should be sufficient to learn that len(w) <= cap(w) at the
+ // beginning of prove where we look for all len/cap ops.
+ 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, d, 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], d, 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, d, 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], d, r|gt)
+ }
+
// Process fence-post implications.
//
// First, make the condition > or >=.
ft := newFactsTable(f)
ft.checkpoint()
- var lens map[ID]*Value
- var caps map[ID]*Value
// Find length and capacity ops.
for _, b := range f.Blocks {
for _, v := range b.Values {
}
switch v.Op {
case OpSliceLen:
- if lens == nil {
- lens = map[ID]*Value{}
+ if ft.lens == nil {
+ ft.lens = map[ID]*Value{}
}
// Set all len Values for the same slice as equal in the poset.
// The poset handles transitive relations, so Values related to
// any OpSliceLen for this slice will be correctly related to others.
- //
- // Since we know that lens/caps are non-negative, their relation
- // can be added in both the signed and unsigned domain.
- if l, ok := lens[v.Args[0].ID]; ok {
+ if l, ok := ft.lens[v.Args[0].ID]; ok {
ft.update(b, v, l, signed, eq)
- ft.update(b, v, l, unsigned, eq)
} else {
- lens[v.Args[0].ID] = v
- }
- if c, ok := caps[v.Args[0].ID]; ok {
- ft.update(b, v, c, signed, lt|eq)
- ft.update(b, v, c, unsigned, lt|eq)
+ ft.lens[v.Args[0].ID] = v
}
case OpSliceCap:
- if caps == nil {
- caps = map[ID]*Value{}
+ if ft.caps == nil {
+ ft.caps = map[ID]*Value{}
}
// Same as case OpSliceLen above, but for slice cap.
- if c, ok := caps[v.Args[0].ID]; ok {
+ if c, ok := ft.caps[v.Args[0].ID]; ok {
ft.update(b, v, c, signed, eq)
- ft.update(b, v, c, unsigned, eq)
} else {
- caps[v.Args[0].ID] = v
- }
- if l, ok := lens[v.Args[0].ID]; ok {
- ft.update(b, v, l, signed, gt|eq)
- ft.update(b, v, l, unsigned, gt|eq)
+ ft.caps[v.Args[0].ID] = v
}
}
}
OpRsh32Ux64, OpRsh32Ux32, OpRsh32Ux16, OpRsh32Ux8,
OpRsh64Ux64, OpRsh64Ux32, OpRsh64Ux16, OpRsh64Ux8:
ft.update(b, v, v.Args[0], unsigned, lt|eq)
- if ft.isNonNegative(v.Args[0]) {
- ft.update(b, v, v.Args[0], signed, lt|eq)
- }
case OpMod64u, OpMod32u, OpMod16u, OpMod8u:
ft.update(b, v, v.Args[0], unsigned, lt|eq)
// Note: we have to be careful that this doesn't imply