mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: learn transitive proofs for safe positive signed adds
I've split this into it's own CL to make git bisect more effective. Change-Id: I3fbb42ec7d29169a29f7f55ef2c188317512f532 Reviewed-on: https://go-review.googlesource.com/c/go/+/685819 Auto-Submit: Michael Knyszek <mknyszek@google.com> Reviewed-by: Keith Randall <khr@golang.org> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Michael Knyszek <mknyszek@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
e5f202bb60
commit
1a72920f09
3 changed files with 111 additions and 14 deletions
|
|
@ -2148,6 +2148,22 @@ func unsignedAddOverflows(a, b uint64, t *types.Type) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func signedAddOverflowsOrUnderflows(a, b int64, t *types.Type) bool {
|
||||||
|
r := a + b
|
||||||
|
switch t.Size() {
|
||||||
|
case 8:
|
||||||
|
return (a >= 0 && b >= 0 && r < 0) || (a < 0 && b < 0 && r >= 0)
|
||||||
|
case 4:
|
||||||
|
return r < math.MinInt32 || math.MaxInt32 < r
|
||||||
|
case 2:
|
||||||
|
return r < math.MinInt16 || math.MaxInt16 < r
|
||||||
|
case 1:
|
||||||
|
return r < math.MinInt8 || math.MaxInt8 < r
|
||||||
|
default:
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func addLocalFacts(ft *factsTable, b *Block) {
|
func addLocalFacts(ft *factsTable, b *Block) {
|
||||||
// Propagate constant ranges among values in this block.
|
// Propagate constant ranges among values in this block.
|
||||||
// We do this before the second loop so that we have the
|
// We do this before the second loop so that we have the
|
||||||
|
|
@ -2182,6 +2198,20 @@ func addLocalFacts(ft *factsTable, b *Block) {
|
||||||
}
|
}
|
||||||
ft.update(b, v, v.Args[0], unsigned, r)
|
ft.update(b, v, v.Args[0], unsigned, r)
|
||||||
}
|
}
|
||||||
|
if x.min >= 0 && !signedAddOverflowsOrUnderflows(x.max, y.max, v.Type) {
|
||||||
|
r := gt
|
||||||
|
if !x.nonzero() {
|
||||||
|
r |= eq
|
||||||
|
}
|
||||||
|
ft.update(b, v, v.Args[1], signed, r)
|
||||||
|
}
|
||||||
|
if y.min >= 0 && !signedAddOverflowsOrUnderflows(x.max, y.max, v.Type) {
|
||||||
|
r := gt
|
||||||
|
if !y.nonzero() {
|
||||||
|
r |= eq
|
||||||
|
}
|
||||||
|
ft.update(b, v, v.Args[0], signed, r)
|
||||||
|
}
|
||||||
case OpAnd64, OpAnd32, OpAnd16, OpAnd8:
|
case OpAnd64, OpAnd32, OpAnd16, OpAnd8:
|
||||||
ft.update(b, v, v.Args[0], unsigned, lt|eq)
|
ft.update(b, v, v.Args[0], unsigned, lt|eq)
|
||||||
ft.update(b, v, v.Args[1], unsigned, lt|eq)
|
ft.update(b, v, v.Args[1], unsigned, lt|eq)
|
||||||
|
|
|
||||||
|
|
@ -2104,6 +2104,73 @@ func transitiveProofsThroughOverflowingUnsignedAdd(x, y, z uint64) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func transitiveProofsThroughNonOverflowingSignedAddPositive(x, y, z int64) {
|
||||||
|
x &= 1<<62 - 1
|
||||||
|
y &= 1<<62 - 1
|
||||||
|
|
||||||
|
a := x + y
|
||||||
|
if a > z {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if x > z { // ERROR "Disproved Less64$"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if y > z { // ERROR "Disproved Less64$"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if a == x {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if a == y {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
x |= 1
|
||||||
|
y |= 1
|
||||||
|
a = x + y
|
||||||
|
if a == x { // ERROR "Disproved Eq64$"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if a == y { // ERROR "Disproved Eq64$"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func transitiveProofsThroughOverflowingSignedAddPositive(x, y, z int64) {
|
||||||
|
if x < 0 || y < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
a := x + y
|
||||||
|
if a > z {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if x > z {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if y > z {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if a == x {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if a == y {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
x |= 1
|
||||||
|
y |= 1
|
||||||
|
a = x + y
|
||||||
|
if a == x { // ERROR "Disproved Eq64$"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if a == y { // ERROR "Disproved Eq64$"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//go:noinline
|
//go:noinline
|
||||||
func useInt(a int) {
|
func useInt(a int) {
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,25 +9,25 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
func f0i(x int) int {
|
func f0i(x int) int {
|
||||||
if x == 20 {
|
if x == 20 {
|
||||||
return x // ERROR "Proved.+is constant 20$"
|
return x // ERROR "Proved.+is constant 20$"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x + 20) == 20 {
|
if (x + 20) == 20 {
|
||||||
return x + 5 // ERROR "Proved.+is constant 0$" "Proved.+is constant 5$"
|
return x + 5 // ERROR "Proved.+is constant 0$" "Proved.+is constant 5$" "x\+d >=? w"
|
||||||
}
|
}
|
||||||
|
|
||||||
return x / 2
|
return x / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
func f0u(x uint) uint {
|
func f0u(x uint) uint {
|
||||||
if x == 20 {
|
if x == 20 {
|
||||||
return x // ERROR "Proved.+is constant 20$"
|
return x // ERROR "Proved.+is constant 20$"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x + 20) == 20 {
|
if (x + 20) == 20 {
|
||||||
return x + 5 // ERROR "Proved.+is constant 0$" "Proved.+is constant 5$"
|
return x + 5 // ERROR "Proved.+is constant 0$" "Proved.+is constant 5$" "x\+d >=? w"
|
||||||
}
|
}
|
||||||
|
|
||||||
return x / 2
|
return x / 2
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue