compileFunc: prevent compiling multiple times

This commit is contained in:
xushiwei
2024-05-05 21:27:22 +08:00
parent 2bbd828f3a
commit be9d209622
4 changed files with 80 additions and 79 deletions

View File

@@ -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:

View File

@@ -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) {

View File

@@ -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

View File

@@ -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 {