/* * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ssa import ( "fmt" "go/constant" "go/token" "go/types" ) // declare void @llvm.coro.destroy(ptr ) // declare void @llvm.coro.resume(ptr ) // declare i1 @llvm.coro.done(ptr ) // declare ptr @llvm.coro.promise(ptr , i32 , i1 ) // declare i32 @llvm.coro.size.i32() // declare i64 @llvm.coro.size.i64() // declare i32 @llvm.coro.align.i32() // declare i64 @llvm.coro.align.i64() // declare ptr @llvm.coro.begin(token , ptr ) // declare ptr @llvm.coro.free(token %id, ptr ) // declare i1 @llvm.coro.alloc(token ) // declare ptr @llvm.coro.noop() // declare ptr @llvm.coro.frame() // declare token @llvm.coro.id(i32 , ptr , ptr , ptr ) // declare token @llvm.coro.id.async(i32 , i32 , ptr , ptr ) // declare token @llvm.coro.id.retcon(i32 , i32 , ptr , ptr , ptr , ptr ) // declare token @llvm.coro.id.retcon.once(i32 , i32 , ptr , ptr , ptr , ptr ) // declare i1 @llvm.coro.end(ptr , i1 , token ) // declare token @llvm.coro.end.results(...) // declare i1 @llvm.coro.end.async(ptr , i1 , ...) // declare i8 @llvm.coro.suspend(token , i1 ) // declare token @llvm.coro.save(ptr ) // declare {ptr, ptr, ptr} @llvm.coro.suspend.async(ptr , ptr , ... ... ) // declare ptr @llvm.coro.prepare.async(ptr ) // declare i1 @llvm.coro.suspend.retcon(...) // declare void @await_suspend_function(ptr %awaiter, ptr %hdl) // declare void @llvm.coro.await.suspend.void(ptr , ptr , ptr ) // declare i1 @llvm.coro.await.suspend.bool(ptr , ptr , ptr ) // declare void @llvm.coro.await.suspend.handle(ptr , ptr , ptr ) // ----------------------------------------------------------------------------- // declare void @llvm.coro.destroy(ptr ) func (p Program) tyCoDestroy() *types.Signature { if p.coDestroyTy == nil { i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) params := types.NewTuple(i8Ptr) p.coDestroyTy = types.NewSignatureType(nil, nil, nil, params, nil, false) } return p.coDestroyTy } // declare void @llvm.coro.resume(ptr ) func (p Program) tyCoResume() *types.Signature { if p.coResumeTy == nil { i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) params := types.NewTuple(i8Ptr) p.coResumeTy = types.NewSignatureType(nil, nil, nil, params, nil, false) } return p.coResumeTy } // declare i1 @llvm.coro.done(ptr ) func (p Program) tyCoDone() *types.Signature { if p.coDoneTy == nil { i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) params := types.NewTuple(i8Ptr) results := types.NewTuple(types.NewParam(token.NoPos, nil, "", p.Bool().raw.Type)) p.coDoneTy = types.NewSignatureType(nil, nil, nil, params, results, false) } return p.coDoneTy } // declare ptr @llvm.coro.promise(ptr , i32 , i1 ) func (p Program) tyCoPromise() *types.Signature { if p.coPromiseTy == nil { i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) i32 := types.NewParam(token.NoPos, nil, "", p.Int32().raw.Type) boolParam := types.NewParam(token.NoPos, nil, "", p.Bool().raw.Type) params := types.NewTuple(i8Ptr, i32, boolParam) results := types.NewTuple(i8Ptr) p.coPromiseTy = types.NewSignatureType(nil, nil, nil, params, results, false) } return p.coPromiseTy } // declare i32 @llvm.coro.size.i32() func (p Program) tyCoSizeI32() *types.Signature { if p.coSizeI32Ty == nil { results := types.NewTuple(types.NewParam(token.NoPos, nil, "", p.Int32().raw.Type)) p.coSizeI32Ty = types.NewSignatureType(nil, nil, nil, nil, results, false) } return p.coSizeI32Ty } // declare i64 @llvm.coro.size.i64() func (p Program) tyCoSizeI64() *types.Signature { if p.coSizeI64Ty == nil { results := types.NewTuple(types.NewParam(token.NoPos, nil, "", p.Int64().raw.Type)) p.coSizeI64Ty = types.NewSignatureType(nil, nil, nil, nil, results, false) } return p.coSizeI64Ty } // declare i32 @llvm.coro.align.i32() func (p Program) tyCoAlignI32() *types.Signature { if p.coAlignI32Ty == nil { results := types.NewTuple(types.NewParam(token.NoPos, nil, "", p.Int32().raw.Type)) p.coAlignI32Ty = types.NewSignatureType(nil, nil, nil, nil, results, false) } return p.coAlignI32Ty } // declare i64 @llvm.coro.align.i64() func (p Program) tyCoAlignI64() *types.Signature { if p.coAlignI64Ty == nil { results := types.NewTuple(types.NewParam(token.NoPos, nil, "", p.Int64().raw.Type)) p.coAlignI64Ty = types.NewSignatureType(nil, nil, nil, nil, results, false) } return p.coAlignI64Ty } // declare ptr @llvm.coro.begin(token , ptr ) func (p Program) tyCoBegin() *types.Signature { if p.coBeginTy == nil { tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type) i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) params := types.NewTuple(tokenParam, i8Ptr) results := types.NewTuple(i8Ptr) p.coBeginTy = types.NewSignatureType(nil, nil, nil, params, results, false) } return p.coBeginTy } // declare ptr @llvm.coro.free(token %id, ptr ) func (p Program) tyCoFree() *types.Signature { if p.coFreeTy == nil { tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type) i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) params := types.NewTuple(tokenParam, i8Ptr) results := types.NewTuple(i8Ptr) p.coFreeTy = types.NewSignatureType(nil, nil, nil, params, results, false) } return p.coFreeTy } // declare i1 @llvm.coro.alloc(token ) func (p Program) tyCoAlloc() *types.Signature { if p.coAllocTy == nil { tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type) params := types.NewTuple(tokenParam) boolParam := types.NewParam(token.NoPos, nil, "", p.Bool().raw.Type) results := types.NewTuple(boolParam) p.coAllocTy = types.NewSignatureType(nil, nil, nil, params, results, false) } return p.coAllocTy } // declare ptr @llvm.coro.noop() func (p Program) tyCoNoop() *types.Signature { if p.coNoopTy == nil { results := types.NewTuple(types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)) p.coNoopTy = types.NewSignatureType(nil, nil, nil, nil, results, false) } return p.coNoopTy } // declare ptr @llvm.coro.frame() func (p Program) tyCoFrame() *types.Signature { if p.coFrameTy == nil { results := types.NewTuple(types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)) p.coFrameTy = types.NewSignatureType(nil, nil, nil, nil, results, false) } return p.coFrameTy } // declare token @llvm.coro.id(i32 , ptr , ptr , ptr ) func (p Program) tyCoID() *types.Signature { if p.coIDTy == nil { i32 := types.NewParam(token.NoPos, nil, "", p.Int32().raw.Type) i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) params := types.NewTuple(i32, i8Ptr, i8Ptr, i8Ptr) tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type) results := types.NewTuple(tokenParam) p.coIDTy = types.NewSignatureType(nil, nil, nil, params, results, false) } return p.coIDTy } /* // declare token @llvm.coro.id.async(i32 , i32 , ptr , ptr ) func (p Program) tyCoIDAsync() *types.Signature { if p.coIDAsyncTy == nil { i32 := types.NewParam(token.NoPos, nil, "", p.Int32().raw.Type) i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) params := types.NewTuple(i32, i32, i8Ptr, i8Ptr) tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type) results := types.NewTuple(tokenParam) p.coIDAsyncTy = types.NewSignatureType(nil, nil, nil, params, results, false) } return p.coIDAsyncTy } // declare token @llvm.coro.id.retcon(i32 , i32 , ptr , ptr , ptr , ptr ) func (p Program) tyCoIDRetcon() *types.Signature { if p.coIDRetconTy == nil { i32 := types.NewParam(token.NoPos, nil, "", p.Int32().raw.Type) i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) params := types.NewTuple(i32, i32, i8Ptr, i8Ptr, i8Ptr, i8Ptr) tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type) results := types.NewTuple(tokenParam) p.coIDRetconTy = types.NewSignatureType(nil, nil, nil, params, results, false) } return p.coIDRetconTy } // declare token @llvm.coro.id.retcon.once(i32 , i32 , ptr , ptr , ptr , ptr ) func (p Program) tyCoIDRetconOnce() *types.Signature { if p.coIDRetconOnceTy == nil { i32 := types.NewParam(token.NoPos, nil, "", p.Int32().raw.Type) i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) params := types.NewTuple(i32, i32, i8Ptr, i8Ptr, i8Ptr, i8Ptr) tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type) results := types.NewTuple(tokenParam) p.coIDRetconOnceTy = types.NewSignatureType(nil, nil, nil, params, results, false) } return p.coIDRetconOnceTy } */ // declare i1 @llvm.coro.end(ptr , i1 , token ) func (p Program) tyCoEnd() *types.Signature { if p.coEndTy == nil { i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) boolParam := types.NewParam(token.NoPos, nil, "", p.Bool().raw.Type) tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type) params := types.NewTuple(i8Ptr, boolParam, tokenParam) results := types.NewTuple(boolParam) p.coEndTy = types.NewSignatureType(nil, nil, nil, params, results, false) } return p.coEndTy } /* // TODO(lijie): varargs // declare token @llvm.coro.end.results(...) func (p Program) tyCoEndResults() *types.Signature { panic("not implemented") } // TODO(lijie): varargs // declare i1 @llvm.coro.end.async(ptr , i1 , ...) func (p Program) tyCoEndAsync() *types.Signature { panic("not implemented") } */ // declare i8 @llvm.coro.suspend(token , i1 ) func (p Program) tyCoSuspend() *types.Signature { if p.coSuspendTy == nil { tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type) boolParam := types.NewParam(token.NoPos, nil, "", p.Bool().raw.Type) params := types.NewTuple(tokenParam, boolParam) paramByte := types.NewParam(token.NoPos, nil, "", p.Byte().raw.Type) results := types.NewTuple(paramByte) p.coSuspendTy = types.NewSignatureType(nil, nil, nil, params, results, false) } return p.coSuspendTy } /* // declare token @llvm.coro.save(ptr ) func (p Program) tyCoSave() *types.Signature { if p.coSaveTy == nil { i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) params := types.NewTuple(i8Ptr) tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type) results := types.NewTuple(tokenParam) p.coSaveTy = types.NewSignatureType(nil, nil, nil, params, results, false) } return p.coSaveTy } // TODO(lijie): varargs // declare {ptr, ptr, ptr} @llvm.coro.suspend.async(ptr , ptr , ... ... ) func (p Program) tyCoSuspendAsync() *types.Signature { panic("not implemented") } // declare ptr @llvm.coro.prepare.async(ptr ) func (p Program) tyCoPrepareAsync() *types.Signature { if p.coPrepareAsyncTy == nil { i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) params := types.NewTuple(i8Ptr) results := types.NewTuple(i8Ptr) p.coPrepareAsyncTy = types.NewSignatureType(nil, nil, nil, params, results, false) } return p.coPrepareAsyncTy } // declare i1 @llvm.coro.suspend.retcon(...) func (p Program) tyCoSuspendRetcon() *types.Signature { panic("not implemented") } // declare void @await_suspend_function(ptr %awaiter, ptr %hdl) func (p Program) tyCoAwaitSuspendFunction() *types.Signature { if p.coAwaitSuspendFunctionTy == nil { i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) params := types.NewTuple(i8Ptr, i8Ptr) p.coAwaitSuspendFunctionTy = types.NewSignatureType(nil, nil, nil, params, nil, false) } return p.coAwaitSuspendFunctionTy } // declare void @llvm.coro.await.suspend.void(ptr , ptr , ptr ) func (p Program) tyCoAwaitSuspendVoid() *types.Signature { if p.coAwaitSuspendVoidTy == nil { i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) params := types.NewTuple(i8Ptr, i8Ptr, i8Ptr) p.coAwaitSuspendVoidTy = types.NewSignatureType(nil, nil, nil, params, nil, false) } return p.coAwaitSuspendVoidTy } // declare i1 @llvm.coro.await.suspend.bool(ptr , ptr , ptr ) func (p Program) tyCoAwaitSuspendBool() *types.Signature { if p.coAwaitSuspendBoolTy == nil { i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) params := types.NewTuple(i8Ptr, i8Ptr, i8Ptr) results := types.NewTuple(types.NewParam(token.NoPos, nil, "", p.Bool().raw.Type)) p.coAwaitSuspendBoolTy = types.NewSignatureType(nil, nil, nil, params, results, false) } return p.coAwaitSuspendBoolTy } // declare void @llvm.coro.await.suspend.handle(ptr , ptr , ptr ) func (p Program) tyCoAwaitSuspendHandle() *types.Signature { if p.coAwaitSuspendHandleTy == nil { i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type) params := types.NewTuple(i8Ptr, i8Ptr, i8Ptr) p.coAwaitSuspendHandleTy = types.NewSignatureType(nil, nil, nil, params, nil, false) } return p.coAwaitSuspendHandleTy } */ // ----------------------------------------------------------------------------- func (b Builder) SetBlockOffset(offset int) { b.blkOffset = offset } func (b Builder) BlockOffset() int { return b.blkOffset } func (b Builder) Async() bool { return b.async } func (b Builder) AsyncToken() Expr { return b.asyncToken } func (b Builder) EndAsync() { b.onReturn() } /* pesudo code: retPtr := malloc(sizeof(Promise)) id := @llvm.coro.id(0, null, null, null) promiseSize := sizeof(Promise[T]) frameSize := @llvm.coro.size.i64() allocSize := promiseSize + frameSize promise := malloc(allocSize) needAlloc := @llvm.coro.alloc(id) ; Allocate memory for return type and coroutine frame frame := null if needAlloc { frame := malloc(frameSize) } hdl := @llvm.coro.begin(id, frame) *retPtr = hdl */ func (b Builder) BeginAsync(fn Function, entryBlk, allocBlk, cleanBlk, suspdBlk, trapBlk, beginBlk BasicBlock) { ty := fn.Type.RawType().(*types.Signature).Results().At(0).Type() ptrTy, ok := ty.(*types.Pointer) if !ok { panic("async function must return a *async.Promise") } promiseTy := b.Prog.Type(ptrTy.Elem(), InGo) b.async = true b.SetBlock(entryBlk) align := b.Const(constant.MakeInt64(0), b.Prog.CInt()).SetName("align") null := b.Const(nil, b.Prog.CIntPtr()) id := b.CoID(align, null, null, null).SetName("id") b.asyncToken = id promiseSize := b.Const(constant.MakeUint64(b.Prog.SizeOf(promiseTy)), b.Prog.Int64()).SetName("alloc.size") frameSize := b.CoSizeI64().SetName("frame.size") allocSize := b.BinOp(token.ADD, promiseSize, frameSize).SetName("alloc.size") promise := b.AllocZ(allocSize).SetName("promise") b.promise = promise promise.Type = b.Prog.Pointer(promiseTy) needAlloc := b.CoAlloc(id).SetName("need.dyn.alloc") b.If(needAlloc, allocBlk, beginBlk) b.SetBlock(allocBlk) frame := b.OffsetPtr(promise, promiseSize) b.Jump(beginBlk) b.SetBlock(beginBlk) phi := b.Phi(b.Prog.VoidPtr()) phi.SetName("frame") phi.AddIncoming(b, []BasicBlock{entryBlk, allocBlk}, func(i int, blk BasicBlock) Expr { if i == 0 { return null } return frame }) hdl := b.CoBegin(id, phi.Expr) hdl.SetName("hdl") b.Store(promise, hdl) b.SetBlock(cleanBlk) b.CoFree(id, hdl) b.Jump(suspdBlk) b.SetBlock(suspdBlk) b.CoEnd(hdl, b.Prog.BoolVal(false), b.Prog.TokenNone()) b.Return(promise) b.SetBlock(trapBlk) b.LLVMTrap() b.Unreachable() b.onSuspBlk = func(nextBlk BasicBlock) (BasicBlock, BasicBlock, BasicBlock) { if nextBlk == nil { nextBlk = trapBlk } return suspdBlk, nextBlk, cleanBlk } b.onReturn = func() { b.CoSuspend(b.asyncToken, b.Prog.BoolVal(true), trapBlk) } } // ----------------------------------------------------------------------------- // declare void @llvm.coro.destroy(ptr ) func (b Builder) CoDestroy(hdl Expr) { fn := b.Pkg.cFunc("llvm.coro.destroy", b.Prog.tyCoDestroy()) b.Call(fn, hdl) } // declare void @llvm.coro.resume(ptr ) func (b Builder) CoResume(hdl Expr) { fn := b.Pkg.cFunc("llvm.coro.resume", b.Prog.tyCoResume()) b.Call(fn, hdl) } // declare i1 @llvm.coro.done(ptr ) func (b Builder) coDone(hdl Expr) Expr { fn := b.Pkg.cFunc("llvm.coro.done", b.Prog.tyCoDone()) return b.Call(fn, hdl) } // return c.Char func (b Builder) CoDone(hdl Expr) Expr { bvar := b.coDone(hdl) // TODO(lijie): inefficient // %6 = zext i1 %5 to i64 // %7 = trunc i64 %6 to i8 return b.valFromData(b.Prog.Byte(), bvar.impl) } // declare ptr @llvm.coro.promise(ptr , i32 , i1 ) func (b Builder) CoPromise(ptr, align, from Expr) Expr { fn := b.Pkg.cFunc("llvm.coro.promise", b.Prog.tyCoPromise()) return b.Call(fn, ptr, align, from) } // declare i32 @llvm.coro.size.i32() func (b Builder) CoSizeI32() Expr { fn := b.Pkg.cFunc("llvm.coro.size.i32", b.Prog.tyCoSizeI32()) return b.Call(fn) } // declare i64 @llvm.coro.size.i64() func (b Builder) CoSizeI64() Expr { fn := b.Pkg.cFunc("llvm.coro.size.i64", b.Prog.tyCoSizeI64()) return b.Call(fn) } // declare i32 @llvm.coro.align.i32() func (b Builder) CoAlignI32() Expr { fn := b.Pkg.cFunc("llvm.coro.align.i32", b.Prog.tyCoAlignI32()) return b.Call(fn) } // declare i64 @llvm.coro.align.i64() func (b Builder) CoAlignI64() Expr { fn := b.Pkg.cFunc("llvm.coro.align.i64", b.Prog.tyCoAlignI64()) return b.Call(fn) } // declare ptr @llvm.coro.begin(token , ptr ) func (b Builder) CoBegin(id, mem Expr) Expr { fn := b.Pkg.cFunc("llvm.coro.begin", b.Prog.tyCoBegin()) return b.Call(fn, id, mem) } // declare ptr @llvm.coro.free(token %id, ptr ) func (b Builder) CoFree(id, frame Expr) Expr { fn := b.Pkg.cFunc("llvm.coro.free", b.Prog.tyCoFree()) return b.Call(fn, id, frame) } // declare i1 @llvm.coro.alloc(token ) func (b Builder) CoAlloc(id Expr) Expr { fn := b.Pkg.cFunc("llvm.coro.alloc", b.Prog.tyCoAlloc()) return b.Call(fn, id) } // declare ptr @llvm.coro.noop() func (b Builder) CoNoop() Expr { fn := b.Pkg.cFunc("llvm.coro.noop", b.Prog.tyCoNoop()) return b.Call(fn) } // declare ptr @llvm.coro.frame() func (b Builder) CoFrame() Expr { fn := b.Pkg.cFunc("llvm.coro.frame", b.Prog.tyCoFrame()) return b.Call(fn) } // declare token @llvm.coro.id(i32 , ptr , ptr , ptr ) func (b Builder) CoID(align Expr, promise, coroAddr, fnAddrs Expr) Expr { if align.Type != b.Prog.Int32() { panic("align must be i32") } fn := b.Pkg.cFunc("llvm.coro.id", b.Prog.tyCoID()) return b.Call(fn, align, promise, coroAddr, fnAddrs) } /* // declare token @llvm.coro.id.async(i32 , i32 , ptr , ptr ) func (b Builder) CoIDAsync(contextSize, align, contextArg, asyncFnPtr Expr) Expr { if contextSize.Type != b.Prog.Int32() { panic("contextSize must be i32") } if align.Type != b.Prog.Int32() { panic("align must be i32") } fn := b.Pkg.cFunc("llvm.coro.id.async", b.Prog.tyCoIDAsync()) return b.Call(fn, contextSize, align, contextArg, asyncFnPtr) } // declare token @llvm.coro.id.retcon(i32 , i32 , ptr , ptr , ptr , ptr ) func (b Builder) CoIDRetcon(size, align, buffer, contProto, alloc, dealloc Expr) Expr { fn := b.Pkg.cFunc("llvm.coro.id.retcon", b.Prog.tyCoIDRetcon()) return b.Call(fn, size, align, buffer, contProto, alloc, dealloc) } // declare token @llvm.coro.id.retcon.once(i32 , i32 , ptr , ptr , ptr , ptr ) func (b Builder) CoIDRetconOnce(size, align, buffer, prototype, alloc, dealloc Expr) Expr { fn := b.Pkg.cFunc("llvm.coro.id.retcon.once", b.Prog.tyCoIDRetconOnce()) return b.Call(fn, size, align, buffer, prototype, alloc, dealloc) } */ // declare i1 @llvm.coro.end(ptr , i1 , token ) func (b Builder) CoEnd(hdl Expr, unwind Expr, resultToken Expr) Expr { fn := b.Pkg.cFunc("llvm.coro.end", b.Prog.tyCoEnd()) return b.Call(fn, hdl, unwind, resultToken) } /* // declare token @llvm.coro.end.results(...) func (b Builder) CoEndResults(args []Expr) Expr { fn := b.Pkg.cFunc("llvm.coro.end.results", b.Prog.tyCoEndResults()) return b.Call(fn, args...) } // declare i1 @llvm.coro.end.async(ptr , i1 , ...) func (b Builder) CoEndAsync(handle, unwind Expr, args ...Expr) Expr { fn := b.Pkg.cFunc("llvm.coro.end.async", b.Prog.tyCoEndAsync()) vargs := append([]Expr{handle, unwind}, args...) return b.Call(fn, vargs...) } */ // declare i8 @llvm.coro.suspend(token , i1 ) func (b Builder) coSuspend(save, final Expr) Expr { fn := b.Pkg.cFunc("llvm.coro.suspend", b.Prog.tyCoSuspend()) return b.Call(fn, save, final) } func (b Builder) CoSuspend(save, final Expr, nextBlk BasicBlock) { if !b.async { panic(fmt.Errorf("suspend %v not in async block", b.Func.Name())) } if nextBlk == nil { b.Func.MakeBlock("") nextBlk = b.Func.Block(b.blk.idx + 1) } ret := b.coSuspend(save, final) susp, next, clean := b.onSuspBlk(nextBlk) swt := b.Switch(ret, susp) swt.Case(b.Const(constant.MakeInt64(0), b.Prog.Byte()), next) swt.Case(b.Const(constant.MakeInt64(1), b.Prog.Byte()), clean) swt.End(b) b.SetBlock(nextBlk) } func (b Builder) CoReturn(setValueFn Function, value Expr) { if !b.async { panic(fmt.Errorf("return %v not in async block", b.Func.Name())) } b.Call(setValueFn.Expr, b.promise, value) _, _, cleanBlk := b.onSuspBlk(nil) b.Jump(cleanBlk) } func (b Builder) CoYield(setValueFn Function, value Expr, final Expr) { if !b.async { panic(fmt.Errorf("yield %v not in async block", b.Func.Name())) } b.Call(setValueFn.Expr, b.promise, value) b.CoSuspend(b.AsyncToken(), final, nil) } /* // declare token @llvm.coro.save(ptr ) func (b Builder) CoSave(hdl Expr) Expr { fn := b.Pkg.cFunc("llvm.coro.save", b.Prog.tyCoSave()) return b.Call(fn, hdl) } // declare ptr @llvm.coro.prepare.async(ptr ) func (b Builder) CoPrepareAsync(f Expr) Expr { fn := b.Pkg.cFunc("llvm.coro.prepare.async", b.Prog.tyCoPrepareAsync()) return b.Call(fn, f) } // declare i1 @llvm.coro.suspend.retcon(...) func (b Builder) CoSuspendRetcon(args []Expr) Expr { fn := b.Pkg.cFunc("llvm.coro.suspend.retcon", b.Prog.tyCoSuspendRetcon()) return b.Call(fn, args...) } // declare void @llvm.coro.await.suspend.void(ptr , ptr , ptr ) func (b Builder) CoAwaitSuspendVoid(awaiter, handle, f Expr) { fn := b.Pkg.cFunc("llvm.coro.await.suspend.void", b.Prog.tyCoAwaitSuspendVoid()) b.Call(fn, awaiter, handle, f) } // declare i1 @llvm.coro.await.suspend.bool(ptr , ptr , ptr ) func (b Builder) CoAwaitSuspendBool(awaiter, handle, f Expr) Expr { fn := b.Pkg.cFunc("llvm.coro.await.suspend.bool", b.Prog.tyCoAwaitSuspendBool()) return b.Call(fn, awaiter, handle, f) } // declare void @llvm.coro.await.suspend.handle(ptr , ptr , ptr ) func (b Builder) CoAwaitSuspendHandle(awaiter, handle, f Expr) { fn := b.Pkg.cFunc("llvm.coro.await.suspend.handle", b.Prog.tyCoAwaitSuspendHandle()) b.Call(fn, awaiter, handle, f) } */