diff options
author | David Chase <drchase@google.com> | 2018-09-19 16:20:35 -0400 |
---|---|---|
committer | David Chase <drchase@google.com> | 2019-03-29 20:08:07 +0000 |
commit | d8f60eea64a568b272222960eb253bfc08cfbac2 (patch) | |
tree | 16396234c088c6890d367662a48900ec6d5d79bd /test/prove.go | |
parent | c90f6dd4966087d85e1dcafc02b64ecb0c7f4e7e (diff) | |
download | go-d8f60eea64a568b272222960eb253bfc08cfbac2.tar.gz go-d8f60eea64a568b272222960eb253bfc08cfbac2.zip |
cmd/compile: enhance induction variable detection for unrolled loops
Would suggest extending capabilities (32-bit, unsigned, etc)
in separate CLs because prove bugs are so mystifying.
This implements the suggestion in this comment
https://go-review.googlesource.com/c/go/+/104041/10/src/cmd/compile/internal/ssa/loopbce.go#164
for inferring properly bounded iteration for loops of the form
for i := K0; i < KNN-(K-1); i += K
for i := K0; i <= KNN-K; i += K
Where KNN is "known non negative" (i.e., len or cap) and K
is also not negative. Because i <= KNN-K, i+K <= KNN and
no overflow occurs.
Also handles decreasing case (K1 > 0)
for i := KNN; i >= K0; i -= K1
which works when MININT+K1 < K0
(i.e. MININT < K0-K1, no overflow)
Signed only, also only 64 bit for now.
Change-Id: I5da6015aba2f781ec76c4ad59c9c48d952325fdc
Reviewed-on: https://go-review.googlesource.com/c/go/+/136375
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alexandru Moșoi <alexandru@mosoi.ro>
Diffstat (limited to 'test/prove.go')
-rw-r--r-- | test/prove.go | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/test/prove.go b/test/prove.go index 275528dde7..39b23c5e0a 100644 --- a/test/prove.go +++ b/test/prove.go @@ -726,6 +726,123 @@ func signHint2(b []byte, n int) { } } +// Induction variable in unrolled loop. +func unrollUpExcl(a []int) int { + var i, x int + for i = 0; i < len(a)-1; i += 2 { // ERROR "Induction variable: limits \[0,\?\), increment 2$" + x += a[i] // ERROR "Proved IsInBounds$" + x += a[i+1] + } + if i == len(a)-1 { + x += a[i] + } + return x +} + +// Induction variable in unrolled loop. +func unrollUpIncl(a []int) int { + var i, x int + for i = 0; i <= len(a)-2; i += 2 { // ERROR "Induction variable: limits \[0,\?\], increment 2$" + x += a[i] + x += a[i+1] + } + if i == len(a)-1 { + x += a[i] + } + return x +} + +// Induction variable in unrolled loop. +func unrollDownExcl0(a []int) int { + var i, x int + for i = len(a) - 1; i > 0; i -= 2 { // ERROR "Induction variable: limits \(0,\?\], increment 2$" + x += a[i] // ERROR "Proved IsInBounds$" + x += a[i-1] // ERROR "Proved IsInBounds$" + } + if i == 0 { + x += a[i] + } + return x +} + +// Induction variable in unrolled loop. +func unrollDownExcl1(a []int) int { + var i, x int + for i = len(a) - 1; i >= 1; i -= 2 { // ERROR "Induction variable: limits \[1,\?\], increment 2$" + x += a[i] // ERROR "Proved IsInBounds$" + x += a[i-1] // ERROR "Proved IsInBounds$" + } + if i == 0 { + x += a[i] + } + return x +} + +// Induction variable in unrolled loop. +func unrollDownInclStep(a []int) int { + var i, x int + for i = len(a); i >= 2; i -= 2 { // ERROR "Induction variable: limits \[2,\?\], increment 2$" + x += a[i-1] // ERROR "Proved IsInBounds$" + x += a[i-2] + } + if i == 1 { + x += a[i-1] + } + return x +} + +// Not an induction variable (step too large) +func unrollExclStepTooLarge(a []int) int { + var i, x int + for i = 0; i < len(a)-1; i += 3 { + x += a[i] + x += a[i+1] + } + if i == len(a)-1 { + x += a[i] + } + return x +} + +// Not an induction variable (step too large) +func unrollInclStepTooLarge(a []int) int { + var i, x int + for i = 0; i <= len(a)-2; i += 3 { + x += a[i] + x += a[i+1] + } + if i == len(a)-1 { + x += a[i] + } + return x +} + +// Not an induction variable (min too small, iterating down) +func unrollDecMin(a []int) int { + var i, x int + for i = len(a); i >= math.MinInt64; i -= 2 { + x += a[i-1] + x += a[i-2] + } + if i == 1 { // ERROR "Disproved Eq64$" + x += a[i-1] + } + return x +} + +// Not an induction variable (min too small, iterating up -- perhaps could allow, but why bother?) +func unrollIncMin(a []int) int { + var i, x int + for i = len(a); i >= math.MinInt64; i += 2 { + x += a[i-1] + x += a[i-2] + } + if i == 1 { // ERROR "Disproved Eq64$" + x += a[i-1] + } + return x +} + //go:noinline func useInt(a int) { } |