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