diff --git a/cl/_testgo/defer/out.ll b/cl/_testgo/defer/out.ll index e2500b92..b37f04be 100644 --- a/cl/_testgo/defer/out.ll +++ b/cl/_testgo/defer/out.ll @@ -52,20 +52,11 @@ _llgo_0: _llgo_1: ; preds = %_llgo_0 store i1 true, ptr @"main.init$guard", align 1 - %1 = load i32, ptr @__llgo_defer, align 4 - %2 = icmp eq i32 %1, ptr null - br i1 %2, label %_llgo_3, label %_llgo_4 + call void @"main.init$after"() br label %_llgo_2 _llgo_2: ; preds = %_llgo_1, %_llgo_0 ret void - -_llgo_3: ; preds = %_llgo_1 - %3 = call i32 @pthread_key_create(ptr @__llgo_defer, ptr null) - br label %_llgo_4 - -_llgo_4: ; preds = %_llgo_3, %_llgo_1 - call void @"main.init$abi"() } define i32 @main(i32 %0, ptr %1) { @@ -74,16 +65,16 @@ _llgo_0: store ptr %1, ptr @__llgo_argv, align 8 call void @"github.com/goplus/llgo/internal/runtime.init"() call void @main.init() - %2 = load i32, ptr @__llgo_defer, align 4 - %3 = call ptr @pthread_getspecific(i32 %2) + %2 = load ptr, ptr @__llgo_defer, align 8 + %3 = call ptr @pthread_getspecific(ptr %2) %4 = alloca i8, i64 32, align 1 %5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %4, i32 0, i32 0 - store ptr @main._llgo_defer, ptr %5, align 8 + store ptr @"main$_llgo_defer", ptr %5, align 8 %6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %4, i32 0, i32 1 store i64 0, ptr %6, align 4 %7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %4, i32 0, i32 2 store ptr %3, ptr %7, align 8 - %8 = call i32 @pthread_setspecific(i32 %2, ptr %4) + %8 = call i32 @pthread_setspecific(ptr %2, ptr %4) %9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %4, i32 0, i32 1 %10 = load i64, ptr %9, align 4 %11 = or i64 %10, 1 @@ -107,7 +98,7 @@ _llgo_2: ; preds = %_llgo_0 %19 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %17, i32 0, i32 1 store i64 5, ptr %19, align 4 %20 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %17, align 8 - %21 = load i32, ptr @__llgo_defer, align 4 + %21 = load ptr, ptr @__llgo_defer, align 8 %22 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %4, i32 0, i32 1 %23 = load i64, ptr %22, align 4 %24 = or i64 %23, 2 @@ -121,14 +112,14 @@ _llgo_3: ; preds = %_llgo_4, %_llgo_2 %27 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %25, i32 0, i32 1 store i64 3, ptr %27, align 4 %28 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %25, align 8 - %29 = load i32, ptr @__llgo_defer, align 4 + %29 = load ptr, ptr @__llgo_defer, align 8 %30 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %4, i32 0, i32 1 %31 = load i64, ptr %30, align 4 %32 = or i64 %31, 4 store i64 %32, ptr %30, align 4 %33 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %4, i32 0, i32 1 %34 = load i64, ptr %33, align 4 - call void @main._llgo_defer(i64 %34) + call void @"main$_llgo_defer"(i64 %34) ret i32 0 _llgo_4: ; preds = %_llgo_0 @@ -138,7 +129,7 @@ _llgo_4: ; preds = %_llgo_0 %37 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %35, i32 0, i32 1 store i64 5, ptr %37, align 4 %38 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %35, align 8 - %39 = load i32, ptr @__llgo_defer, align 4 + %39 = load ptr, ptr @__llgo_defer, align 8 %40 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %4, i32 0, i32 1 %41 = load i64, ptr %40, align 4 %42 = or i64 %41, 8 @@ -147,7 +138,7 @@ _llgo_4: ; preds = %_llgo_0 br label %_llgo_3 } -define void @"main.init$abi"() { +define void @"main.init$after"() { _llgo_0: %0 = load ptr, ptr @_llgo_string, align 8 %1 = icmp eq ptr %0, null @@ -159,6 +150,15 @@ _llgo_1: ; preds = %_llgo_0 br label %_llgo_2 _llgo_2: ; preds = %_llgo_1, %_llgo_0 + %3 = load ptr, ptr @__llgo_defer, align 8 + %4 = icmp eq ptr %3, null + br i1 %4, label %_llgo_3, label %_llgo_4 + +_llgo_3: ; preds = %_llgo_2 + %5 = call i32 @pthread_key_create(ptr @__llgo_defer, ptr null) + br label %_llgo_4 + +_llgo_4: ; preds = %_llgo_3, %_llgo_2 ret void } @@ -183,7 +183,7 @@ _llgo_0: ret void } -define void @main._llgo_defer(i64 %0) { +define void @"main$_llgo_defer"(i64 %0) { _llgo_0: %1 = and i64 %0, 1 %2 = icmp ne i64 %1, 0 diff --git a/cl/compile.go b/cl/compile.go index 3f34ef2a..7ace3f5e 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -285,6 +285,7 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun for _, phi := range p.phis { phi() } + b.EndBuild() }) } return fn, nil, goFunc diff --git a/ssa/abitype.go b/ssa/abitype.go index a0deac81..309f58da 100644 --- a/ssa/abitype.go +++ b/ssa/abitype.go @@ -19,7 +19,6 @@ package ssa import ( "go/token" "go/types" - "unsafe" "github.com/goplus/llgo/ssa/abi" "github.com/goplus/llvm" @@ -285,32 +284,8 @@ func lastParamType(prog Program, fn Expr) Type { // ----------------------------------------------------------------------------- -type abiTypes struct { - iniabi unsafe.Pointer -} - -func (p Package) hasAbiInit() bool { - return p.iniabi != nil -} - -func (p Package) abiInit(b Builder) { - inib := Builder(p.iniabi) - inib.Return() - b.Call(inib.Func.Expr) -} - -func (p Package) abiBuilder() Builder { - if p.iniabi == nil { - sigAbiInit := types.NewSignatureType(nil, nil, nil, nil, nil, false) - fn := p.NewFunc(p.Path()+".init$abi", sigAbiInit, InC) - fnb := fn.MakeBody(1) - p.iniabi = unsafe.Pointer(fnb) - } - return Builder(p.iniabi) -} - func (p Package) abiTypeInit(g Global, t types.Type, pub bool) { - b := p.abiBuilder() + b := p.afterBuilder() tabi := b.abiTypeOf(t) expr := g.Expr var eq Expr diff --git a/ssa/decl.go b/ssa/decl.go index 2cda172f..4dc2badf 100644 --- a/ssa/decl.go +++ b/ssa/decl.go @@ -22,6 +22,7 @@ import ( "sort" "strconv" "strings" + "unsafe" "github.com/goplus/llvm" ) @@ -186,6 +187,8 @@ type aFunction struct { deferNextBit int // next defer bit deferData Expr + deferParam Expr + deferb unsafe.Pointer hasVArg bool } diff --git a/ssa/package.go b/ssa/package.go index aa7ab492..4cb779a3 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -20,6 +20,7 @@ import ( "go/token" "go/types" "strconv" + "unsafe" "github.com/goplus/llgo/ssa/abi" "github.com/goplus/llvm" @@ -157,6 +158,7 @@ type aProgram struct { abiTyPPtr Type deferTy Type deferPtr Type + deferPPtr Type pyImpTy *types.Signature pyNewList *types.Signature @@ -333,14 +335,6 @@ func (p Program) Struct(typs ...Type) Type { return p.rawType(types.NewStruct(els, nil)) } -// DeferPtr returns *runtime.Defer. -func (p Program) DeferPtr() Type { - if p.deferPtr == nil { - p.deferPtr = p.Pointer(p.Defer()) - } - return p.deferPtr -} - // Defer returns runtime.Defer type. func (p Program) Defer() Type { if p.deferTy == nil { @@ -349,7 +343,23 @@ func (p Program) Defer() Type { return p.deferTy } -// AbiTypePtr returns *abi.Type. +// DeferPtr returns *runtime.Defer type. +func (p Program) DeferPtr() Type { + if p.deferPtr == nil { + p.deferPtr = p.Pointer(p.Defer()) + } + return p.deferPtr +} + +// DeferPtrPtr returns **runtime.Defer type. +func (p Program) DeferPtrPtr() Type { + if p.deferPPtr == nil { + p.deferPPtr = p.Pointer(p.DeferPtr()) + } + return p.deferPPtr +} + +// AbiTypePtr returns *abi.Type type. func (p Program) AbiTypePtr() Type { if p.abiTyPtr == nil { p.abiTyPtr = p.rawType(types.NewPointer(p.rtNamed("Type"))) @@ -357,7 +367,7 @@ func (p Program) AbiTypePtr() Type { return p.abiTyPtr } -// AbiTypePtrPtr returns **abi.Type. +// AbiTypePtrPtr returns **abi.Type type. func (p Program) AbiTypePtrPtr() Type { if p.abiTyPPtr == nil { p.abiTyPPtr = p.Pointer(p.AbiTypePtr()) @@ -549,18 +559,17 @@ func (p Program) Uint64() Type { type aPackage struct { mod llvm.Module abi abi.Builder - abiTypes + + Prog Program vars map[string]Global fns map[string]Function stubs map[string]Function pyobjs map[string]PyObjRef pymods map[string]Global - Prog Program + afterb unsafe.Pointer iRoutine int - - deferMgr } type Package = *aPackage @@ -626,18 +635,29 @@ func (p Package) String() string { return p.mod.String() } +// ----------------------------------------------------------------------------- + +func (p Package) afterBuilder() Builder { + if p.afterb == nil { + sigAfterInit := types.NewSignatureType(nil, nil, nil, nil, nil, false) + fn := p.NewFunc(p.Path()+".init$after", sigAfterInit, InC) + fnb := fn.MakeBody(1) + p.afterb = unsafe.Pointer(fnb) + } + return Builder(p.afterb) +} + // AfterInit is called after the package is initialized (init all packages that depends on). func (p Package) AfterInit(b Builder, ret BasicBlock) { - doDeferInit := p.hasDefer() - doAbiInit := p.hasAbiInit() + doAfterb := p.afterb != nil doPyLoadModSyms := p.pyHasModSyms() - if doDeferInit || doAbiInit || doPyLoadModSyms { + if doAfterb || doPyLoadModSyms { b.SetBlockEx(ret, afterInit, false) - if doDeferInit { - p.deferInit(b) - } - if doAbiInit { - p.abiInit(b) + if doAfterb { + afterb := Builder(p.afterb) + p.deferInit(afterb) + afterb.Return() + b.Call(afterb.Func.Expr) } if doPyLoadModSyms { p.pyLoadModSyms(b) @@ -645,6 +665,8 @@ func (p Package) AfterInit(b Builder, ret BasicBlock) { } } +// ----------------------------------------------------------------------------- + /* type CodeGenFileType = llvm.CodeGenFileType diff --git a/ssa/stmt_builder.go b/ssa/stmt_builder.go index 4cbb2ca0..9f92efea 100644 --- a/ssa/stmt_builder.go +++ b/ssa/stmt_builder.go @@ -63,6 +63,11 @@ type aBuilder struct { // Builder represents a builder for creating instructions in a function. type Builder = *aBuilder +// EndBuild ends the build process of a function. +func (b Builder) EndBuild() { + b.endDeferFunc() +} + // Dispose disposes of the builder. func (b Builder) Dispose() { b.impl.Dispose() @@ -136,11 +141,6 @@ const ( deferKey = "__llgo_defer" ) -type deferMgr struct { - deferb unsafe.Pointer - deferparam Expr -} - // func(uintptr) func (p Program) tyDeferFunc() *types.Signature { if p.deferFnTy == nil { @@ -151,14 +151,13 @@ func (p Program) tyDeferFunc() *types.Signature { return p.deferFnTy } -func (p Package) hasDefer() bool { - return p.deferb != nil -} - func (p Package) deferInit(b Builder) { + keyVar := p.VarOf(deferKey) + if keyVar == nil { + return + } prog := p.Prog - keyVar := p.newDeferKey() - keyNil := prog.Null(prog.CIntPtr()) + keyNil := prog.Null(prog.DeferPtrPtr()) keyVar.Init(keyNil) keyVar.impl.SetLinkage(llvm.LinkOnceAnyLinkage) @@ -166,18 +165,19 @@ func (p Package) deferInit(b Builder) { b.IfThen(eq, func() { b.pthreadKeyCreate(keyVar.Expr, prog.Null(prog.VoidPtr())) }) - - b = Builder(p.deferb) - b.Return() } func (p Package) newDeferKey() Global { - return p.NewVarEx(deferKey, p.Prog.CIntPtr()) + return p.NewVarEx(deferKey, p.Prog.DeferPtrPtr()) +} + +func (b Builder) deferKey() Expr { + return b.Load(b.Pkg.newDeferKey().Expr) } // DeferFuncName returns the name of the defer procedure. func (p Function) DeferFuncName() string { - return p.Name() + "._llgo_defer" + return p.Name() + "$_llgo_defer" } // DeferFunc returns the defer procedure of this function. @@ -186,8 +186,12 @@ func (p Function) DeferFunc() Function { return p.Pkg.NewFunc(name, p.Prog.tyDeferFunc(), InC) } -func (b Builder) deferKey() Expr { - return b.Load(b.Pkg.newDeferKey().Expr) +func (b Builder) endDeferFunc() { + self := b.Func + if self.deferb != nil { + b = Builder(self.deferb) + b.Return() + } } // Defer emits a defer instruction. @@ -196,7 +200,6 @@ func (b Builder) Defer(fn Expr, args ...Expr) { logCall("Defer", fn, args) } prog := b.Prog - pkg := b.Pkg self := b.Func next := self.deferNextBit self.deferNextBit++ @@ -205,8 +208,8 @@ func (b Builder) Defer(fn Expr, args ...Expr) { if next == 0 { deferfn := self.DeferFunc() deferb := deferfn.MakeBody(1) - pkg.deferb = unsafe.Pointer(deferb) - pkg.deferparam = deferfn.Param(0) + self.deferb = unsafe.Pointer(deferb) + self.deferParam = deferfn.Param(0) // TODO(xsw): move to funtion start // proc func(uintptr) @@ -221,8 +224,8 @@ func (b Builder) Defer(fn Expr, args ...Expr) { nextbit := prog.Val(uintptr(1 << next)) b.Store(bitsPtr, b.BinOp(token.OR, b.Load(bitsPtr), nextbit)) - b = Builder(pkg.deferb) - has := b.BinOp(token.NEQ, b.BinOp(token.AND, pkg.deferparam, nextbit), zero) + b = Builder(self.deferb) + has := b.BinOp(token.NEQ, b.BinOp(token.AND, self.deferParam, nextbit), zero) b.IfThen(has, func() { b.Call(fn, args...) })