From 11f2ecd675819907451445b1a433123299068c17 Mon Sep 17 00:00:00 2001 From: visualfc Date: Wed, 31 Jul 2024 16:00:02 +0800 Subject: [PATCH 1/2] ssa: defer load/store func and args --- internal/runtime/z_rt.go | 5 ++-- ssa/eh.go | 49 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/internal/runtime/z_rt.go b/internal/runtime/z_rt.go index 672adf62..4b1d1458 100644 --- a/internal/runtime/z_rt.go +++ b/internal/runtime/z_rt.go @@ -32,8 +32,9 @@ type Defer struct { Addr unsafe.Pointer // sigjmpbuf Bits uintptr Link *Defer - Reth unsafe.Pointer // block address after Rethrow - Rund unsafe.Pointer // block address after RunDefers + Reth unsafe.Pointer // block address after Rethrow + Rund unsafe.Pointer // block address after RunDefers + Args []unsafe.Pointer // defer func and args } // Recover recovers a panic. diff --git a/ssa/eh.go b/ssa/eh.go index 2e30e867..eb31c6eb 100644 --- a/ssa/eh.go +++ b/ssa/eh.go @@ -97,6 +97,7 @@ type aDefer struct { bitsPtr Expr // pointer to defer bits rethPtr Expr // next block of Rethrow rundPtr Expr // next block of RunDefers + argsPtr Expr // defer func and args procBlk BasicBlock // deferProc block panicBlk BasicBlock // panic block (runDefers and rethrow) rundsNext []BasicBlock // next blocks of RunDefers @@ -133,11 +134,13 @@ const ( // 2: link *Defer // 3: reth voidptr: block address after Rethrow // 4: rund voidptr: block address after RunDefers + // 5: args []unsafe.Pointer: defer func and args deferSigjmpbuf = iota deferBits deferLink deferRethrow deferRunDefers + deferArgs ) func (b Builder) getDefer(kind DoAction) *aDefer { @@ -167,6 +170,8 @@ func (b Builder) getDefer(kind DoAction) *aDefer { bitsPtr := b.FieldAddr(deferData, deferBits) rethPtr := b.FieldAddr(deferData, deferRethrow) rundPtr := b.FieldAddr(deferData, deferRunDefers) + argsPtr := b.FieldAddr(deferData, deferArgs) + b.Store(argsPtr, b.MakeSlice(prog.Slice(prog.VoidPtr()), prog.Val(0), prog.Val(0))) czero := prog.IntVal(0, prog.CInt()) retval := b.Sigsetjmp(jb, czero) @@ -184,6 +189,7 @@ func (b Builder) getDefer(kind DoAction) *aDefer { bitsPtr: bitsPtr, rethPtr: rethPtr, rundPtr: rundPtr, + argsPtr: argsPtr, procBlk: procBlk, panicBlk: panicBlk, rundsNext: []BasicBlock{rethrowBlk}, @@ -212,12 +218,11 @@ func (b Builder) Defer(kind DoAction, fn Expr, args ...Expr) { if debugInstr { logCall("Defer", fn, args) } - var prog Program + var prog = b.Prog var nextbit Expr var self = b.getDefer(kind) switch kind { case DeferInCond: - prog = b.Prog next := self.nextBit self.nextBit++ bits := b.Load(self.bitsPtr) @@ -228,20 +233,56 @@ func (b Builder) Defer(kind DoAction, fn Expr, args ...Expr) { default: panic("todo: DeferInLoop is not supported - " + b.Func.Name()) } + + var offset int + if fn.kind != vkBuiltin { + offset = 1 + } + typs := make([]Type, len(args)+offset) + flds := make([]llvm.Value, len(args)+offset) + if offset == 1 { + typs[0] = fn.Type + flds[0] = fn.impl + } + for i, arg := range args { + typs[i+offset] = arg.Type + flds[i+offset] = arg.impl + } + t := prog.Struct(typs...) + voidPtr := prog.VoidPtr() + ptr := Expr{b.aggregateMalloc(t, flds...), voidPtr} + b.Store(self.argsPtr, b.BuiltinCall("append", b.Load(self.argsPtr), b.SliceLit(prog.Slice(voidPtr), ptr))) + index := len(self.stmts) self.stmts = append(self.stmts, func(bits Expr) { switch kind { case DeferInCond: 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...) + ptr := b.Load(b.IndexAddr(b.Load(self.argsPtr), b.Prog.Val(index))) + b.callDefer(fn, ptr, t, len(args)) }) case DeferAlways: - b.Call(fn, args...) + ptr := b.Load(b.IndexAddr(b.Load(self.argsPtr), b.Prog.Val(index))) + b.callDefer(fn, ptr, t, len(args)) } }) } +func (b Builder) callDefer(fn Expr, ptr Expr, t Type, n int) { + data := Expr{llvm.CreateLoad(b.impl, t.ll, ptr.impl), t} + args := make([]Expr, n) + var offset int + if fn.kind != vkBuiltin { + fn = b.getField(data, 0) + offset = 1 + } + for i := 0; i < n; i++ { + args[i] = b.getField(data, i+offset) + } + b.Call(fn, args...) +} + // RunDefers emits instructions to run deferred instructions. func (b Builder) RunDefers() { self := b.getDefer(DeferInCond) From 6e8cecd13ed1520e225d1f6ebe884d8dcfeac989 Mon Sep 17 00:00:00 2001 From: visualfc Date: Sat, 30 Nov 2024 14:30:54 +0800 Subject: [PATCH 2/2] cl/_testgo: defer6 --- cl/_testgo/defer6/in.go | 15 ++++++++++++ cl/_testgo/defer6/out.ll | 1 + ssa/eh.go | 51 +++++++++++++++++++++++----------------- 3 files changed, 45 insertions(+), 22 deletions(-) create mode 100644 cl/_testgo/defer6/in.go create mode 100644 cl/_testgo/defer6/out.ll diff --git a/cl/_testgo/defer6/in.go b/cl/_testgo/defer6/in.go new file mode 100644 index 00000000..0dac2594 --- /dev/null +++ b/cl/_testgo/defer6/in.go @@ -0,0 +1,15 @@ +package main + +func main() { + var a int = 5 + defer println(a) + defer func() { + println(a) + }() + a = 10 + panic("error") + //Output: + // 10 + // 5 + // panic: error +} diff --git a/cl/_testgo/defer6/out.ll b/cl/_testgo/defer6/out.ll new file mode 100644 index 00000000..1c8a0e79 --- /dev/null +++ b/cl/_testgo/defer6/out.ll @@ -0,0 +1 @@ +; \ No newline at end of file diff --git a/ssa/eh.go b/ssa/eh.go index eb31c6eb..d156ca64 100644 --- a/ssa/eh.go +++ b/ssa/eh.go @@ -218,11 +218,12 @@ func (b Builder) Defer(kind DoAction, fn Expr, args ...Expr) { if debugInstr { logCall("Defer", fn, args) } - var prog = b.Prog + var prog Program var nextbit Expr var self = b.getDefer(kind) switch kind { case DeferInCond: + prog = b.Prog next := self.nextBit self.nextBit++ bits := b.Load(self.bitsPtr) @@ -233,7 +234,22 @@ func (b Builder) Defer(kind DoAction, fn Expr, args ...Expr) { default: panic("todo: DeferInLoop is not supported - " + b.Func.Name()) } + typ := b.saveDeferArgs(self, fn, args) + self.stmts = append(self.stmts, func(bits Expr) { + switch kind { + case DeferInCond: + zero := prog.Val(uintptr(0)) + has := b.BinOp(token.NEQ, b.BinOp(token.AND, bits, nextbit), zero) + b.IfThen(has, func() { + b.callDefer(self, typ, fn, len(args)) + }) + case DeferAlways: + b.callDefer(self, typ, fn, len(args)) + } + }) +} +func (b Builder) saveDeferArgs(self *aDefer, fn Expr, args []Expr) Type { var offset int if fn.kind != vkBuiltin { offset = 1 @@ -248,36 +264,27 @@ func (b Builder) Defer(kind DoAction, fn Expr, args ...Expr) { typs[i+offset] = arg.Type flds[i+offset] = arg.impl } - t := prog.Struct(typs...) + prog := b.Prog + typ := prog.Struct(typs...) voidPtr := prog.VoidPtr() - ptr := Expr{b.aggregateMalloc(t, flds...), voidPtr} + ptr := Expr{b.aggregateMalloc(typ, flds...), voidPtr} b.Store(self.argsPtr, b.BuiltinCall("append", b.Load(self.argsPtr), b.SliceLit(prog.Slice(voidPtr), ptr))) - index := len(self.stmts) - self.stmts = append(self.stmts, func(bits Expr) { - switch kind { - case DeferInCond: - zero := prog.Val(uintptr(0)) - has := b.BinOp(token.NEQ, b.BinOp(token.AND, bits, nextbit), zero) - b.IfThen(has, func() { - ptr := b.Load(b.IndexAddr(b.Load(self.argsPtr), b.Prog.Val(index))) - b.callDefer(fn, ptr, t, len(args)) - }) - case DeferAlways: - ptr := b.Load(b.IndexAddr(b.Load(self.argsPtr), b.Prog.Val(index))) - b.callDefer(fn, ptr, t, len(args)) - } - }) + return typ } -func (b Builder) callDefer(fn Expr, ptr Expr, t Type, n int) { - data := Expr{llvm.CreateLoad(b.impl, t.ll, ptr.impl), t} - args := make([]Expr, n) +func (b Builder) callDefer(self *aDefer, typ Type, fn Expr, nargs int) { + nLen := b.FieldAddr(Expr{self.argsPtr.impl, b.Prog.Pointer(b.Prog.rtType("Slice"))}, 1) + index := b.BinOp(token.SUB, b.Load(nLen), b.Prog.Val(1)) + ptr := b.Load(b.IndexAddr(b.Load(self.argsPtr), index)) + b.Store(nLen, index) + data := Expr{llvm.CreateLoad(b.impl, typ.ll, ptr.impl), typ} + args := make([]Expr, nargs) var offset int if fn.kind != vkBuiltin { fn = b.getField(data, 0) offset = 1 } - for i := 0; i < n; i++ { + for i := 0; i < nargs; i++ { args[i] = b.getField(data, i+offset) } b.Call(fn, args...)