]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: add a pass to print bound checks
authorAlexandru Moșoi <brtzsnr@gmail.com>
Mon, 4 Apr 2016 21:33:30 +0000 (23:33 +0200)
committerAlexandru Moșoi <alexandru@mosoi.ro>
Tue, 5 Apr 2016 12:46:59 +0000 (12:46 +0000)
Since BCE happens over several passes (opt, loopbce, prove)
it's easy to regress especially with rewriting.

The pass is only activated with special debug flag.

Change-Id: I46205982e7a2751156db8e875d69af6138068f59
Reviewed-on: https://go-review.googlesource.com/21510
Run-TryBot: Alexandru Moșoi <alexandru@mosoi.ro>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
src/cmd/compile/internal/ssa/checkbce.go [new file with mode: 0644]
src/cmd/compile/internal/ssa/compile.go
src/cmd/compile/internal/ssa/phiopt.go
test/checkbce.go [new file with mode: 0644]

diff --git a/src/cmd/compile/internal/ssa/checkbce.go b/src/cmd/compile/internal/ssa/checkbce.go
new file mode 100644 (file)
index 0000000..820ea6e
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2016 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 ssa
+
+// checkbce prints all bounds checks that are present in the function.
+// Useful to find regressions. checkbce is only activated when with
+// corresponsing debug options, so it's off by default.
+// See test/checkbce.go
+func checkbce(f *Func) {
+       if f.pass.debug <= 0 {
+               return
+       }
+
+       for _, b := range f.Blocks {
+               for _, v := range b.Values {
+                       if v.Op == OpIsInBounds || v.Op == OpIsSliceInBounds {
+                               f.Config.Warnl(v.Line, "Found %v", v.Op)
+                       }
+               }
+       }
+}
index 4a880f31f353043aad63d46810f2dc1650b438bd..d52ae9c6dab814c1d466a5f4a73734557315b09e 100644 (file)
@@ -242,6 +242,7 @@ var passes = [...]pass{
        {name: "dec", fn: dec, required: true},
        {name: "late opt", fn: opt, required: true}, // TODO: split required rules and optimizing rules
        {name: "generic deadcode", fn: deadcode},
+       {name: "check bce", fn: checkbce},
        {name: "fuse", fn: fuse},
        {name: "dse", fn: dse},
        {name: "tighten", fn: tighten}, // move values closer to their uses
@@ -290,6 +291,8 @@ var passOrder = [...]constraint{
        // tighten will be most effective when as many values have been removed as possible
        {"generic deadcode", "tighten"},
        {"generic cse", "tighten"},
+       // checkbce needs the values removed
+       {"generic deadcode", "check bce"},
        // don't run optimization pass until we've decomposed builtin objects
        {"decompose builtin", "late opt"},
        // don't layout blocks until critical edges have been removed
index 132366cfc11f5c7995275f30679654c73610c11f..2d0a45733ad39ba4b7cee2c0f8bb704bb0e8371c 100644 (file)
@@ -1,3 +1,7 @@
+// Copyright 2016 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 ssa
 
 // phiopt eliminates boolean Phis based on the previous if.
diff --git a/test/checkbce.go b/test/checkbce.go
new file mode 100644 (file)
index 0000000..a3b0100
--- /dev/null
@@ -0,0 +1,89 @@
+// +build amd64
+// errorcheck -0 -d=ssa/check_bce/debug=3
+
+package main
+
+func f0(a []int) {
+       a[0] = 1 // ERROR "Found IsInBounds$"
+       a[0] = 1
+       a[6] = 1 // ERROR "Found IsInBounds$"
+       a[6] = 1
+       a[5] = 1
+       a[5] = 1
+}
+
+func f1(a [256]int, i int) {
+       useInt(a[i])     // ERROR "Found IsInBounds$"
+       useInt(a[i%256]) // ERROR "Found IsInBounds$"
+       useInt(a[i&255])
+       useInt(a[i&17])
+
+       if 4 <= i && i < len(a) {
+               useInt(a[i])
+               useInt(a[i-1]) // ERROR "Found IsInBounds$"
+               useInt(a[i-4]) // ERROR "Found IsInBounds$"
+       }
+}
+
+func f2(a [256]int, i uint) {
+       useInt(a[i]) // ERROR "Found IsInBounds$"
+       useInt(a[i%256])
+       useInt(a[i&255])
+       useInt(a[i&17])
+}
+
+func f3(a [256]int, i uint8) {
+       useInt(a[i])
+       useInt(a[i+10])
+       useInt(a[i+14])
+}
+
+func f4(a [27]int, i uint8) {
+       useInt(a[i%15])
+       useInt(a[i%19])
+       useInt(a[i%27])
+}
+
+func f5(a []int) {
+       if len(a) > 5 {
+               useInt(a[5])
+               useSlice(a[6:])
+               useSlice(a[:6]) // ERROR "Found IsSliceInBounds$"
+       }
+}
+
+func g1(a []int) {
+       for i := range a {
+               a[i] = i
+               useSlice(a[:i+1])
+               useSlice(a[:i])
+       }
+}
+
+func g2(a []int) {
+       useInt(a[3]) // ERROR "Found IsInBounds$"
+       useInt(a[2])
+       useInt(a[1])
+       useInt(a[0])
+}
+
+func g3(a []int) {
+       for i := range a[:256] { // ERROR "Found IsSliceInBounds$"
+               useInt(a[i]) // ERROR "Found IsInBounds$"
+       }
+       b := a[:256]
+       for i := range b {
+               useInt(b[i])
+       }
+}
+
+//go:noinline
+func useInt(a int) {
+}
+
+//go:noinline
+func useSlice(a []int) {
+}
+
+func main() {
+}