llgo/ssa: defer support panic; IndirectJump/Switch
This commit is contained in:
@@ -27,6 +27,7 @@ import (
|
|||||||
|
|
||||||
// Defer presents defer statements in a function.
|
// Defer presents defer statements in a function.
|
||||||
type Defer struct {
|
type Defer struct {
|
||||||
|
Addr unsafe.Pointer
|
||||||
Bits uintptr
|
Bits uintptr
|
||||||
Link *Defer
|
Link *Defer
|
||||||
Rund int // index of RunDefers
|
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) {
|
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.Call(fn, jb, retval)
|
||||||
|
b.Unreachable()
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -78,10 +79,10 @@ const (
|
|||||||
deferKey = "__llgo_defer"
|
deferKey = "__llgo_defer"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p Function) deferInitBuilder() Builder {
|
func (p Function) deferInitBuilder() (b Builder, next BasicBlock) {
|
||||||
b := p.NewBuilder()
|
b = p.NewBuilder()
|
||||||
b.SetBlockEx(p.blks[0], BeforeLast, true)
|
next = b.setBlockMoveLast(p.blks[0])
|
||||||
return b
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type aDefer struct {
|
type aDefer struct {
|
||||||
@@ -91,8 +92,8 @@ type aDefer struct {
|
|||||||
bitsPtr Expr // pointer to defer bits
|
bitsPtr Expr // pointer to defer bits
|
||||||
rundPtr Expr // pointer to RunDefers index
|
rundPtr Expr // pointer to RunDefers index
|
||||||
procBlk BasicBlock // deferProc block
|
procBlk BasicBlock // deferProc block
|
||||||
stmts []func(bits Expr)
|
|
||||||
runsNext []BasicBlock // next blocks of RunDefers
|
runsNext []BasicBlock // next blocks of RunDefers
|
||||||
|
stmts []func(bits Expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Package) deferInit() {
|
func (p Package) deferInit() {
|
||||||
@@ -123,25 +124,59 @@ func (b Builder) deferKey() Expr {
|
|||||||
func (b Builder) getDefer(kind DoAction) *aDefer {
|
func (b Builder) getDefer(kind DoAction) *aDefer {
|
||||||
self := b.Func
|
self := b.Func
|
||||||
if self.defer_ == nil {
|
if self.defer_ == nil {
|
||||||
// 0: bits uintptr
|
// TODO(xsw): check if in pkg.init
|
||||||
// 1: link *Defer
|
// 0: addr sigjmpbuf
|
||||||
// 2: rund int
|
// 1: bits uintptr
|
||||||
|
// 2: link *Defer
|
||||||
|
// 3: rund int
|
||||||
|
const (
|
||||||
|
deferSigjmpbuf = iota
|
||||||
|
deferBits
|
||||||
|
deferLink
|
||||||
|
deferRund
|
||||||
|
)
|
||||||
|
var next, rundBlk BasicBlock
|
||||||
if kind != DeferAlways {
|
if kind != DeferAlways {
|
||||||
b = self.deferInitBuilder()
|
b, next = self.deferInitBuilder()
|
||||||
}
|
}
|
||||||
prog := b.Prog
|
prog := b.Prog
|
||||||
key := b.deferKey()
|
key := b.deferKey()
|
||||||
zero := prog.Val(uintptr(0))
|
zero := prog.Val(uintptr(0))
|
||||||
link := b.pthreadGetspecific(key)
|
link := Expr{b.pthreadGetspecific(key).impl, prog.DeferPtr()}
|
||||||
ptr := b.aggregateAlloca(prog.Defer(), zero.impl, link.impl)
|
jb := b.AllocaSigjmpBuf()
|
||||||
|
ptr := b.aggregateAlloca(prog.Defer(), jb.impl, zero.impl, link.impl)
|
||||||
deferData := Expr{ptr, prog.DeferPtr()}
|
deferData := Expr{ptr, prog.DeferPtr()}
|
||||||
b.pthreadSetspecific(key, deferData)
|
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{
|
self.defer_ = &aDefer{
|
||||||
key: key,
|
key: key,
|
||||||
data: deferData,
|
data: deferData,
|
||||||
bitsPtr: b.FieldAddr(deferData, 0),
|
bitsPtr: bitsPtr,
|
||||||
rundPtr: b.FieldAddr(deferData, 2),
|
rundPtr: rundPtr,
|
||||||
procBlk: self.MakeBlock(),
|
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_
|
return self.defer_
|
||||||
@@ -202,8 +237,7 @@ func (p Function) endDefer(b Builder) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
nexts := self.runsNext
|
nexts := self.runsNext
|
||||||
n := len(nexts)
|
if len(nexts) == 0 {
|
||||||
if n == 0 {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b.SetBlockEx(self.procBlk, AtEnd, true)
|
b.SetBlockEx(self.procBlk, AtEnd, true)
|
||||||
@@ -216,12 +250,8 @@ func (p Function) endDefer(b Builder) {
|
|||||||
link := b.getField(b.Load(self.data), 2)
|
link := b.getField(b.Load(self.data), 2)
|
||||||
b.pthreadSetspecific(self.key, link)
|
b.pthreadSetspecific(self.key, link)
|
||||||
|
|
||||||
prog := b.Prog
|
// rund := b.Load(self.rundPtr)
|
||||||
rund := b.Load(self.rundPtr)
|
b.IndirectJump(self.rundPtr, nexts)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -200,7 +200,8 @@ func (p Program) tyGetAttrString() *types.Signature {
|
|||||||
func (p Package) PyInit() bool {
|
func (p Package) PyInit() bool {
|
||||||
if fn := p.FuncOf("main"); fn != nil {
|
if fn := p.FuncOf("main"); fn != nil {
|
||||||
b := fn.NewBuilder()
|
b := fn.NewBuilder()
|
||||||
b.SetBlockEx(fn.Block(0), AtStart, false).callPyInit()
|
b.SetBlockEx(fn.Block(0), AtStart, false)
|
||||||
|
b.callPyInit()
|
||||||
b.Dispose()
|
b.Dispose()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,6 +80,21 @@ func (b Builder) SetBlock(blk BasicBlock) Builder {
|
|||||||
return b
|
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
|
type InsertPoint int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -90,7 +105,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// SetBlockEx sets blk as current basic block and pos as its insert point.
|
// 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 {
|
if b.Func != blk.fn {
|
||||||
panic("mismatched function")
|
panic("mismatched function")
|
||||||
}
|
}
|
||||||
@@ -109,7 +124,6 @@ func (b Builder) SetBlockEx(blk BasicBlock, pos InsertPoint, setBlk bool) Builde
|
|||||||
if setBlk {
|
if setBlk {
|
||||||
b.blk = blk
|
b.blk = blk
|
||||||
}
|
}
|
||||||
return b
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func instrAfterInit(blk llvm.BasicBlock) llvm.Value {
|
func instrAfterInit(blk llvm.BasicBlock) llvm.Value {
|
||||||
@@ -188,6 +202,17 @@ func (b Builder) Jump(jmpb BasicBlock) {
|
|||||||
b.impl.CreateBr(jmpb.first)
|
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.
|
// If emits an if instruction.
|
||||||
func (b Builder) If(cond Expr, thenb, elseb BasicBlock) {
|
func (b Builder) If(cond Expr, thenb, elseb BasicBlock) {
|
||||||
if b.Func != thenb.fn || b.Func != elseb.fn {
|
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
|
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.
|
// Phi represents a phi node.
|
||||||
|
|||||||
Reference in New Issue
Block a user