compiler: load constants directly on inline

This commit is contained in:
Evgeniy Stratonikov 2021-02-05 16:15:26 +03:00
parent 27e60455c7
commit 3484025065
4 changed files with 39 additions and 19 deletions

View file

@ -194,20 +194,21 @@ func (c *codegen) emitStoreStructField(i int) {
// getVarIndex returns variable type and position in corresponding slot, // getVarIndex returns variable type and position in corresponding slot,
// according to current scope. // according to current scope.
func (c *codegen) getVarIndex(pkg string, name string) (varType, int) { func (c *codegen) getVarIndex(pkg string, name string) *varInfo {
if pkg == "" { if pkg == "" {
if c.scope != nil { if c.scope != nil {
vt, val := c.scope.vars.getVarIndex(name) vi := c.scope.vars.getVarInfo(name)
if val >= 0 { if vi != nil {
return vt, val return vi
} }
} }
} }
if i, ok := c.globals[c.getIdentName(pkg, name)]; ok { if i, ok := c.globals[c.getIdentName(pkg, name)]; ok {
return varGlobal, i return &varInfo{refType: varGlobal, index: i}
} }
return varLocal, c.scope.newVariable(varLocal, name) c.scope.newVariable(varLocal, name)
return c.scope.vars.getVarInfo(name)
} }
func getBaseOpcode(t varType) (opcode.Opcode, opcode.Opcode) { func getBaseOpcode(t varType) (opcode.Opcode, opcode.Opcode) {
@ -225,8 +226,12 @@ func getBaseOpcode(t varType) (opcode.Opcode, opcode.Opcode) {
// emitLoadVar loads specified variable to the evaluation stack. // emitLoadVar loads specified variable to the evaluation stack.
func (c *codegen) emitLoadVar(pkg string, name string) { func (c *codegen) emitLoadVar(pkg string, name string) {
t, i := c.getVarIndex(pkg, name) vi := c.getVarIndex(pkg, name)
c.emitLoadByIndex(t, i) if vi.tv.Value != nil {
c.emitLoadConst(vi.tv)
return
}
c.emitLoadByIndex(vi.refType, vi.index)
} }
// emitLoadByIndex loads specified variable type with index i. // emitLoadByIndex loads specified variable type with index i.
@ -245,8 +250,8 @@ func (c *codegen) emitStoreVar(pkg string, name string) {
emit.Opcodes(c.prog.BinWriter, opcode.DROP) emit.Opcodes(c.prog.BinWriter, opcode.DROP)
return return
} }
t, i := c.getVarIndex(pkg, name) vi := c.getVarIndex(pkg, name)
c.emitStoreByIndex(t, i) c.emitStoreByIndex(vi.refType, vi.index)
} }
// emitLoadByIndex stores top value in the specified variable type with index i. // emitLoadByIndex stores top value in the specified variable type with index i.

View file

@ -28,13 +28,18 @@ func (c *codegen) inlineCall(f *funcScope, n *ast.CallExpr) {
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() name := sig.Params().At(i).Name()
if tv := c.typeAndValueOf(n.Args[i]); tv.Value != nil {
c.scope.vars.locals = newScope
c.scope.vars.addAlias(name, varLocal, unspecifiedVarIndex, tv)
continue
}
if arg, ok := n.Args[i].(*ast.Ident); ok { if arg, ok := n.Args[i].(*ast.Ident); ok {
// When function argument is variable or const, we may avoid // When function argument is variable or const, we may avoid
// introducing additional variables for parameters. // introducing additional variables for parameters.
// This is done by providing additional alias to variable. // This is done by providing additional alias to variable.
if vt, index := c.scope.vars.getVarIndex(arg.Name); index != -1 { if vi := c.scope.vars.getVarInfo(arg.Name); vi != nil {
c.scope.vars.locals = newScope c.scope.vars.locals = newScope
c.scope.vars.addAlias(name, vt, index) c.scope.vars.addAlias(name, vi.refType, vi.index, vi.tv)
continue continue
} }
} }

View file

@ -110,8 +110,7 @@ func TestInlineConversion(t *testing.T) {
func Main() int { func Main() int {
a := 2 a := 2
{ {
b := 1 return (1 + a) * (1 + a)
return (b + a) * (b + a)
} }
}` }`
b2, err := compiler.Compile("foo.go", strings.NewReader(src2)) b2, err := compiler.Compile("foo.go", strings.NewReader(src2))

View file

@ -1,5 +1,9 @@
package compiler package compiler
import (
"go/types"
)
type varScope struct { type varScope struct {
localsCnt int localsCnt int
argCnt int argCnt int
@ -10,8 +14,11 @@ type varScope struct {
type varInfo struct { type varInfo struct {
refType varType refType varType
index int index int
tv types.TypeAndValue
} }
const unspecifiedVarIndex = -1
func newVarScope() varScope { func newVarScope() varScope {
return varScope{ return varScope{
arguments: make(map[string]int), arguments: make(map[string]int),
@ -26,23 +33,27 @@ 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) { func (c *varScope) addAlias(name string, vt varType, index int, tv types.TypeAndValue) {
c.locals[len(c.locals)-1][name] = varInfo{ c.locals[len(c.locals)-1][name] = varInfo{
refType: vt, refType: vt,
index: index, index: index,
tv: tv,
} }
} }
func (c *varScope) getVarIndex(name string) (varType, int) { func (c *varScope) getVarInfo(name string) *varInfo {
for i := len(c.locals) - 1; i >= 0; i-- { for i := len(c.locals) - 1; i >= 0; i-- {
if vi, ok := c.locals[i][name]; ok { if vi, ok := c.locals[i][name]; ok {
return vi.refType, vi.index return &vi
} }
} }
if i, ok := c.arguments[name]; ok { if i, ok := c.arguments[name]; ok {
return varArgument, i return &varInfo{
refType: varArgument,
index: i,
} }
return 0, -1 }
return nil
} }
// newVariable creates a new local variable or argument in the scope of the function. // newVariable creates a new local variable or argument in the scope of the function.