summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/compile/internal/ssa/prove.go41
-rw-r--r--test/prove.go57
2 files changed, 98 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go
index 7c69327990..697862f986 100644
--- a/src/cmd/compile/internal/ssa/prove.go
+++ b/src/cmd/compile/internal/ssa/prove.go
@@ -530,6 +530,25 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
}
}
+ // Look through value-preserving extensions.
+ // If the domain is appropriate for the pre-extension Type,
+ // repeat the update with the pre-extension Value.
+ if isCleanExt(v) {
+ switch {
+ case d == signed && v.Args[0].Type.IsSigned():
+ fallthrough
+ case d == unsigned && !v.Args[0].Type.IsSigned():
+ ft.update(parent, v.Args[0], w, d, r)
+ }
+ }
+ if isCleanExt(w) {
+ switch {
+ case d == signed && w.Args[0].Type.IsSigned():
+ fallthrough
+ case d == unsigned && !w.Args[0].Type.IsSigned():
+ ft.update(parent, v, w.Args[0], d, r)
+ }
+ }
}
var opMin = map[Op]int64{
@@ -584,6 +603,11 @@ func (ft *factsTable) isNonNegative(v *Value) bool {
}
}
+ // Check if v is a value-preserving extension of a non-negative value.
+ if isCleanExt(v) && ft.isNonNegative(v.Args[0]) {
+ return true
+ }
+
// Check if the signed poset can prove that the value is >= 0
return ft.order[0].OrderedOrEqual(ft.zero, v)
}
@@ -1299,3 +1323,20 @@ func isConstDelta(v *Value) (w *Value, delta int64) {
}
return nil, 0
}
+
+// isCleanExt reports whether v is the result of a value-preserving
+// sign or zero extension
+func isCleanExt(v *Value) bool {
+ switch v.Op {
+ case OpSignExt8to16, OpSignExt8to32, OpSignExt8to64,
+ OpSignExt16to32, OpSignExt16to64, OpSignExt32to64:
+ // signed -> signed is the only value-preserving sign extension
+ return v.Args[0].Type.IsSigned() && v.Type.IsSigned()
+
+ case OpZeroExt8to16, OpZeroExt8to32, OpZeroExt8to64,
+ OpZeroExt16to32, OpZeroExt16to64, OpZeroExt32to64:
+ // unsigned -> signed/unsigned are value-preserving zero extensions
+ return !v.Args[0].Type.IsSigned()
+ }
+ return false
+}
diff --git a/test/prove.go b/test/prove.go
index 6e92b9eec2..7643031c62 100644
--- a/test/prove.go
+++ b/test/prove.go
@@ -853,6 +853,63 @@ func unrollIncMin(a []int) int {
return x
}
+// The 4 xxxxExtNto64 functions below test whether prove is looking
+// through value-preserving sign/zero extensions of index values (issue #26292).
+
+// Look through all extensions
+func signExtNto64(x []int, j8 int8, j16 int16, j32 int32) int {
+ if len(x) < 22 {
+ return 0
+ }
+ if j8 >= 0 && j8 < 22 {
+ return x[j8] // ERROR "Proved IsInBounds$"
+ }
+ if j16 >= 0 && j16 < 22 {
+ return x[j16] // ERROR "Proved IsInBounds$"
+ }
+ if j32 >= 0 && j32 < 22 {
+ return x[j32] // ERROR "Proved IsInBounds$"
+ }
+ return 0
+}
+
+func zeroExtNto64(x []int, j8 uint8, j16 uint16, j32 uint32) int {
+ if len(x) < 22 {
+ return 0
+ }
+ if j8 >= 0 && j8 < 22 {
+ return x[j8] // ERROR "Proved IsInBounds$"
+ }
+ if j16 >= 0 && j16 < 22 {
+ return x[j16] // ERROR "Proved IsInBounds$"
+ }
+ if j32 >= 0 && j32 < 22 {
+ return x[j32] // ERROR "Proved IsInBounds$"
+ }
+ return 0
+}
+
+// Process fence-post implications through 32to64 extensions (issue #29964)
+func signExt32to64Fence(x []int, j int32) int {
+ if x[j] != 0 {
+ return 1
+ }
+ if j > 0 && x[j-1] != 0 { // ERROR "Proved IsInBounds$"
+ return 1
+ }
+ return 0
+}
+
+func zeroExt32to64Fence(x []int, j uint32) int {
+ if x[j] != 0 {
+ return 1
+ }
+ if j > 0 && x[j-1] != 0 { // ERROR "Proved IsInBounds$"
+ return 1
+ }
+ return 0
+}
+
//go:noinline
func useInt(a int) {
}