mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
Prove currently checks for 0 sign bit extraction (x>>63) at the end of the pass, but it is more general and more useful (and not really more work) to model right shift during value range tracking. This handles sign bit extraction (both 0 and -1) but also makes the value ranges available for proving bounds checks. 'go build -a -gcflags=-d=ssa/prove/debug=1 std' finds 105 new things to prove. https://gist.github.com/rsc/8ac41176e53ed9c2f1a664fc668e8336 For example, the compiler now recognizes that this code in strconv does not need to check the second shift for being ≥ 64. msb := xHi >> 63 retMantissa := xHi >> (msb + 38) nor does this code in regexp: return b < utf8.RuneSelf && specialBytes[b%16]&(1<<(b/16)) != 0 This code in math no longer has a bounds check on the first index: if 0 <= n && n <= 308 { return pow10postab32[uint(n)/32] * pow10tab[uint(n)%32] } The diff shows one "lost" proof in ycbcr.go but it's not really lost: the expression was folded to a constant instead, and that only shows up with debug=2. A diff of that output is at https://gist.github.com/rsc/9139ed46c6019ae007f5a1ba4bb3250f Change-Id: I84087311e0a303f00e2820d957a6f8b29ee22519 Reviewed-on: https://go-review.googlesource.com/c/go/+/716140 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Russ Cox <rsc@golang.org> Reviewed-by: David Chase <drchase@google.com>
81 lines
1.6 KiB
Go
81 lines
1.6 KiB
Go
// errorcheck -0 -d=ssa/prove/debug=2
|
|
|
|
//go:build amd64 || arm64
|
|
|
|
// Copyright 2022 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.
|
|
|
|
package main
|
|
|
|
func f0i(x int) int {
|
|
if x == 20 {
|
|
return x // ERROR "Proved.+is constant 20$"
|
|
}
|
|
|
|
if (x + 20) == 20 {
|
|
return x + 5 // ERROR "Proved.+is constant 0$" "Proved.+is constant 5$" "x\+d >=? w"
|
|
}
|
|
|
|
return x + 1
|
|
}
|
|
|
|
func f0u(x uint) int {
|
|
if x == 20 {
|
|
return int(x) // ERROR "Proved.+is constant 20$"
|
|
}
|
|
|
|
if (x + 20) == 20 {
|
|
return int(x + 5) // ERROR "Proved.+is constant 0$" "Proved.+is constant 5$" "x\+d >=? w"
|
|
}
|
|
|
|
if x < 1000 {
|
|
return int(x)>>31 // ERROR "Proved.+is constant 0$"
|
|
}
|
|
if x := int32(x); x < -1000 {
|
|
return int(x>>31) // ERROR "Proved.+is constant -1$"
|
|
}
|
|
|
|
return int(x) + 1
|
|
}
|
|
|
|
// Check that prove is zeroing these right shifts of positive ints by bit-width - 1.
|
|
// e.g (Rsh64x64 <t> n (Const64 <typ.UInt64> [63])) && ft.isNonNegative(n) -> 0
|
|
func sh64(n int64) int64 {
|
|
if n < 0 {
|
|
return n
|
|
}
|
|
return n >> 63 // ERROR "Proved .+ is constant 0$"
|
|
}
|
|
|
|
func sh32(n int32) int32 {
|
|
if n < 0 {
|
|
return n
|
|
}
|
|
return n >> 31 // ERROR "Proved .+ is constant 0$"
|
|
}
|
|
|
|
func sh32x64(n int32) int32 {
|
|
if n < 0 {
|
|
return n
|
|
}
|
|
return n >> uint64(31) // ERROR "Proved .+ is constant 0$"
|
|
}
|
|
|
|
func sh32x64n(n int32) int32 {
|
|
if n >= 0 {
|
|
return 0
|
|
}
|
|
return n >> 31// ERROR "Proved .+ is constant -1$"
|
|
}
|
|
|
|
func sh16(n int16) int16 {
|
|
if n < 0 {
|
|
return n
|
|
}
|
|
return n >> 15 // ERROR "Proved .+ is constant 0$"
|
|
}
|
|
|
|
func sh64noopt(n int64) int64 {
|
|
return n >> 63 // not optimized; n could be negative
|
|
}
|