]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: detect indvars that are bound by other indvars
authorGiovanni Bajo <rasky@develer.com>
Mon, 16 Sep 2019 08:25:48 +0000 (10:25 +0200)
committerGiovanni Bajo <rasky@develer.com>
Thu, 26 Sep 2019 18:47:12 +0000 (18:47 +0000)
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>
src/cmd/compile/internal/ssa/loopbce.go
test/loopbce.go

index 2ce687822a04b961f586e8e87a9e5b6732523f6b..bfa259749356730cd3bd524908ea7b9ab76acee2 100644 (file)
@@ -111,17 +111,25 @@ 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 {
-                       continue
+                       // 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.
index e0a6463c5e496687183f0ba280de474d7c5dcaeb..f0c9bd0f81985d8a2ba2bb78fdbf53c262352747 100644 (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)