llgo/ssa: defer support panic; IndirectJump/Switch
This commit is contained in:
@@ -27,6 +27,7 @@ import (
|
||||
|
||||
// Defer presents defer statements in a function.
|
||||
type Defer struct {
|
||||
Addr unsafe.Pointer
|
||||
Bits uintptr
|
||||
Link *Defer
|
||||
Rund int // index of RunDefers
|
||||
|
||||
76
ssa/eh.go
76
ssa/eh.go
@@ -68,8 +68,9 @@ func (b Builder) Sigsetjmp(jb, savemask Expr) Expr {
|
||||
}
|
||||
|
||||
func (b Builder) Siglongjmp(jb, retval Expr) {
|
||||
fn := b.Pkg.cFunc("siglongjmp", b.Prog.tySiglongjmp())
|
||||
fn := b.Pkg.cFunc("siglongjmp", b.Prog.tySiglongjmp()) // TODO(xsw): mark as noreturn
|
||||
b.Call(fn, jb, retval)
|
||||
b.Unreachable()
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -78,10 +79,10 @@ const (
|
||||
deferKey = "__llgo_defer"
|
||||
)
|
||||
|
||||
func (p Function) deferInitBuilder() Builder {
|
||||
b := p.NewBuilder()
|
||||
b.SetBlockEx(p.blks[0], BeforeLast, true)
|
||||
return b
|
||||
func (p Function) deferInitBuilder() (b Builder, next BasicBlock) {
|
||||
b = p.NewBuilder()
|
||||
next = b.setBlockMoveLast(p.blks[0])
|
||||
return
|
||||
}
|
||||
|
||||
type aDefer struct {
|
||||
@@ -91,8 +92,8 @@ type aDefer struct {
|
||||
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
|
||||
stmts []func(bits Expr)
|
||||
}
|
||||
|
||||
func (p Package) deferInit() {
|
||||
@@ -123,25 +124,59 @@ func (b Builder) deferKey() Expr {
|
||||
func (b Builder) getDefer(kind DoAction) *aDefer {
|
||||
self := b.Func
|
||||
if self.defer_ == nil {
|
||||
// 0: bits uintptr
|
||||
// 1: link *Defer
|
||||
// 2: rund int
|
||||
// TODO(xsw): check if in pkg.init
|
||||
// 0: addr sigjmpbuf
|
||||
// 1: bits uintptr
|
||||
// 2: link *Defer
|
||||
// 3: rund int
|
||||
const (
|
||||
deferSigjmpbuf = iota
|
||||
deferBits
|
||||
deferLink
|
||||
deferRund
|
||||
)
|
||||
var next, rundBlk BasicBlock
|
||||
if kind != DeferAlways {
|
||||
b = self.deferInitBuilder()
|
||||
b, next = self.deferInitBuilder()
|
||||
}
|
||||
prog := b.Prog
|
||||
key := b.deferKey()
|
||||
zero := prog.Val(uintptr(0))
|
||||
link := b.pthreadGetspecific(key)
|
||||
ptr := b.aggregateAlloca(prog.Defer(), zero.impl, link.impl)
|
||||
link := Expr{b.pthreadGetspecific(key).impl, prog.DeferPtr()}
|
||||
jb := b.AllocaSigjmpBuf()
|
||||
ptr := b.aggregateAlloca(prog.Defer(), jb.impl, zero.impl, link.impl)
|
||||
deferData := Expr{ptr, prog.DeferPtr()}
|
||||
b.pthreadSetspecific(key, deferData)
|
||||
blks := self.MakeBlocks(2)
|
||||
procBlk, throwBlk := blks[0], blks[1]
|
||||
bitsPtr := b.FieldAddr(deferData, deferBits)
|
||||
rundPtr := b.FieldAddr(deferData, deferRund)
|
||||
self.defer_ = &aDefer{
|
||||
key: key,
|
||||
data: deferData,
|
||||
bitsPtr: b.FieldAddr(deferData, 0),
|
||||
rundPtr: b.FieldAddr(deferData, 2),
|
||||
procBlk: self.MakeBlock(),
|
||||
bitsPtr: bitsPtr,
|
||||
rundPtr: rundPtr,
|
||||
procBlk: procBlk,
|
||||
runsNext: []BasicBlock{throwBlk},
|
||||
}
|
||||
czero := prog.IntVal(0, prog.CInt())
|
||||
retval := b.Sigsetjmp(jb, czero)
|
||||
if kind != DeferAlways {
|
||||
rundBlk = self.MakeBlock()
|
||||
} else {
|
||||
blks = self.MakeBlocks(2)
|
||||
next, rundBlk = blks[0], blks[1]
|
||||
}
|
||||
b.If(b.BinOp(token.EQL, retval, czero), next, rundBlk)
|
||||
b.SetBlockEx(rundBlk, AtEnd, false) // exec runDefers and throw
|
||||
b.Store(rundPtr, prog.Val(0))
|
||||
b.Jump(procBlk)
|
||||
b.SetBlockEx(throwBlk, AtEnd, false) // throw
|
||||
linkJBPtr := b.FieldAddr(link, deferSigjmpbuf)
|
||||
b.Siglongjmp(b.Load(linkJBPtr), prog.IntVal(1, prog.CInt()))
|
||||
if kind == DeferAlways {
|
||||
b.SetBlockEx(next, AtEnd, false)
|
||||
b.blk.last = next.last
|
||||
}
|
||||
}
|
||||
return self.defer_
|
||||
@@ -202,8 +237,7 @@ func (p Function) endDefer(b Builder) {
|
||||
return
|
||||
}
|
||||
nexts := self.runsNext
|
||||
n := len(nexts)
|
||||
if n == 0 {
|
||||
if len(nexts) == 0 {
|
||||
return
|
||||
}
|
||||
b.SetBlockEx(self.procBlk, AtEnd, true)
|
||||
@@ -216,12 +250,8 @@ func (p Function) endDefer(b Builder) {
|
||||
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)
|
||||
}
|
||||
// rund := b.Load(self.rundPtr)
|
||||
b.IndirectJump(self.rundPtr, nexts)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -200,7 +200,8 @@ func (p Program) tyGetAttrString() *types.Signature {
|
||||
func (p Package) PyInit() bool {
|
||||
if fn := p.FuncOf("main"); fn != nil {
|
||||
b := fn.NewBuilder()
|
||||
b.SetBlockEx(fn.Block(0), AtStart, false).callPyInit()
|
||||
b.SetBlockEx(fn.Block(0), AtStart, false)
|
||||
b.callPyInit()
|
||||
b.Dispose()
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -80,6 +80,21 @@ func (b Builder) SetBlock(blk BasicBlock) Builder {
|
||||
return b
|
||||
}
|
||||
|
||||
func (b Builder) setBlockMoveLast(blk BasicBlock) (next BasicBlock) {
|
||||
blkLast := blk.last
|
||||
last := blkLast.LastInstruction()
|
||||
last.RemoveFromParentAsInstruction()
|
||||
|
||||
impl := b.impl
|
||||
|
||||
next = b.Func.MakeBlock()
|
||||
impl.SetInsertPointAtEnd(next.last)
|
||||
impl.Insert(last)
|
||||
|
||||
impl.SetInsertPointAtEnd(blkLast)
|
||||
return
|
||||
}
|
||||
|
||||
type InsertPoint int
|
||||
|
||||
const (
|
||||
@@ -90,7 +105,7 @@ const (
|
||||
)
|
||||
|
||||
// SetBlockEx sets blk as current basic block and pos as its insert point.
|
||||
func (b Builder) SetBlockEx(blk BasicBlock, pos InsertPoint, setBlk bool) Builder {
|
||||
func (b Builder) SetBlockEx(blk BasicBlock, pos InsertPoint, setBlk bool) {
|
||||
if b.Func != blk.fn {
|
||||
panic("mismatched function")
|
||||
}
|
||||
@@ -109,7 +124,6 @@ func (b Builder) SetBlockEx(blk BasicBlock, pos InsertPoint, setBlk bool) Builde
|
||||
if setBlk {
|
||||
b.blk = blk
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func instrAfterInit(blk llvm.BasicBlock) llvm.Value {
|
||||
@@ -188,6 +202,17 @@ func (b Builder) Jump(jmpb BasicBlock) {
|
||||
b.impl.CreateBr(jmpb.first)
|
||||
}
|
||||
|
||||
// IndirectJump emits an indirect jump instruction.
|
||||
func (b Builder) IndirectJump(addr Expr, dests []BasicBlock) {
|
||||
if debugInstr {
|
||||
log.Printf("IndirectJump %v\n", addr.impl)
|
||||
}
|
||||
ibr := b.impl.CreateIndirectBr(addr.impl, len(dests))
|
||||
for _, dest := range dests {
|
||||
ibr.AddDest(dest.first)
|
||||
}
|
||||
}
|
||||
|
||||
// If emits an if instruction.
|
||||
func (b Builder) If(cond Expr, thenb, elseb BasicBlock) {
|
||||
if b.Func != thenb.fn || b.Func != elseb.fn {
|
||||
@@ -210,6 +235,46 @@ func (b Builder) IfThen(cond Expr, then func()) {
|
||||
b.blk.last = blks[1].last
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/*
|
||||
type caseStmt struct {
|
||||
v llvm.Value
|
||||
blk llvm.BasicBlock
|
||||
}
|
||||
|
||||
type aSwitch struct {
|
||||
v llvm.Value
|
||||
def llvm.BasicBlock
|
||||
cases []caseStmt
|
||||
}
|
||||
|
||||
// Switch represents a switch statement.
|
||||
type Switch = *aSwitch
|
||||
|
||||
// Case emits a case instruction.
|
||||
func (p Switch) Case(v Expr, blk BasicBlock) {
|
||||
if debugInstr {
|
||||
log.Printf("Case %v, _llgo_%v\n", v.impl, blk.idx)
|
||||
}
|
||||
p.cases = append(p.cases, caseStmt{v.impl, blk.first})
|
||||
}
|
||||
|
||||
// End ends a switch statement.
|
||||
func (p Switch) End(b Builder) {
|
||||
sw := b.impl.CreateSwitch(p.v, p.def, len(p.cases))
|
||||
for _, c := range p.cases {
|
||||
sw.AddCase(c.v, c.blk)
|
||||
}
|
||||
}
|
||||
|
||||
// Switch starts a switch statement.
|
||||
func (b Builder) Switch(v Expr, defb BasicBlock) Switch {
|
||||
if debugInstr {
|
||||
log.Printf("Switch %v, _llgo_%v\n", v.impl, defb.idx)
|
||||
}
|
||||
return &aSwitch{v.impl, defb.first, nil}
|
||||
}
|
||||
*/
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Phi represents a phi node.
|
||||
|
||||
Reference in New Issue
Block a user