1// errorcheck -0 -d=ssa/check_bce/debug=3 2 3//go:build amd64 && !gcflags_noopt 4 5// Copyright 2016 The Go Authors. All rights reserved. 6// Use of this source code is governed by a BSD-style 7// license that can be found in the LICENSE file. 8 9// Test that the compiler does bounds check elimination as expected. 10// This avoids accidental regressions. 11 12package main 13 14import "encoding/binary" 15 16func f0(a []int) { 17 a[0] = 1 // ERROR "Found IsInBounds$" 18 a[0] = 1 19 a[6] = 1 // ERROR "Found IsInBounds$" 20 a[6] = 1 21 a[5] = 1 22 a[5] = 1 23} 24 25func f1(a [256]int, i int) { 26 var j int 27 useInt(a[i]) // ERROR "Found IsInBounds$" 28 j = i % 256 29 useInt(a[j]) // ERROR "Found IsInBounds$" 30 j = i & 255 31 useInt(a[j]) 32 j = i & 17 33 useInt(a[j]) 34 35 if 4 <= i && i < len(a) { 36 useInt(a[i]) 37 useInt(a[i-1]) 38 useInt(a[i-4]) 39 } 40} 41 42func f2(a [256]int, i uint) { 43 useInt(a[i]) // ERROR "Found IsInBounds$" 44 j := i % 256 45 useInt(a[j]) 46 j = i & 255 47 useInt(a[j]) 48 j = i & 17 49 useInt(a[j]) 50} 51 52func f2a(a [35]int, i uint8) { 53 useInt(a[i]) // ERROR "Found IsInBounds$" 54 j := i & 34 55 useInt(a[j]) 56 j = i & 17 57 useInt(a[j]) 58} 59 60func f2b(a [35]int, i uint16) { 61 useInt(a[i]) // ERROR "Found IsInBounds$" 62 j := i & 34 63 useInt(a[j]) 64 j = i & 17 65 useInt(a[j]) 66} 67 68func f2c(a [35]int, i uint32) { 69 useInt(a[i]) // ERROR "Found IsInBounds$" 70 j := i & 34 71 useInt(a[j]) 72 j = i & 17 73 useInt(a[j]) 74} 75 76func f3(a [256]int, i uint8) { 77 useInt(a[i]) 78 useInt(a[i+10]) 79 useInt(a[i+14]) 80} 81 82func f4(a [27]int, i uint8) { 83 useInt(a[i%15]) 84 useInt(a[i%19]) 85 useInt(a[i%27]) 86} 87 88func f5(a []int) { 89 if len(a) > 5 { 90 useInt(a[5]) 91 useSlice(a[6:]) 92 useSlice(a[:6]) 93 } 94} 95 96func f6(a [32]int, b [64]int, i int) { 97 useInt(a[uint32(i*0x07C4ACDD)>>27]) 98 useInt(b[uint64(i*0x07C4ACDD)>>58]) 99 useInt(a[uint(i*0x07C4ACDD)>>59]) 100 101 // The following bounds should not be removed because they can overflow. 102 useInt(a[uint32(i*0x106297f105d0cc86)>>26]) // ERROR "Found IsInBounds$" 103 useInt(b[uint64(i*0x106297f105d0cc86)>>57]) // ERROR "Found IsInBounds$" 104 useInt(a[int32(i*0x106297f105d0cc86)>>26]) // ERROR "Found IsInBounds$" 105 useInt(b[int64(i*0x106297f105d0cc86)>>57]) // ERROR "Found IsInBounds$" 106} 107 108func g1(a []int) { 109 for i := range a { 110 a[i] = i 111 useSlice(a[:i+1]) 112 useSlice(a[:i]) 113 } 114} 115 116func g2(a []int) { 117 useInt(a[3]) // ERROR "Found IsInBounds$" 118 useInt(a[2]) 119 useInt(a[1]) 120 useInt(a[0]) 121} 122 123func g3(a []int) { 124 for i := range a[:256] { // ERROR "Found IsSliceInBounds$" 125 useInt(a[i]) // ERROR "Found IsInBounds$" 126 } 127 b := a[:256] 128 for i := range b { 129 useInt(b[i]) 130 } 131} 132 133func g4(a [100]int) { 134 for i := 10; i < 50; i++ { 135 useInt(a[i-10]) 136 useInt(a[i]) 137 useInt(a[i+25]) 138 useInt(a[i+50]) 139 140 // The following are out of bounds. 141 if a[0] == 0xdeadbeef { 142 // This is a trick to prohibit sccp to optimize out the following out of bound check 143 continue 144 } 145 useInt(a[i-11]) // ERROR "Found IsInBounds$" 146 useInt(a[i+51]) // ERROR "Found IsInBounds$" 147 } 148} 149 150func decode1(data []byte) (x uint64) { 151 for len(data) >= 32 { 152 x += binary.BigEndian.Uint64(data[:8]) 153 x += binary.BigEndian.Uint64(data[8:16]) 154 x += binary.BigEndian.Uint64(data[16:24]) 155 x += binary.BigEndian.Uint64(data[24:32]) 156 data = data[32:] 157 } 158 return x 159} 160 161func decode2(data []byte) (x uint64) { 162 // TODO(rasky): this should behave like decode1 and compile to no 163 // boundchecks. We're currently not able to remove all of them. 164 for len(data) >= 32 { 165 x += binary.BigEndian.Uint64(data) 166 data = data[8:] 167 x += binary.BigEndian.Uint64(data) // ERROR "Found IsInBounds$" 168 data = data[8:] 169 x += binary.BigEndian.Uint64(data) // ERROR "Found IsInBounds$" 170 data = data[8:] 171 x += binary.BigEndian.Uint64(data) // ERROR "Found IsInBounds$" 172 data = data[8:] 173 } 174 return x 175} 176 177//go:noinline 178func useInt(a int) { 179} 180 181//go:noinline 182func useSlice(a []int) { 183} 184 185func main() { 186} 187