@@ -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+
19502013func (ft * factsTable ) detectSignedModByPowerOfTwo (v * Value ) bool {
19512014 // We're looking for:
19522015 //
0 commit comments