aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Dempsky <mdempsky@google.com>2019-06-11 19:52:58 -0700
committerRuss Cox <rsc@golang.org>2019-07-01 17:23:23 +0000
commit39b533ed6634079a5c4f6a3488f4b01cdab2d833 (patch)
tree7c59b4203e564c88db9a866c11635aa73343aac7
parent77c14d2973aa9365bf07ebe9b2c17585f8cece0c (diff)
downloadgo-39b533ed6634079a5c4f6a3488f4b01cdab2d833.tar.gz
go-39b533ed6634079a5c4f6a3488f4b01cdab2d833.zip
[release-branch.go1.12] cmd/compile: fix range analysis of small signed integers
For int8, int16, and int32, comparing their unsigned value to MaxInt64 to determine non-negativity doesn't make sense, because they have negative values whose unsigned representation is smaller than that. Fix is simply to compare with the appropriate upper bound based on the value type's size. Fixes #32583. Change-Id: Ie7afad7a56af92bd890ba5ff33c86d1df06cfd9a Reviewed-on: https://go-review.googlesource.com/c/go/+/181797 Run-TryBot: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com> Reviewed-by: David Chase <drchase@google.com> Reviewed-by: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> (cherry picked from commit f44404ebbfeff57f3e45ebf4b314a320bb89841f) Reviewed-on: https://go-review.googlesource.com/c/go/+/181978 Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
-rw-r--r--src/cmd/compile/internal/ssa/prove.go18
-rw-r--r--test/fixedbugs/issue32560.go51
2 files changed, 67 insertions, 2 deletions
diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go
index 1e5f4e9c6c..510af2ece9 100644
--- a/src/cmd/compile/internal/ssa/prove.go
+++ b/src/cmd/compile/internal/ssa/prove.go
@@ -549,15 +549,29 @@ func (ft *factsTable) isNonNegative(v *Value) bool {
return true
}
+ var max int64
+ switch v.Type.Size() {
+ case 1:
+ max = math.MaxInt8
+ case 2:
+ max = math.MaxInt16
+ case 4:
+ max = math.MaxInt32
+ case 8:
+ max = math.MaxInt64
+ default:
+ panic("unexpected integer size")
+ }
+
// Check if the recorded limits can prove that the value is positive
- if l, has := ft.limits[v.ID]; has && (l.min >= 0 || l.umax <= math.MaxInt64) {
+ if l, has := ft.limits[v.ID]; has && (l.min >= 0 || l.umax <= uint64(max)) {
return true
}
// Check if v = x+delta, and we can use x's limits to prove that it's positive
if x, delta := isConstDelta(v); x != nil {
if l, has := ft.limits[x.ID]; has {
- if delta > 0 && l.min >= -delta && l.max <= math.MaxInt64-delta {
+ if delta > 0 && l.min >= -delta && l.max <= max-delta {
return true
}
if delta < 0 && l.min >= -delta {
diff --git a/test/fixedbugs/issue32560.go b/test/fixedbugs/issue32560.go
new file mode 100644
index 0000000000..c6f72b6b55
--- /dev/null
+++ b/test/fixedbugs/issue32560.go
@@ -0,0 +1,51 @@
+// run
+
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Values smaller than 64-bits were mistakenly always proven to be
+// non-negative.
+//
+// The tests here are marked go:noinline to ensure they're
+// independently optimized by SSA.
+
+package main
+
+var x int32 = -1
+
+//go:noinline
+func a() {
+ if x != -1 {
+ panic(1)
+ }
+ if x > 0 || x != -1 {
+ panic(2)
+ }
+}
+
+//go:noinline
+func b() {
+ if x != -1 {
+ panic(3)
+ }
+ if x > 0 {
+ panic(4)
+ }
+}
+
+//go:noinline
+func c() {
+ if x > 0 || x != -1 {
+ panic(5)
+ }
+ if x > 0 || x != -1 {
+ panic(6)
+ }
+}
+
+func main() {
+ a()
+ b()
+ c()
+}