Skip to content

Commit d91148c

Browse files
dr2chasecherrymui
authored andcommitted
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 <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Keith Randall <[email protected]> Reviewed-on: https://go-review.googlesource.com/c/go/+/708863 Reviewed-by: David Chase <[email protected]>
1 parent 20c9377 commit d91148c

File tree

1 file changed

+64
-1
lines changed

1 file changed

+64
-1
lines changed

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

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1766,7 +1766,8 @@ func (ft *factsTable) flowLimit(v *Value) bool {
17661766
b := ft.limits[v.Args[1].ID]
17671767
sub := ft.newLimit(v, a.sub(b, uint(v.Type.Size())*8))
17681768
mod := ft.detectSignedMod(v)
1769-
return sub || mod
1769+
inferred := ft.detectSliceLenRelation(v)
1770+
return sub || mod || inferred
17701771
case OpNeg64, OpNeg32, OpNeg16, OpNeg8:
17711772
a := ft.limits[v.Args[0].ID]
17721773
bitsize := uint(v.Type.Size()) * 8
@@ -1947,6 +1948,68 @@ func (ft *factsTable) detectSignedMod(v *Value) bool {
19471948
// TODO: non-powers-of-2
19481949
return false
19491950
}
1951+
1952+
// detectSliceLenRelation matches the pattern where
1953+
// 1. v := slicelen - index, OR v := slicecap - index
1954+
// AND
1955+
// 2. index <= slicelen - K
1956+
// THEN
1957+
//
1958+
// slicecap - index >= slicelen - index >= K
1959+
//
1960+
// Note that "index" is not useed for indexing in this pattern, but
1961+
// in the motivating example (chunked slice iteration) it is.
1962+
func (ft *factsTable) detectSliceLenRelation(v *Value) (inferred bool) {
1963+
if v.Op != OpSub64 {
1964+
return false
1965+
}
1966+
1967+
if !(v.Args[0].Op == OpSliceLen || v.Args[0].Op == OpSliceCap) {
1968+
return false
1969+
}
1970+
1971+
slice := v.Args[0].Args[0]
1972+
index := v.Args[1]
1973+
1974+
for o := ft.orderings[index.ID]; o != nil; o = o.next {
1975+
if o.d != signed {
1976+
continue
1977+
}
1978+
or := o.r
1979+
if or != lt && or != lt|eq {
1980+
continue
1981+
}
1982+
ow := o.w
1983+
if ow.Op != OpAdd64 && ow.Op != OpSub64 {
1984+
continue
1985+
}
1986+
var lenOffset *Value
1987+
if bound := ow.Args[0]; bound.Op == OpSliceLen && bound.Args[0] == slice {
1988+
lenOffset = ow.Args[1]
1989+
} else if bound := ow.Args[1]; bound.Op == OpSliceLen && bound.Args[0] == slice {
1990+
lenOffset = ow.Args[0]
1991+
}
1992+
if lenOffset == nil || lenOffset.Op != OpConst64 {
1993+
continue
1994+
}
1995+
K := lenOffset.AuxInt
1996+
if ow.Op == OpAdd64 {
1997+
K = -K
1998+
}
1999+
if K < 0 {
2000+
continue
2001+
}
2002+
if or == lt {
2003+
K++
2004+
}
2005+
if K < 0 { // We hate thinking about overflow
2006+
continue
2007+
}
2008+
inferred = inferred || ft.signedMin(v, K)
2009+
}
2010+
return inferred
2011+
}
2012+
19502013
func (ft *factsTable) detectSignedModByPowerOfTwo(v *Value) bool {
19512014
// We're looking for:
19522015
//

0 commit comments

Comments
 (0)