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++ {
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:

View File

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

View File

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

View File

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