From 5a5929048d602cd701c50a56cc749559dd863193 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 2 Jun 2024 14:29:35 +0800 Subject: [PATCH 1/5] defer support; llgo/ssa: IfThen --- cl/_testgo/defer/in.go | 25 +++++++++ cl/_testgo/defer/out.ll | 0 cl/compile.go | 2 + internal/runtime/z_c.go | 2 +- internal/runtime/z_defer.go | 32 +++++++++++ ssa/decl.go | 28 +++++++--- ssa/expr.go | 10 ++-- ssa/goroutine.go | 72 ++++++++++++++++++++++++- ssa/memory.go | 8 +++ ssa/package.go | 83 +++++++++++++++++++++-------- ssa/stmt_builder.go | 103 ++++++++++++++++++++++++++++++++++++ 11 files changed, 328 insertions(+), 37 deletions(-) create mode 100644 cl/_testgo/defer/in.go create mode 100644 cl/_testgo/defer/out.ll create mode 100644 internal/runtime/z_defer.go diff --git a/cl/_testgo/defer/in.go b/cl/_testgo/defer/in.go new file mode 100644 index 00000000..344527b3 --- /dev/null +++ b/cl/_testgo/defer/in.go @@ -0,0 +1,25 @@ +package main + +func f(s string) bool { + return len(s) > 5 +} + +func fail() { + panic("error") +} + +func main() { + defer func() { + println("hi") + if e := recover(); e != nil { + println(e.(string)) + } + }() + if s := "hello"; f(s) { + defer println(s) + } else { + defer println("world") + fail() + } + defer println("bye") +} diff --git a/cl/_testgo/defer/out.ll b/cl/_testgo/defer/out.ll new file mode 100644 index 00000000..e69de29b diff --git a/cl/compile.go b/cl/compile.go index 19b7e265..4b3ed739 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -796,6 +796,8 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) { key := p.compileValue(b, v.Key) val := p.compileValue(b, v.Value) b.MapUpdate(m, key, val) + case *ssa.Defer: + p.call(b, llssa.Defer, &v.Call) case *ssa.Go: p.call(b, llssa.Go, &v.Call) case *ssa.Panic: diff --git a/internal/runtime/z_c.go b/internal/runtime/z_c.go index 2689b8cc..e7a1bef4 100644 --- a/internal/runtime/z_c.go +++ b/internal/runtime/z_c.go @@ -35,7 +35,7 @@ func AllocZ(size uintptr) unsafe.Pointer { } // Zeroinit initializes memory to zero. -func Zeroinit(p c.Pointer, size uintptr) c.Pointer { +func Zeroinit(p unsafe.Pointer, size uintptr) unsafe.Pointer { return c.Memset(p, 0, size) } diff --git a/internal/runtime/z_defer.go b/internal/runtime/z_defer.go new file mode 100644 index 00000000..7f59abb4 --- /dev/null +++ b/internal/runtime/z_defer.go @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package runtime + +// Defer presents defer statements in a function. +type Defer struct { + proc func(uintptr) + bits uintptr + link *Defer +} + +// DeferProc calls deferred statements. +func DeferProc(d *Defer) { + for d != nil { + d.proc(d.bits) + d = d.link + } +} diff --git a/ssa/decl.go b/ssa/decl.go index 255bc1fc..d91d4d1f 100644 --- a/ssa/decl.go +++ b/ssa/decl.go @@ -85,15 +85,13 @@ func (p Package) NewVar(name string, typ types.Type, bg Background) Global { return p.doNewVar(name, t) } -/* -// NewVarFrom creates a new global variable. -func (p Package) NewVarFrom(name string, t Type) Global { +// NewVarEx creates a new global variable. +func (p Package) NewVarEx(name string, t Type) Global { if v, ok := p.vars[name]; ok { return v } return p.doNewVar(name, t) } -*/ func (p Package) doNewVar(name string, t Type) Global { var gbl llvm.Value @@ -185,7 +183,11 @@ type aFunction struct { params []Type freeVars Expr base int // base = 1 if hasFreeVars; base = 0 otherwise - hasVArg bool + + deferNextBit int // next defer bit + deferData Expr + + hasVArg bool } // Function represents a function or method. @@ -222,7 +224,14 @@ func newFunction(fn llvm.Value, t Type, pkg Package, prog Program, hasFreeVars b if hasFreeVars { base = 1 } - return &aFunction{Expr{fn, t}, pkg, prog, nil, params, Expr{}, base, hasVArg} + return &aFunction{ + Expr: Expr{fn, t}, + Pkg: pkg, + Prog: prog, + params: params, + base: base, + hasVArg: hasVArg, + } } func newParams(fn Type, prog Program) (params []Type, hasVArg bool) { @@ -240,12 +249,15 @@ func newParams(fn Type, prog Program) (params []Type, hasVArg bool) { return } -/* // Name returns the function's name. func (p Function) Name() string { return p.impl.Name() } -*/ + +// DeferFuncName returns the name of the defer procedure. +func (p Function) DeferFuncName() string { + return p.Name() + "._llgo_defer" +} // Params returns the function's ith parameter. func (p Function) Param(i int) Expr { diff --git a/ssa/expr.go b/ssa/expr.go index c829d3aa..fa04059a 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -493,7 +493,6 @@ func (b Builder) ChangeType(t Type, x Expr) (ret Expr) { typ := t.raw.Type switch typ.(type) { default: - // TODO(xsw): remove instr name ret.impl = llvm.CreateBitCast(b.impl, x.impl, t.ll) ret.Type = b.Prog.rawType(typ) return @@ -748,7 +747,6 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) { var ll llvm.Type var data Expr var sig *types.Signature - var prog = b.Prog var raw = fn.raw.Type switch kind { case vkClosure: @@ -758,7 +756,7 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) { fallthrough case vkFuncPtr: sig = raw.(*types.Signature) - ll = prog.FuncDecl(sig, InC).ll + ll = b.Prog.FuncDecl(sig, InC).ll case vkFuncDecl: sig = raw.(*types.Signature) ll = fn.ll @@ -768,7 +766,7 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) { default: log.Panicf("unreachable: %d(%T)\n", kind, raw) } - ret.Type = prog.retType(sig) + ret.Type = b.Prog.retType(sig) ret.impl = llvm.CreateCall(b.impl, ll, fn.impl, llvmParamsEx(data, args, sig.Params(), b)) return } @@ -795,8 +793,8 @@ type DoAction int const ( Call DoAction = iota - Go Defer + Go ) // Do call a function with an action. @@ -804,6 +802,8 @@ func (b Builder) Do(da DoAction, fn Expr, args ...Expr) (ret Expr) { switch da { case Call: return b.Call(fn, args...) + case Defer: + b.Defer(fn, args...) case Go: b.Go(fn, args...) } diff --git a/ssa/goroutine.go b/ssa/goroutine.go index e050632a..389ae8df 100644 --- a/ssa/goroutine.go +++ b/ssa/goroutine.go @@ -50,7 +50,7 @@ func (p Program) tyPthreadCreate() *types.Signature { return p.createThdTy } -func (b Builder) createThread(pp, attr, routine, arg Expr) Expr { +func (b Builder) pthreadCreate(pp, attr, routine, arg Expr) Expr { fn := b.Pkg.cFunc("pthread_create", b.Prog.tyPthreadCreate()) return b.Call(fn, pp, attr, routine, arg) } @@ -86,7 +86,7 @@ func (b Builder) Go(fn Expr, args ...Expr) { data := Expr{b.aggregateMalloc(t, flds...), voidPtr} size := prog.SizeOf(voidPtr) pthd := b.Alloca(prog.IntVal(uint64(size), prog.Uintptr())) - b.createThread(pthd, prog.Null(voidPtr), pkg.routine(t, len(args)), data) + b.pthreadCreate(pthd, prog.Null(voidPtr), pkg.routine(t, len(args)), data) } func (p Package) routineName() string { @@ -112,3 +112,71 @@ func (p Package) routine(t Type, n int) Expr { } // ----------------------------------------------------------------------------- + +// func(c.Pointer) +func (p Program) tyDestruct() *types.Signature { + if p.destructTy == nil { + paramPtr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) + params := types.NewTuple(paramPtr) + p.destructTy = types.NewSignatureType(nil, nil, nil, params, nil, false) + } + return p.destructTy +} + +// func(*c.Int, func(c.Pointer)) c.Int +func (p Program) tyPthreadKeyCreate() *types.Signature { + if p.createKeyTy == nil { + cint := p.CInt() + cintPtr := p.Pointer(cint) + paramCintPtr := types.NewParam(token.NoPos, nil, "", cintPtr.raw.Type) + paramDestruct := types.NewParam(token.NoPos, nil, "", p.tyDestruct()) + paramCInt := types.NewParam(token.NoPos, nil, "", cint.raw.Type) + params := types.NewTuple(paramCintPtr, paramDestruct) + results := types.NewTuple(paramCInt) + p.createKeyTy = types.NewSignatureType(nil, nil, nil, params, results, false) + } + return p.createKeyTy +} + +func (b Builder) pthreadKeyCreate(key, destruct Expr) Expr { + fn := b.Pkg.cFunc("pthread_key_create", b.Prog.tyPthreadKeyCreate()) + return b.Call(fn, key, destruct) +} + +// ----------------------------------------------------------------------------- + +// func(c.Int) c.Pointer +func (p Program) tyPthreadGetspecific() *types.Signature { + if p.getSpecTy == nil { + paramCInt := types.NewParam(token.NoPos, nil, "", p.CInt().raw.Type) + paramPtr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) + params := types.NewTuple(paramCInt) + results := types.NewTuple(paramPtr) + p.getSpecTy = types.NewSignatureType(nil, nil, nil, params, results, false) + } + return p.getSpecTy +} + +// func(c.Int, c.Pointer) c.Int +func (p Program) tyPthreadSetspecific() *types.Signature { + if p.setSpecTy == nil { + paramCInt := types.NewParam(token.NoPos, nil, "", p.CInt().raw.Type) + paramPtr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) + params := types.NewTuple(paramCInt, paramPtr) + results := types.NewTuple(paramCInt) + p.setSpecTy = types.NewSignatureType(nil, nil, nil, params, results, false) + } + return p.setSpecTy +} + +func (b Builder) pthreadGetspecific(key Expr) Expr { + fn := b.Pkg.cFunc("pthread_getspecific", b.Prog.tyPthreadGetspecific()) + return b.Call(fn, key) +} + +func (b Builder) pthreadSetspecific(key, val Expr) Expr { + fn := b.Pkg.cFunc("pthread_setspecific", b.Prog.tyPthreadSetspecific()) + return b.Call(fn, key, val) +} + +// ----------------------------------------------------------------------------- diff --git a/ssa/memory.go b/ssa/memory.go index df7b4908..94cfc7f3 100644 --- a/ssa/memory.go +++ b/ssa/memory.go @@ -74,6 +74,14 @@ func (b Builder) aggregateAllocU(t Type, flds ...llvm.Value) llvm.Value { return ptr } +func (b Builder) aggregateAlloca(t Type, flds ...llvm.Value) llvm.Value { + prog := b.Prog + size := prog.SizeOf(t) + ptr := b.Alloca(prog.IntVal(size, prog.Uintptr())).impl + aggregateInit(b.impl, ptr, t.ll, flds...) + return ptr +} + func (b Builder) aggregateMalloc(t Type, flds ...llvm.Value) llvm.Value { prog := b.Prog size := prog.SizeOf(t) diff --git a/ssa/package.go b/ssa/package.go index a81deef7..94a5a18e 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -137,6 +137,7 @@ type aProgram struct { boolTy Type cstrTy Type cintTy Type + cintPtr Type stringTy Type uintptrTy Type intTy Type @@ -148,26 +149,35 @@ type aProgram struct { u32Ty Type i64Ty Type u64Ty Type + pyObjPtr Type pyObjPPtr Type - abiTyptr Type - abiTypptr Type - pyImpTy *types.Signature - pyNewList *types.Signature - pyListSetI *types.Signature - callArgs *types.Signature - callNoArgs *types.Signature - callOneArg *types.Signature - callFOArgs *types.Signature - loadPyModS *types.Signature - getAttrStr *types.Signature + abiTyPtr Type + abiTyPPtr Type + deferTy Type + deferPtr Type + + pyImpTy *types.Signature + pyNewList *types.Signature + pyListSetI *types.Signature + floatFromDbl *types.Signature + callNoArgs *types.Signature + callOneArg *types.Signature + callFOArgs *types.Signature + loadPyModS *types.Signature + getAttrStr *types.Signature mallocTy *types.Signature freeTy *types.Signature + createKeyTy *types.Signature createThdTy *types.Signature + getSpecTy *types.Signature + setSpecTy *types.Signature routineTy *types.Signature + destructTy *types.Signature + deferFnTy *types.Signature paramObjPtr_ *types.Var @@ -333,20 +343,36 @@ func (p Program) Eface() Type { } */ +// 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 { + p.deferTy = p.rtType("Defer") + } + return p.deferTy +} + // AbiTypePtr returns *abi.Type. func (p Program) AbiTypePtr() Type { - if p.abiTyptr == nil { - p.abiTyptr = p.rawType(types.NewPointer(p.rtNamed("Type"))) + if p.abiTyPtr == nil { + p.abiTyPtr = p.rawType(types.NewPointer(p.rtNamed("Type"))) } - return p.abiTyptr + return p.abiTyPtr } // AbiTypePtrPtr returns **abi.Type. func (p Program) AbiTypePtrPtr() Type { - if p.abiTypptr == nil { - p.abiTypptr = p.Pointer(p.AbiTypePtr()) + if p.abiTyPPtr == nil { + p.abiTyPPtr = p.Pointer(p.AbiTypePtr()) } - return p.abiTypptr + return p.abiTyPPtr } // PyObjectPtrPtr returns the **py.Object type. @@ -418,6 +444,15 @@ func (p Program) Any() Type { return p.anyTy } +// CIntPtr returns *c.Int type. +func (p Program) CIntPtr() Type { + if p.cintPtr == nil { + p.cintPtr = p.Pointer(p.CInt()) + } + return p.cintPtr +} + +// CInt returns c.Int type. func (p Program) CInt() Type { if p.cintTy == nil { // C.int p.cintTy = p.rawType(types.Typ[types.Int32]) // TODO(xsw): support 64-bit @@ -528,6 +563,8 @@ type aPackage struct { Prog Program iRoutine int + + deferMgr } type Package = *aPackage @@ -595,10 +632,14 @@ func (p Package) String() string { // 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() doPyLoadModSyms := p.pyHasModSyms() - if doAbiInit || doPyLoadModSyms { + if doDeferInit || doAbiInit || doPyLoadModSyms { b.SetBlockEx(ret, afterInit, false) + if doDeferInit { + p.deferInit(b) + } if doAbiInit { p.abiInit(b) } @@ -739,14 +780,14 @@ func (p Program) tyNewList() *types.Signature { // func(float64) *Object func (p Program) tyFloatFromDouble() *types.Signature { - if p.callArgs == nil { + if p.floatFromDbl == nil { paramObjPtr := p.paramObjPtr() paramFloat := types.NewParam(token.NoPos, nil, "", p.Float64().raw.Type) params := types.NewTuple(paramFloat) results := types.NewTuple(paramObjPtr) - p.callArgs = types.NewSignatureType(nil, nil, nil, params, results, false) + p.floatFromDbl = types.NewSignatureType(nil, nil, nil, params, results, false) } - return p.callArgs + return p.floatFromDbl } // func(*Object, ...) diff --git a/ssa/stmt_builder.go b/ssa/stmt_builder.go index 92fcd37f..43523753 100644 --- a/ssa/stmt_builder.go +++ b/ssa/stmt_builder.go @@ -19,9 +19,11 @@ package ssa import ( "bytes" "fmt" + "go/token" "go/types" "log" "strings" + "unsafe" "github.com/goplus/llvm" ) @@ -128,6 +130,96 @@ func notInit(instr llvm.Value) bool { return true } +// ----------------------------------------------------------------------------- + +const ( + deferKey = "__llgo_defer" +) + +type deferMgr struct { + deferb unsafe.Pointer + deferparam Expr +} + +// func(uintptr) +func (p Program) tyDeferFunc() *types.Signature { + if p.deferFnTy == nil { + paramUintptr := types.NewParam(token.NoPos, nil, "", p.Uintptr().raw.Type) + params := types.NewTuple(paramUintptr) + p.deferFnTy = types.NewSignatureType(nil, nil, nil, params, nil, false) + } + return p.deferFnTy +} + +func (p Package) hasDefer() bool { + return p.deferb != nil +} + +func (p Package) deferInit(b Builder) { + prog := p.Prog + keyVar := p.newDeferKey() + keyNil := prog.Null(prog.CIntPtr()) + keyVar.Init(keyNil) + keyVar.impl.SetLinkage(llvm.LinkOnceAnyLinkage) + + eq := b.BinOp(token.EQL, b.Load(keyVar.Expr), keyNil) + 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()) +} + +func (b Builder) deferKey() Expr { + return b.Load(b.Pkg.newDeferKey().Expr) +} + +// Defer emits a defer instruction. +func (b Builder) Defer(fn Expr, args ...Expr) { + if debugInstr { + logCall("Defer", fn, args) + } + prog := b.Prog + pkg := b.Pkg + self := b.Func + next := self.deferNextBit + self.deferNextBit++ + zero := prog.Val(uintptr(0)) + key := b.deferKey() + if next == 0 { + name := self.DeferFuncName() + deferfn := pkg.NewFunc(name, b.Prog.tyDeferFunc(), InC) + deferb := deferfn.MakeBody(1) + pkg.deferb = unsafe.Pointer(deferb) + pkg.deferparam = deferfn.Param(0) + + // TODO(xsw): move to funtion start + // proc func(uintptr) + // bits uintptr + // link *Defer + link := b.pthreadGetspecific(key) + ptr := b.aggregateAlloca(prog.Defer(), deferfn.impl, zero.impl, link.impl) + self.deferData = Expr{ptr, prog.DeferPtr()} + b.pthreadSetspecific(key, self.deferData) + } + bitsPtr := b.FieldAddr(self.deferData, 1) + 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.IfThen(has, func() { + b.Call(fn, args...) + }) +} + +// ----------------------------------------------------------------------------- + // Panic emits a panic instruction. func (b Builder) Panic(v Expr) { if debugInstr { @@ -206,6 +298,17 @@ func (b Builder) If(cond Expr, thenb, elseb BasicBlock) { b.impl.CreateCondBr(cond.impl, thenb.first, elseb.first) } +// IfThen emits an if-then instruction. +func (b Builder) IfThen(cond Expr, then func()) { + blks := b.Func.MakeBlocks(2) + b.If(cond, blks[0], blks[1]) + b.SetBlockEx(blks[0], AtEnd, false) + then() + b.Jump(blks[1]) + b.SetBlockEx(blks[1], AtEnd, false) + b.blk.last = blks[1].last +} + // ----------------------------------------------------------------------------- // Phi represents a phi node. From ba4521775639304a671b1099f66dc9a9375a2b19 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 2 Jun 2024 15:24:42 +0800 Subject: [PATCH 2/5] llgo/ssa: RunDefers --- cl/_testgo/defer/in.go | 10 +- cl/_testgo/defer/out.ll | 238 ++++++++++++++++++++++++++++++++++++++++ cl/compile.go | 2 + ssa/decl.go | 5 - ssa/expr.go | 26 +++-- ssa/package.go | 18 ++- ssa/stmt_builder.go | 33 +++++- 7 files changed, 303 insertions(+), 29 deletions(-) diff --git a/cl/_testgo/defer/in.go b/cl/_testgo/defer/in.go index 344527b3..b66b5444 100644 --- a/cl/_testgo/defer/in.go +++ b/cl/_testgo/defer/in.go @@ -1,7 +1,7 @@ package main func f(s string) bool { - return len(s) > 5 + return len(s) > 2 } func fail() { @@ -11,9 +11,11 @@ func fail() { func main() { defer func() { println("hi") - if e := recover(); e != nil { - println(e.(string)) - } + /* + if e := recover(); e != nil { + println(e.(string)) + } + */ }() if s := "hello"; f(s) { defer println(s) diff --git a/cl/_testgo/defer/out.ll b/cl/_testgo/defer/out.ll index e69de29b..e2500b92 100644 --- a/cl/_testgo/defer/out.ll +++ b/cl/_testgo/defer/out.ll @@ -0,0 +1,238 @@ +; ModuleID = 'main' +source_filename = "main" + +%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 } +%"github.com/goplus/llgo/internal/runtime.eface" = type { ptr, ptr } +%"github.com/goplus/llgo/internal/runtime.Defer" = type { { ptr, ptr }, i64, ptr } + +@"main.init$guard" = global ptr null +@0 = private unnamed_addr constant [6 x i8] c"error\00", align 1 +@_llgo_string = linkonce global ptr null +@__llgo_argc = global ptr null +@__llgo_argv = global ptr null +@__llgo_defer = linkonce global ptr null +@1 = private unnamed_addr constant [6 x i8] c"hello\00", align 1 +@2 = private unnamed_addr constant [6 x i8] c"hello\00", align 1 +@3 = private unnamed_addr constant [4 x i8] c"bye\00", align 1 +@4 = private unnamed_addr constant [6 x i8] c"world\00", align 1 +@5 = private unnamed_addr constant [3 x i8] c"hi\00", align 1 + +define i1 @main.f(%"github.com/goplus/llgo/internal/runtime.String" %0) { +_llgo_0: + %1 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %0, 1 + %2 = icmp sgt i64 %1, 2 + ret i1 %2 +} + +define void @main.fail() { +_llgo_0: + %0 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %1 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %0, i32 0, i32 0 + store ptr @0, ptr %1, align 8 + %2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %0, i32 0, i32 1 + store i64 5, ptr %2, align 4 + %3 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %0, align 8 + %4 = load ptr, ptr @_llgo_string, align 8 + %5 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16) + store %"github.com/goplus/llgo/internal/runtime.String" %3, ptr %5, align 8 + %6 = alloca %"github.com/goplus/llgo/internal/runtime.eface", align 8 + %7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %6, i32 0, i32 0 + store ptr %4, ptr %7, align 8 + %8 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %6, i32 0, i32 1 + store ptr %5, ptr %8, align 8 + %9 = load %"github.com/goplus/llgo/internal/runtime.eface", ptr %6, align 8 + call void @"github.com/goplus/llgo/internal/runtime.TracePanic"(%"github.com/goplus/llgo/internal/runtime.eface" %9) + unreachable +} + +define void @main.init() { +_llgo_0: + %0 = load i1, ptr @"main.init$guard", align 1 + br i1 %0, label %_llgo_2, label %_llgo_1 + +_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 + 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) { +_llgo_0: + store i32 %0, ptr @__llgo_argc, align 4 + 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) + %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 + %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) + %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 + store i64 %11, ptr %9, align 4 + %12 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %13 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %12, i32 0, i32 0 + store ptr @1, ptr %13, align 8 + %14 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %12, i32 0, i32 1 + store i64 5, ptr %14, align 4 + %15 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %12, align 8 + %16 = call i1 @main.f(%"github.com/goplus/llgo/internal/runtime.String" %15) + br i1 %16, label %_llgo_2, label %_llgo_4 + +_llgo_1: ; No predecessors! + ret i32 0 + +_llgo_2: ; preds = %_llgo_0 + %17 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %18 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %17, i32 0, i32 0 + store ptr @2, ptr %18, align 8 + %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 + %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 + store i64 %24, ptr %22, align 4 + br label %_llgo_3 + +_llgo_3: ; preds = %_llgo_4, %_llgo_2 + %25 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %26 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %25, i32 0, i32 0 + store ptr @3, ptr %26, align 8 + %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 + %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) + ret i32 0 + +_llgo_4: ; preds = %_llgo_0 + %35 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %36 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %35, i32 0, i32 0 + store ptr @4, ptr %36, align 8 + %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 + %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 + store i64 %42, ptr %40, align 4 + call void @main.fail() + br label %_llgo_3 +} + +define void @"main.init$abi"() { +_llgo_0: + %0 = load ptr, ptr @_llgo_string, align 8 + %1 = icmp eq ptr %0, null + br i1 %1, label %_llgo_1, label %_llgo_2 + +_llgo_1: ; preds = %_llgo_0 + %2 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 24) + store ptr %2, ptr @_llgo_string, align 8 + br label %_llgo_2 + +_llgo_2: ; preds = %_llgo_1, %_llgo_0 + ret void +} + +declare ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64) + +declare ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64) + +declare void @"github.com/goplus/llgo/internal/runtime.TracePanic"(%"github.com/goplus/llgo/internal/runtime.eface") + +declare void @"github.com/goplus/llgo/internal/runtime.init"() + +define void @"main.main$1"() { +_llgo_0: + %0 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %1 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %0, i32 0, i32 0 + store ptr @5, ptr %1, align 8 + %2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %0, i32 0, i32 1 + store i64 2, ptr %2, align 4 + %3 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %0, align 8 + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %3) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + ret void +} + +define void @main._llgo_defer(i64 %0) { +_llgo_0: + %1 = and i64 %0, 1 + %2 = icmp ne i64 %1, 0 + br i1 %2, label %_llgo_1, label %_llgo_2 + +_llgo_1: ; preds = %_llgo_0 + call void @"main.main$1"() + br label %_llgo_2 + +_llgo_2: ; preds = %_llgo_1, %_llgo_0 + %3 = and i64 %0, 2 + %4 = icmp ne i64 %3, 0 + br i1 %4, label %_llgo_3, label %_llgo_4 + +_llgo_3: ; preds = %_llgo_2 + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %20) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + br label %_llgo_4 + +_llgo_4: ; preds = %_llgo_3, %_llgo_2 + %5 = and i64 %0, 4 + %6 = icmp ne i64 %5, 0 + br i1 %6, label %_llgo_5, label %_llgo_6 + +_llgo_5: ; preds = %_llgo_4 + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %28) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + br label %_llgo_6 + +_llgo_6: ; preds = %_llgo_5, %_llgo_4 + %7 = and i64 %0, 8 + %8 = icmp ne i64 %7, 0 + br i1 %8, label %_llgo_7, label %_llgo_8 + +_llgo_7: ; preds = %_llgo_6 + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %38) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + br label %_llgo_8 + +_llgo_8: ; preds = %_llgo_7, %_llgo_6 + ret void +} + +declare ptr @pthread_getspecific(i32) + +declare i32 @pthread_setspecific(i32, ptr) + +declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String") + +declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8) + +declare i32 @pthread_key_create(ptr, ptr) diff --git a/cl/compile.go b/cl/compile.go index 4b3ed739..3f34ef2a 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -800,6 +800,8 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) { p.call(b, llssa.Defer, &v.Call) case *ssa.Go: p.call(b, llssa.Go, &v.Call) + case *ssa.RunDefers: + b.RunDefers() case *ssa.Panic: arg := p.compileValue(b, v.X) b.Panic(arg) diff --git a/ssa/decl.go b/ssa/decl.go index d91d4d1f..2cda172f 100644 --- a/ssa/decl.go +++ b/ssa/decl.go @@ -254,11 +254,6 @@ func (p Function) Name() string { return p.impl.Name() } -// DeferFuncName returns the name of the defer procedure. -func (p Function) DeferFuncName() string { - return p.Name() + "._llgo_defer" -} - // Params returns the function's ith parameter. func (p Function) Param(i int) Expr { i += p.base // skip if hasFreeVars diff --git a/ssa/expr.go b/ssa/expr.go index fa04059a..0c81e2a3 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -113,6 +113,16 @@ func (p Program) Zero(t Type) Expr { ret = llvm.ConstStruct(flds, false) case *types.Slice: ret = p.Zero(p.rtType("Slice")).impl + /* TODO(xsw): + case *types.Interface: + var name string + if u.Empty() { + name = "Eface" + } else { + name = "Iface" + } + ret = p.Zero(p.rtType(name)).impl + */ default: log.Panicln("todo:", u) } @@ -818,6 +828,11 @@ func (b Builder) Do(da DoAction, fn Expr, args ...Expr) (ret Expr) { // Go spec (excluding "make" and "new"). func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) { switch fn { + case "String": // unsafe.String + return b.unsafeString(args[0].impl, args[1].impl) + case "Slice": // unsafe.Slice + size := args[1].impl + return b.unsafeSlice(args[0], size, size) case "len": if len(args) == 1 { arg := args[0] @@ -857,8 +872,6 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) { } } } - case "print", "println": - return b.PrintEx(fn == "println", args...) case "copy": if len(args) == 2 { dst := args[0] @@ -874,11 +887,10 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) { } } } - case "String": // unsafe.String - return b.unsafeString(args[0].impl, args[1].impl) - case "Slice": // unsafe.Slice - size := args[1].impl - return b.unsafeSlice(args[0], size, size) + //case "recover": + // return b.Recover() + case "print", "println": + return b.PrintEx(fn == "println", args...) } panic("todo: " + fn) } diff --git a/ssa/package.go b/ssa/package.go index 94a5a18e..aa7ab492 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -333,16 +333,6 @@ func (p Program) Struct(typs ...Type) Type { return p.rawType(types.NewStruct(els, nil)) } -/* -// Eface returns the empty interface type. -func (p Program) Eface() Type { - if p.efaceTy == nil { - p.efaceTy = p.rawType(tyAny) - } - return p.efaceTy -} -*/ - // DeferPtr returns *runtime.Defer. func (p Program) DeferPtr() Type { if p.deferPtr == nil { @@ -436,7 +426,7 @@ func (p Program) String() Type { return p.stringTy } -// Any returns any type. +// Any returns the any (empty interface) type. func (p Program) Any() Type { if p.anyTy == nil { p.anyTy = p.rawType(tyAny) @@ -444,6 +434,12 @@ func (p Program) Any() Type { return p.anyTy } +// Eface returns the empty interface type. +// It is equivalent to Any. +func (p Program) Eface() Type { + return p.Any() +} + // CIntPtr returns *c.Int type. func (p Program) CIntPtr() Type { if p.cintPtr == nil { diff --git a/ssa/stmt_builder.go b/ssa/stmt_builder.go index 43523753..4cbb2ca0 100644 --- a/ssa/stmt_builder.go +++ b/ssa/stmt_builder.go @@ -175,6 +175,17 @@ func (p Package) newDeferKey() Global { return p.NewVarEx(deferKey, p.Prog.CIntPtr()) } +// DeferFuncName returns the name of the defer procedure. +func (p Function) DeferFuncName() string { + return p.Name() + "._llgo_defer" +} + +// DeferFunc returns the defer procedure of this function. +func (p Function) DeferFunc() Function { + name := p.DeferFuncName() + return p.Pkg.NewFunc(name, p.Prog.tyDeferFunc(), InC) +} + func (b Builder) deferKey() Expr { return b.Load(b.Pkg.newDeferKey().Expr) } @@ -192,8 +203,7 @@ func (b Builder) Defer(fn Expr, args ...Expr) { zero := prog.Val(uintptr(0)) key := b.deferKey() if next == 0 { - name := self.DeferFuncName() - deferfn := pkg.NewFunc(name, b.Prog.tyDeferFunc(), InC) + deferfn := self.DeferFunc() deferb := deferfn.MakeBody(1) pkg.deferb = unsafe.Pointer(deferb) pkg.deferparam = deferfn.Param(0) @@ -218,8 +228,27 @@ func (b Builder) Defer(fn Expr, args ...Expr) { }) } +// RunDefers emits instructions to run deferred instructions. +func (b Builder) RunDefers() { + self := b.Func + deferfn := self.DeferFunc() + bitsPtr := b.FieldAddr(self.deferData, 1) + b.Call(deferfn.Expr, b.Load(bitsPtr)) +} + // ----------------------------------------------------------------------------- +/* +// Recover emits a recover instruction. +func (b Builder) Recover() (v Expr) { + if debugInstr { + log.Println("Recover") + } + prog := b.Prog + return prog.Zero(prog.Eface()) +} +*/ + // Panic emits a panic instruction. func (b Builder) Panic(v Expr) { if debugInstr { From 410f9dd7596ac2c0c3b655ee0facd74bc154c80e Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 2 Jun 2024 21:54:51 +0800 Subject: [PATCH 3/5] llgo/ssa: EndBuild --- cl/_testgo/defer/out.ll | 40 ++++++++++++------------- cl/compile.go | 1 + ssa/abitype.go | 27 +---------------- ssa/decl.go | 3 ++ ssa/package.go | 66 +++++++++++++++++++++++++++-------------- ssa/stmt_builder.go | 49 ++++++++++++++++-------------- 6 files changed, 95 insertions(+), 91 deletions(-) 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...) }) From 56a5a7d72e4578e0bdc8edefddf66203a839f6b9 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Mon, 3 Jun 2024 01:06:01 +0800 Subject: [PATCH 4/5] defer refactor --- cl/_testdata/print/out.ll | 4 +- cl/_testdata/vargs/out.ll | 4 +- cl/_testgo/defer/out.ll | 190 +++++++++++++++--------------- cl/_testgo/errors/out.ll | 4 +- cl/_testgo/strucintf/out.ll | 4 +- cl/_testgo/struczero/out.ll | 4 +- cl/_testrt/any/out.ll | 4 +- cl/_testrt/builtin/out.ll | 4 +- cl/_testrt/cast/out.ll | 4 +- cl/_testrt/eface/out.ll | 4 +- cl/_testrt/panic/out.ll | 4 +- internal/abi/llgo_autogen.lla | Bin 3631 -> 3631 bytes internal/runtime/llgo_autogen.lla | Bin 12615 -> 12781 bytes internal/runtime/z_defer.go | 2 + ssa/decl.go | 11 +- ssa/package.go | 2 +- ssa/stmt_builder.go | 133 +++++++++++++-------- 17 files changed, 207 insertions(+), 171 deletions(-) diff --git a/cl/_testdata/print/out.ll b/cl/_testdata/print/out.ll index 9f89186a..8fbc290b 100644 --- a/cl/_testdata/print/out.ll +++ b/cl/_testdata/print/out.ll @@ -85,7 +85,7 @@ _llgo_0: _llgo_1: ; preds = %_llgo_0 store i1 true, ptr @"main.init$guard", align 1 - call void @"main.init$abi"() + call void @"main.init$after"() store i64 0, ptr @main.minhexdigits, align 4 br label %_llgo_2 @@ -1412,7 +1412,7 @@ declare i32 @printf(ptr, ...) declare void @"github.com/goplus/llgo/internal/runtime.init"() -define void @"main.init$abi"() { +define void @"main.init$after"() { _llgo_0: %0 = load ptr, ptr @_llgo_float32, align 8 %1 = icmp eq ptr %0, null diff --git a/cl/_testdata/vargs/out.ll b/cl/_testdata/vargs/out.ll index a687457b..2dcb1327 100644 --- a/cl/_testdata/vargs/out.ll +++ b/cl/_testdata/vargs/out.ll @@ -19,7 +19,7 @@ _llgo_0: _llgo_1: ; preds = %_llgo_0 store i1 true, ptr @"main.init$guard", align 1 - call void @"main.init$abi"() + call void @"main.init$after"() br label %_llgo_2 _llgo_2: ; preds = %_llgo_1, %_llgo_0 @@ -118,7 +118,7 @@ declare void @"github.com/goplus/llgo/internal/runtime.init"() declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64) -define void @"main.init$abi"() { +define void @"main.init$after"() { _llgo_0: %0 = load ptr, ptr @_llgo_int, align 8 %1 = icmp eq ptr %0, null diff --git a/cl/_testgo/defer/out.ll b/cl/_testgo/defer/out.ll index b37f04be..6ef57dab 100644 --- a/cl/_testgo/defer/out.ll +++ b/cl/_testgo/defer/out.ll @@ -3,7 +3,7 @@ source_filename = "main" %"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 } %"github.com/goplus/llgo/internal/runtime.eface" = type { ptr, ptr } -%"github.com/goplus/llgo/internal/runtime.Defer" = type { { ptr, ptr }, i64, ptr } +%"github.com/goplus/llgo/internal/runtime.Defer" = type { { ptr, ptr }, i64, ptr, i64 } @"main.init$guard" = global ptr null @0 = private unnamed_addr constant [6 x i8] c"error\00", align 1 @@ -67,75 +67,119 @@ _llgo_0: call void @main.init() %2 = load ptr, ptr @__llgo_defer, align 8 %3 = call ptr @pthread_getspecific(ptr %2) - %4 = alloca i8, i64 32, align 1 + %4 = alloca i8, i64 40, 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 null, 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(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 - store i64 %11, ptr %9, align 4 - %12 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 - %13 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %12, i32 0, i32 0 - store ptr @1, ptr %13, align 8 - %14 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %12, i32 0, i32 1 - store i64 5, ptr %14, align 4 - %15 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %12, align 8 - %16 = call i1 @main.f(%"github.com/goplus/llgo/internal/runtime.String" %15) - br i1 %16, label %_llgo_2, label %_llgo_4 + %10 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %4, i32 0, i32 3 + %11 = load i64, ptr %9, align 4 + %12 = or i64 %11, 1 + store i64 %12, ptr %9, align 4 + %13 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %14 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %13, i32 0, i32 0 + store ptr @1, ptr %14, align 8 + %15 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %13, i32 0, i32 1 + store i64 5, ptr %15, align 4 + %16 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %13, align 8 + %17 = call i1 @main.f(%"github.com/goplus/llgo/internal/runtime.String" %16) + br i1 %17, label %_llgo_2, label %_llgo_4 _llgo_1: ; No predecessors! ret i32 0 _llgo_2: ; preds = %_llgo_0 - %17 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 - %18 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %17, i32 0, i32 0 - store ptr @2, ptr %18, align 8 - %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 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 - store i64 %24, ptr %22, align 4 + %18 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %19 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %18, i32 0, i32 0 + store ptr @2, ptr %19, align 8 + %20 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %18, i32 0, i32 1 + store i64 5, ptr %20, align 4 + %21 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %18, align 8 + %22 = load i64, ptr %9, align 4 + %23 = or i64 %22, 2 + store i64 %23, ptr %9, align 4 br label %_llgo_3 _llgo_3: ; preds = %_llgo_4, %_llgo_2 - %25 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 - %26 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %25, i32 0, i32 0 - store ptr @3, ptr %26, align 8 - %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 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) - ret i32 0 + %24 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %25 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %24, i32 0, i32 0 + store ptr @3, ptr %25, align 8 + %26 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %24, i32 0, i32 1 + store i64 3, ptr %26, align 4 + %27 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %24, align 8 + %28 = load i64, ptr %9, align 4 + %29 = or i64 %28, 4 + store i64 %29, ptr %9, align 4 + store i64 0, ptr %10, align 4 + br label %_llgo_5 _llgo_4: ; preds = %_llgo_0 - %35 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 - %36 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %35, i32 0, i32 0 - store ptr @4, ptr %36, align 8 - %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 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 - store i64 %42, ptr %40, align 4 + %30 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %31 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %30, i32 0, i32 0 + store ptr @4, ptr %31, align 8 + %32 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %30, i32 0, i32 1 + store i64 5, ptr %32, align 4 + %33 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %30, align 8 + %34 = load i64, ptr %9, align 4 + %35 = or i64 %34, 8 + store i64 %35, ptr %9, align 4 call void @main.fail() br label %_llgo_3 + +_llgo_5: ; preds = %_llgo_3 + %36 = load i64, ptr %9, align 4 + %37 = and i64 %36, 8 + %38 = icmp ne i64 %37, 0 + br i1 %38, label %_llgo_7, label %_llgo_8 + +_llgo_6: ; preds = %_llgo_14 + ret i32 0 + +_llgo_7: ; preds = %_llgo_5 + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %33) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + br label %_llgo_8 + +_llgo_8: ; preds = %_llgo_7, %_llgo_5 + %39 = and i64 %36, 4 + %40 = icmp ne i64 %39, 0 + br i1 %40, label %_llgo_9, label %_llgo_10 + +_llgo_9: ; preds = %_llgo_8 + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %27) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + br label %_llgo_10 + +_llgo_10: ; preds = %_llgo_9, %_llgo_8 + %41 = and i64 %36, 2 + %42 = icmp ne i64 %41, 0 + br i1 %42, label %_llgo_11, label %_llgo_12 + +_llgo_11: ; preds = %_llgo_10 + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %21) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + br label %_llgo_12 + +_llgo_12: ; preds = %_llgo_11, %_llgo_10 + %43 = and i64 %36, 1 + %44 = icmp ne i64 %43, 0 + br i1 %44, label %_llgo_13, label %_llgo_14 + +_llgo_13: ; preds = %_llgo_12 + call void @"main.main$1"() + br label %_llgo_14 + +_llgo_14: ; preds = %_llgo_13, %_llgo_12 + %45 = load %"github.com/goplus/llgo/internal/runtime.Defer", ptr %4, align 8 + %46 = extractvalue %"github.com/goplus/llgo/internal/runtime.Defer" %45, 2 + %47 = call i32 @pthread_setspecific(ptr %2, ptr %46) + %48 = load i64, ptr %10, align 4 + switch i64 %48, label %_llgo_6 [ + ] } define void @"main.init$after"() { @@ -183,50 +227,6 @@ _llgo_0: ret void } -define void @"main$_llgo_defer"(i64 %0) { -_llgo_0: - %1 = and i64 %0, 1 - %2 = icmp ne i64 %1, 0 - br i1 %2, label %_llgo_1, label %_llgo_2 - -_llgo_1: ; preds = %_llgo_0 - call void @"main.main$1"() - br label %_llgo_2 - -_llgo_2: ; preds = %_llgo_1, %_llgo_0 - %3 = and i64 %0, 2 - %4 = icmp ne i64 %3, 0 - br i1 %4, label %_llgo_3, label %_llgo_4 - -_llgo_3: ; preds = %_llgo_2 - call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %20) - call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) - br label %_llgo_4 - -_llgo_4: ; preds = %_llgo_3, %_llgo_2 - %5 = and i64 %0, 4 - %6 = icmp ne i64 %5, 0 - br i1 %6, label %_llgo_5, label %_llgo_6 - -_llgo_5: ; preds = %_llgo_4 - call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %28) - call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) - br label %_llgo_6 - -_llgo_6: ; preds = %_llgo_5, %_llgo_4 - %7 = and i64 %0, 8 - %8 = icmp ne i64 %7, 0 - br i1 %8, label %_llgo_7, label %_llgo_8 - -_llgo_7: ; preds = %_llgo_6 - call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %38) - call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) - br label %_llgo_8 - -_llgo_8: ; preds = %_llgo_7, %_llgo_6 - ret void -} - declare ptr @pthread_getspecific(i32) declare i32 @pthread_setspecific(i32, ptr) diff --git a/cl/_testgo/errors/out.ll b/cl/_testgo/errors/out.ll index 599cc745..56719002 100644 --- a/cl/_testgo/errors/out.ll +++ b/cl/_testgo/errors/out.ll @@ -60,7 +60,7 @@ _llgo_0: _llgo_1: ; preds = %_llgo_0 store i1 true, ptr @"main.init$guard", align 1 - call void @"main.init$abi"() + call void @"main.init$after"() br label %_llgo_2 _llgo_2: ; preds = %_llgo_1, %_llgo_0 @@ -102,7 +102,7 @@ _llgo_0: declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64) -define void @"main.init$abi"() { +define void @"main.init$after"() { _llgo_0: %0 = call ptr @"github.com/goplus/llgo/internal/runtime.NewNamed"(i64 25, i64 0, i64 1) store ptr %0, ptr @_llgo_main.errorString, align 8 diff --git a/cl/_testgo/strucintf/out.ll b/cl/_testgo/strucintf/out.ll index f23f046d..57632d34 100644 --- a/cl/_testgo/strucintf/out.ll +++ b/cl/_testgo/strucintf/out.ll @@ -49,7 +49,7 @@ _llgo_0: _llgo_1: ; preds = %_llgo_0 store i1 true, ptr @"main.init$guard", align 1 call void @"github.com/goplus/llgo/cl/internal/foo.init"() - call void @"main.init$abi"() + call void @"main.init$after"() br label %_llgo_2 _llgo_2: ; preds = %_llgo_1, %_llgo_0 @@ -241,7 +241,7 @@ _llgo_18: ; preds = %_llgo_17, %_llgo_16 declare ptr @"github.com/goplus/llgo/internal/runtime.Zeroinit"(ptr, i64) -define void @"main.init$abi"() { +define void @"main.init$after"() { _llgo_0: %0 = load ptr, ptr @_llgo_int, align 8 %1 = icmp eq ptr %0, null diff --git a/cl/_testgo/struczero/out.ll b/cl/_testgo/struczero/out.ll index 2bd65e65..48894dd4 100644 --- a/cl/_testgo/struczero/out.ll +++ b/cl/_testgo/struczero/out.ll @@ -117,7 +117,7 @@ _llgo_0: _llgo_1: ; preds = %_llgo_0 store i1 true, ptr @"main.init$guard", align 1 call void @"github.com/goplus/llgo/cl/internal/foo.init"() - call void @"main.init$abi"() + call void @"main.init$after"() br label %_llgo_2 _llgo_2: ; preds = %_llgo_1, %_llgo_0 @@ -185,7 +185,7 @@ _llgo_0: ret i32 0 } -define void @"main.init$abi"() { +define void @"main.init$after"() { _llgo_0: %0 = load ptr, ptr @"_llgo_github.com/goplus/llgo/cl/internal/foo.Foo", align 8 %1 = icmp eq ptr %0, null diff --git a/cl/_testrt/any/out.ll b/cl/_testrt/any/out.ll index d2f59f3f..83e277c1 100644 --- a/cl/_testrt/any/out.ll +++ b/cl/_testrt/any/out.ll @@ -68,7 +68,7 @@ _llgo_0: _llgo_1: ; preds = %_llgo_0 store i1 true, ptr @"main.init$guard", align 1 - call void @"main.init$abi"() + call void @"main.init$after"() br label %_llgo_2 _llgo_2: ; preds = %_llgo_1, %_llgo_0 @@ -101,7 +101,7 @@ _llgo_0: ret i32 0 } -define void @"main.init$abi"() { +define void @"main.init$after"() { _llgo_0: %0 = load ptr, ptr @_llgo_int8, align 8 %1 = icmp eq ptr %0, null diff --git a/cl/_testrt/builtin/out.ll b/cl/_testrt/builtin/out.ll index 8045b41c..ffd5bc49 100644 --- a/cl/_testrt/builtin/out.ll +++ b/cl/_testrt/builtin/out.ll @@ -86,7 +86,7 @@ _llgo_0: _llgo_1: ; preds = %_llgo_0 store i1 true, ptr @"main.init$guard", align 1 - call void @"main.init$abi"() + call void @"main.init$after"() store i64 9223372036854775807, ptr @main.a, align 4 store i64 -9223372036854775808, ptr @main.b, align 4 store i64 -1, ptr @main.n, align 4 @@ -643,7 +643,7 @@ declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.SliceAppend"(%"github.com/goplus/llgo/internal/runtime.Slice", ptr, i64, i64) -define void @"main.init$abi"() { +define void @"main.init$after"() { _llgo_0: %0 = load ptr, ptr @_llgo_int, align 8 %1 = icmp eq ptr %0, null diff --git a/cl/_testrt/cast/out.ll b/cl/_testrt/cast/out.ll index 1f6b0f30..5225b11c 100644 --- a/cl/_testrt/cast/out.ll +++ b/cl/_testrt/cast/out.ll @@ -401,7 +401,7 @@ _llgo_0: _llgo_1: ; preds = %_llgo_0 store i1 true, ptr @"main.init$guard", align 1 - call void @"main.init$abi"() + call void @"main.init$after"() br label %_llgo_2 _llgo_2: ; preds = %_llgo_1, %_llgo_0 @@ -472,7 +472,7 @@ _llgo_0: ret i32 0 } -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 diff --git a/cl/_testrt/eface/out.ll b/cl/_testrt/eface/out.ll index af51095f..c809135b 100644 --- a/cl/_testrt/eface/out.ll +++ b/cl/_testrt/eface/out.ll @@ -199,7 +199,7 @@ _llgo_0: _llgo_1: ; preds = %_llgo_0 store i1 true, ptr @"main.init$guard", align 1 call void @"github.com/goplus/llgo/internal/abi.init"() - call void @"main.init$abi"() + call void @"main.init$after"() br label %_llgo_2 _llgo_2: ; preds = %_llgo_1, %_llgo_0 @@ -436,7 +436,7 @@ declare void @"github.com/goplus/llgo/internal/abi.init"() declare void @"github.com/goplus/llgo/internal/runtime.init"() -define void @"main.init$abi"() { +define void @"main.init$after"() { _llgo_0: %0 = load ptr, ptr @_llgo_bool, align 8 %1 = icmp eq ptr %0, null diff --git a/cl/_testrt/panic/out.ll b/cl/_testrt/panic/out.ll index 4bac3016..ce254403 100644 --- a/cl/_testrt/panic/out.ll +++ b/cl/_testrt/panic/out.ll @@ -17,7 +17,7 @@ _llgo_0: _llgo_1: ; preds = %_llgo_0 store i1 true, ptr @"main.init$guard", align 1 - call void @"main.init$abi"() + call void @"main.init$after"() br label %_llgo_2 _llgo_2: ; preds = %_llgo_1, %_llgo_0 @@ -51,7 +51,7 @@ _llgo_0: declare void @"github.com/goplus/llgo/internal/runtime.init"() -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 diff --git a/internal/abi/llgo_autogen.lla b/internal/abi/llgo_autogen.lla index 747da4e5dd5762de366e733a45fe063c15df467a..eb0833a52b935b58b9da512baaa15a58ea7d1dec 100644 GIT binary patch delta 49 zcmZ24vtEWbz?+#xgn@y9gJB!T;fcJe>>0~q(z2GtY_y!t%M28ne3{pn87MZHlTQr* DRmKk9 delta 49 zcmZ24vtEWbz?+#xgn@y9gCV)$;6z?k_MKOw(so~s+GshQml-HD`7*CDGf-?YC!ZPs DcODR) diff --git a/internal/runtime/llgo_autogen.lla b/internal/runtime/llgo_autogen.lla index 6574534d716e05f65771ac9b1371ca6cb75527ab..cfd6dabb077ab6d264d3d66e9d6839992dbd247c 100644 GIT binary patch literal 12781 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 jzlaR*|BuM{|Iru<(%=yPa~=4Yvjy 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 XC0R(Q|1k&sZ>ayLH~+&WKtTQv^H?iq diff --git a/internal/runtime/z_defer.go b/internal/runtime/z_defer.go index 7f59abb4..007d4888 100644 --- a/internal/runtime/z_defer.go +++ b/internal/runtime/z_defer.go @@ -21,6 +21,7 @@ type Defer struct { proc func(uintptr) bits uintptr link *Defer + rund int // index of RunDefers } // DeferProc calls deferred statements. @@ -28,5 +29,6 @@ func DeferProc(d *Defer) { for d != nil { d.proc(d.bits) d = d.link + _ = d.rund } } diff --git a/ssa/decl.go b/ssa/decl.go index 4dc2badf..8abe0339 100644 --- a/ssa/decl.go +++ b/ssa/decl.go @@ -22,7 +22,6 @@ import ( "sort" "strconv" "strings" - "unsafe" "github.com/goplus/llvm" ) @@ -181,16 +180,12 @@ type aFunction struct { blks []BasicBlock + defer_ *aDefer + params []Type freeVars Expr base int // base = 1 if hasFreeVars; base = 0 otherwise - - deferNextBit int // next defer bit - deferData Expr - deferParam Expr - deferb unsafe.Pointer - - hasVArg bool + hasVArg bool } // Function represents a function or method. diff --git a/ssa/package.go b/ssa/package.go index 4cb779a3..98e471b6 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -179,7 +179,7 @@ type aProgram struct { setSpecTy *types.Signature routineTy *types.Signature destructTy *types.Signature - deferFnTy *types.Signature + //deferFnTy *types.Signature paramObjPtr_ *types.Var diff --git a/ssa/stmt_builder.go b/ssa/stmt_builder.go index 9f92efea..17449b86 100644 --- a/ssa/stmt_builder.go +++ b/ssa/stmt_builder.go @@ -23,7 +23,6 @@ import ( "go/types" "log" "strings" - "unsafe" "github.com/goplus/llvm" ) @@ -65,7 +64,7 @@ type Builder = *aBuilder // EndBuild ends the build process of a function. func (b Builder) EndBuild() { - b.endDeferFunc() + b.Func.endDefer(b) } // Dispose disposes of the builder. @@ -141,6 +140,18 @@ const ( deferKey = "__llgo_defer" ) +type aDefer struct { + nextBit int // next defer bit + key Expr // pthread TLS key + data Expr // pointer to runtime.Defer + bitsPtr Expr // pointer to defer bits + rundPtr Expr // pointer to RunDefers index + procBlk BasicBlock // deferProc block + stmts []func(bits Expr) + runsNext []BasicBlock // next blocks of RunDefers +} + +/* // func(uintptr) func (p Program) tyDeferFunc() *types.Signature { if p.deferFnTy == nil { @@ -150,6 +161,7 @@ func (p Program) tyDeferFunc() *types.Signature { } return p.deferFnTy } +*/ func (p Package) deferInit(b Builder) { keyVar := p.VarOf(deferKey) @@ -175,23 +187,31 @@ 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" -} - -// DeferFunc returns the defer procedure of this function. -func (p Function) DeferFunc() Function { - name := p.DeferFuncName() - return p.Pkg.NewFunc(name, p.Prog.tyDeferFunc(), InC) -} - -func (b Builder) endDeferFunc() { +func (b Builder) getDefer() *aDefer { self := b.Func - if self.deferb != nil { - b = Builder(self.deferb) - b.Return() + if self.defer_ == nil { + // TODO(xsw): move to funtion start + // 0: proc func(uintptr) + // 1: bits uintptr + // 2: link *Defer + // 3: rund int + prog := b.Prog + key := b.deferKey() + deferfn := prog.Null(prog.VoidPtr()) + zero := prog.Val(uintptr(0)) + link := b.pthreadGetspecific(key) + ptr := b.aggregateAlloca(prog.Defer(), deferfn.impl, zero.impl, link.impl) + deferData := Expr{ptr, prog.DeferPtr()} + b.pthreadSetspecific(key, deferData) + self.defer_ = &aDefer{ + key: key, + data: deferData, + bitsPtr: b.FieldAddr(deferData, 1), + rundPtr: b.FieldAddr(deferData, 3), + procBlk: self.MakeBlock(), + } } + return self.defer_ } // Defer emits a defer instruction. @@ -200,43 +220,62 @@ func (b Builder) Defer(fn Expr, args ...Expr) { logCall("Defer", fn, args) } prog := b.Prog - self := b.Func - next := self.deferNextBit - self.deferNextBit++ - zero := prog.Val(uintptr(0)) - key := b.deferKey() - if next == 0 { - deferfn := self.DeferFunc() - deferb := deferfn.MakeBody(1) - self.deferb = unsafe.Pointer(deferb) - self.deferParam = deferfn.Param(0) - - // TODO(xsw): move to funtion start - // proc func(uintptr) - // bits uintptr - // link *Defer - link := b.pthreadGetspecific(key) - ptr := b.aggregateAlloca(prog.Defer(), deferfn.impl, zero.impl, link.impl) - self.deferData = Expr{ptr, prog.DeferPtr()} - b.pthreadSetspecific(key, self.deferData) - } - bitsPtr := b.FieldAddr(self.deferData, 1) + self := b.getDefer() + next := self.nextBit + self.nextBit++ + bits := b.Load(self.bitsPtr) nextbit := prog.Val(uintptr(1 << next)) - b.Store(bitsPtr, b.BinOp(token.OR, b.Load(bitsPtr), nextbit)) + b.Store(self.bitsPtr, b.BinOp(token.OR, bits, nextbit)) - 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...) + self.stmts = append(self.stmts, func(bits Expr) { + zero := prog.Val(uintptr(0)) + has := b.BinOp(token.NEQ, b.BinOp(token.AND, bits, nextbit), zero) + b.IfThen(has, func() { + b.Call(fn, args...) + }) }) } // RunDefers emits instructions to run deferred instructions. func (b Builder) RunDefers() { - self := b.Func - deferfn := self.DeferFunc() - bitsPtr := b.FieldAddr(self.deferData, 1) - b.Call(deferfn.Expr, b.Load(bitsPtr)) + prog := b.Prog + self := b.getDefer() + b.Store(self.rundPtr, prog.Val(len(self.runsNext))) + b.Jump(self.procBlk) + + blk := b.Func.MakeBlock() + self.runsNext = append(self.runsNext, blk) + + b.SetBlockEx(blk, AtEnd, false) + b.blk.last = blk.last +} + +func (p Function) endDefer(b Builder) { + self := p.defer_ + if self == nil { + return + } + nexts := self.runsNext + n := len(nexts) + if n == 0 { + return + } + b.SetBlockEx(self.procBlk, AtEnd, true) + bits := b.Load(self.bitsPtr) + stmts := self.stmts + for i := len(stmts) - 1; i >= 0; i-- { + stmts[i](bits) + } + + link := b.getField(b.Load(self.data), 2) + b.pthreadSetspecific(self.key, link) + + prog := b.Prog + rund := b.Load(self.rundPtr) + sw := b.impl.CreateSwitch(rund.impl, nexts[0].first, n-1) + for i := 1; i < n; i++ { + sw.AddCase(prog.Val(i).impl, nexts[i].first) + } } // ----------------------------------------------------------------------------- From 2c799a8ccfa143f5d4632abe33d4630735cfd9be Mon Sep 17 00:00:00 2001 From: xushiwei Date: Mon, 3 Jun 2024 01:32:25 +0800 Subject: [PATCH 5/5] deferInit bugfix --- cl/_testgo/defer/in.go | 11 +--- cl/_testgo/defer/out.ll | 111 +++++++++++++--------------------------- ssa/decl.go | 2 + ssa/package.go | 20 ++++---- ssa/ssa_test.go | 11 ++++ ssa/stmt_builder.go | 3 +- 6 files changed, 63 insertions(+), 95 deletions(-) diff --git a/cl/_testgo/defer/in.go b/cl/_testgo/defer/in.go index b66b5444..82d34e31 100644 --- a/cl/_testgo/defer/in.go +++ b/cl/_testgo/defer/in.go @@ -4,24 +4,15 @@ func f(s string) bool { return len(s) > 2 } -func fail() { - panic("error") -} - func main() { defer func() { println("hi") - /* - if e := recover(); e != nil { - println(e.(string)) - } - */ }() if s := "hello"; f(s) { defer println(s) } else { defer println("world") - fail() + return } defer println("bye") } diff --git a/cl/_testgo/defer/out.ll b/cl/_testgo/defer/out.ll index 6ef57dab..d7649276 100644 --- a/cl/_testgo/defer/out.ll +++ b/cl/_testgo/defer/out.ll @@ -2,20 +2,17 @@ source_filename = "main" %"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 } -%"github.com/goplus/llgo/internal/runtime.eface" = type { ptr, ptr } %"github.com/goplus/llgo/internal/runtime.Defer" = type { { ptr, ptr }, i64, ptr, i64 } @"main.init$guard" = global ptr null -@0 = private unnamed_addr constant [6 x i8] c"error\00", align 1 -@_llgo_string = linkonce global ptr null @__llgo_argc = global ptr null @__llgo_argv = global ptr null @__llgo_defer = linkonce global ptr null +@0 = private unnamed_addr constant [6 x i8] c"hello\00", align 1 @1 = private unnamed_addr constant [6 x i8] c"hello\00", align 1 -@2 = private unnamed_addr constant [6 x i8] c"hello\00", align 1 -@3 = private unnamed_addr constant [4 x i8] c"bye\00", align 1 -@4 = private unnamed_addr constant [6 x i8] c"world\00", align 1 -@5 = private unnamed_addr constant [3 x i8] c"hi\00", align 1 +@2 = private unnamed_addr constant [4 x i8] c"bye\00", align 1 +@3 = private unnamed_addr constant [6 x i8] c"world\00", align 1 +@4 = private unnamed_addr constant [3 x i8] c"hi\00", align 1 define i1 @main.f(%"github.com/goplus/llgo/internal/runtime.String" %0) { _llgo_0: @@ -24,27 +21,6 @@ _llgo_0: ret i1 %2 } -define void @main.fail() { -_llgo_0: - %0 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 - %1 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %0, i32 0, i32 0 - store ptr @0, ptr %1, align 8 - %2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %0, i32 0, i32 1 - store i64 5, ptr %2, align 4 - %3 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %0, align 8 - %4 = load ptr, ptr @_llgo_string, align 8 - %5 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16) - store %"github.com/goplus/llgo/internal/runtime.String" %3, ptr %5, align 8 - %6 = alloca %"github.com/goplus/llgo/internal/runtime.eface", align 8 - %7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %6, i32 0, i32 0 - store ptr %4, ptr %7, align 8 - %8 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %6, i32 0, i32 1 - store ptr %5, ptr %8, align 8 - %9 = load %"github.com/goplus/llgo/internal/runtime.eface", ptr %6, align 8 - call void @"github.com/goplus/llgo/internal/runtime.TracePanic"(%"github.com/goplus/llgo/internal/runtime.eface" %9) - unreachable -} - define void @main.init() { _llgo_0: %0 = load i1, ptr @"main.init$guard", align 1 @@ -82,12 +58,12 @@ _llgo_0: store i64 %12, ptr %9, align 4 %13 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 %14 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %13, i32 0, i32 0 - store ptr @1, ptr %14, align 8 + store ptr @0, ptr %14, align 8 %15 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %13, i32 0, i32 1 store i64 5, ptr %15, align 4 %16 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %13, align 8 %17 = call i1 @main.f(%"github.com/goplus/llgo/internal/runtime.String" %16) - br i1 %17, label %_llgo_2, label %_llgo_4 + br i1 %17, label %_llgo_2, label %_llgo_3 _llgo_1: ; No predecessors! ret i32 0 @@ -95,19 +71,16 @@ _llgo_1: ; No predecessors! _llgo_2: ; preds = %_llgo_0 %18 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 %19 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %18, i32 0, i32 0 - store ptr @2, ptr %19, align 8 + store ptr @1, ptr %19, align 8 %20 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %18, i32 0, i32 1 store i64 5, ptr %20, align 4 %21 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %18, align 8 %22 = load i64, ptr %9, align 4 %23 = or i64 %22, 2 store i64 %23, ptr %9, align 4 - br label %_llgo_3 - -_llgo_3: ; preds = %_llgo_4, %_llgo_2 %24 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 %25 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %24, i32 0, i32 0 - store ptr @3, ptr %25, align 8 + store ptr @2, ptr %25, align 8 %26 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %24, i32 0, i32 1 store i64 3, ptr %26, align 4 %27 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %24, align 8 @@ -115,36 +88,39 @@ _llgo_3: ; preds = %_llgo_4, %_llgo_2 %29 = or i64 %28, 4 store i64 %29, ptr %9, align 4 store i64 0, ptr %10, align 4 - br label %_llgo_5 + br label %_llgo_4 -_llgo_4: ; preds = %_llgo_0 +_llgo_3: ; preds = %_llgo_0 %30 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 %31 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %30, i32 0, i32 0 - store ptr @4, ptr %31, align 8 + store ptr @3, ptr %31, align 8 %32 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %30, i32 0, i32 1 store i64 5, ptr %32, align 4 %33 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %30, align 8 %34 = load i64, ptr %9, align 4 %35 = or i64 %34, 8 store i64 %35, ptr %9, align 4 - call void @main.fail() - br label %_llgo_3 + store i64 1, ptr %10, align 4 + br label %_llgo_4 -_llgo_5: ; preds = %_llgo_3 +_llgo_4: ; preds = %_llgo_3, %_llgo_2 %36 = load i64, ptr %9, align 4 %37 = and i64 %36, 8 %38 = icmp ne i64 %37, 0 br i1 %38, label %_llgo_7, label %_llgo_8 +_llgo_5: ; preds = %_llgo_14 + ret i32 0 + _llgo_6: ; preds = %_llgo_14 ret i32 0 -_llgo_7: ; preds = %_llgo_5 +_llgo_7: ; preds = %_llgo_4 call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %33) call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) br label %_llgo_8 -_llgo_8: ; preds = %_llgo_7, %_llgo_5 +_llgo_8: ; preds = %_llgo_7, %_llgo_4 %39 = and i64 %36, 4 %40 = icmp ne i64 %39, 0 br i1 %40, label %_llgo_9, label %_llgo_10 @@ -178,47 +154,18 @@ _llgo_14: ; preds = %_llgo_13, %_llgo_12 %46 = extractvalue %"github.com/goplus/llgo/internal/runtime.Defer" %45, 2 %47 = call i32 @pthread_setspecific(ptr %2, ptr %46) %48 = load i64, ptr %10, align 4 - switch i64 %48, label %_llgo_6 [ + switch i64 %48, label %_llgo_5 [ + i64 1, label %_llgo_6 ] } -define void @"main.init$after"() { -_llgo_0: - %0 = load ptr, ptr @_llgo_string, align 8 - %1 = icmp eq ptr %0, null - br i1 %1, label %_llgo_1, label %_llgo_2 - -_llgo_1: ; preds = %_llgo_0 - %2 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 24) - store ptr %2, ptr @_llgo_string, align 8 - 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 -} - -declare ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64) - -declare ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64) - -declare void @"github.com/goplus/llgo/internal/runtime.TracePanic"(%"github.com/goplus/llgo/internal/runtime.eface") - declare void @"github.com/goplus/llgo/internal/runtime.init"() define void @"main.main$1"() { _llgo_0: %0 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 %1 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %0, i32 0, i32 0 - store ptr @5, ptr %1, align 8 + store ptr @4, ptr %1, align 8 %2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %0, i32 0, i32 1 store i64 2, ptr %2, align 4 %3 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %0, align 8 @@ -235,4 +182,18 @@ declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8) +define void @"main.init$after"() { +_llgo_0: + %0 = load ptr, ptr @__llgo_defer, align 8 + %1 = icmp eq ptr %0, null + br i1 %1, label %_llgo_1, label %_llgo_2 + +_llgo_1: ; preds = %_llgo_0 + %2 = call i32 @pthread_key_create(ptr @__llgo_defer, ptr null) + br label %_llgo_2 + +_llgo_2: ; preds = %_llgo_1, %_llgo_0 + ret void +} + declare i32 @pthread_key_create(ptr, ptr) diff --git a/ssa/decl.go b/ssa/decl.go index 8abe0339..889f5aa1 100644 --- a/ssa/decl.go +++ b/ssa/decl.go @@ -247,10 +247,12 @@ func newParams(fn Type, prog Program) (params []Type, hasVArg bool) { return } +/* // Name returns the function's name. func (p Function) Name() string { return p.impl.Name() } +*/ // Params returns the function's ith parameter. func (p Function) Param(i int) Expr { diff --git a/ssa/package.go b/ssa/package.go index 98e471b6..e96a595d 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -131,14 +131,14 @@ type aProgram struct { rtSliceTy llvm.Type rtMapTy llvm.Type - anyTy Type - voidTy Type - voidPtr Type - voidPPtr Type - boolTy Type - cstrTy Type - cintTy Type - cintPtr Type + anyTy Type + voidTy Type + voidPtr Type + voidPPtr Type + boolTy Type + cstrTy Type + cintTy Type + //cintPtr Type stringTy Type uintptrTy Type intTy Type @@ -444,6 +444,7 @@ func (p Program) Any() Type { return p.anyTy } +/* // Eface returns the empty interface type. // It is equivalent to Any. func (p Program) Eface() Type { @@ -457,6 +458,7 @@ func (p Program) CIntPtr() Type { } return p.cintPtr } +*/ // CInt returns c.Int type. func (p Program) CInt() Type { @@ -649,13 +651,13 @@ func (p Package) afterBuilder() Builder { // AfterInit is called after the package is initialized (init all packages that depends on). func (p Package) AfterInit(b Builder, ret BasicBlock) { + p.deferInit() doAfterb := p.afterb != nil doPyLoadModSyms := p.pyHasModSyms() if doAfterb || doPyLoadModSyms { b.SetBlockEx(ret, afterInit, false) if doAfterb { afterb := Builder(p.afterb) - p.deferInit(afterb) afterb.Return() b.Call(afterb.Func.Expr) } diff --git a/ssa/ssa_test.go b/ssa/ssa_test.go index f861fb97..b9ef006d 100644 --- a/ssa/ssa_test.go +++ b/ssa/ssa_test.go @@ -27,6 +27,16 @@ import ( "github.com/goplus/llvm" ) +func TestEndDefer(t *testing.T) { + prog := NewProgram(nil) + pkg := prog.NewPackage("foo", "foo") + sigMain := types.NewSignatureType(nil, nil, nil, nil, nil, false) + fn := pkg.NewFunc("main", sigMain, InC) + b := fn.MakeBody(1) + fn.defer_ = &aDefer{} + fn.endDefer(b) +} + func TestUnsafeString(t *testing.T) { prog := NewProgram(nil) prog.SetRuntime(func() *types.Package { @@ -187,6 +197,7 @@ func TestVar(t *testing.T) { if pkg.NewVar("a", types.Typ[types.Int], InGo) != a { t.Fatal("NewVar(a) failed") } + pkg.NewVarEx("a", prog.Type(types.Typ[types.Int], InGo)) a.Init(prog.Val(100)) b := pkg.NewVar("b", types.Typ[types.Int], InGo) b.Init(a.Expr) diff --git a/ssa/stmt_builder.go b/ssa/stmt_builder.go index 17449b86..36da0a9d 100644 --- a/ssa/stmt_builder.go +++ b/ssa/stmt_builder.go @@ -163,7 +163,7 @@ func (p Program) tyDeferFunc() *types.Signature { } */ -func (p Package) deferInit(b Builder) { +func (p Package) deferInit() { keyVar := p.VarOf(deferKey) if keyVar == nil { return @@ -173,6 +173,7 @@ func (p Package) deferInit(b Builder) { keyVar.Init(keyNil) keyVar.impl.SetLinkage(llvm.LinkOnceAnyLinkage) + b := p.afterBuilder() eq := b.BinOp(token.EQL, b.Load(keyVar.Expr), keyNil) b.IfThen(eq, func() { b.pthreadKeyCreate(keyVar.Expr, prog.Null(prog.VoidPtr()))