From 386ad0ab9056e2f9a0d05d7f86c8ae323262228b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Oudompheng?= Date: Mon, 11 Mar 2013 21:24:51 +0100 Subject: [PATCH] cmd/gc: enable inlining in generated method wrappers. Method calls on interfaces with large stored values will call the pointer receiver method which may be a wrapper over a method with value receiver. This is particularly inefficient for very small bodies. Inlining the wrapped method body saves a potentially expensive function call. benchmark old ns/op new ns/op delta BenchmarkSortString1K 802295 641387 -20.06% BenchmarkSortInt1K 359914 238234 -33.81% BenchmarkSortInt64K 35764226 22803078 -36.24% Fixes #4707. R=golang-dev, daniel.morsing, rsc CC=golang-dev https://golang.org/cl/7214044 --- src/cmd/gc/inl.c | 23 +++++++++++++++-------- src/cmd/gc/obj.c | 14 ++++++++++++++ src/cmd/gc/subr.c | 1 + 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/cmd/gc/inl.c b/src/cmd/gc/inl.c index 1cc13a3045..f80aa9559b 100644 --- a/src/cmd/gc/inl.c +++ b/src/cmd/gc/inl.c @@ -565,24 +565,31 @@ mkinlcall1(Node **np, Node *fn, int isddd) inlretvars = nil; i = 0; // Make temp names to use instead of the originals - for(ll = dcl; ll; ll=ll->next) + for(ll = dcl; ll; ll=ll->next) { + if(ll->n->class == PPARAMOUT) // return values handled below. + continue; if(ll->n->op == ONAME) { ll->n->inlvar = inlvar(ll->n); // Typecheck because inlvar is not necessarily a function parameter. typecheck(&ll->n->inlvar, Erv); if ((ll->n->class&~PHEAP) != PAUTO) ninit = list(ninit, nod(ODCL, ll->n->inlvar, N)); // otherwise gen won't emit the allocations for heapallocs - if (ll->n->class == PPARAMOUT) // we rely on the order being correct here - inlretvars = list(inlretvars, ll->n->inlvar); } + } - // anonymous return values, synthesize names for use in assignment that replaces return - if(inlretvars == nil && fn->type->outtuple > 0) - for(t = getoutargx(fn->type)->type; t; t = t->down) { + // temporaries for return values. + for(t = getoutargx(fn->type)->type; t; t = t->down) { + if(t != T && t->nname != N && !isblank(t->nname)) { + m = inlvar(t->nname); + typecheck(&m, Erv); + t->nname->inlvar = m; + } else { + // anonymous return values, synthesize names for use in assignment that replaces return m = retvar(t, i++); - ninit = list(ninit, nod(ODCL, m, N)); - inlretvars = list(inlretvars, m); } + ninit = list(ninit, nod(ODCL, m, N)); + inlretvars = list(inlretvars, m); + } // assign receiver. if(fn->type->thistuple && n->left->op == ODOTMETH) { diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c index b87d35b7bd..e4bcd11703 100644 --- a/src/cmd/gc/obj.c +++ b/src/cmd/gc/obj.c @@ -16,6 +16,8 @@ static void dumpglobls(void); void dumpobj(void) { + NodeList *externs, *tmp; + bout = Bopen(outfile, OWRITE); if(bout == nil) { flusherrors(); @@ -31,8 +33,20 @@ dumpobj(void) outhist(bout); + externs = nil; + if(externdcl != nil) + externs = externdcl->end; + dumpglobls(); dumptypestructs(); + + // Dump extra globals. + tmp = externdcl; + if(externs != nil) + externdcl = externs->next; + dumpglobls(); + externdcl = tmp; + dumpdata(); dumpfuncs(); diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index c53eaf2857..604cf14020 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -2565,6 +2565,7 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface) fn->dupok = 1; typecheck(&fn, Etop); typechecklist(fn->nbody, Etop); + inlcalls(fn); curfn = nil; funccompile(fn, 0); }