Commit a62722bb authored by Luuk van Dijk's avatar Luuk van Dijk

gc: inlining (disabled without -l)

Cross- and intra package inlining of single assignments or return <expression>.
Minus some hairy cases, currently including other calls, expressions with closures and ... arguments.

R=rsc, rogpeppe, adg, gri
CC=golang-dev
https://golang.org/cl/5400043
parent e25a83d0
......@@ -27,6 +27,7 @@ OFILES=\
fmt.$O\
gen.$O\
init.$O\
inl.$O\
lex.$O\
md5.$O\
mparith1.$O\
......
......@@ -7,7 +7,7 @@
#include "go.h"
#include "y.tab.h"
static void dumpexporttype(Type*);
static void dumpexporttype(Type *t);
// Mark n's symbol as exported
void
......@@ -78,7 +78,7 @@ dumppkg(Pkg *p)
{
char *suffix;
if(p == nil || p == localpkg || p->exported)
if(p == nil || p == localpkg || p->exported || p == builtinpkg)
return;
p->exported = 1;
suffix = "";
......@@ -87,6 +87,68 @@ dumppkg(Pkg *p)
Bprint(bout, "\timport %s \"%Z\"%s\n", p->name, p->path, suffix);
}
// Look for anything we need for the inline body
static void reexportdep(Node *n);
static void
reexportdeplist(NodeList *ll)
{
for(; ll ;ll=ll->next)
reexportdep(ll->n);
}
static void
reexportdep(Node *n)
{
Type *t;
if(!n)
return;
switch(n->op) {
case ONAME:
switch(n->class&~PHEAP) {
case PFUNC:
case PEXTERN:
if (n->sym && n->sym->pkg != localpkg && n->sym->pkg != builtinpkg)
exportlist = list(exportlist, n);
}
break;
case OTYPE:
case OLITERAL:
if (n->sym && n->sym->pkg != localpkg && n->sym->pkg != builtinpkg)
exportlist = list(exportlist, n);
break;
// for operations that need a type when rendered, put the type on the export list.
case OCONV:
case OCONVIFACE:
case OCONVNOP:
case ODOTTYPE:
case OSTRUCTLIT:
case OPTRLIT:
t = n->type;
if(!t->sym && t->type)
t = t->type;
if (t && t->sym && t->sym->def && t->sym->pkg != localpkg && t->sym->pkg != builtinpkg) {
// print("reexport convnop %+hN\n", t->sym->def);
exportlist = list(exportlist, t->sym->def);
}
break;
}
reexportdep(n->left);
reexportdep(n->right);
reexportdeplist(n->list);
reexportdeplist(n->rlist);
reexportdeplist(n->ninit);
reexportdep(n->ntest);
reexportdep(n->nincr);
reexportdeplist(n->nbody);
reexportdeplist(n->nelse);
}
static void
dumpexportconst(Sym *s)
{
......@@ -123,9 +185,13 @@ dumpexportvar(Sym *s)
t = n->type;
dumpexporttype(t);
if(t->etype == TFUNC && n->class == PFUNC)
Bprint(bout, "\tfunc %#S%#hT\n", s, t);
else
if(t->etype == TFUNC && n->class == PFUNC) {
if (n->inl) {
Bprint(bout, "\tfunc %#S%#hT { %#H }\n", s, t, n->inl);
reexportdeplist(n->inl);
} else
Bprint(bout, "\tfunc %#S%#hT\n", s, t);
} else
Bprint(bout, "\tvar %#S %#T\n", s, t);
}
......@@ -148,7 +214,6 @@ dumpexporttype(Type *t)
if(t == T)
return;
if(t->printed || t == types[t->etype] || t == bytetype || t == runetype || t == errortype)
return;
t->printed = 1;
......@@ -177,7 +242,11 @@ dumpexporttype(Type *t)
Bprint(bout, "\ttype %#S %#lT\n", t->sym, t);
for(i=0; i<n; i++) {
f = m[i];
Bprint(bout, "\tfunc (%#T) %#hhS%#hT\n", getthisx(f->type)->type, f->sym, f->type);
if (f->type->nname && f->type->nname->inl) { // nname was set by caninl
Bprint(bout, "\tfunc (%#T) %#hhS%#hT { %#H }\n", getthisx(f->type)->type, f->sym, f->type, f->type->nname->inl);
reexportdeplist(f->type->nname->inl);
} else
Bprint(bout, "\tfunc (%#T) %#hhS%#hT\n", getthisx(f->type)->type, f->sym, f->type);
}
}
......
......@@ -141,7 +141,7 @@ struct Type
uchar local; // created in this file
uchar deferwidth;
uchar broke;
uchar isddd; // TFIELD is ... argument
uchar isddd; // TFIELD is ... argument
uchar align;
Node* nod; // canonical OTYPE node
......@@ -260,6 +260,7 @@ struct Node
NodeList* exit;
NodeList* cvars; // closure params
NodeList* dcl; // autodcl for this func/closure
NodeList* inl; // copy of the body for use in inlining
// OLITERAL/OREGISTER
Val val;
......@@ -280,6 +281,9 @@ struct Node
Node* outer; // outer PPARAMREF in nested closure
Node* closure; // ONAME/PHEAP <-> ONAME/PPARAMREF
// ONAME substitute while inlining
Node* inlvar;
// OPACK
Pkg* pkg;
......@@ -473,6 +477,7 @@ enum
// misc
ODDD,
ODDDARG,
OINLCALL, // intermediary representation of an inlined call
// for back ends
OCMP, ODEC, OEXTEND, OINC, OREGISTER, OINDREG,
......@@ -986,6 +991,12 @@ Node* temp(Type*);
void fninit(NodeList *n);
Sym* renameinit(void);
/*
* inl.c
*/
void caninl(Node *fn);
void inlcalls(Node *fn);
/*
* lex.c
*/
......
......@@ -1295,6 +1295,12 @@ hidden_fndcl:
checkwidth($$->type);
addmethod($4, $$->type, 0);
funchdr($$);
// inl.c's inlnode in on a dotmeth node expects to find the inlineable body as
// (dotmeth's type)->nname->inl, and dotmeth's type has been pulled
// out by typecheck's lookdot as this $$->ttype. So by providing
// this back link here we avoid special casing there.
$$->type->nname = $$;
}
fntype:
......@@ -1790,11 +1796,15 @@ hidden_import:
if($2 == N)
break;
$2->inl = $3;
funcbody($2);
importlist = list(importlist, $2);
if(debug['E']) {
print("import [%Z] func %lN \n", $2->sym->pkg->path, $2);
print("import [%Z] func %lN \n", importpkg->path, $2);
if(debug['l'] > 2 && $2->inl)
print("inl body:%+H\n", $2->inl);
}
}
......
This diff is collapsed.
......@@ -336,11 +336,43 @@ main(int argc, char *argv[])
if(nsavederrors+nerrors)
errorexit();
// Phase 4: escape analysis.
// Phase 4: Inlining
if (debug['l']) { // TODO only if debug['l'] > 1, otherwise lazily when used.
// Typecheck imported function bodies
for(l=importlist; l; l=l->next) {
if (l->n->inl == nil)
continue;
curfn = l->n;
saveerrors();
importpkg = l->n->sym->pkg;
if (debug['l']>2)
print("typecheck import [%S] %lN { %#H }\n", l->n->sym, l->n, l->n->inl);
typechecklist(l->n->inl, Etop);
importpkg = nil;
}
curfn = nil;
if(nsavederrors+nerrors)
errorexit();
}
if (debug['l']) {
// Find functions that can be inlined and clone them before walk expands them.
for(l=xtop; l; l=l->next)
if(l->n->op == ODCLFUNC)
caninl(l->n);
// Expand inlineable calls in all functions
for(l=xtop; l; l=l->next)
if(l->n->op == ODCLFUNC)
inlcalls(l->n);
}
// Phase 5: escape analysis.
if(!debug['N'])
escapes();
// Phase 5: Compile top level functions.
// Phase 6: Compile top level functions.
for(l=xtop; l; l=l->next)
if(l->n->op == ODCLFUNC)
funccompile(l->n, 0);
......@@ -348,7 +380,7 @@ main(int argc, char *argv[])
if(nsavederrors+nerrors == 0)
fninit(xtop);
// Phase 5b: Compile all closures.
// Phase 6b: Compile all closures.
while(closures) {
l = closures;
closures = nil;
......@@ -356,7 +388,7 @@ main(int argc, char *argv[])
funccompile(l->n, 1);
}
// Phase 6: check external declarations.
// Phase 7: check external declarations.
for(l=externdcl; l; l=l->next)
if(l->n->op == ONAME)
typecheck(&l->n, Erv);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment