From be9d209622d8db8accc29e9874889ba528135eff Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 5 May 2024 21:27:22 +0800 Subject: [PATCH] compileFunc: prevent compiling multiple times --- cl/compile.go | 124 +++++++++++++++++++++++++++------------------ cl/compile_test.go | 2 +- cl/import.go | 28 ---------- ssa/decl.go | 5 ++ 4 files changed, 80 insertions(+), 79 deletions(-) diff --git a/cl/compile.go b/cl/compile.go index dd29bd09..156e1825 100644 --- a/cl/compile.go +++ b/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++ { 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,60 +200,87 @@ 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) - 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 { - p.compileBlock(b, block, i == 0 && name == "main") - } - for _, phi := range p.phis { - phi() - } - }) + 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 + if debugGoSSA { + f.WriteTo(os.Stderr) + } + if debugInstr { + log.Println("==> FuncBody", name) + } + b := fn.NewBuilder() + p.bvals = make(map[ssa.Value]llssa.Expr) + for i, block := range f.Blocks { + p.compileBlock(b, block, i == 0 && name == "main") + } + for _, phi := range p.phis { + 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: diff --git a/cl/compile_test.go b/cl/compile_test.go index 961af903..b9c3443f 100644 --- a/cl/compile_test.go +++ b/cl/compile_test.go @@ -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) { diff --git a/cl/import.go b/cl/import.go index 53f70cd2..600abf82 100644 --- a/cl/import.go +++ b/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 diff --git a/ssa/decl.go b/ssa/decl.go index 53ad05e4..90255749 100644 --- a/ssa/decl.go +++ b/ssa/decl.go @@ -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 {