/* * 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 ( "go/constant" "go/token" "go/types" "testing" "unsafe" "github.com/goplus/gogen/packages" "github.com/goplus/llvm" ) func TestEndDefer(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("foo", "foo") fn := pkg.NewFunc("main", NoArgsNoRet, InC) b := fn.MakeBody(1) fn.defer_ = &aDefer{} fn.endDefer(b) } func TestUnsafeString(t *testing.T) { prog := NewProgram(nil) prog.SetRuntime(func() *types.Package { fset := token.NewFileSet() imp := packages.NewImporter(fset) pkg, _ := imp.Import(PkgRuntime) return pkg }) pkg := prog.NewPackage("foo", "foo") b := pkg.NewFunc("main", NoArgsNoRet, InC).MakeBody(1) b.Println(b.BuiltinCall("String", b.CStr("hello"), prog.Val(5))) b.Return() } func TestPointerSize(t *testing.T) { expected := unsafe.Sizeof(uintptr(0)) if size := NewProgram(nil).PointerSize(); size != int(expected) { t.Fatal("bad PointerSize:", size) } } func TestSetBlock(t *testing.T) { defer func() { if r := recover(); r == nil { t.Log("SetBlock: no error?") } }() fn := &aFunction{} b := &aBuilder{Func: fn} b.SetBlock(&aBasicBlock{}) } func TestSetBlockEx(t *testing.T) { defer func() { if r := recover(); r == nil { t.Log("SetBlockEx: no error?") } }() fn := &aFunction{} b := &aBuilder{Func: fn} b.SetBlockEx(&aBasicBlock{fn: fn}, -1, false) } func TestSetPython(t *testing.T) { prog := NewProgram(nil) typ := types.NewPackage("foo", "foo") prog.SetPython(typ) } func TestClosureCtx(t *testing.T) { defer func() { if r := recover(); r == nil { t.Log("closureCtx: no error?") } }() var f aFunction f.closureCtx(nil) } func TestTypes(t *testing.T) { ctx := llvm.NewContext() llvmIntType(ctx, 4) intT := types.NewVar(0, nil, "", types.Typ[types.Int]) ret := types.NewTuple(intT, intT) sig := types.NewSignatureType(nil, nil, nil, nil, ret, false) prog := NewProgram(nil) prog.retType(sig) } func TestIndexType(t *testing.T) { defer func() { if r := recover(); r == nil { t.Log("indexType: no error?") } }() indexType(types.Typ[types.Int]) } func TestCvtType(t *testing.T) { gt := newGoTypes() params := types.NewTuple(types.NewParam(0, nil, "", NoArgsNoRet)) sig := types.NewSignatureType(nil, nil, nil, params, nil, false) ret1 := gt.cvtFunc(sig, nil) if ret1 == sig { t.Fatal("cvtFunc failed") } defer func() { if r := recover(); r == nil { t.Log("cvtType: no error?") } }() gt.cvtType(nil) } func TestUserdefExpr(t *testing.T) { c := &pyVarTy{} b := &builtinTy{} _ = c.String() _ = b.String() test := func(a types.Type) { defer func() { if r := recover(); r == nil { t.Log("TestUserdefExpr: no error?") } }() a.Underlying() } test(c) test(b) } func TestAny(t *testing.T) { prog := NewProgram(nil) prog.SetRuntime(func() *types.Package { ret := types.NewPackage("runtime", "runtime") scope := ret.Scope() name := types.NewTypeName(0, ret, "Eface", nil) types.NewNamed(name, types.NewStruct(nil, nil), nil) scope.Insert(name) return ret }) prog.Any() } func assertPkg(t *testing.T, p Package, expected string) { t.Helper() if v := p.String(); v != expected { t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected) } } func TestPyFunc(t *testing.T) { prog := NewProgram(nil) py := types.NewPackage("foo", "foo") o := types.NewTypeName(0, py, "Object", nil) types.NewNamed(o, types.Typ[types.Int], nil) py.Scope().Insert(o) prog.SetPython(py) pkg := prog.NewPackage("bar", "foo/bar") a := pkg.PyNewFunc("a", NoArgsNoRet, false) if pkg.PyNewFunc("a", NoArgsNoRet, false) != a { t.Fatal("NewPyFunc(a) failed") } foo := pkg.PyNewModVar("foo", false) if pkg.PyNewModVar("foo", false) != foo { t.Fatal("NewPyModVar(foo) failed") } } func TestVar(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") typ := types.NewPointer(types.Typ[types.Int]) a := pkg.NewVar("a", typ, InGo) if pkg.NewVar("a", typ, InGo) != a { t.Fatal("NewVar(a) failed") } pkg.NewVarEx("a", prog.Type(typ, InGo)) a.Init(prog.Val(100)) b := pkg.NewVar("b", typ, InGo) b.Init(a.Expr) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" @a = global i64 100, align 8 @b = global i64 @a, align 8 `) } func TestConst(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Bool])) sig := types.NewSignatureType(nil, nil, nil, nil, rets, false) b := pkg.NewFunc("fn", sig, InGo).MakeBody(1) b.Return(b.Const(constant.MakeBool(true), prog.Bool())) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" define i1 @fn() { _llgo_0: ret i1 true } `) } func TestStruct(t *testing.T) { empty := types.NewStruct(nil, nil) prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") pkg.NewVar("a", types.NewPointer(empty), InGo) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" @a = external global {}, align 1 `) if prog.NeedRuntime { t.Fatal("NeedRuntime?") } } func TestNamedStruct(t *testing.T) { src := types.NewPackage("bar", "foo/bar") empty := types.NewNamed(types.NewTypeName(0, src, "Empty", nil), types.NewStruct(nil, nil), nil) prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") pkg.NewVar("a", types.NewPointer(empty), InGo) if pkg.VarOf("a") == nil { t.Fatal("VarOf failed") } assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" %bar.Empty = type {} @a = external global %bar.Empty, align 1 `) } func TestDeclFunc(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") params := types.NewTuple(types.NewVar(0, nil, "a", types.Typ[types.Int])) sig := types.NewSignatureType(nil, nil, nil, params, nil, false) pkg.NewFunc("fn", sig, InGo) if pkg.FuncOf("fn") == nil { t.Fatal("FuncOf failed") } if prog.retType(sig) != prog.Void() { t.Fatal("retType failed") } assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" declare void @fn(i64) `) } func TestBasicFunc(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") params := types.NewTuple( types.NewVar(0, nil, "a", types.Typ[types.Int]), types.NewVar(0, nil, "b", types.Typ[types.Float64])) rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int])) sig := types.NewSignatureType(nil, nil, nil, params, rets, false) pkg.NewFunc("fn", sig, InGo).MakeBody(1). Return(prog.Val(1)) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" define i64 @fn(i64 %0, double %1) { _llgo_0: ret i64 1 } `) } func TestFuncParam(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") params := types.NewTuple( types.NewVar(0, nil, "a", types.Typ[types.Int]), types.NewVar(0, nil, "b", types.Typ[types.Float64])) rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int])) sig := types.NewSignatureType(nil, nil, nil, params, rets, false) fn := pkg.NewFunc("fn", sig, InGo) fn.MakeBody(1).Return(fn.Param(0)) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" define i64 @fn(i64 %0, double %1) { _llgo_0: ret i64 %0 } `) } func TestFuncCall(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") params := types.NewTuple( types.NewVar(0, nil, "a", types.Typ[types.Int]), types.NewVar(0, nil, "b", types.Typ[types.Float64])) rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int])) sig := types.NewSignatureType(nil, nil, nil, params, rets, false) fn := pkg.NewFunc("fn", sig, InGo) fn.MakeBody(1). Return(prog.Val(1)) b := pkg.NewFunc("main", NoArgsNoRet, InGo).MakeBody(1) b.Call(fn.Expr, prog.Val(1), prog.Val(1.2)) b.Return() assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" define i64 @fn(i64 %0, double %1) { _llgo_0: ret i64 1 } define void @main() { _llgo_0: %0 = call i64 @fn(i64 1, double 1.200000e+00) ret void } `) } func TestFuncMultiRet(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") params := types.NewTuple( types.NewVar(0, nil, "b", types.Typ[types.Float64])) rets := types.NewTuple( types.NewVar(0, nil, "c", types.Typ[types.Int]), types.NewVar(0, nil, "d", types.Typ[types.Float64])) sig := types.NewSignatureType(nil, nil, nil, params, rets, false) a := pkg.NewVar("a", types.NewPointer(types.Typ[types.Int]), InGo) fn := pkg.NewFunc("fn", sig, InGo) b := fn.MakeBody(1) b.Return(a.Expr, fn.Param(0)) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" @a = external global i64, align 8 define { i64, double } @fn(double %0) { _llgo_0: %1 = alloca { i64, double }, align 8 %2 = getelementptr inbounds { i64, double }, ptr %1, i32 0, i32 0 store ptr @a, ptr %2, align 8 %3 = getelementptr inbounds { i64, double }, ptr %1, i32 0, i32 1 store double %0, ptr %3, align 8 %4 = load { i64, double }, ptr %1, align 8 ret { i64, double } %4 } `) } func TestJump(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") fn := pkg.NewFunc("loop", NoArgsNoRet, InGo) b := fn.MakeBody(1) b.Jump(fn.Block(0)) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" define void @loop() { _llgo_0: br label %_llgo_0 } `) } func TestIf(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") params := types.NewTuple(types.NewVar(0, nil, "a", types.Typ[types.Int])) rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int])) sig := types.NewSignatureType(nil, nil, nil, params, rets, false) fn := pkg.NewFunc("fn", sig, InGo) b := fn.MakeBody(3) iftrue := fn.Block(1) iffalse := fn.Block(2) if iftrue.Index() != 1 || iftrue.Parent() != fn { t.Fatal("iftrue") } cond := b.BinOp(token.GTR, fn.Param(0), prog.Val(0)) b.If(cond, iftrue, iffalse) b.SetBlock(iftrue).Return(prog.Val(1)) b.SetBlock(iffalse).Return(prog.Val(0)) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" define i64 @fn(i64 %0) { _llgo_0: %1 = icmp sgt i64 %0, 0 br i1 %1, label %_llgo_1, label %_llgo_2 _llgo_1: ; preds = %_llgo_0 ret i64 1 _llgo_2: ; preds = %_llgo_0 ret i64 0 } `) } func TestPrintf(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") pchar := types.NewPointer(types.Typ[types.Int8]) params := types.NewTuple(types.NewVar(0, nil, "format", pchar), VArg()) rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int32])) sig := types.NewSignatureType(nil, nil, nil, params, rets, true) pkg.NewFunc("printf", sig, InC) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" declare i32 @printf(ptr, ...) `) } func TestBinOp(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") params := types.NewTuple( types.NewVar(0, nil, "a", types.Typ[types.Int]), types.NewVar(0, nil, "b", types.Typ[types.Float64])) rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int])) sig := types.NewSignatureType(nil, nil, nil, params, rets, false) fn := pkg.NewFunc("fn", sig, InGo) b := fn.MakeBody(1) ret := b.BinOp(token.ADD, fn.Param(0), prog.Val(1)) b.Return(ret) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" define i64 @fn(i64 %0, double %1) { _llgo_0: %2 = add i64 %0, 1 ret i64 %2 } `) } func TestSwitch(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") params := types.NewTuple(types.NewVar(0, nil, "a", types.Typ[types.Int])) rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int])) sig := types.NewSignatureType(nil, nil, nil, params, rets, false) fn := pkg.NewFunc("fn", sig, InGo) b := fn.MakeBody(4) cond := fn.Param(0) case1 := fn.Block(1) case2 := fn.Block(2) defb := fn.Block(3) swc := b.Switch(cond, defb) swc.Case(prog.Val(1), case1) swc.Case(prog.Val(2), case2) swc.End(b) b.SetBlock(case1).Return(prog.Val(3)) b.SetBlock(case2).Return(prog.Val(4)) b.SetBlock(defb).Return(prog.Val(5)) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" define i64 @fn(i64 %0) { _llgo_0: switch i64 %0, label %_llgo_3 [ i64 1, label %_llgo_1 i64 2, label %_llgo_2 ] _llgo_1: ; preds = %_llgo_0 ret i64 3 _llgo_2: ; preds = %_llgo_0 ret i64 4 _llgo_3: ; preds = %_llgo_0 ret i64 5 } `) } func TestUnOp(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") params := types.NewTuple( types.NewVar(0, nil, "p", types.NewPointer(types.Typ[types.Int])), ) rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int])) sig := types.NewSignatureType(nil, nil, nil, params, rets, false) fn := pkg.NewFunc("fn", sig, InGo) b := fn.MakeBody(1) ptr := fn.Param(0) val := b.UnOp(token.MUL, ptr) val2 := b.BinOp(token.XOR, val, prog.Val(1)) b.Store(ptr, val2) b.Return(val2) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" define i64 @fn(ptr %0) { _llgo_0: %1 = load i64, ptr %0, align 4 %2 = xor i64 %1, 1 store i64 %2, ptr %0, align 4 ret i64 %2 } `) } func TestBasicType(t *testing.T) { type typeInfo struct { typ Type kind types.BasicKind } prog := NewProgram(nil) infos := []*typeInfo{ {prog.Bool(), types.Bool}, {prog.Byte(), types.Byte}, {prog.Int(), types.Int}, {prog.Uint(), types.Uint}, {prog.Int32(), types.Int32}, {prog.Int64(), types.Int64}, {prog.Uint32(), types.Uint32}, {prog.Uint64(), types.Uint64}, {prog.Uintptr(), types.Uintptr}, {prog.VoidPtr(), types.UnsafePointer}, } for _, info := range infos { if info.typ.RawType() != types.Typ[info.kind] { t.Fatal("bad type", info) } } } func TestCompareSelect(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") params := types.NewTuple( types.NewVar(0, nil, "a", types.Typ[types.Int]), types.NewVar(0, nil, "b", types.Typ[types.Int]), types.NewVar(0, nil, "c", types.Typ[types.Int]), ) rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int])) sig := types.NewSignatureType(nil, nil, nil, params, rets, false) fn := pkg.NewFunc("fn", sig, InGo) b := fn.MakeBody(1) result := b.compareSelect(token.GTR, fn.Param(0), fn.Param(1), fn.Param(2)) b.Return(result) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" define i64 @fn(i64 %0, i64 %1, i64 %2) { _llgo_0: %3 = icmp sgt i64 %0, %1 %4 = select i1 %3, i64 %0, i64 %1 %5 = icmp sgt i64 %4, %2 %6 = select i1 %5, i64 %4, i64 %2 ret i64 %6 } `) } func TestPointerOffset(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") params := types.NewTuple( types.NewVar(0, nil, "p", types.NewPointer(types.Typ[types.Int])), types.NewVar(0, nil, "offset", types.Typ[types.Int]), ) rets := types.NewTuple(types.NewVar(0, nil, "", types.NewPointer(types.Typ[types.Int]))) sig := types.NewSignatureType(nil, nil, nil, params, rets, false) fn := pkg.NewFunc("fn", sig, InGo) b := fn.MakeBody(1) ptr := fn.Param(0) offset := fn.Param(1) result := b.OffsetPtr(ptr, offset) b.Return(result) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" define ptr @fn(ptr %0, i64 %1) { _llgo_0: %2 = getelementptr ptr, ptr %0, i64 %1 ret ptr %2 } `) } func TestLLVMTrap(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") b := pkg.NewFunc("fn", NoArgsNoRet, InGo).MakeBody(1) b.LLVMTrap() b.Unreachable() assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" define void @fn() { _llgo_0: call void @llvm.trap() unreachable } ; Function Attrs: cold noreturn nounwind memory(inaccessiblemem: write) declare void @llvm.trap() `) } func TestCoroFuncs(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") fn := pkg.NewFunc("fn", NoArgsNoRet, InGo) entryBlk := fn.MakeBlock("entry") suspdBlk := fn.MakeBlock("suspend") cleanBlk := fn.MakeBlock("clean") b := fn.NewBuilder() b.async = true b.SetBlock(entryBlk) align := b.Const(constant.MakeInt64(0), prog.Int32()) align8 := b.Const(constant.MakeInt64(8), prog.Int32()) null := b.Const(nil, b.Prog.CIntPtr()) b.promise = null id := b.CoID(align, null, null, null) bf := b.Const(constant.MakeBool(false), prog.Bool()) b.CoSizeI32() size := b.CoSizeI64() b.CoAlignI32() b.CoAlignI64() b.CoAlloc(id) frame := b.Alloca(size) hdl := b.CoBegin(id, frame) b.SetBlock(cleanBlk) b.CoFree(id, frame) b.Jump(suspdBlk) b.SetBlock(suspdBlk) b.CoEnd(hdl, bf, prog.TokenNone()) // b.Return(b.promise) b.SetBlock(entryBlk) b.CoResume(hdl) b.CoDone(hdl) b.CoDestroy(hdl) b.CoPromise(null, align8, bf) b.CoNoop() b.CoFrame() setArgs := types.NewTuple(types.NewVar(0, nil, "value", types.Typ[types.Int])) setSig := types.NewSignatureType(nil, nil, nil, setArgs, nil, false) setFn := pkg.NewFunc("setValue", setSig, InGo) one := b.Const(constant.MakeInt64(1), prog.Int()) b.onSuspBlk = func(next BasicBlock) (BasicBlock, BasicBlock, BasicBlock) { return suspdBlk, next, cleanBlk } b.CoYield(setFn, one, bf) b.CoReturn(setFn, one) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" define void @fn() { entry: %0 = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null) %1 = call i32 @llvm.coro.size.i32() %2 = call i64 @llvm.coro.size.i64() %3 = call i32 @llvm.coro.align.i32() %4 = call i64 @llvm.coro.align.i64() %5 = call i1 @llvm.coro.alloc(token %0) %6 = alloca i8, i64 %2, align 1 %7 = call ptr @llvm.coro.begin(token %0, ptr %6) call void @llvm.coro.resume(ptr %7) %8 = call i1 @llvm.coro.done(ptr %7) %9 = zext i1 %8 to i64 %10 = trunc i64 %9 to i8 call void @llvm.coro.destroy(ptr %7) %11 = call ptr @llvm.coro.promise(ptr null, i32 8, i1 false) %12 = call ptr @llvm.coro.noop() %13 = call ptr @llvm.coro.frame() call void @setValue(ptr null, i64 1) %14 = call i8 @llvm.coro.suspend(, i1 false) switch i8 %14, label %suspend [ i8 0, label %suspend i8 1, label %clean ] suspend: ; preds = %entry, %entry, %clean %15 = call i1 @llvm.coro.end(ptr %7, i1 false, token none) call void @setValue(ptr null, i64 1) br label %clean clean: ; preds = %suspend, %entry %16 = call ptr @llvm.coro.free(token %0, ptr %6) br label %suspend _llgo_3: ; No predecessors! } ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: read) declare token @llvm.coro.id(i32, ptr readnone, ptr nocapture readonly, ptr) ; Function Attrs: nounwind memory(none) declare i32 @llvm.coro.size.i32() ; Function Attrs: nounwind memory(none) declare i64 @llvm.coro.size.i64() ; Function Attrs: nounwind memory(none) declare i32 @llvm.coro.align.i32() ; Function Attrs: nounwind memory(none) declare i64 @llvm.coro.align.i64() ; Function Attrs: nounwind declare i1 @llvm.coro.alloc(token) ; Function Attrs: nounwind declare ptr @llvm.coro.begin(token, ptr writeonly) ; Function Attrs: nounwind memory(argmem: read) declare ptr @llvm.coro.free(token, ptr nocapture readonly) ; Function Attrs: nounwind declare i1 @llvm.coro.end(ptr, i1, token) declare void @llvm.coro.resume(ptr) ; Function Attrs: nounwind memory(argmem: readwrite) declare i1 @llvm.coro.done(ptr nocapture readonly) declare void @llvm.coro.destroy(ptr) ; Function Attrs: nounwind memory(none) declare ptr @llvm.coro.promise(ptr nocapture, i32, i1) ; Function Attrs: nounwind memory(none) declare ptr @llvm.coro.noop() ; Function Attrs: nounwind memory(none) declare ptr @llvm.coro.frame() declare void @setValue(i64) ; Function Attrs: nounwind declare i8 @llvm.coro.suspend(token, i1) `) }