Files
TransPyC/lib/core/Handles/HandlesAsyncFunctions.py
T
TermiNexus 13a8f6c1b6 feat(coro): 语言内协程 M1——async def + await + coro_run 状态机
TPC 新增协程生成器 AsyncFunctionHandle(lib/core/Handles/HandlesAsyncFunctions.py):
async def 编译为帧结构体 {state, done, ret, 局部变量槽} + create_<name>()(malloc
分配)+ resume_<name>()(switch 状态机,0=SUSPEND/1=DONE)。await 按顶层赋值
切分函数体:创建子帧 -> resume -> 取子帧 ret -> 存父帧槽 -> 父挂起(state 前进);
普通调用 async 函数生成 create(返回帧指针);coro.coro_run 在调用点内联翻译为
resume 循环。vast parser 已支持语法;新增 includes/coro.vp(Coroutine + 占位
运行时)与 Test/CoroTest(期望输出 coro result = 14)。

M1 限制:async 无参数、返回 i32/int;协程体仅顶层 AnnAssign/Assign/Expr/Return;
await 仅顶层赋值形式、子协程假设一次完成(无嵌套挂起);coro_run 依赖本模块
先赋值的协程变量。M2 将支持参数/嵌套 await/控制流。
2026-08-21 12:36:00 +08:00

470 lines
24 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
import vast as ast
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo
from lib.includes import t
class AsyncFunctionHandle(BaseHandle):
"""语言内协程 M1:async def + await + coro_run 状态机翻译。
M1 语义约定:
- async def 无参数、返回 i32/int。
- 每个 async 函数生成 3 部分:
1. 帧结构体 %Coro_<name> = type { i32, i32, i32, <跨 await 局部变量> }
(前 3 槽:state, done, ret)
2. create_<name>() -> %Coro_<name>*:stdlib.malloc 分配帧,state/done/ret 置 0
3. resume_<name>(%Coro_<name>*) -> i32:0=SUSPEND 1=DONE;switch(state) 切分 await 点
- await <async调用>:创建子帧 -> call resume(child)(M1 假设一次完成)
-> 取子帧 ret -> 存父帧局部变量槽 -> 父挂起(state=下一切片、ret=0(SUSPEND))
- return expr:写帧 ret + done=1 + br 完成块;函数体结尾隐式同 return 路径。
- 普通函数调用 async 函数(如 main 里 task()):生成 create 调用(返回帧指针)。
- coro.coro_run(帧):内联翻译为 resume 循环,返回帧 ret。
"""
# ------------------------------------------------------------------
# 公共查询
# ------------------------------------------------------------------
def _IsAsyncFunc(self, name: str) -> bool:
Gen: LlvmCodeGenerator | None = getattr(self.Trans, 'LlvmGen', None)
if Gen is None:
return False
return name in getattr(Gen, '_async_funcs', {})
def _RegisterAsyncFunc(self, name: str, Node: ast.AsyncFunctionDef) -> None:
Gen: LlvmCodeGenerator | None = getattr(self.Trans, 'LlvmGen', None)
if Gen is None:
return
if not hasattr(Gen, '_async_funcs'):
Gen._async_funcs = {}
Gen._async_funcs[name] = {'node': Node}
def _GetAsyncCallName(self, call: ast.Call) -> str | None:
if isinstance(call.func, ast.Name):
name: str = call.func.id
if self._IsAsyncFunc(name):
return name
return None
def _IsCoroModule(self, name: str) -> bool:
if name == 'coro':
return True
aliases: Any = getattr(self.Trans.SymbolTable, 'import_aliases', {})
return aliases.get(name) == 'coro'
# ------------------------------------------------------------------
# 入口:async 函数定义
# ------------------------------------------------------------------
def _EmitAsyncFunctionLlvm(self, Node: ast.AsyncFunctionDef, Gen: LlvmCodeGenerator) -> None:
name: str = Node.name
if Node.args.args:
raise SyntaxError(
f"[coro-M1] async 函数 '{name}' 暂不支持参数(M1 仅支持无参数 async def)"
)
# 防重复生成:模块可能被多次编译(泛型特化等触发),避免 create_/resume_ 重名
if f'create_{name}' in Gen.functions or name in getattr(Gen, '_coro_frame_types', {}):
return
self._RegisterAsyncFunc(name, Node)
# 保存外层 Gen 状态(create/resume 生成期间会切换 builder/func/variables)
saved_builder: ir.IRBuilder | None = Gen.builder
saved_func: Any = Gen.func
saved_variables: Any = Gen.variables
saved_reg_values: Any = Gen._reg_values
saved_direct_values: Any = Gen._direct_values
saved_var_signedness: Any = Gen.var_signedness
saved_var_struct_class: Any = Gen.var_struct_class
saved_var_type_info: Any = Gen.var_type_info
saved_var_type_assignments: Any = Gen.var_type_assignments
saved_var_scope_len: int = len(self.Trans.VarScopes)
saved_coro_state = {
'state_ptr': getattr(Gen, '_coro_state_ptr', None),
'done_ptr': getattr(Gen, '_coro_done_ptr', None),
'ret_ptr': getattr(Gen, '_coro_ret_field_ptr', None),
'exit_bb': getattr(Gen, '_coro_exit_bb', None),
'next_state': getattr(Gen, '_coro_next_state', None),
'await_slot': getattr(Gen, '_coro_await_slot_ptr', None),
'frame_ptr': getattr(Gen, '_coro_frame_ptr', None),
}
try:
self.Trans.VarScopes.append({})
frame_ty: ir.IdentifiedStructType = self._GetOrCreateFrameType(name, Node, Gen)
self._EmitCreateFunction(name, frame_ty, Gen)
self._EmitResumeFunction(name, Node, frame_ty, Gen)
# 符号表注册(普通名称),供 _HandleCallLlvm 的类型解析
if not self.Trans.SymbolTable.has(name):
FuncInfo: CTypeInfo = CTypeInfo()
FuncInfo.Name = name
FuncInfo.IsFunction = True
FuncInfo.file = '<stdin>'
self.Trans.SymbolTable.insert(name, FuncInfo)
self.Trans.FunctionReturnTypes[name] = CTypeInfo.FromTypeName('int')
finally:
while len(self.Trans.VarScopes) > saved_var_scope_len:
self.Trans.VarScopes.pop()
Gen.builder = saved_builder
Gen.func = saved_func
Gen.variables = saved_variables
Gen._reg_values = saved_reg_values
Gen._direct_values = saved_direct_values
Gen.var_signedness = saved_var_signedness
Gen.var_struct_class = saved_var_struct_class
Gen.var_type_info = saved_var_type_info
Gen.var_type_assignments = saved_var_type_assignments
Gen._coro_state_ptr = saved_coro_state['state_ptr']
Gen._coro_done_ptr = saved_coro_state['done_ptr']
Gen._coro_ret_field_ptr = saved_coro_state['ret_ptr']
Gen._coro_exit_bb = saved_coro_state['exit_bb']
Gen._coro_next_state = saved_coro_state['next_state']
Gen._coro_await_slot_ptr = saved_coro_state['await_slot']
Gen._coro_frame_ptr = saved_coro_state['frame_ptr']
# ------------------------------------------------------------------
# 帧结构体与局部变量收集
# ------------------------------------------------------------------
def _GetOrCreateFrameType(self, name: str, Node: ast.AsyncFunctionDef, Gen: LlvmCodeGenerator) -> ir.IdentifiedStructType:
if not hasattr(Gen, '_coro_frame_types'):
Gen._coro_frame_types = {}
if not hasattr(Gen, '_coro_local_vars'):
Gen._coro_local_vars = {}
if name in Gen._coro_frame_types:
return Gen._coro_frame_types[name]
local_names: list[str] = self._CollectLocalVars(Node)
fields: list[ir.Type] = [
ir.IntType(32), # 0: state
ir.IntType(32), # 1: done
ir.IntType(32), # 2: ret
]
for _ in local_names:
fields.append(ir.IntType(32))
frame_ty: ir.IdentifiedStructType = ir.IdentifiedStructType(Gen.module, f'Coro_{name}')
frame_ty.set_body(*fields)
Gen._coro_frame_types[name] = frame_ty
Gen._coro_local_vars[name] = local_names
return frame_ty
def _CollectLocalVars(self, Node: ast.AsyncFunctionDef) -> list[str]:
"""收集协程体内顶层 AnnAssign/Assign 的 Name 目标(M1 仅 i32 槽)。"""
names: list[str] = []
seen: set[str] = set()
for stmt in Node.body:
target: str | None = None
if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.target, ast.Name):
target = stmt.target.id
elif (isinstance(stmt, ast.Assign)
and len(stmt.targets) == 1
and isinstance(stmt.targets[0], ast.Name)):
target = stmt.targets[0].id
if target is not None and target not in seen:
seen.add(target)
names.append(target)
return names
# ------------------------------------------------------------------
# create_<name>() -> %Coro_<name>*
# ------------------------------------------------------------------
def _GetMalloc(self, Gen: LlvmCodeGenerator) -> ir.Function:
for fn in Gen.module.global_values:
if getattr(fn, 'name', None) == 'malloc':
return fn
malloc_ty: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
fn: ir.Function = ir.Function(Gen.module, malloc_ty, name='malloc')
Gen.functions['malloc'] = fn
return fn
def _RegisterCoroFunction(self, Gen: LlvmCodeGenerator, raw_name: str, fn: ir.Function) -> None:
"""按 _EmitFunctionForwardDeclLlvm 惯例注册 create_/resume_ 函数。"""
mangled: str = Gen._mangle_func_name(raw_name)
Gen.functions[mangled] = fn
if mangled == raw_name or raw_name not in Gen._export_extern_funcs:
Gen.functions[raw_name] = fn
def _EmitCreateFunction(self, name: str, frame_ty: ir.IdentifiedStructType, Gen: LlvmCodeGenerator) -> None:
malloc_fn: ir.Function = self._GetMalloc(Gen)
frame_size: int = Gen._get_struct_size(frame_ty)
create_ty: ir.FunctionType = ir.FunctionType(ir.PointerType(frame_ty), [])
create_fn: ir.Function = ir.Function(Gen.module, create_ty, name=Gen._mangle_func_name(f'create_{name}'))
self._RegisterCoroFunction(Gen, f'create_{name}', create_fn)
create_fn.attributes.add('noredzone')
entry: ir.Block = create_fn.append_basic_block('entry')
Gen.builder = ir.IRBuilder(entry)
Gen.func = create_fn
raw: ir.Value = Gen.builder.call(malloc_fn, [ir.Constant(ir.IntType(64), frame_size)], name='frame_raw')
frame_ptr: ir.Value = Gen.builder.bitcast(raw, ir.PointerType(frame_ty), name='frame')
zero32: ir.Constant = ir.Constant(ir.IntType(32), 0)
for i in range(3):
slot_ptr: ir.Value = Gen.builder.gep(frame_ptr, [zero32, ir.Constant(ir.IntType(32), i)], name=f'init_slot{i}')
Gen._store(zero32, slot_ptr)
Gen.builder.ret(frame_ptr)
Gen.builder = None
Gen.func = None
# ------------------------------------------------------------------
# resume_<name>(%Coro_<name>*) -> i32 状态机
# ------------------------------------------------------------------
def _SplitBody(self, body: list[ast.stmt]) -> list[list[ast.stmt]]:
"""按顶层 await 切分函数体。
await 仅识别 AnnAssign.value / Assign.value(Name 目标)顶层形式;
含 await 的语句作为所在段的最后一条(翻译后 br exit 挂起)。
"""
segments: list[list[ast.stmt]] = []
current: list[ast.stmt] = []
for stmt in body:
has_await: bool = False
if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.value, ast.Await):
has_await = True
elif (isinstance(stmt, ast.Assign)
and len(stmt.targets) == 1
and isinstance(stmt.targets[0], ast.Name)
and isinstance(stmt.value, ast.Await)):
has_await = True
current.append(stmt)
if has_await:
segments.append(current)
current = []
if current:
segments.append(current)
return segments
def _EmitResumeFunction(self, name: str, Node: ast.AsyncFunctionDef, frame_ty: ir.IdentifiedStructType, Gen: LlvmCodeGenerator) -> None:
resume_ty: ir.FunctionType = ir.FunctionType(ir.IntType(32), [ir.PointerType(frame_ty)])
resume_fn: ir.Function = ir.Function(Gen.module, resume_ty, name=Gen._mangle_func_name(f'resume_{name}'))
self._RegisterCoroFunction(Gen, f'resume_{name}', resume_fn)
resume_fn.attributes.add('noredzone')
Gen.func = resume_fn
segments: list[list[ast.stmt]] = self._SplitBody(Node.body)
entry: ir.Block = resume_fn.append_basic_block('entry')
Gen.builder = ir.IRBuilder(entry)
frame_arg: ir.Argument = resume_fn.args[0]
frame_arg.name = 'frame'
zero32: ir.Constant = ir.Constant(ir.IntType(32), 0)
one32: ir.Constant = ir.Constant(ir.IntType(32), 1)
two32: ir.Constant = ir.Constant(ir.IntType(32), 2)
state_ptr: ir.Value = Gen.builder.gep(frame_arg, [zero32, zero32], name='state_ptr')
done_ptr: ir.Value = Gen.builder.gep(frame_arg, [zero32, one32], name='done_ptr')
ret_ptr: ir.Value = Gen.builder.gep(frame_arg, [zero32, two32], name='ret_ptr')
# 局部变量槽 → Gen.variables(读取/写入自动走帧字段 GEP)
local_slot_ptrs: dict[str, ir.Value] = {}
for idx, var in enumerate(Gen._coro_local_vars.get(name, [])):
slot_ptr: ir.Value = Gen.builder.gep(
frame_arg,
[zero32, ir.Constant(ir.IntType(32), 3 + idx)],
name=f'{var}_slot',
)
local_slot_ptrs[var] = slot_ptr
state_val: ir.Value = Gen._load(state_ptr, name='state')
exit_bb: ir.Block = resume_fn.append_basic_block('coro_exit')
Gen._coro_state_ptr = state_ptr
Gen._coro_done_ptr = done_ptr
Gen._coro_ret_field_ptr = ret_ptr
Gen._coro_exit_bb = exit_bb
Gen._coro_frame_ptr = frame_arg
switch_instr: Any = Gen.builder.switch(state_val, exit_bb)
state_bbs: list[ir.Block] = []
for i in range(len(segments)):
bb: ir.Block = resume_fn.append_basic_block(f'state{i}')
state_bbs.append(bb)
switch_instr.add_case(ir.Constant(ir.IntType(32), i), bb)
# 逐段生成
for i, seg in enumerate(segments):
Gen.builder.position_at_start(state_bbs[i])
Gen.variables = dict(local_slot_ptrs)
Gen._coro_next_state = i + 1
self._HandleCoroSegment(seg, Gen)
if Gen.builder is not None and not Gen.builder.block.is_terminated:
self._EmitCoroImplicitReturn(Gen)
# 完成块:返回 done(0=SUSPEND 1=DONE)
Gen.builder.position_at_start(exit_bb)
done_val: ir.Value = Gen._load(done_ptr, name='done')
Gen.builder.ret(done_val)
Gen.builder = None
Gen.func = None
# ------------------------------------------------------------------
# 协程体段翻译
# ------------------------------------------------------------------
def _HandleCoroSegment(self, stmts: list[ast.stmt], Gen: LlvmCodeGenerator) -> None:
for stmt in stmts:
if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.value, ast.Await):
self._HandleCoroAwaitAnnAssign(stmt, Gen)
return
if (isinstance(stmt, ast.Assign)
and len(stmt.targets) == 1
and isinstance(stmt.targets[0], ast.Name)
and isinstance(stmt.value, ast.Await)):
self._HandleCoroAwaitAssign(stmt, Gen)
return
if isinstance(stmt, ast.Return):
self._HandleCoroReturn(stmt, Gen)
return
# M1 防御:await 仅支持顶层(AnnAssign/Assign 的 value 直接是 Await)
if any(isinstance(n, ast.Await) for n in ast.walk(stmt)):
raise SyntaxError(
f"[coro-M1] await 仅支持顶层赋值形式 `var: int = await fn()` "
f"(line {getattr(stmt, 'lineno', 0)})"
)
if isinstance(stmt, ast.AnnAssign):
self.Trans.AnnAssignHandler._HandleAnnAssignLlvm(stmt)
continue
if isinstance(stmt, ast.Assign):
self.Trans.AssignHandler._HandleAssignLlvm(stmt)
continue
if isinstance(stmt, ast.Expr):
self.Trans.ExprHandler.HandleExprLlvm(stmt.value)
continue
raise SyntaxError(
f"[coro-M1] async 函数体暂不支持语句: {type(stmt).__name__} "
f"(line {getattr(stmt, 'lineno', 0)})"
)
def _HandleCoroAwaitAnnAssign(self, stmt: ast.AnnAssign, Gen: LlvmCodeGenerator) -> None:
target: str = stmt.target.id
self._HandleCoroAwaitCommon(target, stmt.value, Gen)
# 注册作用域信息(模拟 AnnAssignHandler 的局部变量路径)
TypeInfo: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(stmt.annotation)
if TypeInfo is None:
TypeInfo = CTypeInfo()
TypeInfo.BaseType = t.CInt()
if self.Trans.VarScopes:
self.Trans.VarScopes[-1][target] = TypeInfo
Gen._record_var_signedness(target, False)
def _HandleCoroAwaitAssign(self, stmt: ast.Assign, Gen: LlvmCodeGenerator) -> None:
target: str = stmt.targets[0].id
self._HandleCoroAwaitCommon(target, stmt.value, Gen)
Gen._record_var_signedness(target, False)
def _HandleCoroAwaitCommon(self, target: str, await_node: ast.Await, Gen: LlvmCodeGenerator) -> None:
"""await 顶层翻译:设置目标槽后调用 _HandleAwaitLlvm(生成子帧/resume/挂起)。"""
Gen._coro_await_slot_ptr = Gen.variables.get(target)
# 校验 await 目标必须是 async 函数调用,且子协程已生成
call: Any = await_node.value
async_name: str | None = self._GetAsyncCallName(call) if isinstance(call, ast.Call) else None
if not async_name:
raise SyntaxError(
f"[coro-M1] await 目标必须是 async 函数调用 (line {getattr(await_node, 'lineno', 0)})"
)
self.Trans.ExprHandler.HandleExprLlvm(await_node) # → _HandleAwaitLlvm
def _HandleAwaitLlvm(self, Node: ast.Await, Gen: LlvmCodeGenerator) -> ir.Value:
"""await 表达式翻译:
创建子帧 -> resume 到 DONE(M1 假设一次完成)-> 取子帧 ret -> 存父帧槽 -> 父挂起。
"""
zero32: ir.Constant = ir.Constant(ir.IntType(32), 0)
call: Any = Node.value
async_name: str | None = self._GetAsyncCallName(call) if isinstance(call, ast.Call) else None
if not async_name:
return zero32
frame_ty: ir.IdentifiedStructType | None = getattr(Gen, '_coro_frame_types', {}).get(async_name)
create_fn: ir.Function | None = Gen._get_function(f'create_{async_name}')
resume_fn: ir.Function | None = Gen._get_function(f'resume_{async_name}')
if not frame_ty or not create_fn or not resume_fn:
return zero32
child: ir.Value = Gen.builder.call(create_fn, [], name=f'create_{async_name}')
Gen.builder.call(resume_fn, [child], name=f'resume_{async_name}')
child_ret_ptr: ir.Value = Gen.builder.gep(
child,
[zero32, ir.Constant(ir.IntType(32), 2)],
name='child_ret_ptr',
)
child_ret: ir.Value = Gen._load(child_ret_ptr, name='child_ret')
# 存父帧局部变量槽
slot: ir.Value | None = getattr(Gen, '_coro_await_slot_ptr', None)
if slot is not None:
Gen._store(child_ret, slot)
# 父挂起:state = 下一切片,ret = 0(SUSPEND)
state_ptr: ir.Value | None = getattr(Gen, '_coro_state_ptr', None)
if state_ptr is not None:
Gen._store(ir.Constant(ir.IntType(32), getattr(Gen, '_coro_next_state', 1)), state_ptr)
ret_field_ptr: ir.Value | None = getattr(Gen, '_coro_ret_field_ptr', None)
if ret_field_ptr is not None:
Gen._store(zero32, ret_field_ptr)
exit_bb: ir.Block | None = getattr(Gen, '_coro_exit_bb', None)
if exit_bb is not None:
Gen.builder.branch(exit_bb)
return child_ret
def _HandleCoroReturn(self, stmt: ast.Return, Gen: LlvmCodeGenerator) -> None:
val: ir.Value | None = None
if stmt.value:
val = self.Trans.ExprHandler.HandleExprLlvm(stmt.value)
if val is None:
val = ir.Constant(ir.IntType(32), 0)
if isinstance(val.type, ir.IntType) and val.type.width != 32:
if val.type.width < 32:
val = Gen.builder.zext(val, ir.IntType(32), name='zext_coro_ret')
else:
val = Gen.builder.trunc(val, ir.IntType(32), name='trunc_coro_ret')
Gen._store(val, Gen._coro_ret_field_ptr)
Gen._store(ir.Constant(ir.IntType(32), 1), Gen._coro_done_ptr)
Gen.builder.branch(Gen._coro_exit_bb)
def _EmitCoroImplicitReturn(self, Gen: LlvmCodeGenerator) -> None:
"""函数体自然结束:同 return 路径(ret=0 + done=1)。"""
Gen._store(ir.Constant(ir.IntType(32), 0), Gen._coro_ret_field_ptr)
Gen._store(ir.Constant(ir.IntType(32), 1), Gen._coro_done_ptr)
Gen.builder.branch(Gen._coro_exit_bb)
# ------------------------------------------------------------------
# 普通函数调用 async 函数:task() -> create_task()(返回帧指针)
# ------------------------------------------------------------------
def _HandleAsyncCreateCallLlvm(self, Node: ast.Call, FuncName: str) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
create_fn: ir.Function | None = Gen._get_function(f'create_{FuncName}')
if not create_fn:
return ir.Constant(ir.IntType(32), 0)
result: ir.Value = Gen.builder.call(create_fn, [], name=f'create_{FuncName}')
return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name='coro_frame_i8ptr')
# ------------------------------------------------------------------
# coro.coro_run(帧) 内联翻译(M1)
# ------------------------------------------------------------------
def _HandleCoroRunLlvm(self, Node: ast.Call, Gen: LlvmCodeGenerator) -> ir.Value:
if not Node.args:
return ir.Constant(ir.IntType(32), 0)
arg: ast.expr = Node.args[0]
async_name: str | None = None
if isinstance(arg, ast.Name):
async_name = getattr(Gen, '_coro_var_async', {}).get(arg.id)
if not async_name:
return ir.Constant(ir.IntType(32), 0)
frame_ty: ir.IdentifiedStructType | None = getattr(Gen, '_coro_frame_types', {}).get(async_name)
resume_fn: ir.Function | None = Gen._get_function(f'resume_{async_name}')
if not frame_ty or not resume_fn:
return ir.Constant(ir.IntType(32), 0)
frame_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(arg)
if frame_val is None:
return ir.Constant(ir.IntType(32), 0)
if isinstance(frame_val.type, ir.PointerType):
frame_ptr: ir.Value = Gen.builder.bitcast(frame_val, ir.PointerType(frame_ty), name='coro_frame')
elif isinstance(frame_val.type, ir.IntType):
frame_ptr = Gen.builder.inttoptr(frame_val, ir.PointerType(frame_ty), name='coro_frame')
else:
return ir.Constant(ir.IntType(32), 0)
loop_bb: ir.Block = Gen.func.append_basic_block('coro_loop')
after_bb: ir.Block = Gen.func.append_basic_block('coro_after')
Gen.builder.branch(loop_bb)
Gen.builder.position_at_start(loop_bb)
status: ir.Value = Gen.builder.call(resume_fn, [frame_ptr], name=f'resume_{async_name}')
done_cond: ir.Value = Gen.builder.icmp_signed('!=', status, ir.Constant(ir.IntType(32), 0), name='coro_done_cond')
Gen.builder.cbranch(done_cond, after_bb, loop_bb)
Gen.builder.position_at_start(after_bb)
ret_ptr: ir.Value = Gen.builder.gep(
frame_ptr,
[ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 2)],
name='coro_ret_ptr',
)
return Gen._load(ret_ptr, name='coro_result')