diff --git a/c/c.go b/c/c.go index cfa9a77c..9726879f 100644 --- a/c/c.go +++ b/c/c.go @@ -57,9 +57,6 @@ func Alloca(size uintptr) Pointer //go:linkname AllocaCStr llgo.allocaCStr func AllocaCStr(s string) *Char -//go:linkname Unreachable llgo.unreachable -func Unreachable() - //go:linkname Malloc C.malloc func Malloc(size uintptr) Pointer @@ -84,6 +81,20 @@ func Remove(path *Char) Int // ----------------------------------------------------------------------------- +//go:linkname AllocaSigjmpBuf llgo.sigjmpbuf +func AllocaSigjmpBuf() Pointer + +//go:linkname Sigsetjmp llgo.sigsetjmp +func Sigsetjmp(jb Pointer, savemask Int) Int + +//go:linkname Siglongjmp llgo.siglongjmp +func Siglongjmp(jb Pointer, retval Int) + +//go:linkname Unreachable llgo.unreachable +func Unreachable() + +// ----------------------------------------------------------------------------- + //go:linkname Exit C.exit func Exit(Int) diff --git a/cl/_testlibc/setjmp/in.go b/cl/_testlibc/setjmp/in.go new file mode 100644 index 00000000..90367ce8 --- /dev/null +++ b/cl/_testlibc/setjmp/in.go @@ -0,0 +1,17 @@ +package main + +import ( + "github.com/goplus/llgo/c" +) + +func main() { + jb := c.AllocaSigjmpBuf() + switch ret := c.Sigsetjmp(jb, 0); ret { + case 0: + cstr := c.Str("?Hello, setjmp!\n") + c.Fprintf(c.Stderr, c.Advance(cstr, 1)) + c.Siglongjmp(jb, 1) + default: + println("exception:", ret) + } +} diff --git a/cl/_testlibc/setjmp/out.ll b/cl/_testlibc/setjmp/out.ll new file mode 100644 index 00000000..937a1b67 --- /dev/null +++ b/cl/_testlibc/setjmp/out.ll @@ -0,0 +1,73 @@ +; ModuleID = 'main' +source_filename = "main" + +%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 } + +@"main.init$guard" = global ptr null +@__llgo_argc = global ptr null +@__llgo_argv = global ptr null +@0 = private unnamed_addr constant [17 x i8] c"?Hello, setjmp!\0A\00", align 1 +@__stderrp = external global ptr +@1 = private unnamed_addr constant [11 x i8] c"exception:\00", align 1 + +define void @main.init() { +_llgo_0: + %0 = load i1, ptr @"main.init$guard", align 1 + br i1 %0, label %_llgo_2, label %_llgo_1 + +_llgo_1: ; preds = %_llgo_0 + store i1 true, ptr @"main.init$guard", align 1 + br label %_llgo_2 + +_llgo_2: ; preds = %_llgo_1, %_llgo_0 + ret void +} + +define i32 @main(i32 %0, ptr %1) { +_llgo_0: + store i32 %0, ptr @__llgo_argc, align 4 + store ptr %1, ptr @__llgo_argv, align 8 + call void @"github.com/goplus/llgo/internal/runtime.init"() + call void @main.init() + %2 = alloca i8, i64 196, align 1 + %3 = call i32 @sigsetjmp(ptr %2, i32 0) + %4 = icmp eq i32 %3, 0 + br i1 %4, label %_llgo_2, label %_llgo_3 + +_llgo_1: ; preds = %_llgo_3, %_llgo_2 + ret i32 0 + +_llgo_2: ; preds = %_llgo_0 + %5 = load ptr, ptr @__stderrp, align 8 + %6 = call i32 (ptr, ptr, ...) @fprintf(ptr %5, ptr getelementptr (i8, ptr @0, i64 1)) + call void @siglongjmp(ptr %2, i32 1) + br label %_llgo_1 + +_llgo_3: ; preds = %_llgo_0 + %7 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %8 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %7, i32 0, i32 0 + store ptr @1, ptr %8, align 8 + %9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %7, i32 0, i32 1 + store i64 10, ptr %9, align 4 + %10 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %7, align 8 + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %10) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32) + %11 = sext i32 %3 to i64 + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %11) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + br label %_llgo_1 +} + +declare void @"github.com/goplus/llgo/internal/runtime.init"() + +declare i32 @sigsetjmp(ptr, i32) + +declare i32 @fprintf(ptr, ptr, ...) + +declare void @siglongjmp(ptr, i32) + +declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String") + +declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8) + +declare void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64) diff --git a/cl/compile.go b/cl/compile.go index 469cd296..4239cd76 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -332,6 +332,12 @@ func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyObj ftype = llgoStringData case "pyList": ftype = llgoPyList + case "sigjmpbuf": + ftype = llgoSigjmpbuf + case "sigsetjmp": + ftype = llgoSigsetjmp + case "siglongjmp": + ftype = llgoSiglongjmp case "unreachable": ftype = llgoUnreachable default: @@ -512,6 +518,25 @@ func (p *context) stringData(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) panic("stringData(s string): invalid arguments") } +func (p *context) sigsetjmp(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { + if len(args) == 2 { + jb := p.compileValue(b, args[0]) + savemask := p.compileValue(b, args[1]) + return b.Sigsetjmp(jb, savemask) + } + panic("sigsetjmp(jb c.SigjmpBuf, savemask c.Int): invalid arguments") +} + +func (p *context) siglongjmp(b llssa.Builder, args []ssa.Value) { + if len(args) == 2 { + jb := p.compileValue(b, args[0]) + retval := p.compileValue(b, args[1]) + b.Siglongjmp(jb, retval) + return + } + panic("siglongjmp(jb c.SigjmpBuf, retval c.Int): invalid arguments") +} + func isPhi(i ssa.Instruction) bool { _, ok := i.(*ssa.Phi) return ok @@ -611,6 +636,12 @@ func (p *context) call(b llssa.Builder, act llssa.DoAction, call *ssa.CallCommon ret = p.allocaCStr(b, args) case llgoStringData: ret = p.stringData(b, args) + case llgoSigsetjmp: + ret = p.sigsetjmp(b, args) + case llgoSiglongjmp: + p.siglongjmp(b, args) + case llgoSigjmpbuf: // func sigjmpbuf() + ret = b.AllocaSigjmpBuf() case llgoUnreachable: // func unreachable() b.Unreachable() default: diff --git a/cl/import.go b/cl/import.go index 35ef5317..7cd23813 100644 --- a/cl/import.go +++ b/cl/import.go @@ -309,6 +309,9 @@ const ( llgoIndex = llgoInstrBase + 5 llgoStringData = llgoInstrBase + 6 llgoPyList = llgoInstrBase + 7 + llgoSigjmpbuf = llgoInstrBase + 10 + llgoSigsetjmp = llgoInstrBase + 11 + llgoSiglongjmp = llgoInstrBase + 12 ) func (p *context) funcName(fn *ssa.Function, ignore bool) (*types.Package, string, int) { diff --git a/ssa/eh.go b/ssa/eh.go index 47b69e90..f6beca0c 100644 --- a/ssa/eh.go +++ b/ssa/eh.go @@ -16,15 +16,64 @@ package ssa +// #include +import "C" + import ( "go/token" + "go/types" "log" + "unsafe" "github.com/goplus/llvm" ) // ----------------------------------------------------------------------------- +type sigjmpbuf = C.sigjmp_buf + +// func(env unsafe.Pointer, savemask c.Int) c.Int +func (p Program) tySigsetjmp() *types.Signature { + if p.sigsetjmpTy == nil { + paramPtr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) + paramCInt := types.NewParam(token.NoPos, nil, "", p.CInt().raw.Type) + params := types.NewTuple(paramPtr, paramCInt) + results := types.NewTuple(paramCInt) + p.sigsetjmpTy = types.NewSignatureType(nil, nil, nil, params, results, false) + } + return p.sigsetjmpTy +} + +// func(env unsafe.Pointer, retval c.Int) +func (p Program) tySiglongjmp() *types.Signature { + if p.sigljmpTy == nil { + paramPtr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) + paramCInt := types.NewParam(token.NoPos, nil, "", p.CInt().raw.Type) + params := types.NewTuple(paramPtr, paramCInt) + p.sigljmpTy = types.NewSignatureType(nil, nil, nil, params, nil, false) + } + return p.sigljmpTy +} + +func (b Builder) AllocaSigjmpBuf() Expr { + prog := b.Prog + n := unsafe.Sizeof(sigjmpbuf{}) + size := prog.IntVal(uint64(n), prog.Uintptr()) + return b.Alloca(size) +} + +func (b Builder) Sigsetjmp(jb, savemask Expr) Expr { + fn := b.Pkg.cFunc("sigsetjmp", b.Prog.tySigsetjmp()) + return b.Call(fn, jb, savemask) +} + +func (b Builder) Siglongjmp(jb, retval Expr) { + fn := b.Pkg.cFunc("siglongjmp", b.Prog.tySiglongjmp()) + b.Call(fn, jb, retval) +} + +// ----------------------------------------------------------------------------- + const ( deferKey = "__llgo_defer" ) diff --git a/ssa/package.go b/ssa/package.go index 762c3843..24171164 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -179,7 +179,8 @@ type aProgram struct { setSpecTy *types.Signature routineTy *types.Signature destructTy *types.Signature - //deferFnTy *types.Signature + sigsetjmpTy *types.Signature + sigljmpTy *types.Signature paramObjPtr_ *types.Var