mirror of
https://github.com/golang/go
synced 2024-11-26 03:07:57 -07:00
cmd/compile: rewrite the constant parts of the prove pass
Handles a lot more cases where constant ranges can eliminate various (mostly bounds failure) paths. Fixes #66826 Fixes #66692 Fixes #48213 Update #57959 TODO: remove constant logic from poset code, no longer needed. Change-Id: Id196436fcd8a0c84c7d59c04f93bd92e26a0fd7e Reviewed-on: https://go-review.googlesource.com/c/go/+/599096 Reviewed-by: David Chase <drchase@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Knyszek <mknyszek@google.com>
This commit is contained in:
parent
553443d41f
commit
3b96eebcbd
@ -796,7 +796,7 @@ func (f *Func) invalidateCFG() {
|
|||||||
// base.DebugHashMatch(this function's package.name)
|
// base.DebugHashMatch(this function's package.name)
|
||||||
//
|
//
|
||||||
// for use in bug isolation. The return value is true unless
|
// for use in bug isolation. The return value is true unless
|
||||||
// environment variable GOSSAHASH is set, in which case "it depends".
|
// environment variable GOCOMPILEDEBUG=gossahash=X is set, in which case "it depends on X".
|
||||||
// See [base.DebugHashMatch] for more information.
|
// See [base.DebugHashMatch] for more information.
|
||||||
func (f *Func) DebugHashMatch() bool {
|
func (f *Func) DebugHashMatch() bool {
|
||||||
if !base.HasDebugHash() {
|
if !base.HasDebugHash() {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1188,6 +1188,8 @@ func logRule(s string) {
|
|||||||
|
|
||||||
var ruleFile io.Writer
|
var ruleFile io.Writer
|
||||||
|
|
||||||
|
// TODO: replace these with the built-in min/max once they are available
|
||||||
|
// during bootstrap (when bootstrapping with 1.21 or later).
|
||||||
func min(x, y int64) int64 {
|
func min(x, y int64) int64 {
|
||||||
if x < y {
|
if x < y {
|
||||||
return x
|
return x
|
||||||
@ -1200,6 +1202,18 @@ func max(x, y int64) int64 {
|
|||||||
}
|
}
|
||||||
return y
|
return y
|
||||||
}
|
}
|
||||||
|
func minU(x, y uint64) uint64 {
|
||||||
|
if x < y {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
func maxU(x, y uint64) uint64 {
|
||||||
|
if x > y {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
|
||||||
func isConstZero(v *Value) bool {
|
func isConstZero(v *Value) bool {
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
|
@ -159,16 +159,14 @@ func decode1(data []byte) (x uint64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func decode2(data []byte) (x uint64) {
|
func decode2(data []byte) (x uint64) {
|
||||||
// TODO(rasky): this should behave like decode1 and compile to no
|
|
||||||
// boundchecks. We're currently not able to remove all of them.
|
|
||||||
for len(data) >= 32 {
|
for len(data) >= 32 {
|
||||||
x += binary.BigEndian.Uint64(data)
|
x += binary.BigEndian.Uint64(data)
|
||||||
data = data[8:]
|
data = data[8:]
|
||||||
x += binary.BigEndian.Uint64(data) // ERROR "Found IsInBounds$"
|
x += binary.BigEndian.Uint64(data)
|
||||||
data = data[8:]
|
data = data[8:]
|
||||||
x += binary.BigEndian.Uint64(data) // ERROR "Found IsInBounds$"
|
x += binary.BigEndian.Uint64(data)
|
||||||
data = data[8:]
|
data = data[8:]
|
||||||
x += binary.BigEndian.Uint64(data) // ERROR "Found IsInBounds$"
|
x += binary.BigEndian.Uint64(data)
|
||||||
data = data[8:]
|
data = data[8:]
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
|
@ -268,7 +268,7 @@ func CmpToZero(a, b, d int32, e, f int64, deOptC0, deOptC1 bool) int32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CmpLogicalToZero(a, b, c uint32, d, e uint64) uint64 {
|
func CmpLogicalToZero(a, b, c uint32, d, e, f, g uint64) uint64 {
|
||||||
|
|
||||||
// ppc64x:"ANDCC",-"CMPW"
|
// ppc64x:"ANDCC",-"CMPW"
|
||||||
// wasm:"I64Eqz",-"I32Eqz",-"I64ExtendI32U",-"I32WrapI64"
|
// wasm:"I64Eqz",-"I32Eqz",-"I64ExtendI32U",-"I32WrapI64"
|
||||||
@ -289,7 +289,7 @@ func CmpLogicalToZero(a, b, c uint32, d, e uint64) uint64 {
|
|||||||
}
|
}
|
||||||
// ppc64x:"ORCC",-"CMP"
|
// ppc64x:"ORCC",-"CMP"
|
||||||
// wasm:"I64Eqz",-"I32Eqz",-"I64ExtendI32U",-"I32WrapI64"
|
// wasm:"I64Eqz",-"I32Eqz",-"I64ExtendI32U",-"I32WrapI64"
|
||||||
if d|e == 0 {
|
if f|g == 0 {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ func f0c(a []int) int {
|
|||||||
x := 0
|
x := 0
|
||||||
for i := range a { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
for i := range a { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
||||||
b := a[:i+1] // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
|
b := a[:i+1] // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
|
||||||
x += b[0]
|
x += b[0] // ERROR "(\([0-9]+\) )?Proved IsInBounds$"
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
@ -294,8 +294,10 @@ func k3neg2(a [100]int) [100]int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func k4(a [100]int) [100]int {
|
func k4(a [100]int) [100]int {
|
||||||
min := (-1) << 63
|
// Note: can't use (-1)<<63 here, because i-min doesn't get rewritten to i+(-min),
|
||||||
for i := min; i < min+50; i++ { // ERROR "Induction variable: limits \[-9223372036854775808,-9223372036854775758\), increment 1$"
|
// and it isn't worth adding that special case to prove.
|
||||||
|
min := (-1)<<63 + 1
|
||||||
|
for i := min; i < min+50; i++ { // ERROR "Induction variable: limits \[-9223372036854775807,-9223372036854775757\), increment 1$"
|
||||||
a[i-min] = i // ERROR "(\([0-9]+\) )?Proved IsInBounds$"
|
a[i-min] = i // ERROR "(\([0-9]+\) )?Proved IsInBounds$"
|
||||||
}
|
}
|
||||||
return a
|
return a
|
||||||
@ -314,7 +316,7 @@ func d1(a [100]int) [100]int {
|
|||||||
for i := 0; i < 100; i++ { // ERROR "Induction variable: limits \[0,100\), increment 1$"
|
for i := 0; i < 100; i++ { // ERROR "Induction variable: limits \[0,100\), increment 1$"
|
||||||
for j := 0; j < i; j++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
for j := 0; j < i; j++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
||||||
a[j] = 0 // ERROR "Proved IsInBounds$"
|
a[j] = 0 // ERROR "Proved IsInBounds$"
|
||||||
a[j+1] = 0 // FIXME: this boundcheck should be eliminated
|
a[j+1] = 0 // ERROR "Proved IsInBounds$"
|
||||||
a[j+2] = 0
|
a[j+2] = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -325,7 +327,7 @@ func d2(a [100]int) [100]int {
|
|||||||
for i := 0; i < 100; i++ { // ERROR "Induction variable: limits \[0,100\), increment 1$"
|
for i := 0; i < 100; i++ { // ERROR "Induction variable: limits \[0,100\), increment 1$"
|
||||||
for j := 0; i > j; j++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
for j := 0; i > j; j++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
||||||
a[j] = 0 // ERROR "Proved IsInBounds$"
|
a[j] = 0 // ERROR "Proved IsInBounds$"
|
||||||
a[j+1] = 0 // FIXME: this boundcheck should be eliminated
|
a[j+1] = 0 // ERROR "Proved IsInBounds$"
|
||||||
a[j+2] = 0
|
a[j+2] = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -419,12 +421,12 @@ func nobce2(a string) {
|
|||||||
for i := int64(0); i < int64(len(a))-31337; i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
for i := int64(0); i < int64(len(a))-31337; i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
||||||
useString(a[i:]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
|
useString(a[i:]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
|
||||||
}
|
}
|
||||||
for i := int64(0); i < int64(len(a))+int64(-1<<63); i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
for i := int64(0); i < int64(len(a))+int64(-1<<63); i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$" "Disproved Less64"
|
||||||
useString(a[i:]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
|
useString(a[i:])
|
||||||
}
|
}
|
||||||
j := int64(len(a)) - 123
|
j := int64(len(a)) - 123
|
||||||
for i := int64(0); i < j+123+int64(-1<<63); i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
for i := int64(0); i < j+123+int64(-1<<63); i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$" "Disproved Less64"
|
||||||
useString(a[i:]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
|
useString(a[i:])
|
||||||
}
|
}
|
||||||
for i := int64(0); i < j+122+int64(-1<<63); i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
for i := int64(0); i < j+122+int64(-1<<63); i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
||||||
// len(a)-123+122+MinInt overflows when len(a) == 0, so a bound check is needed here
|
// len(a)-123+122+MinInt overflows when len(a) == 0, so a bound check is needed here
|
||||||
|
@ -400,8 +400,8 @@ func f13f(a, b int64) int64 {
|
|||||||
if b != math.MaxInt64 {
|
if b != math.MaxInt64 {
|
||||||
return 42
|
return 42
|
||||||
}
|
}
|
||||||
if a > b {
|
if a > b { // ERROR "Disproved Less64$"
|
||||||
if a == 0 { // ERROR "Disproved Eq64$"
|
if a == 0 {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -684,20 +684,6 @@ func constsuffix(s string) bool {
|
|||||||
return suffix(s, "abc") // ERROR "Proved IsSliceInBounds$"
|
return suffix(s, "abc") // ERROR "Proved IsSliceInBounds$"
|
||||||
}
|
}
|
||||||
|
|
||||||
// oforuntil tests the pattern created by OFORUNTIL blocks. These are
|
|
||||||
// handled by addLocalInductiveFacts rather than findIndVar.
|
|
||||||
func oforuntil(b []int) {
|
|
||||||
i := 0
|
|
||||||
if len(b) > i {
|
|
||||||
top:
|
|
||||||
println(b[i]) // ERROR "Induction variable: limits \[0,\?\), increment 1$" "Proved IsInBounds$"
|
|
||||||
i++
|
|
||||||
if i < len(b) {
|
|
||||||
goto top
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func atexit(foobar []func()) {
|
func atexit(foobar []func()) {
|
||||||
for i := len(foobar) - 1; i >= 0; i-- { // ERROR "Induction variable: limits \[0,\?\], increment 1"
|
for i := len(foobar) - 1; i >= 0; i-- { // ERROR "Induction variable: limits \[0,\?\], increment 1"
|
||||||
f := foobar[i]
|
f := foobar[i]
|
||||||
@ -877,11 +863,11 @@ func unrollDecMin(a []int, b int) int {
|
|||||||
return 42
|
return 42
|
||||||
}
|
}
|
||||||
var i, x int
|
var i, x int
|
||||||
for i = len(a); i >= b; i -= 2 {
|
for i = len(a); i >= b; i -= 2 { // ERROR "Proved Leq64"
|
||||||
x += a[i-1]
|
x += a[i-1]
|
||||||
x += a[i-2]
|
x += a[i-2]
|
||||||
}
|
}
|
||||||
if i == 1 { // ERROR "Disproved Eq64$"
|
if i == 1 {
|
||||||
x += a[i-1]
|
x += a[i-1]
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
@ -893,11 +879,11 @@ func unrollIncMin(a []int, b int) int {
|
|||||||
return 42
|
return 42
|
||||||
}
|
}
|
||||||
var i, x int
|
var i, x int
|
||||||
for i = len(a); i >= b; i += 2 {
|
for i = len(a); i >= b; i += 2 { // ERROR "Proved Leq64"
|
||||||
x += a[i-1]
|
x += a[i-1]
|
||||||
x += a[i-2]
|
x += a[i-2]
|
||||||
}
|
}
|
||||||
if i == 1 { // ERROR "Disproved Eq64$"
|
if i == 1 {
|
||||||
x += a[i-1]
|
x += a[i-1]
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
@ -1124,6 +1110,43 @@ func issue45928(x int) {
|
|||||||
useInt(combinedFrac)
|
useInt(combinedFrac)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func constantBounds1(i, j uint) int {
|
||||||
|
var a [10]int
|
||||||
|
if j < 11 && i < j {
|
||||||
|
return a[i] // ERROR "Proved IsInBounds$"
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func constantBounds2(i, j uint) int {
|
||||||
|
var a [10]int
|
||||||
|
if i < j && j < 11 {
|
||||||
|
return a[i] // ERROR "Proved IsInBounds"
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func constantBounds3(i, j, k, l uint) int {
|
||||||
|
var a [8]int
|
||||||
|
if i < j && j < k && k < l && l < 11 {
|
||||||
|
return a[i] // ERROR "Proved IsInBounds"
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func equalityPropagation(a [1]int, i, j uint) int {
|
||||||
|
if i == j && i == 5 {
|
||||||
|
return a[j-5] // ERROR "Proved IsInBounds"
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
func inequalityPropagation(a [1]int, i, j uint) int {
|
||||||
|
if i != j && j >= 5 && j <= 6 && i == 5 {
|
||||||
|
return a[j-6] // ERROR "Proved IsInBounds"
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
//go:noinline
|
//go:noinline
|
||||||
func useInt(a int) {
|
func useInt(a int) {
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ func f0i(x int) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (x + 20) == 20 {
|
if (x + 20) == 20 {
|
||||||
return x + 5 // ERROR "Proved.+is constant 0$"
|
return x + 5 // ERROR "Proved.+is constant 0$" "Proved.+is constant 5$"
|
||||||
}
|
}
|
||||||
|
|
||||||
return x / 2
|
return x / 2
|
||||||
@ -26,7 +26,7 @@ func f0u(x uint) uint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (x + 20) == 20 {
|
if (x + 20) == 20 {
|
||||||
return x + 5 // ERROR "Proved.+is constant 0$"
|
return x + 5 // ERROR "Proved.+is constant 0$" "Proved.+is constant 5$"
|
||||||
}
|
}
|
||||||
|
|
||||||
return x / 2
|
return x / 2
|
||||||
|
Loading…
Reference in New Issue
Block a user