diff --git a/cl/_testrt/intgen/out.ll b/cl/_testrt/intgen/out.ll index dbf5271e..ab28bc81 100644 --- a/cl/_testrt/intgen/out.ll +++ b/cl/_testrt/intgen/out.ll @@ -22,11 +22,12 @@ _llgo_1: ; preds = %_llgo_2, %_llgo_0 br i1 %8, label %_llgo_2, label %_llgo_3 _llgo_2: ; preds = %_llgo_1 - %9 = extractvalue { ptr, ptr } %1, 0 - %10 = call i32 %9() - %11 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %4) - %12 = getelementptr inbounds i32, ptr %11, i64 %7 - store i32 %10, ptr %12, align 4 + %9 = extractvalue { ptr, ptr } %1, 1 + %10 = extractvalue { ptr, ptr } %1, 0 + %11 = call i32 %10(ptr %9) + %12 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %4) + %13 = getelementptr inbounds i32, ptr %12, i64 %7 + store i32 %11, ptr %13, align 4 br label %_llgo_1 _llgo_3: ; preds = %_llgo_1 @@ -54,7 +55,7 @@ _llgo_0: store i32 1, ptr %0, align 4 %1 = alloca { ptr, ptr }, align 8 %2 = getelementptr inbounds { ptr, ptr }, ptr %1, i32 0, i32 0 - store ptr @rand, ptr %2, align 8 + store ptr @__llgo_stub.rand, ptr %2, align 8 %3 = getelementptr inbounds { ptr, ptr }, ptr %1, i32 0, i32 1 store ptr null, ptr %3, align 8 %4 = load { ptr, ptr }, ptr %1, align 8 @@ -118,6 +119,12 @@ declare void @"github.com/goplus/llgo/internal/runtime.init"() declare i32 @rand() +define i32 @__llgo_stub.rand(ptr %0) { +_llgo_0: + %1 = call i32 @rand() + ret i32 %1 +} + declare i32 @printf(ptr, ...) define i32 @"main.main$1"({ ptr } %0) { diff --git a/ssa/decl.go b/ssa/decl.go index 7ac0e42e..53ad05e4 100644 --- a/ssa/decl.go +++ b/ssa/decl.go @@ -26,8 +26,9 @@ import ( // ----------------------------------------------------------------------------- const ( - ClosureCtx = "__llgo_ctx" - NameValist = "__llgo_va_list" + ClosureCtx = "__llgo_ctx" + ClosureStub = "__llgo_stub." + NameValist = "__llgo_va_list" ) func VArg() *types.Var { diff --git a/ssa/expr.go b/ssa/expr.go index 70e67402..f1f0153a 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -358,10 +358,7 @@ func (b Builder) UnOp(op token.Token, x Expr) Expr { func checkExpr(v Expr, t types.Type, b Builder) Expr { if t, ok := t.(*types.Struct); ok && isClosure(t) { if v.kind != vkClosure { - log.Panicln("checkExpr:", v.impl.Name()) - prog := b.Prog - nilVal := prog.Null(prog.VoidPtr()).impl - return b.aggregateValue(prog.rawType(t), v.impl, nilVal) + return b.Func.Pkg.closureStub(b, t, v) } } return v diff --git a/ssa/package.go b/ssa/package.go index a73651df..a0de6d0b 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -17,6 +17,7 @@ package ssa import ( + "go/token" "go/types" "log" @@ -223,10 +224,11 @@ func (p Program) NewPackage(name, pkgPath string) Package { mod := p.ctx.NewModule(pkgPath) // TODO(xsw): Finalize may cause panic, so comment it. // mod.Finalize() - fns := make(map[string]Function) gbls := make(map[string]Global) + fns := make(map[string]Function) + stubs := make(map[string]Function) p.needRuntime = false - return &aPackage{mod, fns, gbls, p} + return &aPackage{mod, gbls, fns, stubs, p} } // Void returns void type. @@ -309,10 +311,11 @@ func (p Program) Float64() Type { // initializer) and "init#%d", the nth declared init function, // and unspecified other things too. type aPackage struct { - mod llvm.Module - fns map[string]Function - vars map[string]Global - Prog Program + mod llvm.Module + vars map[string]Global + fns map[string]Function + stubs map[string]Function + Prog Program } type Package = *aPackage @@ -365,6 +368,30 @@ func (p Package) rtFunc(fnName string) Expr { return p.NewFunc(name, sig, InGo).Expr } +func (p Package) closureStub(b Builder, t *types.Struct, v Expr) Expr { + name := v.impl.Name() + prog := b.Prog + nilVal := prog.Null(prog.VoidPtr()).impl + if fn, ok := p.stubs[name]; ok { + v = fn.Expr + } else { + sig := v.raw.Type.(*types.Signature) + n := sig.Params().Len() + ctx := types.NewParam(token.NoPos, nil, ClosureCtx, types.Typ[types.UnsafePointer]) + sig = FuncAddCtx(ctx, sig) + fn := p.NewFunc(ClosureStub+name, sig, InC) + args := make([]Expr, n) + for i := 0; i < n; i++ { + args[i] = fn.Param(i + 1) + } + b := fn.MakeBody(1) + b.Return(b.Call(v, args...)) + p.stubs[name] = fn + v = fn.Expr + } + return b.aggregateValue(prog.rawType(t), v.impl, nilVal) +} + // FuncOf returns a function by name. func (p Package) FuncOf(name string) Function { return p.fns[name]