Skip to content

Commit 1658263

Browse files
committed
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 <[email protected]>
1 parent 9740b60 commit 1658263

File tree

2 files changed

+49
-8
lines changed

2 files changed

+49
-8
lines changed

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

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,17 +111,25 @@ func findIndVar(f *Func) []indVar {
111111
continue
112112
}
113113

114-
// See if the arguments are reversed (i < len() <=> len() > i)
115-
less := true
116-
if max.Op == OpPhi {
117-
ind, max = max, ind
118-
less = false
119-
}
120-
121114
// See if this is really an induction variable
115+
less := true
122116
min, inc, nxt := parseIndVar(ind)
123117
if min == nil {
124-
continue
118+
// We failed to parse the induction variable. Before punting, we want to check
119+
// whether the control op was written with arguments in non-idiomatic order,
120+
// so that we believe being "max" (the upper bound) is actually the induction
121+
// variable itself. This would happen for code like:
122+
// for i := 0; len(n) > i; i++
123+
min, inc, nxt = parseIndVar(max)
124+
if min == nil {
125+
// No recognied induction variable on either operand
126+
continue
127+
}
128+
129+
// Ok, the arguments were reversed. Swap them, and remember that we're
130+
// looking at a ind >/>= loop (so the induction must be decrementing).
131+
ind, max = max, ind
132+
less = false
125133
}
126134

127135
// Expect the increment to be a nonzero constant.

test/loopbce.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,39 @@ func k5(a [100]int) [100]int {
257257
return a
258258
}
259259

260+
func d1(a [100]int) [100]int {
261+
for i := 0; i < 100; i++ { // ERROR "Induction variable: limits \[0,100\), increment 1$"
262+
for j := 0; j < i; j++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
263+
a[j] = 0 // ERROR "Proved IsInBounds$"
264+
a[j+1] = 0 // FIXME: this boundcheck should be eliminated
265+
a[j+2] = 0
266+
}
267+
}
268+
return a
269+
}
270+
271+
func d2(a [100]int) [100]int {
272+
for i := 0; i < 100; i++ { // ERROR "Induction variable: limits \[0,100\), increment 1$"
273+
for j := 0; i > j; j++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
274+
a[j] = 0 // ERROR "Proved IsInBounds$"
275+
a[j+1] = 0 // FIXME: this boundcheck should be eliminated
276+
a[j+2] = 0
277+
}
278+
}
279+
return a
280+
}
281+
282+
func d3(a [100]int) [100]int {
283+
for i := 0; i <= 99; i++ { // ERROR "Induction variable: limits \[0,99\], increment 1$"
284+
for j := 0; j <= i-1; j++ { // ERROR "Induction variable: limits \[0,\?\], increment 1$"
285+
a[j] = 0 // ERROR "Proved IsInBounds$"
286+
a[j+1] = 0 // ERROR "Proved IsInBounds$"
287+
a[j+2] = 0
288+
}
289+
}
290+
return a
291+
}
292+
260293
func nobce1() {
261294
// tests overflow of max-min
262295
a := int64(9223372036854774057)

0 commit comments

Comments
 (0)