diff options
author | Luuk van Dijk <lvd@golang.org> | 2011-05-31 20:52:21 +0200 |
---|---|---|
committer | Luuk van Dijk <lvd@golang.org> | 2011-05-31 20:52:21 +0200 |
commit | 9b82408f6df2dde74828f9c945112ef554f67397 (patch) | |
tree | 94bb6b5e1852b640ffb2fd894c973afb733a39a3 | |
parent | 6216307e25d00bfd5ca18b8dacbb6ac85f2b9d6a (diff) | |
download | go-9b82408f6df2dde74828f9c945112ef554f67397.tar.gz go-9b82408f6df2dde74828f9c945112ef554f67397.zip |
gc: elide call to runtime.closure for function literals called in-place.
before:
runtime_test.BenchmarkCallClosure 5000000 499 ns/op
runtime_test.BenchmarkCallClosure1 5000000 681 ns/op
after:
runtime_test.BenchmarkCallClosure 500000000 5 ns/op
runtime_test.BenchmarkCallClosure1 10000000 160 ns/op
R=rsc
CC=golang-dev
https://golang.org/cl/4515167
-rw-r--r-- | src/cmd/gc/closure.c | 38 | ||||
-rw-r--r-- | src/cmd/gc/go.h | 1 | ||||
-rw-r--r-- | src/cmd/gc/walk.c | 9 | ||||
-rw-r--r-- | src/pkg/runtime/closure_test.go | 21 |
4 files changed, 68 insertions, 1 deletions
diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c index eb70143665..091abde622 100644 --- a/src/cmd/gc/closure.c +++ b/src/cmd/gc/closure.c @@ -199,3 +199,41 @@ walkclosure(Node *func, NodeList **init) walkexpr(&call, init); return call; } + +// Special case for closures that get called in place. +// Optimize runtime.closure(X, __func__xxxx_, .... ) away +// to __func__xxxx_(Y ....). +// On entry, expect n->op == OCALL, n->left->op == OCLOSURE. +void +walkcallclosure(Node *n, NodeList **init) +{ + Node *z; + NodeList *ll, *cargs; + + walkexpr(&n->left, init); + cargs = n->left // FUNC runtime.closure + ->list // arguments + ->next // skip first + ->next; // skip second + + n->left = n->left // FUNC runtime.closure + ->list // arguments + ->next // skip first + ->n // AS (to indreg) + ->right; // argument == the generated function + + // New arg list for n. First the closure-args, stolen from + // runtime.closure's 3rd and following, + ll = nil; + for (; cargs; cargs = cargs->next) + ll = list(ll, cargs->n->right); // cargs->n is the OAS(INDREG, arg) + + // then an extra zero, to fill the dummy return pointer slot, + z = nod(OXXX, N, N); + nodconst(z, types[TUINTPTR], 0); + z->typecheck = 1; + ll = list(ll, z); + + // and finally the original parameter list. + n->list = concat(ll, n->list); +} diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 3f07befcbd..f4ca58b737 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -817,6 +817,7 @@ Node* closurebody(NodeList *body); void closurehdr(Node *ntype); void typecheckclosure(Node *func); Node* walkclosure(Node *func, NodeList **init); +void walkcallclosure(Node *n, NodeList **init); /* * const.c diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index b3b400556c..68885e6596 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -770,8 +770,15 @@ walkexpr(Node **np, NodeList **init) t = n->left->type; if(n->list && n->list->n->op == OAS) goto ret; - walkexpr(&n->left, init); + + if(n->left->op == OCLOSURE) { + walkcallclosure(n, init); + t = n->left->type; + } else + walkexpr(&n->left, init); + walkexprlist(n->list, init); + ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init); n->list = reorder1(ll); if(isselect(n)) { diff --git a/src/pkg/runtime/closure_test.go b/src/pkg/runtime/closure_test.go new file mode 100644 index 0000000000..199016fcf7 --- /dev/null +++ b/src/pkg/runtime/closure_test.go @@ -0,0 +1,21 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +package runtime_test + +import "testing" + +var s int + +func BenchmarkCallClosure(b *testing.B) { + for i := 0; i < b.N; i++ { + s += func(ii int) int { return 2 * ii }(i) + } +} + +func BenchmarkCallClosure1(b *testing.B) { + for i := 0; i < b.N; i++ { + j := i + s += func(ii int) int { return 2*ii + j }(i) + } +} |