summaryrefslogtreecommitdiff
path: root/test/prove.go
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2018-01-11 16:32:02 -0500
committerAustin Clements <austin@google.com>2018-03-08 22:25:28 +0000
commit6436270dadb232e3ef1afc0d4cf714bcb9434910 (patch)
tree143f097abbe291268925934ccc1a77b0bf5ff89f /test/prove.go
parent941fc129e2f059a5fb9f5ab77f5cb12aedecd145 (diff)
downloadgo-git-6436270dadb232e3ef1afc0d4cf714bcb9434910.tar.gz
cmd/compile: add fence-post implications to prove
This adds four new deductions to the prove pass, all related to adding or subtracting one from a value. This is the first hint of actual arithmetic relations in the prove pass. The most effective of these is x-1 >= w && x > min ⇒ x > w This helps eliminate bounds checks in code like if x > 0 { // do something with s[x-1] } Altogether, these deductions prove an additional 260 branches in std and cmd. Furthermore, they will let us eliminate some tricky compiler-inserted panics in the runtime that are interfering with static analysis. Fixes #23354. Change-Id: I7088223e0e0cd6ff062a75c127eb4bb60e6dce02 Reviewed-on: https://go-review.googlesource.com/87480 Reviewed-by: Keith Randall <khr@golang.org> Reviewed-by: Alexandru Moșoi <alexandru@mosoi.ro>
Diffstat (limited to 'test/prove.go')
-rw-r--r--test/prove.go54
1 files changed, 54 insertions, 0 deletions
diff --git a/test/prove.go b/test/prove.go
index 13e18cd728..97614939ac 100644
--- a/test/prove.go
+++ b/test/prove.go
@@ -506,6 +506,60 @@ func lim1(x, y, z int) {
}
}
+// fence1–4 correspond to the four fence-post implications.
+
+func fence1(b []int, x, y int) {
+ // Test proofs that rely on fence-post implications.
+ if x+1 > y {
+ if x < y { // ERROR "Disproved Less64$"
+ return
+ }
+ }
+ if len(b) < cap(b) {
+ // This eliminates the growslice path.
+ b = append(b, 1) // ERROR "Disproved Greater64$"
+ }
+}
+
+func fence2(x, y int) {
+ if x-1 < y {
+ if x > y { // ERROR "Disproved Greater64$"
+ return
+ }
+ }
+}
+
+func fence3(b []int, x, y int64) {
+ if x-1 >= y {
+ if x <= y { // Can't prove because x may have wrapped.
+ return
+ }
+ }
+
+ if x != math.MinInt64 && x-1 >= y {
+ if x <= y { // ERROR "Disproved Leq64$"
+ return
+ }
+ }
+
+ if n := len(b); n > 0 {
+ b[n-1] = 0 // ERROR "Proved IsInBounds$"
+ }
+}
+
+func fence4(x, y int64) {
+ if x >= y+1 {
+ if x <= y {
+ return
+ }
+ }
+ if y != math.MaxInt64 && x >= y+1 {
+ if x <= y { // ERROR "Disproved Leq64$"
+ return
+ }
+ }
+}
+
//go:noinline
func useInt(a int) {
}