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