llgo/ssa: DeferAlways/DeferInCond/DeferInLoop
This commit is contained in:
@@ -12,7 +12,6 @@ func main() {
|
|||||||
defer println(s)
|
defer println(s)
|
||||||
} else {
|
} else {
|
||||||
defer println("world")
|
defer println("world")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
defer println("bye")
|
defer println("bye")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,8 +148,11 @@ type context struct {
|
|||||||
loaded map[*types.Package]*pkgInfo // loaded packages
|
loaded map[*types.Package]*pkgInfo // loaded packages
|
||||||
bvals map[ssa.Value]llssa.Expr // block values
|
bvals map[ssa.Value]llssa.Expr // block values
|
||||||
vargs map[*ssa.Alloc][]llssa.Expr // varargs
|
vargs map[*ssa.Alloc][]llssa.Expr // varargs
|
||||||
inits []func()
|
|
||||||
phis []func()
|
blkInfos []blockInfo
|
||||||
|
|
||||||
|
inits []func()
|
||||||
|
phis []func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) inMain(instr ssa.Instruction) bool {
|
func (p *context) inMain(instr ssa.Instruction) bool {
|
||||||
@@ -277,10 +280,16 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
|
|||||||
for i, block := range f.Blocks {
|
for i, block := range f.Blocks {
|
||||||
off[i] = p.compilePhis(b, block)
|
off[i] = p.compilePhis(b, block)
|
||||||
}
|
}
|
||||||
for i, block := range f.Blocks {
|
p.blkInfos = blockInfos(f.Blocks)
|
||||||
|
i := 0
|
||||||
|
for {
|
||||||
|
block := f.Blocks[i]
|
||||||
doMainInit := (i == 0 && name == "main")
|
doMainInit := (i == 0 && name == "main")
|
||||||
doModInit := (i == 1 && f.Name() == "init" && sig.Recv() == nil)
|
doModInit := (i == 1 && f.Name() == "init" && sig.Recv() == nil)
|
||||||
p.compileBlock(b, block, off[i], doMainInit, doModInit)
|
p.compileBlock(b, block, off[i], doMainInit, doModInit)
|
||||||
|
if i = p.blkInfos[i].next; i < 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for _, phi := range p.phis {
|
for _, phi := range p.phis {
|
||||||
phi()
|
phi()
|
||||||
@@ -291,6 +300,24 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
|
|||||||
return fn, nil, goFunc
|
return fn, nil, goFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type blockInfo struct {
|
||||||
|
kind llssa.DoAction
|
||||||
|
next int
|
||||||
|
}
|
||||||
|
|
||||||
|
func blockInfos(blks []*ssa.BasicBlock) []blockInfo {
|
||||||
|
n := len(blks)
|
||||||
|
infos := make([]blockInfo, n)
|
||||||
|
for i := range blks {
|
||||||
|
next := i + 1
|
||||||
|
if next >= n {
|
||||||
|
next = -1
|
||||||
|
}
|
||||||
|
infos[i] = blockInfo{kind: llssa.DeferInCond, next: next}
|
||||||
|
}
|
||||||
|
return infos
|
||||||
|
}
|
||||||
|
|
||||||
// funcOf returns a function by name and set ftype = goFunc, cFunc, etc.
|
// funcOf returns a function by name and set ftype = goFunc, cFunc, etc.
|
||||||
// or returns nil and set ftype = llgoCstr, llgoAlloca, llgoUnreachable, etc.
|
// or returns nil and set ftype = llgoCstr, llgoAlloca, llgoUnreachable, etc.
|
||||||
func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyObjRef, ftype int) {
|
func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyObjRef, ftype int) {
|
||||||
@@ -516,7 +543,7 @@ func (p *context) compilePhis(b llssa.Builder, block *ssa.BasicBlock) int {
|
|||||||
for n < ninstr && isPhi(block.Instrs[n]) {
|
for n < ninstr && isPhi(block.Instrs[n]) {
|
||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
rets := make([]llssa.Expr, n)
|
rets := make([]llssa.Expr, n) // TODO(xsw): check to remove this
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
iv := block.Instrs[i].(*ssa.Phi)
|
iv := block.Instrs[i].(*ssa.Phi)
|
||||||
rets[i] = p.compilePhi(b, iv)
|
rets[i] = p.compilePhi(b, iv)
|
||||||
@@ -798,7 +825,7 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
|
|||||||
val := p.compileValue(b, v.Value)
|
val := p.compileValue(b, v.Value)
|
||||||
b.MapUpdate(m, key, val)
|
b.MapUpdate(m, key, val)
|
||||||
case *ssa.Defer:
|
case *ssa.Defer:
|
||||||
p.call(b, llssa.Defer, &v.Call)
|
p.call(b, p.blkInfos[v.Block().Index].kind, &v.Call)
|
||||||
case *ssa.Go:
|
case *ssa.Go:
|
||||||
p.call(b, llssa.Go, &v.Call)
|
p.call(b, llssa.Go, &v.Call)
|
||||||
case *ssa.RunDefers:
|
case *ssa.RunDefers:
|
||||||
|
|||||||
@@ -803,8 +803,10 @@ type DoAction int
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
Call DoAction = iota
|
Call DoAction = iota
|
||||||
Defer
|
|
||||||
Go
|
Go
|
||||||
|
DeferAlways // defer statement executes always
|
||||||
|
DeferInCond // defer statement executes in a conditional block
|
||||||
|
DeferInLoop // defer statement executes in a loop block
|
||||||
)
|
)
|
||||||
|
|
||||||
// Do call a function with an action.
|
// Do call a function with an action.
|
||||||
@@ -812,10 +814,10 @@ func (b Builder) Do(da DoAction, fn Expr, args ...Expr) (ret Expr) {
|
|||||||
switch da {
|
switch da {
|
||||||
case Call:
|
case Call:
|
||||||
return b.Call(fn, args...)
|
return b.Call(fn, args...)
|
||||||
case Defer:
|
|
||||||
b.Defer(fn, args...)
|
|
||||||
case Go:
|
case Go:
|
||||||
b.Go(fn, args...)
|
b.Go(fn, args...)
|
||||||
|
default:
|
||||||
|
b.Defer(da, fn, args...)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,24 +216,37 @@ func (b Builder) getDefer() *aDefer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Defer emits a defer instruction.
|
// Defer emits a defer instruction.
|
||||||
func (b Builder) Defer(fn Expr, args ...Expr) {
|
func (b Builder) Defer(kind DoAction, fn Expr, args ...Expr) {
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
logCall("Defer", fn, args)
|
logCall("Defer", fn, args)
|
||||||
}
|
}
|
||||||
prog := b.Prog
|
var prog Program
|
||||||
self := b.getDefer()
|
var nextbit Expr
|
||||||
next := self.nextBit
|
var self = b.getDefer()
|
||||||
self.nextBit++
|
switch kind {
|
||||||
bits := b.Load(self.bitsPtr)
|
case DeferInCond:
|
||||||
nextbit := prog.Val(uintptr(1 << next))
|
prog = b.Prog
|
||||||
b.Store(self.bitsPtr, b.BinOp(token.OR, bits, nextbit))
|
next := self.nextBit
|
||||||
|
self.nextBit++
|
||||||
|
bits := b.Load(self.bitsPtr)
|
||||||
|
nextbit = prog.Val(uintptr(1 << next))
|
||||||
|
b.Store(self.bitsPtr, b.BinOp(token.OR, bits, nextbit))
|
||||||
|
case DeferAlways:
|
||||||
|
// nothing to do
|
||||||
|
default:
|
||||||
|
panic("todo: DeferInLoop is not supported")
|
||||||
|
}
|
||||||
self.stmts = append(self.stmts, func(bits Expr) {
|
self.stmts = append(self.stmts, func(bits Expr) {
|
||||||
zero := prog.Val(uintptr(0))
|
switch kind {
|
||||||
has := b.BinOp(token.NEQ, b.BinOp(token.AND, bits, nextbit), zero)
|
case DeferInCond:
|
||||||
b.IfThen(has, func() {
|
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...)
|
||||||
|
})
|
||||||
|
case DeferAlways:
|
||||||
b.Call(fn, args...)
|
b.Call(fn, args...)
|
||||||
})
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user