Commit f44404eb authored by Matthew Dempsky's avatar Matthew Dempsky

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 #32560.

Change-Id: Ie7afad7a56af92bd890ba5ff33c86d1df06cfd9a
Reviewed-on: https://go-review.googlesource.com/c/go/+/181797
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: default avatarJosh Bleecher Snyder <josharian@gmail.com>
Reviewed-by: default avatarDavid Chase <drchase@google.com>
Reviewed-by: default avatarKeith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 87367cf8
...@@ -553,15 +553,29 @@ func (ft *factsTable) isNonNegative(v *Value) bool { ...@@ -553,15 +553,29 @@ func (ft *factsTable) isNonNegative(v *Value) bool {
return true 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 // 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 return true
} }
// Check if v = x+delta, and we can use x's limits to prove that it's positive // 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 x, delta := isConstDelta(v); x != nil {
if l, has := ft.limits[x.ID]; has { 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 return true
} }
if delta < 0 && l.min >= -delta { if delta < 0 && l.min >= -delta {
......
// 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()
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment