compiler: do not introduce excessive locals on inline

When function call-site parameter is an identifier,
we may load it directly. Currently it can be also modified,
this will be fixed in a separate commit.
This commit is contained in:
Evgeniy Stratonikov 2021-02-04 16:26:33 +03:00
parent 1ae0d022dd
commit 27e60455c7
3 changed files with 32 additions and 12 deletions

View file

@ -27,9 +27,19 @@ func (c *codegen) inlineCall(f *funcScope, n *ast.CallExpr) {
defer c.scope.vars.dropScope() defer c.scope.vars.dropScope()
for i := range n.Args { for i := range n.Args {
c.scope.vars.locals = oldScope c.scope.vars.locals = oldScope
name := sig.Params().At(i).Name()
if arg, ok := n.Args[i].(*ast.Ident); ok {
// When function argument is variable or const, we may avoid
// introducing additional variables for parameters.
// This is done by providing additional alias to variable.
if vt, index := c.scope.vars.getVarIndex(arg.Name); index != -1 {
c.scope.vars.locals = newScope
c.scope.vars.addAlias(name, vt, index)
continue
}
}
ast.Walk(c, n.Args[i]) ast.Walk(c, n.Args[i])
c.scope.vars.locals = newScope c.scope.vars.locals = newScope
name := sig.Params().At(i).Name()
c.scope.newLocal(name) c.scope.newLocal(name)
c.emitStoreVar("", name) c.emitStoreVar("", name)
} }

View file

@ -111,12 +111,7 @@ func TestInlineConversion(t *testing.T) {
a := 2 a := 2
{ {
b := 1 b := 1
c := a return (b + a) * (b + a)
{
bb := b
cc := c
return (bb + cc) * (b + c)
}
} }
}` }`
b2, err := compiler.Compile("foo.go", strings.NewReader(src2)) b2, err := compiler.Compile("foo.go", strings.NewReader(src2))

View file

@ -4,7 +4,12 @@ type varScope struct {
localsCnt int localsCnt int
argCnt int argCnt int
arguments map[string]int arguments map[string]int
locals []map[string]int locals []map[string]varInfo
}
type varInfo struct {
refType varType
index int
} }
func newVarScope() varScope { func newVarScope() varScope {
@ -14,17 +19,24 @@ func newVarScope() varScope {
} }
func (c *varScope) newScope() { func (c *varScope) newScope() {
c.locals = append(c.locals, map[string]int{}) c.locals = append(c.locals, map[string]varInfo{})
} }
func (c *varScope) dropScope() { func (c *varScope) dropScope() {
c.locals = c.locals[:len(c.locals)-1] c.locals = c.locals[:len(c.locals)-1]
} }
func (c *varScope) addAlias(name string, vt varType, index int) {
c.locals[len(c.locals)-1][name] = varInfo{
refType: vt,
index: index,
}
}
func (c *varScope) getVarIndex(name string) (varType, int) { func (c *varScope) getVarIndex(name string) (varType, int) {
for i := len(c.locals) - 1; i >= 0; i-- { for i := len(c.locals) - 1; i >= 0; i-- {
if i, ok := c.locals[i][name]; ok { if vi, ok := c.locals[i][name]; ok {
return varLocal, i return vi.refType, vi.index
} }
} }
if i, ok := c.arguments[name]; ok { if i, ok := c.arguments[name]; ok {
@ -56,7 +68,10 @@ func (c *varScope) newVariable(t varType, name string) int {
func (c *varScope) newLocal(name string) int { func (c *varScope) newLocal(name string) int {
idx := len(c.locals) - 1 idx := len(c.locals) - 1
m := c.locals[idx] m := c.locals[idx]
m[name] = c.localsCnt m[name] = varInfo{
refType: varLocal,
index: c.localsCnt,
}
c.localsCnt++ c.localsCnt++
c.locals[idx] = m c.locals[idx] = m
return c.localsCnt - 1 return c.localsCnt - 1