Skip to content

Commit 8c6a579

Browse files
committed
cmd/compile: make prove use non-equality in subtraction for a stronger bound
Given: s := /* slice */ k := /* proved valid index in s (0 <= k < len(s)) */ v := s[k:] len(v) >= 1, so v[0] needs no bounds check. However, for len(v) = len(s) - k, we only checked if len(s) >= k and so could only prove len(v) >= 0, thus the bounds check wasn't removed. As far as I can tell these checks were commented out for performance, but after benchmarking prove I see no difference. Fixes: #76429
1 parent cead111 commit 8c6a579

File tree

3 files changed

+23
-17
lines changed

3 files changed

+23
-17
lines changed

src/cmd/compile/internal/ssa/prove.go

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2162,24 +2162,22 @@ func (ft *factsTable) detectSubRelations(v *Value) {
21622162
return // x-y might overflow
21632163
}
21642164

2165-
// Subtracting a positive number only makes
2166-
// things smaller.
2167-
if yLim.min >= 0 {
2165+
// Subtracting a positive non-zero number only makes
2166+
// things smaller. If it's positive or zero, it might
2167+
// also do nothing (x-0 == v).
2168+
if yLim.min > 0 {
2169+
ft.update(v.Block, v, x, signed, lt)
2170+
} else if yLim.min == 0 {
21682171
ft.update(v.Block, v, x, signed, lt|eq)
2169-
// TODO: is this worth it?
2170-
//if yLim.min > 0 {
2171-
// ft.update(v.Block, v, x, signed, lt)
2172-
//}
21732172
}
21742173

21752174
// Subtracting a number from a bigger one
2176-
// can't go below 0.
2177-
if ft.orderS.OrderedOrEqual(y, x) {
2175+
// can't go below 1. If the numbers might be
2176+
// equal, then it can't go below 0.
2177+
if ft.orderS.Ordered(y, x) {
2178+
ft.signedMin(v, 1)
2179+
} else if ft.orderS.OrderedOrEqual(y, x) {
21782180
ft.setNonNegative(v)
2179-
// TODO: is this worth it?
2180-
//if ft.orderS.Ordered(y, x) {
2181-
// ft.signedMin(v, 1)
2182-
//}
21832181
}
21842182
}
21852183

test/loopbce.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ func f0a(a []int) int {
1717
func f0b(a []int) int {
1818
x := 0
1919
for i := range a { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
20-
b := a[i:] // ERROR "Proved IsSliceInBounds$"
21-
x += b[0]
20+
b := a[i:] // ERROR "Proved IsSliceInBounds$" "Proved slicemask not needed \(by limit\)$"
21+
x += b[0] // ERROR "Proved IsInBounds$"
2222
}
2323
return x
2424
}
@@ -417,7 +417,7 @@ func bce1() {
417417

418418
func nobce2(a string) {
419419
for i := int64(0); i < int64(len(a)); i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
420-
useString(a[i:]) // ERROR "Proved IsSliceInBounds$"
420+
useString(a[i:]) // ERROR "Proved IsSliceInBounds$" "Proved slicemask not needed \(by limit\)$"
421421
}
422422
for i := int64(0); i < int64(len(a))-31337; i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
423423
useString(a[i:]) // ERROR "Proved IsSliceInBounds$" "Proved slicemask not needed"

test/prove.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2552,7 +2552,7 @@ func swapbound(v []int) {
25522552
for i := 0; i < len(v)/2; i++ { // ERROR "Proved Div64 is unsigned|Induction variable"
25532553
v[i], // ERROR "Proved IsInBounds"
25542554
v[len(v)-1-i] = // ERROR "Proved IsInBounds"
2555-
v[len(v)-1-i],
2555+
v[len(v)-1-i], // ERROR "Proved IsInBounds"
25562556
v[i] // ERROR "Proved IsInBounds"
25572557
}
25582558
}
@@ -2718,6 +2718,14 @@ func detectStringLenRelation(s string) bool {
27182718
return false
27192719
}
27202720

2721+
func issue76429(s []byte, k int) byte {
2722+
if k < 0 || k >= len(s) {
2723+
return 0
2724+
}
2725+
s = s[k:] // ERROR "Proved IsSliceInBounds" "Proved slicemask not needed"
2726+
return s[0] // ERROR "Proved IsInBounds"
2727+
}
2728+
27212729
//go:noinline
27222730
func prove(x int) {
27232731
}

0 commit comments

Comments
 (0)