mirror of
https://github.com/golang/go
synced 2024-11-23 00:00:07 -07:00
cmd/compile: implement loop BCE in prove
Reuse findIndVar to discover induction variables, and then register the facts we know about them into the facts table when entering the loop block. Moreover, handle "x+delta > w" while updating the facts table, to be able to prove accesses to slices with constant offsets such as slice[i-10]. Change-Id: I2a63d050ed58258136d54712ac7015b25c893d71 Reviewed-on: https://go-review.googlesource.com/104038 Run-TryBot: Giovanni Bajo <rasky@develer.com> Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
29162ec9a7
commit
7ec25d0acf
@ -646,6 +646,7 @@ var knownFormats = map[string]string{
|
|||||||
"cmd/compile/internal/ssa.Op %s": "",
|
"cmd/compile/internal/ssa.Op %s": "",
|
||||||
"cmd/compile/internal/ssa.Op %v": "",
|
"cmd/compile/internal/ssa.Op %v": "",
|
||||||
"cmd/compile/internal/ssa.ValAndOff %s": "",
|
"cmd/compile/internal/ssa.ValAndOff %s": "",
|
||||||
|
"cmd/compile/internal/ssa.domain %v": "",
|
||||||
"cmd/compile/internal/ssa.posetNode %v": "",
|
"cmd/compile/internal/ssa.posetNode %v": "",
|
||||||
"cmd/compile/internal/ssa.posetTestOp %v": "",
|
"cmd/compile/internal/ssa.posetTestOp %v": "",
|
||||||
"cmd/compile/internal/ssa.rbrank %d": "",
|
"cmd/compile/internal/ssa.rbrank %d": "",
|
||||||
|
@ -137,7 +137,7 @@ nextb:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.pass.debug > 1 {
|
if f.pass.debug >= 1 {
|
||||||
if min.Op == OpConst64 {
|
if min.Op == OpConst64 {
|
||||||
b.Func.Warnl(b.Pos, "Induction variable with minimum %d and increment %d", min.AuxInt, inc.AuxInt)
|
b.Func.Warnl(b.Pos, "Induction variable with minimum %d and increment %d", min.AuxInt, inc.AuxInt)
|
||||||
} else {
|
} else {
|
||||||
|
@ -388,6 +388,77 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process: x+delta > w (with delta,w constants)
|
||||||
|
//
|
||||||
|
// We want to derive: x+delta > w ⇒ x > w-delta
|
||||||
|
//
|
||||||
|
// We do this for signed numbers for now, as that allows to prove many
|
||||||
|
// accesses to slices in loops.
|
||||||
|
//
|
||||||
|
// From x+delta > w, we compute (using integers of the correct size):
|
||||||
|
// min = w - delta
|
||||||
|
// max = MaxInt - delta
|
||||||
|
//
|
||||||
|
// And we prove that:
|
||||||
|
// if min<max: min < x AND x <= max
|
||||||
|
// if min>max: min < x OR x <= max
|
||||||
|
//
|
||||||
|
// This is always correct, even in case of overflow.
|
||||||
|
//
|
||||||
|
// If the initial fact is x+delta >= w instead, the derived conditions are:
|
||||||
|
// if min<max: min <= x AND x <= max
|
||||||
|
// if min>max: min <= x OR x <= max
|
||||||
|
//
|
||||||
|
// Notice the conditions for max are still <=, as they handle overflows.
|
||||||
|
if r == gt || r == gt|eq {
|
||||||
|
if x, delta := isConstDelta(v); x != nil && w.isGenericIntConst() && d == signed {
|
||||||
|
if parent.Func.pass.debug > 1 {
|
||||||
|
parent.Func.Warnl(parent.Pos, "x+d >= w; x:%v %v delta:%v w:%v d:%v", x, parent.String(), delta, w.AuxInt, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
var min, max int64
|
||||||
|
var vmin, vmax *Value
|
||||||
|
switch x.Type.Size() {
|
||||||
|
case 8:
|
||||||
|
min = w.AuxInt - delta
|
||||||
|
max = int64(^uint64(0)>>1) - delta
|
||||||
|
|
||||||
|
vmin = parent.NewValue0I(parent.Pos, OpConst64, parent.Func.Config.Types.Int64, min)
|
||||||
|
vmax = parent.NewValue0I(parent.Pos, OpConst64, parent.Func.Config.Types.Int64, max)
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
min = int64(int32(w.AuxInt) - int32(delta))
|
||||||
|
max = int64(int32(^uint32(0)>>1) - int32(delta))
|
||||||
|
|
||||||
|
vmin = parent.NewValue0I(parent.Pos, OpConst32, parent.Func.Config.Types.Int32, min)
|
||||||
|
vmax = parent.NewValue0I(parent.Pos, OpConst32, parent.Func.Config.Types.Int32, max)
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
if min < max {
|
||||||
|
// Record that x > min and max >= x
|
||||||
|
ft.update(parent, x, vmin, d, r)
|
||||||
|
ft.update(parent, vmax, x, d, r|eq)
|
||||||
|
} else {
|
||||||
|
// We know that either x>min OR x<=max. factsTable cannot record OR conditions,
|
||||||
|
// so let's see if we can already prove that one of them is false, in which case
|
||||||
|
// the other must be true
|
||||||
|
if l, has := ft.limits[x.ID]; has {
|
||||||
|
if l.max <= min {
|
||||||
|
// x>min is impossible, so it must be x<=max
|
||||||
|
ft.update(parent, vmax, x, d, r|eq)
|
||||||
|
} else if l.min > max {
|
||||||
|
// x<=max is impossible, so it must be x>min
|
||||||
|
ft.update(parent, x, vmin, d, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var opMin = map[Op]int64{
|
var opMin = map[Op]int64{
|
||||||
@ -405,8 +476,25 @@ func (ft *factsTable) isNonNegative(v *Value) bool {
|
|||||||
if isNonNegative(v) {
|
if isNonNegative(v) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
l, has := ft.limits[v.ID]
|
|
||||||
return has && (l.min >= 0 || l.umax <= math.MaxInt64)
|
// Check if the recorded limits can prove that the value is positive
|
||||||
|
if l, has := ft.limits[v.ID]; has && (l.min >= 0 || l.umax <= math.MaxInt64) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if v = x+delta, and we can use x's limits to prove that it's positive
|
||||||
|
if x, delta := isConstDelta(v); x != nil {
|
||||||
|
if l, has := ft.limits[x.ID]; has {
|
||||||
|
if delta > 0 && l.min >= -delta && l.max <= math.MaxInt64-delta {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if delta < 0 && l.min >= -delta {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkpoint saves the current state of known relations.
|
// checkpoint saves the current state of known relations.
|
||||||
@ -595,6 +683,16 @@ func prove(f *Func) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find induction variables. Currently, findIndVars
|
||||||
|
// is limited to one induction variable per block.
|
||||||
|
var indVars map[*Block]indVar
|
||||||
|
for _, v := range findIndVar(f) {
|
||||||
|
if indVars == nil {
|
||||||
|
indVars = make(map[*Block]indVar)
|
||||||
|
}
|
||||||
|
indVars[v.entry] = v
|
||||||
|
}
|
||||||
|
|
||||||
// current node state
|
// current node state
|
||||||
type walkState int
|
type walkState int
|
||||||
const (
|
const (
|
||||||
@ -634,6 +732,10 @@ func prove(f *Func) {
|
|||||||
switch node.state {
|
switch node.state {
|
||||||
case descend:
|
case descend:
|
||||||
ft.checkpoint()
|
ft.checkpoint()
|
||||||
|
if iv, ok := indVars[node.block]; ok {
|
||||||
|
addIndVarRestrictions(ft, parent, iv)
|
||||||
|
}
|
||||||
|
|
||||||
if branch != unknown {
|
if branch != unknown {
|
||||||
addBranchRestrictions(ft, parent, branch)
|
addBranchRestrictions(ft, parent, branch)
|
||||||
if ft.unsat {
|
if ft.unsat {
|
||||||
@ -688,6 +790,19 @@ func getBranch(sdom SparseTree, p *Block, b *Block) branch {
|
|||||||
return unknown
|
return unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addIndVarRestrictions updates the factsTables ft with the facts
|
||||||
|
// learned from the induction variable indVar which drives the loop
|
||||||
|
// starting in Block b.
|
||||||
|
func addIndVarRestrictions(ft *factsTable, b *Block, iv indVar) {
|
||||||
|
d := signed
|
||||||
|
if isNonNegative(iv.min) && isNonNegative(iv.max) {
|
||||||
|
d |= unsigned
|
||||||
|
}
|
||||||
|
|
||||||
|
addRestrictions(b, ft, d, iv.min, iv.ind, lt|eq)
|
||||||
|
addRestrictions(b, ft, d, iv.ind, iv.max, lt)
|
||||||
|
}
|
||||||
|
|
||||||
// addBranchRestrictions updates the factsTables ft with the facts learned when
|
// addBranchRestrictions updates the factsTables ft with the facts learned when
|
||||||
// branching from Block b in direction br.
|
// branching from Block b in direction br.
|
||||||
func addBranchRestrictions(ft *factsTable, b *Block, br branch) {
|
func addBranchRestrictions(ft *factsTable, b *Block, br branch) {
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
// +build amd64
|
// +build amd64
|
||||||
// errorcheck -0 -d=ssa/loopbce/debug=3
|
// errorcheck -0 -d=ssa/prove/debug=1
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
func f0a(a []int) int {
|
func f0a(a []int) int {
|
||||||
x := 0
|
x := 0
|
||||||
for i := range a { // ERROR "Induction variable with minimum 0 and increment 1$"
|
for i := range a { // ERROR "Induction variable with minimum 0 and increment 1$"
|
||||||
x += a[i] // ERROR "Found redundant IsInBounds$"
|
x += a[i] // ERROR "Proved IsInBounds$"
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
@ -14,7 +14,7 @@ func f0a(a []int) int {
|
|||||||
func f0b(a []int) int {
|
func f0b(a []int) int {
|
||||||
x := 0
|
x := 0
|
||||||
for i := range a { // ERROR "Induction variable with minimum 0 and increment 1$"
|
for i := range a { // ERROR "Induction variable with minimum 0 and increment 1$"
|
||||||
b := a[i:] // ERROR "Found redundant IsSliceInBounds$"
|
b := a[i:] // ERROR "Proved IsSliceInBounds$"
|
||||||
x += b[0]
|
x += b[0]
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
@ -23,7 +23,7 @@ func f0b(a []int) int {
|
|||||||
func f0c(a []int) int {
|
func f0c(a []int) int {
|
||||||
x := 0
|
x := 0
|
||||||
for i := range a { // ERROR "Induction variable with minimum 0 and increment 1$"
|
for i := range a { // ERROR "Induction variable with minimum 0 and increment 1$"
|
||||||
b := a[:i+1] // ERROR "Found redundant IsSliceInBounds \(len promoted to cap\)$"
|
b := a[:i+1] // ERROR "Proved IsSliceInBounds$"
|
||||||
x += b[0]
|
x += b[0]
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
@ -40,7 +40,7 @@ func f1(a []int) int {
|
|||||||
func f2(a []int) int {
|
func f2(a []int) int {
|
||||||
x := 0
|
x := 0
|
||||||
for i := 1; i < len(a); i++ { // ERROR "Induction variable with minimum 1 and increment 1$"
|
for i := 1; i < len(a); i++ { // ERROR "Induction variable with minimum 1 and increment 1$"
|
||||||
x += a[i] // ERROR "Found redundant IsInBounds$"
|
x += a[i] // ERROR "Proved IsInBounds$"
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ func f2(a []int) int {
|
|||||||
func f4(a [10]int) int {
|
func f4(a [10]int) int {
|
||||||
x := 0
|
x := 0
|
||||||
for i := 0; i < len(a); i += 2 { // ERROR "Induction variable with minimum 0 and increment 2$"
|
for i := 0; i < len(a); i += 2 { // ERROR "Induction variable with minimum 0 and increment 2$"
|
||||||
x += a[i] // ERROR "Found redundant IsInBounds$"
|
x += a[i] // ERROR "Proved IsInBounds$"
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ func f5(a [10]int) int {
|
|||||||
|
|
||||||
func f6(a []int) {
|
func f6(a []int) {
|
||||||
for i := range a { // ERROR "Induction variable with minimum 0 and increment 1$"
|
for i := range a { // ERROR "Induction variable with minimum 0 and increment 1$"
|
||||||
b := a[0:i] // ERROR "Found redundant IsSliceInBounds \(len promoted to cap\)$"
|
b := a[0:i] // ERROR "Proved IsSliceInBounds$"
|
||||||
f6(b)
|
f6(b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,7 +71,7 @@ func f6(a []int) {
|
|||||||
func g0a(a string) int {
|
func g0a(a string) int {
|
||||||
x := 0
|
x := 0
|
||||||
for i := 0; i < len(a); i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
|
for i := 0; i < len(a); i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
|
||||||
x += int(a[i]) // ERROR "Found redundant IsInBounds$"
|
x += int(a[i]) // ERROR "Proved IsInBounds$"
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
@ -79,7 +79,7 @@ func g0a(a string) int {
|
|||||||
func g0b(a string) int {
|
func g0b(a string) int {
|
||||||
x := 0
|
x := 0
|
||||||
for i := 0; len(a) > i; i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
|
for i := 0; len(a) > i; i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
|
||||||
x += int(a[i]) // ERROR "Found redundant IsInBounds$"
|
x += int(a[i]) // ERROR "Proved IsInBounds$"
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
@ -88,7 +88,7 @@ func g1() int {
|
|||||||
a := "evenlength"
|
a := "evenlength"
|
||||||
x := 0
|
x := 0
|
||||||
for i := 0; i < len(a); i += 2 { // ERROR "Induction variable with minimum 0 and increment 2$"
|
for i := 0; i < len(a); i += 2 { // ERROR "Induction variable with minimum 0 and increment 2$"
|
||||||
x += int(a[i]) // ERROR "Found redundant IsInBounds$"
|
x += int(a[i]) // ERROR "Proved IsInBounds$"
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
@ -98,7 +98,7 @@ func g2() int {
|
|||||||
x := 0
|
x := 0
|
||||||
for i := 0; i < len(a); i += 2 { // ERROR "Induction variable with minimum 0 and increment 2$"
|
for i := 0; i < len(a); i += 2 { // ERROR "Induction variable with minimum 0 and increment 2$"
|
||||||
j := i
|
j := i
|
||||||
if a[i] == 'e' { // ERROR "Found redundant IsInBounds$"
|
if a[i] == 'e' { // ERROR "Proved IsInBounds$"
|
||||||
j = j + 1
|
j = j + 1
|
||||||
}
|
}
|
||||||
x += int(a[j])
|
x += int(a[j])
|
||||||
@ -109,27 +109,27 @@ func g2() int {
|
|||||||
func g3a() {
|
func g3a() {
|
||||||
a := "this string has length 25"
|
a := "this string has length 25"
|
||||||
for i := 0; i < len(a); i += 5 { // ERROR "Induction variable with minimum 0 and increment 5$"
|
for i := 0; i < len(a); i += 5 { // ERROR "Induction variable with minimum 0 and increment 5$"
|
||||||
useString(a[i:]) // ERROR "Found redundant IsSliceInBounds$"
|
useString(a[i:]) // ERROR "Proved IsSliceInBounds$"
|
||||||
useString(a[:i+3])
|
useString(a[:i+3])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func g3b(a string) {
|
func g3b(a string) {
|
||||||
for i := 0; i < len(a); i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
|
for i := 0; i < len(a); i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
|
||||||
useString(a[i+1:]) // ERROR "Found redundant IsSliceInBounds$"
|
useString(a[i+1:]) // ERROR "Proved IsSliceInBounds$"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func g3c(a string) {
|
func g3c(a string) {
|
||||||
for i := 0; i < len(a); i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
|
for i := 0; i < len(a); i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
|
||||||
useString(a[:i+1]) // ERROR "Found redundant IsSliceInBounds$"
|
useString(a[:i+1]) // ERROR "Proved IsSliceInBounds$"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func h1(a []byte) {
|
func h1(a []byte) {
|
||||||
c := a[:128]
|
c := a[:128]
|
||||||
for i := range c { // ERROR "Induction variable with minimum 0 and increment 1$"
|
for i := range c { // ERROR "Induction variable with minimum 0 and increment 1$"
|
||||||
c[i] = byte(i) // ERROR "Found redundant IsInBounds$"
|
c[i] = byte(i) // ERROR "Proved IsInBounds$"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,11 +142,11 @@ func h2(a []byte) {
|
|||||||
func k0(a [100]int) [100]int {
|
func k0(a [100]int) [100]int {
|
||||||
for i := 10; i < 90; i++ { // ERROR "Induction variable with minimum 10 and increment 1$"
|
for i := 10; i < 90; i++ { // ERROR "Induction variable with minimum 10 and increment 1$"
|
||||||
a[i-11] = i
|
a[i-11] = i
|
||||||
a[i-10] = i // ERROR "Found redundant \(IsInBounds ind 100\), ind < 80$"
|
a[i-10] = i // ERROR "Proved IsInBounds$"
|
||||||
a[i-5] = i // ERROR "Found redundant \(IsInBounds ind 100\), ind < 85$"
|
a[i-5] = i // ERROR "Proved IsInBounds$"
|
||||||
a[i] = i // ERROR "Found redundant \(IsInBounds ind 100\), ind < 90$"
|
a[i] = i // ERROR "Proved IsInBounds$"
|
||||||
a[i+5] = i // ERROR "Found redundant \(IsInBounds ind 100\), ind < 95$"
|
a[i+5] = i // ERROR "Proved IsInBounds$"
|
||||||
a[i+10] = i // ERROR "Found redundant \(IsInBounds ind 100\), ind < 100$"
|
a[i+10] = i // ERROR "Proved IsInBounds$"
|
||||||
a[i+11] = i
|
a[i+11] = i
|
||||||
}
|
}
|
||||||
return a
|
return a
|
||||||
@ -155,12 +155,13 @@ func k0(a [100]int) [100]int {
|
|||||||
func k1(a [100]int) [100]int {
|
func k1(a [100]int) [100]int {
|
||||||
for i := 10; i < 90; i++ { // ERROR "Induction variable with minimum 10 and increment 1$"
|
for i := 10; i < 90; i++ { // ERROR "Induction variable with minimum 10 and increment 1$"
|
||||||
useSlice(a[:i-11])
|
useSlice(a[:i-11])
|
||||||
useSlice(a[:i-10]) // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 80$"
|
useSlice(a[:i-10]) // ERROR "Proved IsSliceInBounds$"
|
||||||
useSlice(a[:i-5]) // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 85$"
|
useSlice(a[:i-5]) // ERROR "Proved IsSliceInBounds$"
|
||||||
useSlice(a[:i]) // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 90$"
|
useSlice(a[:i]) // ERROR "Proved IsSliceInBounds$"
|
||||||
useSlice(a[:i+5]) // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 95$"
|
useSlice(a[:i+5]) // ERROR "Proved IsSliceInBounds$"
|
||||||
useSlice(a[:i+10]) // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 100$"
|
useSlice(a[:i+10]) // ERROR "Proved IsSliceInBounds$"
|
||||||
useSlice(a[:i+11]) // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 101$"
|
useSlice(a[:i+11]) // ERROR "Proved IsSliceInBounds$"
|
||||||
|
useSlice(a[:i+12])
|
||||||
|
|
||||||
}
|
}
|
||||||
return a
|
return a
|
||||||
@ -169,19 +170,22 @@ func k1(a [100]int) [100]int {
|
|||||||
func k2(a [100]int) [100]int {
|
func k2(a [100]int) [100]int {
|
||||||
for i := 10; i < 90; i++ { // ERROR "Induction variable with minimum 10 and increment 1$"
|
for i := 10; i < 90; i++ { // ERROR "Induction variable with minimum 10 and increment 1$"
|
||||||
useSlice(a[i-11:])
|
useSlice(a[i-11:])
|
||||||
useSlice(a[i-10:]) // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 80$"
|
useSlice(a[i-10:]) // ERROR "Proved IsSliceInBounds$"
|
||||||
useSlice(a[i-5:]) // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 85$"
|
useSlice(a[i-5:]) // ERROR "Proved IsSliceInBounds$"
|
||||||
useSlice(a[i:]) // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 90$"
|
useSlice(a[i:]) // ERROR "Proved IsSliceInBounds$"
|
||||||
useSlice(a[i+5:]) // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 95$"
|
useSlice(a[i+5:]) // ERROR "Proved IsSliceInBounds$"
|
||||||
useSlice(a[i+10:]) // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 100$"
|
useSlice(a[i+10:]) // ERROR "Proved IsSliceInBounds$"
|
||||||
useSlice(a[i+11:]) // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 101$"
|
useSlice(a[i+11:]) // ERROR "Proved IsSliceInBounds$"
|
||||||
|
useSlice(a[i+12:])
|
||||||
}
|
}
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
func k3(a [100]int) [100]int {
|
func k3(a [100]int) [100]int {
|
||||||
for i := -10; i < 90; i++ { // ERROR "Induction variable with minimum -10 and increment 1$"
|
for i := -10; i < 90; i++ { // ERROR "Induction variable with minimum -10 and increment 1$"
|
||||||
a[i+10] = i // ERROR "Found redundant \(IsInBounds ind 100\), ind < 100$"
|
a[i+9] = i
|
||||||
|
a[i+10] = i // ERROR "Proved IsInBounds$"
|
||||||
|
a[i+11] = i
|
||||||
}
|
}
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
@ -189,7 +193,7 @@ func k3(a [100]int) [100]int {
|
|||||||
func k4(a [100]int) [100]int {
|
func k4(a [100]int) [100]int {
|
||||||
min := (-1) << 63
|
min := (-1) << 63
|
||||||
for i := min; i < min+50; i++ { // ERROR "Induction variable with minimum -9223372036854775808 and increment 1$"
|
for i := min; i < min+50; i++ { // ERROR "Induction variable with minimum -9223372036854775808 and increment 1$"
|
||||||
a[i-min] = i // ERROR "Found redundant \(IsInBounds ind 100\), ind < 50$"
|
a[i-min] = i // ERROR "Proved IsInBounds$"
|
||||||
}
|
}
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
@ -197,8 +201,8 @@ func k4(a [100]int) [100]int {
|
|||||||
func k5(a [100]int) [100]int {
|
func k5(a [100]int) [100]int {
|
||||||
max := (1 << 63) - 1
|
max := (1 << 63) - 1
|
||||||
for i := max - 50; i < max; i++ { // ERROR "Induction variable with minimum 9223372036854775757 and increment 1$"
|
for i := max - 50; i < max; i++ { // ERROR "Induction variable with minimum 9223372036854775757 and increment 1$"
|
||||||
a[i-max+50] = i // ERROR "Found redundant \(IsInBounds ind 100\), ind < 50$"
|
a[i-max+50] = i // ERROR "Proved IsInBounds$"
|
||||||
a[i-(max-70)] = i // ERROR "Found redundant \(IsInBounds ind 100\), ind < 70$"
|
a[i-(max-70)] = i // ERROR "Proved IsInBounds$"
|
||||||
}
|
}
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
@ -221,10 +225,10 @@ func nobce1() {
|
|||||||
|
|
||||||
func nobce2(a string) {
|
func nobce2(a string) {
|
||||||
for i := int64(0); i < int64(len(a)); i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
|
for i := int64(0); i < int64(len(a)); i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
|
||||||
useString(a[i:]) // ERROR "Found redundant IsSliceInBounds$"
|
useString(a[i:]) // ERROR "Proved IsSliceInBounds$"
|
||||||
}
|
}
|
||||||
for i := int64(0); i < int64(len(a))-31337; i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
|
for i := int64(0); i < int64(len(a))-31337; i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
|
||||||
useString(a[i:]) // ERROR "Found redundant IsSliceInBounds$"
|
useString(a[i:]) // ERROR "Proved IsSliceInBounds$"
|
||||||
}
|
}
|
||||||
for i := int64(0); i < int64(len(a))+int64(-1<<63); i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
|
for i := int64(0); i < int64(len(a))+int64(-1<<63); i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
|
||||||
// tests an overflow of StringLen-MinInt64
|
// tests an overflow of StringLen-MinInt64
|
||||||
|
@ -62,7 +62,7 @@ func f1c(a []int, i int64) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func f2(a []int) int {
|
func f2(a []int) int {
|
||||||
for i := range a {
|
for i := range a { // ERROR "Induction variable with minimum 0 and increment 1"
|
||||||
a[i+1] = i
|
a[i+1] = i
|
||||||
a[i+1] = i // ERROR "Proved IsInBounds$"
|
a[i+1] = i // ERROR "Proved IsInBounds$"
|
||||||
}
|
}
|
||||||
@ -464,8 +464,7 @@ func f16(s []int) []int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func f17(b []int) {
|
func f17(b []int) {
|
||||||
for i := 0; i < len(b); i++ {
|
for i := 0; i < len(b); i++ { // ERROR "Induction variable with minimum 0 and increment 1"
|
||||||
useSlice(b[i:]) // Learns i <= len
|
|
||||||
// This tests for i <= cap, which we can only prove
|
// This tests for i <= cap, which we can only prove
|
||||||
// using the derived relation between len and cap.
|
// using the derived relation between len and cap.
|
||||||
// This depends on finding the contradiction, since we
|
// This depends on finding the contradiction, since we
|
||||||
|
Loading…
Reference in New Issue
Block a user