go/test/checkbce.go

182 lines
3.6 KiB
Go
Raw Normal View History

// +build amd64,!gcflags_noopt
// errorcheck -0 -d=ssa/check_bce/debug=3
// 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.
// Test that the compiler does bounds check elimination as expected.
// This avoids accidental regressions.
package main
import "encoding/binary"
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) {
var j int
useInt(a[i]) // ERROR "Found IsInBounds$"
j = i % 256
useInt(a[j]) // ERROR "Found IsInBounds$"
j = i & 255
useInt(a[j])
j = i & 17
useInt(a[j])
if 4 <= i && i < len(a) {
useInt(a[i])
useInt(a[i-1])
cmd/compile: optimize integer "in range" expressions Use unsigned comparisons to reduce from two comparisons to one for integer "in range" checks, such as a <= b && b < c. We already do this for bounds checks. Extend it to user code. This is much easier to do in the front end than SSA. A back end optimization would be more powerful, but this is a good start. This reduces the power of some of SSA prove inferences (#16653), but those regressions appear to be rare and not worth holding this CL for. Fixes #15844. Fixes #16697. strconv benchmarks: name old time/op new time/op delta Atof64Decimal-8 41.4ns ± 3% 38.9ns ± 2% -5.89% (p=0.000 n=24+25) Atof64Float-8 48.5ns ± 0% 46.8ns ± 3% -3.64% (p=0.000 n=20+23) Atof64FloatExp-8 97.7ns ± 4% 93.5ns ± 1% -4.25% (p=0.000 n=25+20) Atof64Big-8 187ns ± 8% 162ns ± 2% -13.54% (p=0.000 n=24+22) Atof64RandomBits-8 250ns ± 6% 233ns ± 5% -6.76% (p=0.000 n=25+25) Atof64RandomFloats-8 160ns ± 0% 152ns ± 0% -5.00% (p=0.000 n=21+22) Atof32Decimal-8 41.1ns ± 1% 38.7ns ± 2% -5.86% (p=0.000 n=24+24) Atof32Float-8 46.1ns ± 1% 43.5ns ± 3% -5.63% (p=0.000 n=21+24) Atof32FloatExp-8 101ns ± 4% 100ns ± 2% -1.59% (p=0.000 n=24+23) Atof32Random-8 136ns ± 3% 133ns ± 3% -2.83% (p=0.000 n=22+22) Atoi-8 33.8ns ± 3% 30.6ns ± 3% -9.51% (p=0.000 n=24+25) AtoiNeg-8 31.6ns ± 3% 29.1ns ± 2% -8.05% (p=0.000 n=23+24) Atoi64-8 48.6ns ± 1% 43.8ns ± 1% -9.81% (p=0.000 n=20+23) Atoi64Neg-8 47.1ns ± 4% 42.0ns ± 2% -10.83% (p=0.000 n=25+25) FormatFloatDecimal-8 177ns ± 9% 178ns ± 6% ~ (p=0.460 n=25+25) FormatFloat-8 282ns ± 6% 282ns ± 3% ~ (p=0.954 n=25+22) FormatFloatExp-8 259ns ± 7% 255ns ± 6% ~ (p=0.089 n=25+24) FormatFloatNegExp-8 253ns ± 6% 254ns ± 6% ~ (p=0.941 n=25+24) FormatFloatBig-8 340ns ± 6% 341ns ± 8% ~ (p=0.600 n=22+25) AppendFloatDecimal-8 79.4ns ± 0% 80.6ns ± 6% ~ (p=0.861 n=20+25) AppendFloat-8 175ns ± 3% 174ns ± 0% ~ (p=0.722 n=25+20) AppendFloatExp-8 142ns ± 4% 142ns ± 2% ~ (p=0.948 n=25+24) AppendFloatNegExp-8 137ns ± 2% 138ns ± 2% +0.70% (p=0.001 n=24+25) AppendFloatBig-8 218ns ± 3% 218ns ± 4% ~ (p=0.596 n=25+25) AppendFloatBinaryExp-8 80.0ns ± 4% 78.0ns ± 1% -2.43% (p=0.000 n=24+21) AppendFloat32Integer-8 82.3ns ± 3% 79.3ns ± 4% -3.69% (p=0.000 n=24+25) AppendFloat32ExactFraction-8 143ns ± 2% 143ns ± 0% ~ (p=0.177 n=23+19) AppendFloat32Point-8 175ns ± 3% 175ns ± 3% ~ (p=0.062 n=24+25) AppendFloat32Exp-8 139ns ± 2% 137ns ± 4% -1.05% (p=0.001 n=24+24) AppendFloat32NegExp-8 134ns ± 0% 137ns ± 4% +2.06% (p=0.000 n=22+25) AppendFloat64Fixed1-8 97.8ns ± 0% 98.6ns ± 3% ~ (p=0.711 n=20+25) AppendFloat64Fixed2-8 110ns ± 3% 110ns ± 5% -0.45% (p=0.037 n=24+24) AppendFloat64Fixed3-8 102ns ± 3% 102ns ± 3% ~ (p=0.684 n=24+24) AppendFloat64Fixed4-8 112ns ± 3% 110ns ± 0% -1.43% (p=0.000 n=25+18) FormatInt-8 3.18µs ± 4% 3.10µs ± 6% -2.54% (p=0.001 n=24+25) AppendInt-8 1.81µs ± 5% 1.80µs ± 5% ~ (p=0.648 n=25+25) FormatUint-8 812ns ± 6% 816ns ± 6% ~ (p=0.777 n=25+25) AppendUint-8 536ns ± 4% 538ns ± 3% ~ (p=0.798 n=20+22) Quote-8 605ns ± 6% 602ns ± 9% ~ (p=0.573 n=25+25) QuoteRune-8 99.5ns ± 8% 100.2ns ± 7% ~ (p=0.432 n=25+25) AppendQuote-8 361ns ± 3% 363ns ± 4% ~ (p=0.085 n=25+25) AppendQuoteRune-8 23.3ns ± 3% 22.4ns ± 2% -3.79% (p=0.000 n=25+24) UnquoteEasy-8 146ns ± 4% 145ns ± 5% ~ (p=0.112 n=24+24) UnquoteHard-8 804ns ± 6% 771ns ± 6% -4.10% (p=0.000 n=25+24) Change-Id: Ibd384e46e90f1cfa40503c8c6352a54c65b72980 Reviewed-on: https://go-review.googlesource.com/27652 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> Reviewed-by: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-05-27 01:08:24 +00:00
useInt(a[i-4])
}
}
func f2(a [256]int, i uint) {
useInt(a[i]) // ERROR "Found IsInBounds$"
j := i % 256
useInt(a[j])
j = i & 255
useInt(a[j])
j = i & 17
useInt(a[j])
}
func f2a(a [35]int, i uint8) {
useInt(a[i]) // ERROR "Found IsInBounds$"
j := i & 34
useInt(a[j])
j = i & 17
useInt(a[j])
}
func f2b(a [35]int, i uint16) {
useInt(a[i]) // ERROR "Found IsInBounds$"
j := i & 34
useInt(a[j])
j = i & 17
useInt(a[j])
}
func f2c(a [35]int, i uint32) {
useInt(a[i]) // ERROR "Found IsInBounds$"
j := i & 34
useInt(a[j])
j = i & 17
useInt(a[j])
}
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])
}
}
func f6(a [32]int, b [64]int, i int) {
useInt(a[uint32(i*0x07C4ACDD)>>27])
useInt(b[uint64(i*0x07C4ACDD)>>58])
useInt(a[uint(i*0x07C4ACDD)>>59])
// The following bounds should not be removed because they can overflow.
useInt(a[uint32(i*0x106297f105d0cc86)>>26]) // ERROR "Found IsInBounds$"
useInt(b[uint64(i*0x106297f105d0cc86)>>57]) // ERROR "Found IsInBounds$"
useInt(a[int32(i*0x106297f105d0cc86)>>26]) // ERROR "Found IsInBounds$"
useInt(b[int64(i*0x106297f105d0cc86)>>57]) // ERROR "Found IsInBounds$"
}
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])
}
}
func g4(a [100]int) {
for i := 10; i < 50; i++ {
useInt(a[i-10])
useInt(a[i])
useInt(a[i+25])
useInt(a[i+50])
// The following are out of bounds.
useInt(a[i-11]) // ERROR "Found IsInBounds$"
useInt(a[i+51]) // ERROR "Found IsInBounds$"
}
}
func decode1(data []byte) (x uint64) {
for len(data) >= 32 {
x += binary.BigEndian.Uint64(data[:8])
x += binary.BigEndian.Uint64(data[8:16])
x += binary.BigEndian.Uint64(data[16:24])
x += binary.BigEndian.Uint64(data[24:32])
data = data[32:]
}
return x
}
func decode2(data []byte) (x uint64) {
// TODO(rasky): this should behave like decode1 and compile to no
// boundchecks. We're currently not able to remove all of them.
for len(data) >= 32 {
x += binary.BigEndian.Uint64(data)
data = data[8:]
x += binary.BigEndian.Uint64(data) // ERROR "Found IsInBounds$"
data = data[8:]
x += binary.BigEndian.Uint64(data) // ERROR "Found IsInBounds$"
data = data[8:]
x += binary.BigEndian.Uint64(data) // ERROR "Found IsInBounds$"
data = data[8:]
}
return x
}
//go:noinline
func useInt(a int) {
}
//go:noinline
func useSlice(a []int) {
}
func main() {
}