]> Cypherpunks.ru repositories - gostls13.git/blob - test/inline.go
cmd/compile: constant-fold switches early in compilation
[gostls13.git] / test / inline.go
1 // errorcheckwithauto -0 -m -d=inlfuncswithclosures=1
2
3 // Copyright 2015 The Go Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file.
6
7 // Test, using compiler diagnostic flags, that inlining is working.
8 // Compiles but does not run.
9
10 package foo
11
12 import (
13         "runtime"
14         "unsafe"
15 )
16
17 func add2(p *byte, n uintptr) *byte { // ERROR "can inline add2" "leaking param: p to result"
18         return (*byte)(add1(unsafe.Pointer(p), n)) // ERROR "inlining call to add1"
19 }
20
21 func add1(p unsafe.Pointer, x uintptr) unsafe.Pointer { // ERROR "can inline add1" "leaking param: p to result"
22         return unsafe.Pointer(uintptr(p) + x)
23 }
24
25 func f(x *byte) *byte { // ERROR "can inline f" "leaking param: x to result"
26         return add2(x, 1) // ERROR "inlining call to add2" "inlining call to add1"
27 }
28
29 //go:noinline
30 func g(x int) int {
31         return x + 1
32 }
33
34 func h(x int) int { // ERROR "can inline h"
35         return x + 2
36 }
37
38 func i(x int) int { // ERROR "can inline i"
39         const y = 2
40         return x + y
41 }
42
43 func j(x int) int { // ERROR "can inline j"
44         switch {
45         case x > 0:
46                 return x + 2
47         default:
48                 return x + 1
49         }
50 }
51
52 func f2() int { // ERROR "can inline f2"
53         tmp1 := h
54         tmp2 := tmp1
55         return tmp2(0) // ERROR "inlining call to h"
56 }
57
58 var somethingWrong error
59
60 // local closures can be inlined
61 func l(x, y int) (int, int, error) { // ERROR "can inline l"
62         e := func(err error) (int, int, error) { // ERROR "can inline l.func1" "func literal does not escape" "leaking param: err to result"
63                 return 0, 0, err
64         }
65         if x == y {
66                 e(somethingWrong) // ERROR "inlining call to l.func1"
67         } else {
68                 f := e
69                 f(nil) // ERROR "inlining call to l.func1"
70         }
71         return y, x, nil
72 }
73
74 // any re-assignment prevents closure inlining
75 func m() int {
76         foo := func() int { return 1 } // ERROR "can inline m.func1" "func literal does not escape"
77         x := foo()
78         foo = func() int { return 2 } // ERROR "can inline m.func2" "func literal does not escape"
79         return x + foo()
80 }
81
82 // address taking prevents closure inlining
83 func n() int {
84         foo := func() int { return 1 } // ERROR "can inline n.func1" "func literal does not escape"
85         bar := &foo
86         x := (*bar)() + foo()
87         return x
88 }
89
90 // make sure assignment inside closure is detected
91 func o() int {
92         foo := func() int { return 1 } // ERROR "can inline o.func1" "func literal does not escape"
93         func(x int) {                  // ERROR "can inline o.func2"
94                 if x > 10 {
95                         foo = func() int { return 2 } // ERROR "can inline o.func2"
96                 }
97         }(11) // ERROR "func literal does not escape" "inlining call to o.func2"
98         return foo()
99 }
100
101 func p() int { // ERROR "can inline p"
102         return func() int { return 42 }() // ERROR "can inline p.func1" "inlining call to p.func1"
103 }
104
105 func q(x int) int { // ERROR "can inline q"
106         foo := func() int { return x * 2 } // ERROR "can inline q.func1" "func literal does not escape"
107         return foo()                       // ERROR "inlining call to q.func1"
108 }
109
110 func r(z int) int {
111         foo := func(x int) int { // ERROR "can inline r.func1" "func literal does not escape"
112                 return x + z
113         }
114         bar := func(x int) int { // ERROR "func literal does not escape" "can inline r.func2"
115                 return x + func(y int) int { // ERROR "can inline r.func2.1" "can inline r.func3"
116                         return 2*y + x*z
117                 }(x) // ERROR "inlining call to r.func2.1"
118         }
119         return foo(42) + bar(42) // ERROR "inlining call to r.func1" "inlining call to r.func2" "inlining call to r.func3"
120 }
121
122 func s0(x int) int { // ERROR "can inline s0"
123         foo := func() { // ERROR "can inline s0.func1" "func literal does not escape"
124                 x = x + 1
125         }
126         foo() // ERROR "inlining call to s0.func1"
127         return x
128 }
129
130 func s1(x int) int { // ERROR "can inline s1"
131         foo := func() int { // ERROR "can inline s1.func1" "func literal does not escape"
132                 return x
133         }
134         x = x + 1
135         return foo() // ERROR "inlining call to s1.func1"
136 }
137
138 func switchBreak(x, y int) int { // ERROR "can inline switchBreak"
139         var n int
140         switch x {
141         case 0:
142                 n = 1
143         Done:
144                 switch y {
145                 case 0:
146                         n += 10
147                         break Done
148                 }
149                 n = 2
150         }
151         return n
152 }
153
154 func switchType(x interface{}) int { // ERROR "can inline switchType" "x does not escape"
155         switch x.(type) {
156         case int:
157                 return x.(int)
158         default:
159                 return 0
160         }
161 }
162
163 // Test that switches on constant things, with constant cases, only cost anything for
164 // the case that matches. See issue 50253.
165 func switchConst1(p func(string)) { // ERROR "can inline switchConst" "p does not escape"
166         const c = 1
167         switch c {
168         case 0:
169                 p("zero")
170         case 1:
171                 p("one")
172         case 2:
173                 p("two")
174         default:
175                 p("other")
176         }
177 }
178
179 func switchConst2() string { // ERROR "can inline switchConst2"
180         switch runtime.GOOS {
181         case "linux":
182                 return "Leenooks"
183         case "windows":
184                 return "Windoze"
185         case "darwin":
186                 return "MackBone"
187         case "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100":
188                 return "Numbers"
189         default:
190                 return "oh nose!"
191         }
192 }
193 func switchConst3() string { // ERROR "can inline switchConst3"
194         switch runtime.GOOS {
195         case "Linux":
196                 panic("Linux")
197         case "Windows":
198                 panic("Windows")
199         case "Darwin":
200                 panic("Darwin")
201         case "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100":
202                 panic("Numbers")
203         default:
204                 return "oh nose!"
205         }
206 }
207
208 func inlineRangeIntoMe(data []int) { // ERROR "can inline inlineRangeIntoMe" "data does not escape"
209         rangeFunc(data, 12) // ERROR "inlining call to rangeFunc"
210 }
211
212 func rangeFunc(xs []int, b int) int { // ERROR "can inline rangeFunc" "xs does not escape"
213         for i, x := range xs {
214                 if x == b {
215                         return i
216                 }
217         }
218         return -1
219 }
220
221 type T struct{}
222
223 func (T) meth(int, int) {} // ERROR "can inline T.meth"
224
225 func k() (T, int, int) { return T{}, 0, 0 } // ERROR "can inline k"
226
227 func f3() { // ERROR "can inline f3"
228         T.meth(k()) // ERROR "inlining call to k" "inlining call to T.meth"
229         // ERRORAUTO "inlining call to T.meth"
230 }
231
232 func small1() { // ERROR "can inline small1"
233         runtime.GC()
234 }
235 func small2() int { // ERROR "can inline small2"
236         return runtime.GOMAXPROCS(0)
237 }
238 func small3(t T) { // ERROR "can inline small3"
239         t.meth2(3, 5)
240 }
241 func small4(t T) { // not inlineable - has 2 calls.
242         t.meth2(runtime.GOMAXPROCS(0), 5)
243 }
244 func (T) meth2(int, int) { // not inlineable - has 2 calls.
245         runtime.GC()
246         runtime.GC()
247 }
248
249 // Issue #29737 - make sure we can do inlining for a chain of recursive functions
250 func ee() { // ERROR "can inline ee"
251         ff(100) // ERROR "inlining call to ff" "inlining call to gg" "inlining call to hh"
252 }
253
254 func ff(x int) { // ERROR "can inline ff"
255         if x < 0 {
256                 return
257         }
258         gg(x - 1)
259 }
260 func gg(x int) { // ERROR "can inline gg"
261         hh(x - 1)
262 }
263 func hh(x int) { // ERROR "can inline hh"
264         ff(x - 1) // ERROR "inlining call to ff"  // ERROR "inlining call to gg"
265 }
266
267 // Issue #14768 - make sure we can inline for loops.
268 func for1(fn func() bool) { // ERROR "can inline for1" "fn does not escape"
269         for {
270                 if fn() {
271                         break
272                 } else {
273                         continue
274                 }
275         }
276 }
277
278 func for2(fn func() bool) { // ERROR "can inline for2" "fn does not escape"
279 Loop:
280         for {
281                 if fn() {
282                         break Loop
283                 } else {
284                         continue Loop
285                 }
286         }
287 }
288
289 // Issue #18493 - make sure we can do inlining of functions with a method value
290 type T1 struct{}
291
292 func (a T1) meth(val int) int { // ERROR "can inline T1.meth"
293         return val + 5
294 }
295
296 func getMeth(t1 T1) func(int) int { // ERROR "can inline getMeth"
297         return t1.meth // ERROR "t1.meth escapes to heap"
298         // ERRORAUTO "inlining call to T1.meth"
299 }
300
301 func ii() { // ERROR "can inline ii"
302         var t1 T1
303         f := getMeth(t1) // ERROR "inlining call to getMeth" "t1.meth does not escape"
304         _ = f(3)
305 }
306
307 // Issue #42194 - make sure that functions evaluated in
308 // go and defer statements can be inlined.
309 func gd1(int) {
310         defer gd1(gd2()) // ERROR "inlining call to gd2"
311         defer gd3()()    // ERROR "inlining call to gd3"
312         go gd1(gd2())    // ERROR "inlining call to gd2"
313         go gd3()()       // ERROR "inlining call to gd3"
314 }
315
316 func gd2() int { // ERROR "can inline gd2"
317         return 1
318 }
319
320 func gd3() func() { // ERROR "can inline gd3"
321         return ii
322 }
323
324 // Issue #42788 - ensure ODEREF OCONVNOP* OADDR is low cost.
325 func EncodeQuad(d []uint32, x [6]float32) { // ERROR "can inline EncodeQuad" "d does not escape"
326         _ = d[:6]
327         d[0] = float32bits(x[0]) // ERROR "inlining call to float32bits"
328         d[1] = float32bits(x[1]) // ERROR "inlining call to float32bits"
329         d[2] = float32bits(x[2]) // ERROR "inlining call to float32bits"
330         d[3] = float32bits(x[3]) // ERROR "inlining call to float32bits"
331         d[4] = float32bits(x[4]) // ERROR "inlining call to float32bits"
332         d[5] = float32bits(x[5]) // ERROR "inlining call to float32bits"
333 }
334
335 // float32bits is a copy of math.Float32bits to ensure that
336 // these tests pass with `-gcflags=-l`.
337 func float32bits(f float32) uint32 { // ERROR "can inline float32bits"
338         return *(*uint32)(unsafe.Pointer(&f))
339 }
340
341 // Ensure OCONVNOP is zero cost.
342 func Conv(v uint64) uint64 { // ERROR "can inline Conv"
343         return conv2(conv2(conv2(v))) // ERROR "inlining call to (conv1|conv2)"
344 }
345 func conv2(v uint64) uint64 { // ERROR "can inline conv2"
346         return conv1(conv1(conv1(conv1(v)))) // ERROR "inlining call to conv1"
347 }
348 func conv1(v uint64) uint64 { // ERROR "can inline conv1"
349         return uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(v)))))))))))
350 }
351
352 func select1(x, y chan bool) int { // ERROR "can inline select1" "x does not escape" "y does not escape"
353         select {
354         case <-x:
355                 return 1
356         case <-y:
357                 return 2
358         }
359 }
360
361 func select2(x, y chan bool) { // ERROR "can inline select2" "x does not escape" "y does not escape"
362 loop: // test that labeled select can be inlined.
363         select {
364         case <-x:
365                 break loop
366         case <-y:
367         }
368 }
369
370 func inlineSelect2(x, y chan bool) { // ERROR "can inline inlineSelect2" ERROR "x does not escape" "y does not escape"
371 loop:
372         for i := 0; i < 5; i++ {
373                 if i == 3 {
374                         break loop
375                 }
376                 select2(x, y) // ERROR "inlining call to select2"
377         }
378 }