Files
TransPyC/lib/core/Handles/HandlesAsyncFunctions.py
T
TermiNexus 3acf24c7d0 feat(coro): M3——For 内 await、coro_sleep 挂起、coro_destroy 释放帧
- For 内 await:range 迭代变换为 While(__f_idx_N/__f_len_N 帧槽),复用协程版 While
  就地挂起/恢复;For 迭代目标进帧槽跨挂起存活;仅支持 range 1/2 参数
- coro_sleep(ms):帧加 __coro_wake_us(i64)唤醒槽,挂起后 coro_run 轮询
  GetTickCount64,未到点 Sleep(1) 续轮询,到点自动恢复
- coro_destroy(帧):coro.coro_destroy 内联翻译为 free 释放帧内存
- coro.vp 追加 coro_sleep/coro_destroy 占位;CoroTest 用例覆盖
  for+await/sleep/destroy(期望 coro result = 15)
2026-08-21 14:17:27 +08:00

977 lines
50 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):
"""语言内协程 M3:async def + await + coro_run 状态机翻译。
M3 在 M2 基础上扩展:
- For 内 await:range 迭代变换为 While(__f_idx_N/__f_len_N 帧槽),复用协程版 While。
- coro_sleep(ms):帧加 wake 槽(i64),挂起后 coro_run 轮询 GetTickCount64 到点续跑。
- coro_destroy(帧):释放帧内存(free)。
M2 能力:async 参数、嵌套 await 提升(__await_N 槽)、If/While 控制流、动态状态号恢复块。
帧布局:%Coro_<name> = type { i32 state, i32 done, i32 ret, <参数槽>, <局部槽>, <额外槽(wake/for/await)> }
状态机:create_<name>(args...) 分配帧 + 存参数;resume_<name>(frame) -> i32
(0=SUSPEND 1=DONE)按 state 分发到主入口 state0 与各恢复块。
"""
# ------------------------------------------------------------------
# 公共查询
# ------------------------------------------------------------------
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
# 防重复生成:模块可能被多次编译(泛型特化等触发),避免 create_/resume_ 重名
if f'create_{name}' in Gen.functions or name in getattr(Gen, '_coro_frame_types', {}):
return
self._RegisterAsyncFunc(name, Node)
# 预扫描额外槽(嵌套 await 临时变量 + For 索引/上限 + coro_sleep 唤醒槽)
extra_slots: list[str] = self._PreScanExtraSlots(Node, Gen)
if not hasattr(Gen, '_coro_extra_slots'):
Gen._coro_extra_slots = {}
Gen._coro_extra_slots[name] = extra_slots
# 保存外层 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_loop_len: int = len(Gen.loop_break_targets)
saved_cont_len: int = len(Gen.loop_continue_targets)
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),
'switch': getattr(Gen, '_coro_switch_instr', None),
'state_counter': getattr(Gen, '_coro_state_counter', None),
'hoist_counter': getattr(Gen, '_coro_hoist_counter', None),
'for_counter': getattr(Gen, '_coro_for_counter', None),
'wake_ptr': getattr(Gen, '_coro_wake_ptr', None),
}
try:
self.Trans.VarScopes.append({})
frame_ty: ir.IdentifiedStructType = self._GetOrCreateFrameType(name, Node, Gen, extra_slots)
Gen._coro_hoist_counter = 0
Gen._coro_for_counter = 0
self._EmitCreateFunction(name, Node, 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()
del Gen.loop_break_targets[saved_loop_len:]
del Gen.loop_continue_targets[saved_cont_len:]
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']
Gen._coro_switch_instr = saved_coro_state['switch']
Gen._coro_state_counter = saved_coro_state['state_counter']
Gen._coro_hoist_counter = saved_coro_state['hoist_counter']
Gen._coro_for_counter = saved_coro_state['for_counter']
Gen._coro_wake_ptr = saved_coro_state['wake_ptr']
# ------------------------------------------------------------------
# 帧结构体与局部变量收集
# ------------------------------------------------------------------
def _ResolveSlotType(self, annotation: ast.expr | None, Gen: LlvmCodeGenerator) -> ir.Type:
"""从注解推断帧槽 LLVM 类型;失败/void/结构体值一律按安全标量处理。"""
if annotation is None:
return ir.IntType(32)
try:
TypeInfo: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(annotation)
except Exception:
TypeInfo = None
if TypeInfo is None:
return ir.IntType(32)
try:
llvm_ty: ir.Type | None = TypeInfo.ToLLVM(Gen)
except Exception:
return ir.IntType(32)
if llvm_ty is None or isinstance(llvm_ty, ir.VoidType):
return ir.IntType(32)
if isinstance(llvm_ty, ir.IdentifiedStructType):
llvm_ty = ir.PointerType(llvm_ty)
return llvm_ty
def _CollectFrameVars(self, Node: ast.AsyncFunctionDef, Gen: LlvmCodeGenerator) -> list[tuple[str, ir.Type]]:
"""递归收集协程体内所有 AnnAssign/Assign 的 Name 目标及其槽类型(含控制流内部)。"""
vars_: list[tuple[str, ir.Type]] = []
seen: set[str] = set()
def _walk(stmts: list[ast.stmt]) -> None:
for stmt in stmts:
if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.target, ast.Name):
target: str = stmt.target.id
slot_ty: ir.Type = self._ResolveSlotType(stmt.annotation, Gen)
elif (isinstance(stmt, ast.Assign)
and len(stmt.targets) == 1
and isinstance(stmt.targets[0], ast.Name)):
target = stmt.targets[0].id
slot_ty = ir.IntType(32)
elif isinstance(stmt, ast.For):
# For 迭代目标进帧槽(协程版 For 变换后跨挂起存活)
if isinstance(stmt.target, ast.Name):
_tname: str = stmt.target.id
if _tname not in seen:
seen.add(_tname)
vars_.append((_tname, ir.IntType(32)))
_walk(stmt.body)
if stmt.orelse:
_walk(stmt.orelse)
continue
elif isinstance(stmt, (ast.If, ast.While)):
_walk(stmt.body)
if stmt.orelse:
_walk(stmt.orelse)
continue
else:
continue
if target not in seen:
seen.add(target)
vars_.append((target, slot_ty))
_walk(Node.body)
return vars_
def _GetOrCreateFrameType(self, name: str, Node: ast.AsyncFunctionDef, Gen: LlvmCodeGenerator, extra_slots: list[str]) -> ir.IdentifiedStructType:
if not hasattr(Gen, '_coro_frame_types'):
Gen._coro_frame_types = {}
if not hasattr(Gen, '_coro_slot_vars'):
Gen._coro_slot_vars = {}
if not hasattr(Gen, '_coro_param_vars'):
Gen._coro_param_vars = {}
if name in Gen._coro_frame_types:
return Gen._coro_frame_types[name]
# 参数:名字 + LLVM 类型
params: list[tuple[str, ir.Type]] = []
for a in Node.args.args:
pname: str = a.arg
pty: ir.Type = self._ResolveSlotType(a.annotation, Gen)
params.append((pname, pty))
locals_: list[tuple[str, ir.Type]] = self._CollectFrameVars(Node, Gen)
param_names: set[str] = {p for p, _ in params}
# 额外槽:__coro_wake_us(i64) / __f_idx_N/__f_len_N / __await_N(i32)
fields: list[ir.Type] = [
ir.IntType(32), # 0: state
ir.IntType(32), # 1: done
ir.IntType(32), # 2: ret
]
slot_vars: list[str] = []
for pname, pty in params:
fields.append(pty)
slot_vars.append(pname)
for lname, lty in locals_:
if lname in param_names or lname in slot_vars:
continue
fields.append(lty)
slot_vars.append(lname)
for sname in extra_slots:
fields.append(ir.IntType(64) if sname == '__coro_wake_us' else ir.IntType(32))
slot_vars.append(sname)
frame_ty: ir.IdentifiedStructType = ir.IdentifiedStructType(Gen.module, f'Coro_{name}')
frame_ty.set_body(*fields)
Gen._coro_frame_types[name] = frame_ty
Gen.structs[f'Coro_{name}'] = frame_ty
Gen._coro_slot_vars[name] = slot_vars
Gen._coro_param_vars[name] = params
return frame_ty
# ------------------------------------------------------------------
# 预扫描:嵌套 await 提升(分配 __await_N 临时槽)
# ------------------------------------------------------------------
def _PreScanExtraSlots(self, Node: ast.AsyncFunctionDef, Gen: LlvmCodeGenerator) -> list[str]:
"""按 DFS 顺序收集额外帧槽名(与翻译端分配顺序一致):
- __coro_wake_us:函数体使用 coro_sleep 时置首位(i64 槽)
- __f_idx_N / __f_len_N:range-For(body 含 await)的迭代索引/上限
- __await_N:嵌套 await 提升临时变量
"""
slots: list[str] = []
await_counter: int = 0
for_counter: int = 0
uses_sleep: list[bool] = [False]
def _walk(stmts: list[ast.stmt]) -> None:
for stmt in stmts:
if isinstance(stmt, (ast.If, ast.While)):
_walk(stmt.body)
if stmt.orelse:
_walk(stmt.orelse)
continue
if isinstance(stmt, ast.For):
if not any(isinstance(n, ast.Await) for n in ast.walk(stmt)):
continue # 无 await:委托 ForHandler,不需额外槽
if not self._IsRangeFor(stmt):
raise SyntaxError(
f"[coro-M3] 协程内 For 仅支持 range 迭代(含 await)"
f"(line {getattr(stmt, 'lineno', 0)})"
)
slots.append(f'__f_idx_{for_counter}')
slots.append(f'__f_len_{for_counter}')
for_counter += 1
_walk(stmt.body)
continue
# 顶层 await(value 直接是 Await)不提升,但仍检测 coro_sleep
if (isinstance(stmt, ast.AnnAssign) and isinstance(stmt.value, ast.Await)) or (
isinstance(stmt, ast.Assign)
and len(stmt.targets) == 1
and isinstance(stmt.targets[0], ast.Name)
and isinstance(stmt.value, ast.Await)) or (
isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Await)):
for _n in ast.walk(stmt):
if isinstance(_n, ast.Call) and self._IsCoroSleepCall(_n):
uses_sleep[0] = True
continue
for n in ast.walk(stmt):
if isinstance(n, ast.Await):
slots.append(f'__await_{await_counter}')
await_counter += 1
if isinstance(n, ast.Call) and self._IsCoroSleepCall(n):
uses_sleep[0] = True
_walk(Node.body)
if uses_sleep[0]:
slots.insert(0, '__coro_wake_us')
return slots
# ------------------------------------------------------------------
# create_<name>(args...) -> %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, Node: ast.AsyncFunctionDef, frame_ty: ir.IdentifiedStructType, Gen: LlvmCodeGenerator) -> None:
malloc_fn: ir.Function = self._GetMalloc(Gen)
frame_size: int = Gen._get_struct_size(frame_ty)
params: list[tuple[str, ir.Type]] = getattr(Gen, '_coro_param_vars', {}).get(name, [])
param_tys: list[ir.Type] = [ty for _, ty in params]
create_ty: ir.FunctionType = ir.FunctionType(ir.PointerType(frame_ty), param_tys)
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)
# 参数存入帧槽(3 + i)
for i in range(len(params)):
slot_ptr = Gen.builder.gep(frame_ptr, [zero32, ir.Constant(ir.IntType(32), 3 + i)], name=f'param{i}_slot')
arg_val: ir.Argument = create_fn.args[i]
arg_val.name = f'arg{i}'
Gen._store(arg_val, slot_ptr)
Gen.builder.ret(frame_ptr)
Gen.builder = None
Gen.func = None
# ------------------------------------------------------------------
# resume_<name>(%Coro_<name>*) -> i32 状态机(动态状态号)
# ------------------------------------------------------------------
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
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] = {}
slot_vars: list[str] = getattr(Gen, '_coro_slot_vars', {}).get(name, [])
for idx, var in enumerate(slot_vars):
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
if var == '__coro_wake_us':
Gen._coro_wake_ptr = 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)
Gen._coro_switch_instr = switch_instr
Gen._coro_state_counter = 1
state0: ir.Block = resume_fn.append_basic_block('state0')
switch_instr.add_case(ir.Constant(ir.IntType(32), 0), state0)
# 主入口:翻译整个函数体(If/While 内 await 会动态分配恢复块)
Gen.builder.position_at_start(state0)
Gen.variables = dict(local_slot_ptrs)
self._HandleCoroSegment(Node.body, 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 Gen.builder is None or Gen.builder.block.is_terminated:
return
Gen._set_node_info(stmt)
if isinstance(stmt, ast.Return):
self._HandleCoroReturn(stmt, Gen)
continue
if (isinstance(stmt, ast.AnnAssign)
and isinstance(stmt.target, ast.Name)
and isinstance(stmt.value, ast.Await)):
self._HandleCoroAwaitAnnAssign(stmt, Gen)
continue
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)
continue
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Await):
self._HandleCoroAwaitCommon('__discard__', stmt.value, Gen)
continue
if isinstance(stmt, ast.If):
self._HandleCoroIf(stmt, Gen)
continue
if isinstance(stmt, ast.While):
self._HandleCoroWhile(stmt, Gen)
continue
if isinstance(stmt, ast.For):
self._HandleCoroFor(stmt, Gen)
continue
if isinstance(stmt, ast.Break):
if Gen.loop_break_targets:
Gen.builder.branch(Gen.loop_break_targets[-1])
continue
if isinstance(stmt, ast.Continue):
if Gen.loop_continue_targets:
Gen.builder.branch(Gen.loop_continue_targets[-1])
continue
if isinstance(stmt, ast.Pass):
continue
# 语句内嵌套 await(非顶层)→ 提升
if any(isinstance(n, ast.Await) for n in ast.walk(stmt)):
self._HandleNestedAwaitStmt(stmt, Gen)
continue
self._TranslateOrdinaryStmt(stmt, Gen)
def _TranslateOrdinaryStmt(self, stmt: ast.stmt, Gen: LlvmCodeGenerator) -> None:
if isinstance(stmt, ast.AnnAssign):
self.Trans.AnnAssignHandler._HandleAnnAssignLlvm(stmt)
return
if isinstance(stmt, ast.Assign):
self.Trans.AssignHandler._HandleAssignLlvm(stmt)
return
if isinstance(stmt, ast.Expr):
self.Trans.ExprHandler.HandleExprLlvm(stmt.value)
return
raise SyntaxError(
f"[coro-M2] async 函数体暂不支持语句: {type(stmt).__name__} "
f"(line {getattr(stmt, 'lineno', 0)})"
)
# ------------------------------------------------------------------
# 嵌套 await 提升:a = b + await f() → __await_N = await f(); a = b + __await_N
# ------------------------------------------------------------------
def _FindFirstAwait(self, node: ast.AST) -> ast.Await | None:
for n in ast.walk(node):
if isinstance(n, ast.Await):
return n
return None
def _ReplaceAwaitWithName(self, node: ast.AST, temp_name: str) -> bool:
"""把语句树中第一个 Await 替换为 Name(temp_name, Load)(DFS 顺序)。"""
for field in node._fields:
val: Any = getattr(node, field, None)
if isinstance(val, ast.Await):
setattr(node, field, ast.Name(temp_name, ast.Load()))
return True
if isinstance(val, list):
for i, item in enumerate(val):
if isinstance(item, ast.Await):
val[i] = ast.Name(temp_name, ast.Load())
return True
if isinstance(item, ast.AST):
if self._ReplaceAwaitWithName(item, temp_name):
return True
elif isinstance(val, ast.AST):
if self._ReplaceAwaitWithName(val, temp_name):
return True
return False
def _HandleNestedAwaitStmt(self, stmt: ast.stmt, Gen: LlvmCodeGenerator) -> None:
"""把语句中所有嵌套 await 提升为顶层临时赋值(与预扫描顺序一致)。"""
counter: int = getattr(Gen, '_coro_hoist_counter', 0)
while True:
await_node: ast.Await | None = self._FindFirstAwait(stmt)
if await_node is None:
break
temp_name: str = f'__await_{counter}'
counter += 1
hoisted: ast.Assign = ast.Assign(
targets=[ast.Name(temp_name, ast.Store())],
value=await_node,
type_comment=None,
)
# 提升赋值挂起 + position 到恢复块
self._HandleCoroAwaitAssign(hoisted, Gen)
self._ReplaceAwaitWithName(stmt, temp_name)
Gen._coro_hoist_counter = counter
self._TranslateOrdinaryStmt(stmt, Gen)
# ------------------------------------------------------------------
# await 表达式翻译
# ------------------------------------------------------------------
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 函数调用 或 coro_sleep(ms)
call: Any = await_node.value
if isinstance(call, ast.Call) and self._IsCoroSleepCall(call):
self.Trans.ExprHandler.HandleExprLlvm(await_node) # → _HandleAwaitLlvm(sleep)
return
async_name: str | None = self._GetAsyncCallName(call) if isinstance(call, ast.Call) else None
if not async_name:
raise SyntaxError(
f"[coro-M3] await 目标必须是 async 函数调用或 coro_sleep(ms) "
f"(line {getattr(await_node, 'lineno', 0)})"
)
self.Trans.ExprHandler.HandleExprLlvm(await_node) # → _HandleAwaitLlvm
def _IsCoroSleepCall(self, call: ast.Call) -> bool:
return (isinstance(call.func, ast.Name) and call.func.id == 'coro_sleep') or (
isinstance(call.func, ast.Attribute)
and call.func.attr == 'coro_sleep'
and isinstance(call.func.value, ast.Name)
and self._IsCoroModule(call.func.value.id)
)
def _GetWinFunc(self, name: str, Gen: LlvmCodeGenerator, ret_ty: ir.Type,
args: list[ir.Type] | None = None) -> ir.Function:
fn: ir.Function | None = Gen._get_function(name)
if fn is not None:
return fn
fn = ir.Function(Gen.module, ir.FunctionType(ret_ty, args or []), name=name)
Gen.functions[name] = fn
return fn
def _GetFree(self, Gen: LlvmCodeGenerator) -> ir.Function:
for fn in Gen.module.global_values:
if getattr(fn, 'name', None) == 'free':
return fn
fn = ir.Function(Gen.module, ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]), name='free')
Gen.functions['free'] = fn
return fn
def _HandleAwaitSleepLlvm(self, call: ast.Call, Gen: LlvmCodeGenerator) -> ir.Value:
"""await coro_sleep(ms):wake = GetTickCount64() + ms 存帧,挂起(coro_run 轮询续跑)。"""
zero32: ir.Constant = ir.Constant(ir.IntType(32), 0)
ms_val: ir.Value = ir.Constant(ir.IntType(64), 0)
if call.args:
ms_v: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(call.args[0])
if ms_v is not None and isinstance(ms_v.type, ir.IntType):
if ms_v.type.width < 64:
ms_val = Gen.builder.zext(ms_v, ir.IntType(64), name='zext_sleep_ms')
elif ms_v.type.width > 64:
ms_val = Gen.builder.trunc(ms_v, ir.IntType(64), name='trunc_sleep_ms')
else:
ms_val = ms_v
now_fn: ir.Function = self._GetWinFunc('GetTickCount64', Gen, ir.IntType(64))
now_val: ir.Value = Gen.builder.call(now_fn, [], name='tick_now')
wake_val: ir.Value = Gen.builder.add(now_val, ms_val, name='coro_wake_us')
wake_ptr: ir.Value | None = getattr(Gen, '_coro_wake_ptr', None)
if wake_ptr is not None:
Gen._store(wake_val, wake_ptr)
# 挂起:分配恢复块 + state + ret=0 + br exit + position 恢复块
state_no: int = getattr(Gen, '_coro_state_counter', 1)
Gen._coro_state_counter = state_no + 1
resume_bb: ir.Block = Gen.func.append_basic_block(f'state{state_no}')
switch_instr: Any = getattr(Gen, '_coro_switch_instr', None)
if switch_instr is not None:
switch_instr.add_case(ir.Constant(ir.IntType(32), state_no), resume_bb)
state_ptr: ir.Value | None = getattr(Gen, '_coro_state_ptr', None)
if state_ptr is not None:
Gen._store(ir.Constant(ir.IntType(32), state_no), 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)
Gen.builder.position_at_start(resume_bb)
return zero32
def _HandleCoroDestroyLlvm(self, Node: ast.Call, Gen: LlvmCodeGenerator) -> ir.Value:
"""coro.coro_destroy(帧):释放帧内存(free)。"""
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)
if not frame_ty:
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)
free_fn: ir.Function = self._GetFree(Gen)
raw: ir.Value = Gen.builder.bitcast(frame_ptr, ir.IntType(8).as_pointer(), name='coro_free_ptr')
Gen.builder.call(free_fn, [raw])
return ir.Constant(ir.IntType(32), 0)
def _CoerceArg(self, v: ir.Value | None, target_ty: ir.Type, Gen: LlvmCodeGenerator, name: str = 'arg') -> ir.Value:
"""实参转换到 create 形参类型(int 宽转换 / 指针 bitcast)。"""
if v is None:
if isinstance(target_ty, ir.IntType):
return ir.Constant(target_ty, 0)
return ir.Constant(target_ty, None)
src_ty: ir.Type = v.type
if src_ty == target_ty:
return v
if isinstance(src_ty, ir.IntType) and isinstance(target_ty, ir.IntType):
if src_ty.width < target_ty.width:
return Gen.builder.zext(v, target_ty, name=f'zext_{name}')
if src_ty.width > target_ty.width:
return Gen.builder.trunc(v, target_ty, name=f'trunc_{name}')
return v
if isinstance(src_ty, ir.PointerType) and isinstance(target_ty, ir.PointerType):
return Gen.builder.bitcast(v, target_ty, name=f'bitcast_{name}')
return v
def _HandleAwaitLlvm(self, Node: ast.Await, Gen: LlvmCodeGenerator) -> ir.Value:
"""await 表达式翻译:
创建子帧(含参数)-> resume 到 DONE -> 取子帧 ret -> 存父帧槽
-> 父挂起(state=新恢复块编号、ret=0)-> position 到恢复块继续。
"""
zero32: ir.Constant = ir.Constant(ir.IntType(32), 0)
call: Any = Node.value
# M3: await coro_sleep(ms) —— 挂起到指定时刻(帧 wake 槽)
if isinstance(call, ast.Call) and self._IsCoroSleepCall(call):
return self._HandleAwaitSleepLlvm(call, Gen)
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
# 子协程参数
call_args: list[ir.Value] = []
if call.args:
param_info: list[tuple[str, ir.Type]] = getattr(Gen, '_coro_param_vars', {}).get(async_name, [])
for i, arg_node in enumerate(call.args):
arg_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(arg_node)
if i < len(param_info):
arg_val = self._CoerceArg(arg_val, param_info[i][1], Gen, name=f'arg{i}')
call_args.append(arg_val)
child: ir.Value = Gen.builder.call(create_fn, call_args, 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)
# 父挂起:分配新恢复块(switch case),state=新块编号,ret=0(SUSPEND)
state_no: int = getattr(Gen, '_coro_state_counter', 1)
Gen._coro_state_counter = state_no + 1
resume_bb: ir.Block = Gen.func.append_basic_block(f'state{state_no}')
switch_instr: Any = getattr(Gen, '_coro_switch_instr', None)
if switch_instr is not None:
switch_instr.add_case(ir.Constant(ir.IntType(32), state_no), resume_bb)
state_ptr: ir.Value | None = getattr(Gen, '_coro_state_ptr', None)
if state_ptr is not None:
Gen._store(ir.Constant(ir.IntType(32), state_no), 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)
Gen.builder.position_at_start(resume_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)
# ------------------------------------------------------------------
# 控制流(协程版:body 内 await 就地挂起/恢复)
# ------------------------------------------------------------------
def _HandleCoroIf(self, Node: ast.If, Gen: LlvmCodeGenerator) -> None:
if any(isinstance(n, ast.Await) for n in ast.walk(Node.test)):
raise SyntaxError(
f"[coro-M2] if 条件中不支持 await (line {getattr(Node, 'lineno', 0)})"
)
Cond: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.test)
if not Cond:
return
if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1:
if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)):
Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name='coro_ifcond')
else:
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name='coro_ifcond')
ThenBB: ir.Block = Gen.func.append_basic_block(name='coro_then')
ElseBB: ir.Block | None = Gen.func.append_basic_block(name='coro_else') if Node.orelse else None
MergeBB: ir.Block = Gen.func.append_basic_block(name='coro_endif')
if not Gen.builder.block.is_terminated:
Gen.builder.cbranch(Cond, ThenBB, ElseBB if ElseBB else MergeBB)
Gen.builder.position_at_start(ThenBB)
self._HandleCoroSegment(Node.body, Gen)
if Gen.builder is not None and not Gen.builder.block.is_terminated:
Gen.builder.branch(MergeBB)
if ElseBB:
Gen.builder.position_at_start(ElseBB)
self._HandleCoroSegment(Node.orelse, Gen)
if Gen.builder is not None and not Gen.builder.block.is_terminated:
Gen.builder.branch(MergeBB)
if not MergeBB.is_terminated:
Gen.builder.position_at_start(MergeBB)
else:
Gen.builder.position_at_end(MergeBB)
def _HandleCoroWhile(self, Node: ast.While, Gen: LlvmCodeGenerator) -> None:
if any(isinstance(n, ast.Await) for n in ast.walk(Node.test)):
raise SyntaxError(
f"[coro-M2] while 条件中不支持 await (line {getattr(Node, 'lineno', 0)})"
)
CondBB: ir.Block = Gen.func.append_basic_block(name='coro_wcond')
BodyBB: ir.Block = Gen.func.append_basic_block(name='coro_wbody')
ElseBB: ir.Block | None = Gen.func.append_basic_block(name='coro_welse') if Node.orelse else None
AfterBB: ir.Block = Gen.func.append_basic_block(name='coro_wend')
Gen.loop_break_targets.append(AfterBB)
Gen.loop_continue_targets.append(CondBB)
Gen.builder.branch(CondBB)
Gen.builder.position_at_start(CondBB)
Cond: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.test)
if Cond:
if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1:
if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)):
Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name='coro_wcond')
else:
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name='coro_wcond')
if not Gen.builder.block.is_terminated:
Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB)
else:
if not Gen.builder.block.is_terminated:
Gen.builder.branch(ElseBB if ElseBB else AfterBB)
Gen.builder.position_at_start(BodyBB)
self._HandleCoroSegment(Node.body, Gen)
if Gen.builder is not None and not Gen.builder.block.is_terminated:
Gen.builder.branch(CondBB)
Gen.loop_break_targets.pop()
Gen.loop_continue_targets.pop()
if ElseBB:
Gen.builder.position_at_start(ElseBB)
self._HandleCoroSegment(Node.orelse, Gen)
if Gen.builder is not None and not Gen.builder.block.is_terminated:
Gen.builder.branch(AfterBB)
if not AfterBB.is_terminated:
Gen.builder.position_at_start(AfterBB)
else:
Gen.builder.position_at_end(AfterBB)
def _HandleCoroFor(self, Node: ast.For, Gen: LlvmCodeGenerator) -> None:
if any(isinstance(n, ast.Await) for n in ast.walk(Node)):
if not self._IsRangeFor(Node):
raise SyntaxError(
f"[coro-M3] 协程内 For 仅支持 range 迭代(含 await)"
f"(line {getattr(Node, 'lineno', 0)})"
)
self._HandleCoroForRange(Node, Gen)
return
if any(isinstance(n, ast.Return) for n in ast.walk(Node.body)):
raise SyntaxError(
f"[coro-M2] For 循环体内暂不支持 return(M3 实现)(line {getattr(Node, 'lineno', 0)})"
)
# 无 await/return:委托现有 ForHandler(迭代索引等 alloca 不跨挂起,安全)
self.Trans.ForHandler._HandleForLlvm(Node)
def _IsRangeFor(self, Node: ast.For) -> bool:
"""判断是否为可协程化 range-For:单 Name 目标 + range 1/2 参数(step=1)。"""
if not (isinstance(Node.iter, ast.Call)
and isinstance(Node.iter.func, ast.Name)
and Node.iter.func.id == 'range'):
return False
if not isinstance(Node.target, ast.Name):
return False
if len(Node.iter.args) not in (1, 2):
return False
for a in Node.iter.args:
if any(isinstance(n, ast.Await) for n in ast.walk(a)):
return False
return True
def _HandleCoroForRange(self, Node: ast.For, Gen: LlvmCodeGenerator) -> None:
"""协程版 range-For:变换为 While 复用协程路径
__f_idx_N = start; __f_len_N = end;
while __f_idx_N < __f_len_N: target = __f_idx_N; <body>; __f_idx_N += 1
"""
k: int = getattr(Gen, '_coro_for_counter', 0)
Gen._coro_for_counter = k + 1
idx_name: str = f'__f_idx_{k}'
len_name: str = f'__f_len_{k}'
args: list[ast.expr] = Node.iter.args
if len(args) == 1:
start_node: ast.expr = ast.Constant(0)
end_node: ast.expr = args[0]
else:
start_node = args[0]
end_node = args[1]
target: str = Node.target.id
idx_load: ast.expr = ast.Name(idx_name, ast.Load())
init_stmts: list[ast.stmt] = [
ast.Assign(targets=[ast.Name(idx_name, ast.Store())], value=start_node, type_comment=None),
ast.Assign(targets=[ast.Name(len_name, ast.Store())], value=end_node, type_comment=None),
]
while_node: ast.While = ast.While(
test=ast.Compare(left=idx_load, ops=[ast.Lt()],
comparators=[ast.Name(len_name, ast.Load())]),
body=[
ast.Assign(targets=[ast.Name(target, ast.Store())], value=idx_load, type_comment=None),
] + list(Node.body) + [
ast.Assign(targets=[ast.Name(idx_name, ast.Store())],
value=ast.BinOp(left=idx_load, op=ast.Add(), right=ast.Constant(1)),
type_comment=None),
],
orelse=[],
)
self._HandleCoroSegment(init_stmts + [while_node], Gen)
# ------------------------------------------------------------------
# 普通函数调用 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)
call_args: list[ir.Value] = []
if Node.args:
param_info: list[tuple[str, ir.Type]] = getattr(Gen, '_coro_param_vars', {}).get(FuncName, [])
for i, arg_node in enumerate(Node.args):
arg_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(arg_node)
if i < len(param_info):
arg_val = self._CoerceArg(arg_val, param_info[i][1], Gen, name=f'arg{i}')
call_args.append(arg_val)
result: ir.Value = Gen.builder.call(create_fn, call_args, name=f'create_{FuncName}')
return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name='coro_frame_i8ptr')
# ------------------------------------------------------------------
# coro.coro_run(帧) 内联翻译
# ------------------------------------------------------------------
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')
check_bb: ir.Block = Gen.func.append_basic_block('coro_wcheck')
wake_wait_bb: ir.Block = Gen.func.append_basic_block('coro_wsleep')
wake_due_bb: ir.Block = Gen.func.append_basic_block('coro_wdue')
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, check_bb)
# SUSPEND:若 coro_sleep 唤醒槽存在且未到点,Sleep(1) 后继续轮询
Gen.builder.position_at_start(check_bb)
wake_ptr: ir.Value | None = getattr(Gen, '_coro_wake_ptr', None)
if wake_ptr is not None:
wake_val: ir.Value = Gen._load(wake_ptr, name='coro_wake')
now_fn: ir.Function = self._GetWinFunc('GetTickCount64', Gen, ir.IntType(64))
now_val: ir.Value = Gen.builder.call(now_fn, [], name='tick_now')
not_wake: ir.Value = Gen.builder.icmp_signed('==', wake_val, ir.Constant(ir.IntType(64), 0), name='coro_wake_zero')
due: ir.Value = Gen.builder.icmp_unsigned('>=', now_val, wake_val, name='coro_wake_due')
sleep_cond: ir.Value = Gen.builder.or_(not_wake, due, name='coro_continue_cond')
Gen.builder.cbranch(sleep_cond, wake_due_bb, wake_wait_bb)
Gen.builder.position_at_start(wake_wait_bb)
sleep_fn: ir.Function = self._GetWinFunc('Sleep', Gen, ir.VoidType(), [ir.IntType(32)])
Gen.builder.call(sleep_fn, [ir.Constant(ir.IntType(32), 1)])
Gen.builder.branch(loop_bb)
Gen.builder.position_at_start(wake_due_bb)
else:
Gen.builder.branch(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')