cmd/compile: add a pass to print bound checks

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>
This commit is contained in:
Alexandru Moșoi 2016-04-04 23:33:30 +02:00 committed by Alexandru Moșoi
parent 3bbede0c51
commit 1747788c56
4 changed files with 119 additions and 0 deletions

View File

@ -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)
}
}
}
}

View 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

View 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.

89
test/checkbce.go Normal file
View File

@ -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() {
}