cmd/compile: implement reverse bounds check elimination
When an index expression of the form base+k (where k > 0) is proven
to be within bounds, we can also deduce that base is within bounds.
This allows eliminating redundant bounds checks when array accesses
happen in "reverse" order.
For example:
if i >= 0 && i+1 < len(a) {
_ = a[i+1] // bounds check needed
_ = a[i] // bounds check can now be eliminated
}
This optimization benefits common patterns like digit conversion
in strconv.Itoa where digits are written in pairs from high
to low indices.
Fixes #75955
diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go
index de16dfb..d40b085 100644
--- a/src/cmd/compile/internal/ssa/prove.go
+++ b/src/cmd/compile/internal/ssa/prove.go
@@ -741,6 +741,14 @@
ft.setNonNegative(v.Args[0])
ft.update(v.Block, v.Args[0], v.Args[1], signed, r)
ft.update(v.Block, v.Args[0], v.Args[1], unsigned, r)
+ // If the index is of the form base+k where k > 0,
+ // then base+k < bound implies base < bound.
+ // This allows eliminating bounds checks on base
+ // after we've checked base+k (reverse BCE).
+ if base, delta := isConstDelta(v.Args[0]); base != nil && delta > 0 {
+ ft.update(v.Block, base, v.Args[1], signed, r)
+ ft.update(v.Block, base, v.Args[1], unsigned, r)
+ }
} else {
// On the negative branch, we learn (0 > a0 ||
// a0 >= a1). In the unsigned domain, this is
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
This is not correct, for this program:
```
package main
//go:noinline
func f(a string, i int) {
_ = a[i+1]
_ = a[i]
}
func main() {
f("foo", -1)
}
```We still need the idx >= 0 check on the second line. I think this CL removes it because of the unsigned rule. (Because -1 is not less than 3 in the unsigned domain.)
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |