aboutsummaryrefslogtreecommitdiff
path: root/test/inline.go
diff options
context:
space:
mode:
authorHugues Bruant <hugues.bruant@gmail.com>2017-09-18 14:54:10 -0700
committerDaniel Martí <mvdan@mvdan.cc>2017-10-11 22:32:36 +0000
commit4f70a2a699d23bb47eae36c5170086688d2fa764 (patch)
treed764c2417d55ecf69bd8ae20822e9c5fafff9893 /test/inline.go
parent44d9e96da9b7625be81f2c7eacf73fcc609874ce (diff)
downloadgo-4f70a2a699d23bb47eae36c5170086688d2fa764.tar.gz
go-4f70a2a699d23bb47eae36c5170086688d2fa764.zip
cmd/compile: inline calls to local closures
Calls to a closure held in a local, non-escaping, variable can be inlined, provided the closure body can be inlined and the variable is never written to. The current implementation has the following limitations: - closures with captured variables are not inlined because doing so naively triggers invariant violation in the SSA phase - re-assignment check is currently approximated by checking the Addrtaken property of the variable which should be safe but may miss optimization opportunities if the address is not used for a write before the invocation Updates #15561 Change-Id: I508cad5d28f027bd7e933b1f793c14dcfef8b5a1 Reviewed-on: https://go-review.googlesource.com/65071 Run-TryBot: Daniel Martí <mvdan@mvdan.cc> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Hugues Bruant <hugues.bruant@gmail.com> Reviewed-by: Keith Randall <khr@golang.org>
Diffstat (limited to 'test/inline.go')
-rw-r--r--test/inline.go49
1 files changed, 48 insertions, 1 deletions
diff --git a/test/inline.go b/test/inline.go
index 7bb86ef8b2..7d8b2ceba9 100644
--- a/test/inline.go
+++ b/test/inline.go
@@ -9,7 +9,10 @@
package foo
-import "unsafe"
+import (
+ "errors"
+ "unsafe"
+)
func add2(p *byte, n uintptr) *byte { // ERROR "can inline add2" "leaking param: p to result"
return (*byte)(add1(unsafe.Pointer(p), n)) // ERROR "inlining call to add1"
@@ -46,6 +49,50 @@ func j(x int) int { // ERROR "can inline j"
}
}
+var somethingWrong error = errors.New("something went wrong")
+
+// local closures can be inlined
+func l(x, y int) (int, int, error) {
+ e := func(err error) (int, int, error) { // ERROR "can inline l.func1" "func literal does not escape" "leaking param: err to result"
+ return 0, 0, err
+ }
+ if x == y {
+ e(somethingWrong) // ERROR "inlining call to l.func1"
+ }
+ return y, x, nil
+}
+
+// any re-assignment prevents closure inlining
+func m() int {
+ foo := func() int { return 1 } // ERROR "can inline m.func1" "func literal does not escape"
+ x := foo()
+ foo = func() int { return 2 } // ERROR "can inline m.func2" "func literal does not escape"
+ return x + foo()
+}
+
+// address taking prevents closure inlining
+func n() int {
+ foo := func() int { return 1 } // ERROR "can inline n.func1" "func literal does not escape"
+ bar := &foo // ERROR "&foo does not escape"
+ x := (*bar)() + foo()
+ return x
+}
+
+// make sure assignment inside closure is detected
+func o() int {
+ foo := func() int { return 1 } // ERROR "can inline o.func1" "func literal does not escape"
+ func(x int) { // ERROR "func literal does not escape"
+ if x > 10 {
+ foo = func() int { return 2 } // ERROR "can inline o.func2" "func literal escapes"
+ }
+ }(11)
+ return foo()
+}
+
+func p() int {
+ return func() int { return 42 }() // ERROR "can inline p.func1" "inlining call to p.func1"
+}
+
// can't currently inline functions with a break statement
func switchBreak(x, y int) int {
var n int