mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: enhance prove to infer bounds in slice len/cap calculations
the example comes up in chunked reslicing, e.g. A[i:] where i has a relationship with len(A)-K. Cherry-picked from the dev.simd branch. This CL is not necessarily SIMD specific. Apply early to reduce risk. Change-Id: Ib97dede6cfc7bbbd27b4f384988f741760686604 Reviewed-on: https://go-review.googlesource.com/c/go/+/704875 Reviewed-by: Keith Randall <khr@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Keith Randall <khr@golang.org> Reviewed-on: https://go-review.googlesource.com/c/go/+/708863 Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
20c9377e47
commit
d91148c7a8
1 changed files with 64 additions and 1 deletions
|
|
@ -1766,7 +1766,8 @@ func (ft *factsTable) flowLimit(v *Value) bool {
|
||||||
b := ft.limits[v.Args[1].ID]
|
b := ft.limits[v.Args[1].ID]
|
||||||
sub := ft.newLimit(v, a.sub(b, uint(v.Type.Size())*8))
|
sub := ft.newLimit(v, a.sub(b, uint(v.Type.Size())*8))
|
||||||
mod := ft.detectSignedMod(v)
|
mod := ft.detectSignedMod(v)
|
||||||
return sub || mod
|
inferred := ft.detectSliceLenRelation(v)
|
||||||
|
return sub || mod || inferred
|
||||||
case OpNeg64, OpNeg32, OpNeg16, OpNeg8:
|
case OpNeg64, OpNeg32, OpNeg16, OpNeg8:
|
||||||
a := ft.limits[v.Args[0].ID]
|
a := ft.limits[v.Args[0].ID]
|
||||||
bitsize := uint(v.Type.Size()) * 8
|
bitsize := uint(v.Type.Size()) * 8
|
||||||
|
|
@ -1947,6 +1948,68 @@ func (ft *factsTable) detectSignedMod(v *Value) bool {
|
||||||
// TODO: non-powers-of-2
|
// TODO: non-powers-of-2
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// detectSliceLenRelation matches the pattern where
|
||||||
|
// 1. v := slicelen - index, OR v := slicecap - index
|
||||||
|
// AND
|
||||||
|
// 2. index <= slicelen - K
|
||||||
|
// THEN
|
||||||
|
//
|
||||||
|
// slicecap - index >= slicelen - index >= K
|
||||||
|
//
|
||||||
|
// Note that "index" is not useed for indexing in this pattern, but
|
||||||
|
// in the motivating example (chunked slice iteration) it is.
|
||||||
|
func (ft *factsTable) detectSliceLenRelation(v *Value) (inferred bool) {
|
||||||
|
if v.Op != OpSub64 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !(v.Args[0].Op == OpSliceLen || v.Args[0].Op == OpSliceCap) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
slice := v.Args[0].Args[0]
|
||||||
|
index := v.Args[1]
|
||||||
|
|
||||||
|
for o := ft.orderings[index.ID]; o != nil; o = o.next {
|
||||||
|
if o.d != signed {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
or := o.r
|
||||||
|
if or != lt && or != lt|eq {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ow := o.w
|
||||||
|
if ow.Op != OpAdd64 && ow.Op != OpSub64 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var lenOffset *Value
|
||||||
|
if bound := ow.Args[0]; bound.Op == OpSliceLen && bound.Args[0] == slice {
|
||||||
|
lenOffset = ow.Args[1]
|
||||||
|
} else if bound := ow.Args[1]; bound.Op == OpSliceLen && bound.Args[0] == slice {
|
||||||
|
lenOffset = ow.Args[0]
|
||||||
|
}
|
||||||
|
if lenOffset == nil || lenOffset.Op != OpConst64 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
K := lenOffset.AuxInt
|
||||||
|
if ow.Op == OpAdd64 {
|
||||||
|
K = -K
|
||||||
|
}
|
||||||
|
if K < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if or == lt {
|
||||||
|
K++
|
||||||
|
}
|
||||||
|
if K < 0 { // We hate thinking about overflow
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
inferred = inferred || ft.signedMin(v, K)
|
||||||
|
}
|
||||||
|
return inferred
|
||||||
|
}
|
||||||
|
|
||||||
func (ft *factsTable) detectSignedModByPowerOfTwo(v *Value) bool {
|
func (ft *factsTable) detectSignedModByPowerOfTwo(v *Value) bool {
|
||||||
// We're looking for:
|
// We're looking for:
|
||||||
//
|
//
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue