Merge pull request #630 from visualfc/deferargs

ssa: defer load/store func and args
This commit is contained in:
xushiwei
2024-12-02 13:51:25 +08:00
committed by GitHub
4 changed files with 69 additions and 4 deletions

15
cl/_testgo/defer6/in.go Normal file
View File

@@ -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
}

1
cl/_testgo/defer6/out.ll Normal file
View File

@@ -0,0 +1 @@
;

View File

@@ -32,8 +32,9 @@ type Defer struct {
Addr unsafe.Pointer // sigjmpbuf Addr unsafe.Pointer // sigjmpbuf
Bits uintptr Bits uintptr
Link *Defer Link *Defer
Reth unsafe.Pointer // block address after Rethrow Reth unsafe.Pointer // block address after Rethrow
Rund unsafe.Pointer // block address after RunDefers Rund unsafe.Pointer // block address after RunDefers
Args []unsafe.Pointer // defer func and args
} }
// Recover recovers a panic. // Recover recovers a panic.

View File

@@ -97,6 +97,7 @@ type aDefer struct {
bitsPtr Expr // pointer to defer bits bitsPtr Expr // pointer to defer bits
rethPtr Expr // next block of Rethrow rethPtr Expr // next block of Rethrow
rundPtr Expr // next block of RunDefers rundPtr Expr // next block of RunDefers
argsPtr Expr // defer func and args
procBlk BasicBlock // deferProc block procBlk BasicBlock // deferProc block
panicBlk BasicBlock // panic block (runDefers and rethrow) panicBlk BasicBlock // panic block (runDefers and rethrow)
rundsNext []BasicBlock // next blocks of RunDefers rundsNext []BasicBlock // next blocks of RunDefers
@@ -133,11 +134,13 @@ const (
// 2: link *Defer // 2: link *Defer
// 3: reth voidptr: block address after Rethrow // 3: reth voidptr: block address after Rethrow
// 4: rund voidptr: block address after RunDefers // 4: rund voidptr: block address after RunDefers
// 5: args []unsafe.Pointer: defer func and args
deferSigjmpbuf = iota deferSigjmpbuf = iota
deferBits deferBits
deferLink deferLink
deferRethrow deferRethrow
deferRunDefers deferRunDefers
deferArgs
) )
func (b Builder) getDefer(kind DoAction) *aDefer { func (b Builder) getDefer(kind DoAction) *aDefer {
@@ -167,6 +170,8 @@ func (b Builder) getDefer(kind DoAction) *aDefer {
bitsPtr := b.FieldAddr(deferData, deferBits) bitsPtr := b.FieldAddr(deferData, deferBits)
rethPtr := b.FieldAddr(deferData, deferRethrow) rethPtr := b.FieldAddr(deferData, deferRethrow)
rundPtr := b.FieldAddr(deferData, deferRunDefers) 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()) czero := prog.IntVal(0, prog.CInt())
retval := b.Sigsetjmp(jb, czero) retval := b.Sigsetjmp(jb, czero)
@@ -184,6 +189,7 @@ func (b Builder) getDefer(kind DoAction) *aDefer {
bitsPtr: bitsPtr, bitsPtr: bitsPtr,
rethPtr: rethPtr, rethPtr: rethPtr,
rundPtr: rundPtr, rundPtr: rundPtr,
argsPtr: argsPtr,
procBlk: procBlk, procBlk: procBlk,
panicBlk: panicBlk, panicBlk: panicBlk,
rundsNext: []BasicBlock{rethrowBlk}, rundsNext: []BasicBlock{rethrowBlk},
@@ -228,20 +234,62 @@ func (b Builder) Defer(kind DoAction, fn Expr, args ...Expr) {
default: default:
panic("todo: DeferInLoop is not supported - " + b.Func.Name()) panic("todo: DeferInLoop is not supported - " + b.Func.Name())
} }
typ := b.saveDeferArgs(self, fn, args)
self.stmts = append(self.stmts, func(bits Expr) { self.stmts = append(self.stmts, func(bits Expr) {
switch kind { switch kind {
case DeferInCond: case DeferInCond:
zero := prog.Val(uintptr(0)) zero := prog.Val(uintptr(0))
has := b.BinOp(token.NEQ, b.BinOp(token.AND, bits, nextbit), zero) has := b.BinOp(token.NEQ, b.BinOp(token.AND, bits, nextbit), zero)
b.IfThen(has, func() { b.IfThen(has, func() {
b.Call(fn, args...) b.callDefer(self, typ, fn, len(args))
}) })
case DeferAlways: case DeferAlways:
b.Call(fn, args...) 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
}
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
}
prog := b.Prog
typ := prog.Struct(typs...)
voidPtr := prog.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)))
return typ
}
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 < nargs; i++ {
args[i] = b.getField(data, i+offset)
}
b.Call(fn, args...)
}
// RunDefers emits instructions to run deferred instructions. // RunDefers emits instructions to run deferred instructions.
func (b Builder) RunDefers() { func (b Builder) RunDefers() {
self := b.getDefer(DeferInCond) self := b.getDefer(DeferInCond)