1
0
mirror of https://github.com/golang/go synced 2024-11-11 18:21:40 -07:00

cmd/compile: detect indvars that are bound by other indvars

prove wasn't able to detect induction variables that was bound
by another inducation variable. This happened because an indvar
is a Phi, and thus in case of a dependency, the loop bounding
condition looked as Phi < Phi. This triggered an existing
codepath that checked whether the upper bound was a Phi to
detect loop conditions written in reversed order respect to the
idiomatic way (eg: for i:=0; len(n)>i; i++).

To fix this, we call the indvar pattern matching on both operands
of the loop condition, so that the first operand that matches
will be treated as the indvar.

Updates #24660 (removes a boundcheck from Fannkuch)

Change-Id: Iade83d8deb54f14277ed3f2e37b190e1ed173d11
Reviewed-on: https://go-review.googlesource.com/c/go/+/195220
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Giovanni Bajo 2019-09-16 10:25:48 +02:00
parent 9740b60e14
commit 1658263bbf
2 changed files with 49 additions and 8 deletions

View File

@ -111,19 +111,27 @@ func findIndVar(f *Func) []indVar {
continue
}
// See if the arguments are reversed (i < len() <=> len() > i)
less := true
if max.Op == OpPhi {
ind, max = max, ind
less = false
}
// See if this is really an induction variable
less := true
min, inc, nxt := parseIndVar(ind)
if min == nil {
// We failed to parse the induction variable. Before punting, we want to check
// whether the control op was written with arguments in non-idiomatic order,
// so that we believe being "max" (the upper bound) is actually the induction
// variable itself. This would happen for code like:
// for i := 0; len(n) > i; i++
min, inc, nxt = parseIndVar(max)
if min == nil {
// No recognied induction variable on either operand
continue
}
// Ok, the arguments were reversed. Swap them, and remember that we're
// looking at a ind >/>= loop (so the induction must be decrementing).
ind, max = max, ind
less = false
}
// Expect the increment to be a nonzero constant.
if inc.Op != OpConst64 {
continue

View File

@ -257,6 +257,39 @@ func k5(a [100]int) [100]int {
return a
}
func d1(a [100]int) [100]int {
for i := 0; i < 100; i++ { // ERROR "Induction variable: limits \[0,100\), increment 1$"
for j := 0; j < i; j++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
a[j] = 0 // ERROR "Proved IsInBounds$"
a[j+1] = 0 // FIXME: this boundcheck should be eliminated
a[j+2] = 0
}
}
return a
}
func d2(a [100]int) [100]int {
for i := 0; i < 100; i++ { // ERROR "Induction variable: limits \[0,100\), increment 1$"
for j := 0; i > j; j++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
a[j] = 0 // ERROR "Proved IsInBounds$"
a[j+1] = 0 // FIXME: this boundcheck should be eliminated
a[j+2] = 0
}
}
return a
}
func d3(a [100]int) [100]int {
for i := 0; i <= 99; i++ { // ERROR "Induction variable: limits \[0,99\], increment 1$"
for j := 0; j <= i-1; j++ { // ERROR "Induction variable: limits \[0,\?\], increment 1$"
a[j] = 0 // ERROR "Proved IsInBounds$"
a[j+1] = 0 // ERROR "Proved IsInBounds$"
a[j+2] = 0
}
}
return a
}
func nobce1() {
// tests overflow of max-min
a := int64(9223372036854774057)