compileFunc: prevent compiling multiple times
This commit is contained in:
124
cl/compile.go
124
cl/compile.go
@@ -169,7 +169,7 @@ func (p *context) compileMethods(pkg llssa.Package, typ types.Type) {
|
|||||||
for i, n := 0, mthds.Len(); i < n; i++ {
|
for i, n := 0, mthds.Len(); i < n; i++ {
|
||||||
mthd := mthds.At(i)
|
mthd := mthds.At(i)
|
||||||
if ssaMthd := prog.MethodValue(mthd); ssaMthd != nil {
|
if ssaMthd := prog.MethodValue(mthd); ssaMthd != nil {
|
||||||
p.compileFunc(pkg, mthd.Obj().Pkg(), ssaMthd, false)
|
p.compileFunc(pkg, mthd.Obj().Pkg(), ssaMthd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,60 +200,87 @@ func makeClosureCtx(pkg *types.Package, vars []*ssa.FreeVar) *types.Var {
|
|||||||
return types.NewParam(token.NoPos, pkg, "__llgo_ctx", t)
|
return types.NewParam(token.NoPos, pkg, "__llgo_ctx", t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa.Function, closure bool) llssa.Function {
|
func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa.Function) llssa.Function {
|
||||||
|
name, ftype := p.funcName(pkgTypes, f, true)
|
||||||
|
if ftype != goFunc {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fn := pkg.FuncOf(name)
|
||||||
|
if fn != nil && fn.HasBody() {
|
||||||
|
return fn
|
||||||
|
}
|
||||||
|
|
||||||
var sig = f.Signature
|
var sig = f.Signature
|
||||||
var name string
|
var hasCtx = len(f.FreeVars) > 0
|
||||||
var ftype int
|
if hasCtx {
|
||||||
var hasCtx bool
|
|
||||||
if closure {
|
|
||||||
name, ftype = funcName(pkgTypes, f), goFunc
|
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
log.Println("==> NewClosure", name, "type:", sig)
|
log.Println("==> NewClosure", name, "type:", sig)
|
||||||
}
|
}
|
||||||
if vars := f.FreeVars; len(vars) > 0 {
|
ctx := makeClosureCtx(pkgTypes, f.FreeVars)
|
||||||
ctx := makeClosureCtx(pkgTypes, vars)
|
sig = llssa.FuncAddCtx(ctx, sig)
|
||||||
sig, hasCtx = llssa.FuncAddCtx(ctx, sig), true
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
name, ftype = p.funcName(pkgTypes, f, true)
|
|
||||||
switch ftype {
|
|
||||||
case ignoredFunc, llgoInstr: // llgo extended instructions
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
log.Println("==> NewFunc", name, "type:", sig.Recv(), sig)
|
log.Println("==> NewFunc", name, "type:", sig.Recv(), sig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn := pkg.NewFuncEx(name, sig, llssa.Background(ftype), hasCtx)
|
if fn == nil {
|
||||||
p.inits = append(p.inits, func() {
|
fn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), hasCtx)
|
||||||
p.fn = fn
|
}
|
||||||
defer func() {
|
if nblk := len(f.Blocks); nblk > 0 {
|
||||||
p.fn = nil
|
fn.MakeBlocks(nblk) // to set fn.HasBody() = true
|
||||||
}()
|
p.inits = append(p.inits, func() {
|
||||||
p.phis = nil
|
p.fn = fn
|
||||||
nblk := len(f.Blocks)
|
defer func() {
|
||||||
if nblk == 0 { // external function
|
p.fn = nil
|
||||||
return
|
}()
|
||||||
}
|
p.phis = nil
|
||||||
if debugGoSSA {
|
if debugGoSSA {
|
||||||
f.WriteTo(os.Stderr)
|
f.WriteTo(os.Stderr)
|
||||||
}
|
}
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
log.Println("==> FuncBody", name)
|
log.Println("==> FuncBody", name)
|
||||||
}
|
}
|
||||||
fn.MakeBlocks(nblk)
|
b := fn.NewBuilder()
|
||||||
b := fn.NewBuilder()
|
p.bvals = make(map[ssa.Value]llssa.Expr)
|
||||||
p.bvals = make(map[ssa.Value]llssa.Expr)
|
for i, block := range f.Blocks {
|
||||||
for i, block := range f.Blocks {
|
p.compileBlock(b, block, i == 0 && name == "main")
|
||||||
p.compileBlock(b, block, i == 0 && name == "main")
|
}
|
||||||
}
|
for _, phi := range p.phis {
|
||||||
for _, phi := range p.phis {
|
phi()
|
||||||
phi()
|
}
|
||||||
}
|
})
|
||||||
})
|
}
|
||||||
return fn
|
return fn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// funcOf returns a function by name and set ftype = goFunc, cFunc, etc.
|
||||||
|
// or returns nil and set ftype = llgoCstr, llgoAlloca, llgoUnreachable, etc.
|
||||||
|
func (p *context) funcOf(fn *ssa.Function) (ret llssa.Function, ftype int) {
|
||||||
|
pkgTypes := p.ensureLoaded(fn.Pkg.Pkg)
|
||||||
|
pkg := p.pkg
|
||||||
|
name, ftype := p.funcName(pkgTypes, fn, false)
|
||||||
|
if ftype == llgoInstr {
|
||||||
|
switch name {
|
||||||
|
case "cstr":
|
||||||
|
ftype = llgoCstr
|
||||||
|
case "advance":
|
||||||
|
ftype = llgoAdvance
|
||||||
|
case "alloca":
|
||||||
|
ftype = llgoAlloca
|
||||||
|
case "allocaCStr":
|
||||||
|
ftype = llgoAllocaCStr
|
||||||
|
case "unreachable":
|
||||||
|
ftype = llgoUnreachable
|
||||||
|
default:
|
||||||
|
panic("unknown llgo instruction: " + name)
|
||||||
|
}
|
||||||
|
} else if ret = pkg.FuncOf(name); ret == nil && len(fn.FreeVars) == 0 {
|
||||||
|
sig := fn.Signature
|
||||||
|
ret = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, doInit bool) llssa.BasicBlock {
|
func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, doInit bool) llssa.BasicBlock {
|
||||||
ret := p.fn.Block(block.Index)
|
ret := p.fn.Block(block.Index)
|
||||||
b.SetBlock(ret)
|
b.SetBlock(ret)
|
||||||
@@ -618,14 +645,11 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *ssa.Function:
|
case *ssa.Function:
|
||||||
if v.Blocks != nil {
|
if v.Pkg == p.goPkg { // function in this package
|
||||||
fn := p.compileFunc(p.pkg, p.goTyps, v, true)
|
fn := p.compileFunc(p.pkg, p.goTyps, v)
|
||||||
return fn.Expr
|
return fn.Expr
|
||||||
}
|
}
|
||||||
fn, ftype := p.funcOf(v)
|
fn, _ := p.funcOf(v)
|
||||||
if ftype >= llgoInstrBase {
|
|
||||||
panic("can't use llgo instruction as a value")
|
|
||||||
}
|
|
||||||
return fn.Expr
|
return fn.Expr
|
||||||
case *ssa.Global:
|
case *ssa.Global:
|
||||||
g := p.varOf(v)
|
g := p.varOf(v)
|
||||||
@@ -718,7 +742,7 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll
|
|||||||
// Do not try to build generic (non-instantiated) functions.
|
// Do not try to build generic (non-instantiated) functions.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ctx.compileFunc(ret, member.Pkg.Pkg, member, false)
|
ctx.compileFunc(ret, member.Pkg.Pkg, member)
|
||||||
case *ssa.Type:
|
case *ssa.Type:
|
||||||
ctx.compileType(ret, member)
|
ctx.compileType(ret, member)
|
||||||
case *ssa.Global:
|
case *ssa.Global:
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func testCompile(t *testing.T, src, expected string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFromTestrt(t *testing.T) {
|
func TestFromTestrt(t *testing.T) {
|
||||||
cltest.FromDir(t, "intgen", "./_testrt", true)
|
cltest.FromDir(t, "", "./_testrt", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFromTestdata(t *testing.T) {
|
func TestFromTestdata(t *testing.T) {
|
||||||
|
|||||||
28
cl/import.go
28
cl/import.go
@@ -234,34 +234,6 @@ func (p *context) varName(pkg *types.Package, v *ssa.Global) (vName string, vtyp
|
|||||||
return name, goVar
|
return name, goVar
|
||||||
}
|
}
|
||||||
|
|
||||||
// funcOf returns a function by name and set ftype = goFunc, cFunc, etc.
|
|
||||||
// or returns nil and set ftype = llgoCstr, llgoAlloca, llgoUnreachable, etc.
|
|
||||||
func (p *context) funcOf(fn *ssa.Function) (ret llssa.Function, ftype int) {
|
|
||||||
pkgTypes := p.ensureLoaded(fn.Pkg.Pkg)
|
|
||||||
pkg := p.pkg
|
|
||||||
name, ftype := p.funcName(pkgTypes, fn, false)
|
|
||||||
if ftype == llgoInstr {
|
|
||||||
switch name {
|
|
||||||
case "cstr":
|
|
||||||
ftype = llgoCstr
|
|
||||||
case "advance":
|
|
||||||
ftype = llgoAdvance
|
|
||||||
case "alloca":
|
|
||||||
ftype = llgoAlloca
|
|
||||||
case "allocaCStr":
|
|
||||||
ftype = llgoAllocaCStr
|
|
||||||
case "unreachable":
|
|
||||||
ftype = llgoUnreachable
|
|
||||||
default:
|
|
||||||
panic("unknown llgo instruction: " + name)
|
|
||||||
}
|
|
||||||
} else if ret = pkg.FuncOf(name); ret == nil {
|
|
||||||
sig := fn.Signature
|
|
||||||
ret = pkg.NewFunc(name, sig, llssa.Background(ftype))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *context) varOf(v *ssa.Global) (ret llssa.Global) {
|
func (p *context) varOf(v *ssa.Global) (ret llssa.Global) {
|
||||||
pkgTypes := p.ensureLoaded(v.Pkg.Pkg)
|
pkgTypes := p.ensureLoaded(v.Pkg.Pkg)
|
||||||
pkg := p.pkg
|
pkg := p.pkg
|
||||||
|
|||||||
@@ -184,6 +184,11 @@ func (p Function) NewBuilder() Builder {
|
|||||||
return &aBuilder{b, p, prog}
|
return &aBuilder{b, p, prog}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasBody reports whether the function has a body.
|
||||||
|
func (p Function) HasBody() bool {
|
||||||
|
return len(p.blks) > 0
|
||||||
|
}
|
||||||
|
|
||||||
// MakeBody creates nblk basic blocks for the function, and creates
|
// MakeBody creates nblk basic blocks for the function, and creates
|
||||||
// a new Builder associated to #0 block.
|
// a new Builder associated to #0 block.
|
||||||
func (p Function) MakeBody(nblk int) Builder {
|
func (p Function) MakeBody(nblk int) Builder {
|
||||||
|
|||||||
Reference in New Issue
Block a user