compileFunc: prevent compiling multiple times
This commit is contained in:
@@ -169,7 +169,7 @@ func (p *context) compileMethods(pkg llssa.Package, typ types.Type) {
|
||||
for i, n := 0, mthds.Len(); i < n; i++ {
|
||||
mthd := mthds.At(i)
|
||||
if ssaMthd := prog.MethodValue(mthd); ssaMthd != nil {
|
||||
p.compileFunc(pkg, mthd.Obj().Pkg(), ssaMthd, false)
|
||||
p.compileFunc(pkg, mthd.Obj().Pkg(), ssaMthd)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,48 +200,46 @@ func makeClosureCtx(pkg *types.Package, vars []*ssa.FreeVar) *types.Var {
|
||||
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 name string
|
||||
var ftype int
|
||||
var hasCtx bool
|
||||
if closure {
|
||||
name, ftype = funcName(pkgTypes, f), goFunc
|
||||
var hasCtx = len(f.FreeVars) > 0
|
||||
if hasCtx {
|
||||
if debugInstr {
|
||||
log.Println("==> NewClosure", name, "type:", sig)
|
||||
}
|
||||
if vars := f.FreeVars; len(vars) > 0 {
|
||||
ctx := makeClosureCtx(pkgTypes, vars)
|
||||
sig, hasCtx = llssa.FuncAddCtx(ctx, sig), true
|
||||
}
|
||||
ctx := makeClosureCtx(pkgTypes, f.FreeVars)
|
||||
sig = llssa.FuncAddCtx(ctx, sig)
|
||||
} else {
|
||||
name, ftype = p.funcName(pkgTypes, f, true)
|
||||
switch ftype {
|
||||
case ignoredFunc, llgoInstr: // llgo extended instructions
|
||||
return nil
|
||||
}
|
||||
if debugInstr {
|
||||
log.Println("==> NewFunc", name, "type:", sig.Recv(), sig)
|
||||
}
|
||||
}
|
||||
fn := pkg.NewFuncEx(name, sig, llssa.Background(ftype), hasCtx)
|
||||
if fn == nil {
|
||||
fn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), hasCtx)
|
||||
}
|
||||
if nblk := len(f.Blocks); nblk > 0 {
|
||||
fn.MakeBlocks(nblk) // to set fn.HasBody() = true
|
||||
p.inits = append(p.inits, func() {
|
||||
p.fn = fn
|
||||
defer func() {
|
||||
p.fn = nil
|
||||
}()
|
||||
p.phis = nil
|
||||
nblk := len(f.Blocks)
|
||||
if nblk == 0 { // external function
|
||||
return
|
||||
}
|
||||
if debugGoSSA {
|
||||
f.WriteTo(os.Stderr)
|
||||
}
|
||||
if debugInstr {
|
||||
log.Println("==> FuncBody", name)
|
||||
}
|
||||
fn.MakeBlocks(nblk)
|
||||
b := fn.NewBuilder()
|
||||
p.bvals = make(map[ssa.Value]llssa.Expr)
|
||||
for i, block := range f.Blocks {
|
||||
@@ -251,9 +249,38 @@ func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa
|
||||
phi()
|
||||
}
|
||||
})
|
||||
}
|
||||
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 {
|
||||
ret := p.fn.Block(block.Index)
|
||||
b.SetBlock(ret)
|
||||
@@ -618,14 +645,11 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr {
|
||||
}
|
||||
}
|
||||
case *ssa.Function:
|
||||
if v.Blocks != nil {
|
||||
fn := p.compileFunc(p.pkg, p.goTyps, v, true)
|
||||
if v.Pkg == p.goPkg { // function in this package
|
||||
fn := p.compileFunc(p.pkg, p.goTyps, v)
|
||||
return fn.Expr
|
||||
}
|
||||
fn, ftype := p.funcOf(v)
|
||||
if ftype >= llgoInstrBase {
|
||||
panic("can't use llgo instruction as a value")
|
||||
}
|
||||
fn, _ := p.funcOf(v)
|
||||
return fn.Expr
|
||||
case *ssa.Global:
|
||||
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.
|
||||
continue
|
||||
}
|
||||
ctx.compileFunc(ret, member.Pkg.Pkg, member, false)
|
||||
ctx.compileFunc(ret, member.Pkg.Pkg, member)
|
||||
case *ssa.Type:
|
||||
ctx.compileType(ret, member)
|
||||
case *ssa.Global:
|
||||
|
||||
@@ -29,7 +29,7 @@ func testCompile(t *testing.T, src, expected string) {
|
||||
}
|
||||
|
||||
func TestFromTestrt(t *testing.T) {
|
||||
cltest.FromDir(t, "intgen", "./_testrt", true)
|
||||
cltest.FromDir(t, "", "./_testrt", true)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 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) {
|
||||
pkgTypes := p.ensureLoaded(v.Pkg.Pkg)
|
||||
pkg := p.pkg
|
||||
|
||||
@@ -184,6 +184,11 @@ func (p Function) NewBuilder() Builder {
|
||||
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
|
||||
// a new Builder associated to #0 block.
|
||||
func (p Function) MakeBody(nblk int) Builder {
|
||||
|
||||
Reference in New Issue
Block a user