From: Alexandru Moșoi Date: Mon, 4 Apr 2016 21:33:30 +0000 (+0200) Subject: cmd/compile: add a pass to print bound checks X-Git-Tag: go1.7beta1~900 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=1747788c5668e76a238221ae4982daa5bdf24939;p=gostls13.git 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 TryBot-Result: Gobot Gobot Reviewed-by: David Chase --- diff --git a/src/cmd/compile/internal/ssa/checkbce.go b/src/cmd/compile/internal/ssa/checkbce.go new file mode 100644 index 0000000000..820ea6e809 --- /dev/null +++ b/src/cmd/compile/internal/ssa/checkbce.go @@ -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) + } + } + } +} diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index 4a880f31f3..d52ae9c6da 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -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 diff --git a/src/cmd/compile/internal/ssa/phiopt.go b/src/cmd/compile/internal/ssa/phiopt.go index 132366cfc1..2d0a45733a 100644 --- a/src/cmd/compile/internal/ssa/phiopt.go +++ b/src/cmd/compile/internal/ssa/phiopt.go @@ -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 index 0000000000..a3b0100db8 --- /dev/null +++ b/test/checkbce.go @@ -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() { +}