Files
TransPyC/lib/core/Handles/HandlesAsyncFunctions.py
T
TermiNexus c83fc752c6 fix(sizeof,parse): 尺寸链去静默兜底,解析报错可定位,补 C 解析器缺口
StructGen: _get_struct_size/_get_align 去 opaque→8/ptr_size、未知→4 兜底并补 VectorType;LiteralStructType.fields→.elements(llvmlite 无 fields,必然 AttributeError)

HandlesClassDef: union 载荷尺寸经不存在的 ir.DataLayout 静默退化成 8 字节;HandlesExprCall/ExprBuiltin: sizeof 各静默 0 分支改 fail-fast,数组元素 sizeof 统一走 _get_struct_size

HandlesFor: nonlocal struct/array 堆分配不再退化成 malloc(8)

vast/vast_c: 补一元 * / & 解析,装饰器后 extern/export 分派修复,C 侧报错带 token 与行号;StubGen.Converter: 宏展开丢尾随空行修 .pyi 缩进非法

其余为 rawptr 迁移 / fail-fast 口径等历史改动一并入库
2026-09-26 19:27:22 +08:00

1472 lines
78 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, EXCEPTION_CODE_MAP
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, i32 exc, i8* msg, <参数槽>, <局部槽>, <额外槽(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),
'exc_ptr': getattr(Gen, '_coro_exc_ptr', None),
'try_stack': getattr(Gen, '_coro_try_stack', None),
'msg_ptr': getattr(Gen, '_coro_msg_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']
Gen._coro_exc_ptr = saved_coro_state['exc_ptr']
Gen._coro_try_stack = saved_coro_state['try_stack']
Gen._coro_msg_ptr = saved_coro_state['msg_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
elif isinstance(stmt, ast.Try):
# except X as e:e 进帧槽(异常码)
for _h in stmt.handlers:
if _h.name and _h.name not in seen:
seen.add(_h.name)
vars_.append((_h.name, ir.IntType(32)))
_walk(stmt.body)
for _h in stmt.handlers:
_walk(_h.body)
if stmt.orelse:
_walk(stmt.orelse)
if stmt.finalbody:
_walk(stmt.finalbody)
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
ir.IntType(32), # 3: exc(异常码,0=无异常)
ir.PointerType(ir.IntType(8)), # 4: msg(异常消息,null=无)
]
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:
nonlocal await_counter, for_counter
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.Try):
_walk(stmt.body)
for _h in stmt.handlers:
_walk(_h.body)
if stmt.orelse:
_walk(stmt.orelse)
if stmt.finalbody:
_walk(stmt.finalbody)
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):
# 注入行偏移还原:AST 行号含 _inject_auto_imports 注入的 N 行
_lineno: int = int(getattr(stmt, 'lineno', 0) or 0)
_line_offset: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
if _line_offset > 0 and _lineno > _line_offset:
_lineno -= _line_offset
raise SyntaxError(
f"[coro-M3] 协程内 For 仅支持 range 迭代(含 await)"
f"(line {_lineno})"
)
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 _GetCoroPool(self, name: str, Gen: LlvmCodeGenerator) -> ir.GlobalVariable:
"""每帧类型的全局 free-list 池头(i8*),跨 create/destroy 复用帧内存。"""
pool_name: str = f'coro_pool_{Gen._mangle_func_name(name)}'
for gv in Gen.module.global_values:
if getattr(gv, 'name', None) == pool_name:
return gv
gv: ir.GlobalVariable = ir.GlobalVariable(Gen.module, ir.PointerType(ir.IntType(8)), pool_name)
gv.initializer = ir.Constant(ir.PointerType(ir.IntType(8)), None)
gv.linkage = 'internal'
return gv
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 = Gen._NewIrBuilder(entry)
Gen.func = create_fn
zero32: ir.Constant = ir.Constant(ir.IntType(32), 0)
null_i8p: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
# 帧池:pop(非空则复用,空则 malloc)
pool_gv: ir.GlobalVariable = self._GetCoroPool(name, Gen)
pool_head: ir.Value = Gen.builder.load(pool_gv, name='pool_head')
pool_hit_bb: ir.Block = create_fn.append_basic_block('pool_hit')
pool_miss_bb: ir.Block = create_fn.append_basic_block('pool_miss')
join_bb: ir.Block = create_fn.append_basic_block('pool_join')
head_is_null: ir.Value = Gen.builder.icmp_signed('==', pool_head, null_i8p, name='pool_empty')
Gen.builder.cbranch(head_is_null, pool_miss_bb, pool_hit_bb)
# pool_hit:弹出一个池节点(帧头部存 next)
Gen.builder.position_at_start(pool_hit_bb)
next_head: ir.Value = Gen.builder.load(
Gen.builder.bitcast(pool_head, ir.PointerType(ir.PointerType(ir.IntType(8))), name='pool_node_next_ptr'),
name='pool_next')
Gen.builder.store(next_head, pool_gv)
hit_frame: ir.Value = Gen.builder.bitcast(pool_head, ir.PointerType(frame_ty), name='frame')
Gen.builder.branch(join_bb)
# pool_miss:malloc + 状态清零
Gen.builder.position_at_start(pool_miss_bb)
raw: ir.Value = Gen.builder.call(malloc_fn, [ir.Constant(ir.IntType(64), frame_size)], name='frame_raw')
miss_frame: ir.Value = Gen.builder.bitcast(raw, ir.PointerType(frame_ty), name='frame')
for i in range(4):
slot_ptr: ir.Value = Gen.builder.gep(miss_frame, [zero32, ir.Constant(ir.IntType(32), i)], name=f'init_slot{i}')
Gen._store(zero32, slot_ptr)
msg_slot: ir.Value = Gen.builder.gep(miss_frame, [zero32, ir.Constant(ir.IntType(32), 4)], name='init_msg_slot')
Gen._store(null_i8p, msg_slot)
Gen.builder.branch(join_bb)
# join:phi 选择帧 + 参数存入(池取/新建都要写参数槽)
Gen.builder.position_at_start(join_bb)
frame_phi: Any = Gen.builder.phi(ir.PointerType(frame_ty), name='frame')
frame_phi.add_incoming(hit_frame, pool_hit_bb)
frame_phi.add_incoming(miss_frame, pool_miss_bb)
for i in range(len(params)):
slot_ptr = Gen.builder.gep(frame_phi, [zero32, ir.Constant(ir.IntType(32), 5 + 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_phi)
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 = Gen._NewIrBuilder(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), 5 + 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
exc_ptr: ir.Value = Gen.builder.gep(frame_arg, [zero32, ir.Constant(ir.IntType(32), 3)], name='exc_ptr')
Gen._coro_exc_ptr = exc_ptr
msg_ptr: ir.Value = Gen.builder.gep(frame_arg, [zero32, ir.Constant(ir.IntType(32), 4)], name='msg_ptr')
Gen._coro_msg_ptr = msg_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.Raise):
self._HandleCoroRaiseLlvm(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.Try):
if stmt.finalbody and not stmt.handlers:
self._HandleCoroTryFinally(stmt, Gen)
else:
self._HandleCoroTry(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
# 注入行偏移还原:AST 行号含 _inject_auto_imports 注入的 N 行
_lineno: int = int(getattr(stmt, 'lineno', 0) or 0)
_line_offset: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
if _line_offset > 0 and _lineno > _line_offset:
_lineno -= _line_offset
raise SyntaxError(
f"[coro-M2] async 函数体暂不支持语句: {type(stmt).__name__} "
f"(line {_lineno})"
)
# ------------------------------------------------------------------
# 嵌套 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/挂起)。"""
if target == '__ret__':
Gen._coro_await_slot_ptr = getattr(Gen, '_coro_ret_field_ptr', None)
else:
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:
# 注入行偏移还原:AST 行号含 _inject_auto_imports 注入的 N 行
_lineno: int = int(getattr(await_node, 'lineno', 0) or 0)
_line_offset: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
if _line_offset > 0 and _lineno > _line_offset:
_lineno -= _line_offset
raise SyntaxError(
f"[coro-M3] await 目标必须是 async 函数调用或 coro_sleep(ms) "
f"(line {_lineno})"
)
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)
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-list):帧头部存当前池头,池头指向本帧
pool_gv: ir.GlobalVariable = self._GetCoroPool(async_name, Gen)
pool_head: ir.Value = Gen.builder.load(pool_gv, name='pool_head')
node_next_ptr: ir.Value = Gen.builder.bitcast(
frame_ptr, ir.PointerType(ir.PointerType(ir.IntType(8))), name='pool_node_next')
Gen.builder.store(pool_head, node_next_ptr)
Gen.builder.store(
Gen.builder.bitcast(frame_ptr, ir.IntType(8).as_pointer(), name='pool_node'), pool_gv)
return ir.Constant(ir.IntType(32), 0)
def _ResolveRaiseInfo(self, exc_node: ast.expr) -> tuple[int, ast.expr | None] | None:
"""解析 raise 目标的异常类型(返回 (异常码, 消息表达式));普通表达式返回 None 走值路径。"""
name: str | None = None
msg_node: ast.expr | None = None
if isinstance(exc_node, ast.Name):
name = exc_node.id
elif isinstance(exc_node, ast.Call) and isinstance(exc_node.func, ast.Name):
name = exc_node.func.id
if exc_node.args:
msg_node = exc_node.args[0]
elif isinstance(exc_node, ast.Attribute):
name = exc_node.attr
if name:
if name in EXCEPTION_CODE_MAP or name in getattr(self.Trans, 'exception_registry', {}):
try:
return (self.Trans.RaiseHandler._get_exception_code(name), msg_node)
except Exception:
return None
return None
def _HandleCoroRaiseLlvm(self, stmt: ast.Raise, Gen: LlvmCodeGenerator) -> None:
"""协程内 raise:异常类型/值 → 帧 exc 槽;try 内跳 except,否则终止协程。"""
exc_code: ir.Value = ir.Constant(ir.IntType(32), 1)
if stmt.exc is not None:
v: ir.Value | None = None
resolved: tuple[int, ast.expr | None] | None = self._ResolveRaiseInfo(stmt.exc)
if resolved is not None:
exc_code = ir.Constant(ir.IntType(32), resolved[0])
msg_node: ast.expr | None = resolved[1]
if msg_node is not None:
msg_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(msg_node)
msg_ptr_r: ir.Value | None = getattr(Gen, '_coro_msg_ptr', None)
if msg_val is not None and isinstance(msg_val.type, ir.PointerType) and msg_ptr_r is not None:
Gen._store(msg_val, msg_ptr_r)
else:
v = self.Trans.ExprHandler.HandleExprLlvm(stmt.exc)
if v is not None:
if isinstance(v.type, ir.IntType):
if v.type.width < 32:
exc_code = Gen.builder.zext(v, ir.IntType(32), name='zext_exc')
elif v.type.width > 32:
exc_code = Gen.builder.trunc(v, ir.IntType(32), name='trunc_exc')
else:
exc_code = v
elif isinstance(v.type, ir.PointerType):
exc_code = Gen.builder.ptrtoint(v, ir.IntType(32), name='exc_ptr2int')
exc_ptr: ir.Value | None = getattr(Gen, '_coro_exc_ptr', None)
if exc_ptr is not None:
Gen._store(exc_code, exc_ptr)
coro_try_stack: list[ir.Block] | None = getattr(Gen, '_coro_try_stack', None)
if coro_try_stack:
Gen.builder.branch(coro_try_stack[-1])
return
done_ptr_r: ir.Value | None = getattr(Gen, '_coro_done_ptr', None)
if done_ptr_r is not None:
Gen._store(ir.Constant(ir.IntType(32), 1), done_ptr_r)
exit_bb: ir.Block | None = getattr(Gen, '_coro_exit_bb', None)
if exit_bb is not None:
Gen.builder.branch(exit_bb)
def _HandleCoroExceptionLlvm(self, Node: ast.Call, Gen: LlvmCodeGenerator) -> ir.Value:
"""coro.coro_exception(帧):返回帧 exc 槽(异常码,0=无异常)。"""
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)
exc_ptr: ir.Value = Gen.builder.gep(
frame_ptr,
[ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 3)],
name='coro_exc_ptr',
)
return Gen._load(exc_ptr, name='coro_exc')
def _HandleCoroExceptionMsgLlvm(self, Node: ast.Call, Gen: LlvmCodeGenerator) -> ir.Value:
"""coro.coro_exception_msg(帧):返回帧 msg 槽(异常消息指针,null=无)。"""
if not Node.args:
return ir.Constant(ir.PointerType(ir.IntType(8)), None)
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.PointerType(ir.IntType(8)), None)
frame_ty: ir.IdentifiedStructType | None = getattr(Gen, '_coro_frame_types', {}).get(async_name)
if not frame_ty:
return ir.Constant(ir.PointerType(ir.IntType(8)), None)
frame_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(arg)
if frame_val is None:
return ir.Constant(ir.PointerType(ir.IntType(8)), None)
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.PointerType(ir.IntType(8)), None)
msg_ptr: ir.Value = Gen.builder.gep(
frame_ptr,
[ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 4)],
name='coro_msg_ptr',
)
return Gen._load(msg_ptr, name='coro_msg')
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')
# M4: 子协程异常传播——子帧 exc != 0 时父协程带异常终止
child_exc_ptr: ir.Value = Gen.builder.gep(
child,
[zero32, ir.Constant(ir.IntType(32), 3)],
name='child_exc_ptr',
)
child_exc: ir.Value = Gen._load(child_exc_ptr, name='child_exc')
normal_bb: ir.Block = Gen.func.append_basic_block('coro_ok')
exc_bb: ir.Block = Gen.func.append_basic_block('coro_exc')
exc_cond: ir.Value = Gen.builder.icmp_signed('==', child_exc, zero32, name='child_exc_ok')
Gen.builder.cbranch(exc_cond, normal_bb, exc_bb)
Gen.builder.position_at_start(exc_bb)
parent_exc_ptr: ir.Value | None = getattr(Gen, '_coro_exc_ptr', None)
if parent_exc_ptr is not None:
Gen._store(child_exc, parent_exc_ptr)
child_msg_ptr: ir.Value = Gen.builder.gep(
child,
[zero32, ir.Constant(ir.IntType(32), 4)],
name='child_msg_ptr',
)
child_msg: ir.Value = Gen._load(child_msg_ptr, name='child_msg')
parent_msg_ptr: ir.Value | None = getattr(Gen, '_coro_msg_ptr', None)
if parent_msg_ptr is not None:
Gen._store(child_msg, parent_msg_ptr)
coro_try: list[ir.Block] | None = getattr(Gen, '_coro_try_stack', None)
if coro_try:
Gen.builder.branch(coro_try[-1])
else:
parent_done_ptr: ir.Value | None = getattr(Gen, '_coro_done_ptr', None)
if parent_done_ptr is not None:
Gen._store(ir.Constant(ir.IntType(32), 1), parent_done_ptr)
exit_bb_ref: ir.Block | None = getattr(Gen, '_coro_exit_bb', None)
if exit_bb_ref is not None:
Gen.builder.branch(exit_bb_ref)
# 正常路径:存父帧局部变量槽 + 挂起
Gen.builder.position_at_start(normal_bb)
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)
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:
# return await x:await 直接存父帧 ret 槽(挂起前),恢复块仅完成协程
if stmt.value is not None and isinstance(stmt.value, ast.Await):
self._HandleCoroAwaitCommon('__ret__', stmt.value, Gen)
done_ptr_r: ir.Value | None = getattr(Gen, '_coro_done_ptr', None)
if done_ptr_r is not None:
Gen._store(ir.Constant(ir.IntType(32), 1), done_ptr_r)
exit_bb_r: ir.Block | None = getattr(Gen, '_coro_exit_bb', None)
if exit_bb_r is not None:
Gen.builder.branch(exit_bb_r)
return
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)):
# 注入行偏移还原:AST 行号含 _inject_auto_imports 注入的 N 行
_lineno: int = int(getattr(Node, 'lineno', 0) or 0)
_line_offset: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
if _line_offset > 0 and _lineno > _line_offset:
_lineno -= _line_offset
raise SyntaxError(
f"[coro-M2] if 条件中不支持 await (line {_lineno})"
)
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)):
# 注入行偏移还原:AST 行号含 _inject_auto_imports 注入的 N 行
_lineno: int = int(getattr(Node, 'lineno', 0) or 0)
_line_offset: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
if _line_offset > 0 and _lineno > _line_offset:
_lineno -= _line_offset
raise SyntaxError(
f"[coro-M2] while 条件中不支持 await (line {_lineno})"
)
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 _HandleCoroTry(self, Node: ast.Try, Gen: LlvmCodeGenerator) -> None:
"""协程内 try/except:捕获 raise 与 await 传播异常(M6:多 except 类型匹配;Exception/裸 except 捕获所有)。"""
if not Node.handlers:
# 注入行偏移还原:AST 行号含 _inject_auto_imports 注入的 N 行
_lineno: int = int(getattr(Node, 'lineno', 0) or 0)
_line_offset: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
if _line_offset > 0 and _lineno > _line_offset:
_lineno -= _line_offset
raise SyntaxError(
f"[coro-M6] 协程内 try 需要 except 子句 (line {_lineno})"
)
if Node.finalbody:
# 注入行偏移还原:AST 行号含 _inject_auto_imports 注入的 N 行
_lineno = int(getattr(Node, 'lineno', 0) or 0)
_line_offset = int(getattr(self.Trans, '_line_offset', 0) or 0)
if _line_offset > 0 and _lineno > _line_offset:
_lineno -= _line_offset
raise SyntaxError(
f"[coro-M6] 协程内暂不支持 try/finally (line {_lineno})"
)
except_bb: ir.Block = Gen.func.append_basic_block('coro_try_except')
merge_bb: ir.Block = Gen.func.append_basic_block('coro_try_merge')
if not getattr(Gen, '_coro_try_stack', None):
Gen._coro_try_stack = []
Gen._coro_try_stack.append(except_bb)
# try body
self._HandleCoroSegment(Node.body, Gen)
if Gen.builder is not None and not Gen.builder.block.is_terminated:
Gen.builder.branch(merge_bb)
Gen._coro_try_stack.pop()
# ---- 异常分发:exc 码依次匹配各 except ----
Gen.builder.position_at_start(except_bb)
exc_ptr: ir.Value | None = getattr(Gen, '_coro_exc_ptr', None)
if exc_ptr is not None:
exc_val: ir.Value = Gen._load(exc_ptr, name='coro_exc_val')
else:
exc_val = ir.Constant(ir.IntType(32), 0)
check_bbs: list[ir.Block] = [except_bb] + [Gen.func.append_basic_block(f'coro_exc_check_{i}')
for i in range(len(Node.handlers) - 1)]
handler_bbs: list[ir.Block] = [Gen.func.append_basic_block(f'coro_except_{i}')
for i in range(len(Node.handlers))]
unmatched_bb: ir.Block = Gen.func.append_basic_block('coro_try_reraise')
try_handler: Any = self.Trans.TryHandler
for i, handler in enumerate(Node.handlers):
catch_all: bool = handler.type is None
codes: list[int] = [1]
if handler.type is not None:
ename: str | None = try_handler._get_exception_name(handler.type)
if ename == 'Exception':
catch_all = True
else:
codes = try_handler._get_all_match_codes(handler.type)
Gen.builder.position_at_end(check_bbs[i])
if check_bbs[i].is_terminated:
break
if catch_all:
Gen.builder.branch(handler_bbs[i])
break
next_check: ir.Block = check_bbs[i + 1] if i + 1 < len(Node.handlers) else unmatched_bb
match_cond: ir.Value | None = None
for c in codes:
eq: ir.Value = Gen.builder.icmp_signed('==', exc_val, ir.Constant(ir.IntType(32), c), name=f'coro_exc_match_{i}')
match_cond = eq if match_cond is None else Gen.builder.or_(match_cond, eq, name=f'coro_exc_or_{i}')
Gen.builder.cbranch(match_cond, handler_bbs[i], next_check)
# 未匹配:异常继续传播(重新终止协程)
Gen.builder.position_at_start(unmatched_bb)
if not unmatched_bb.is_terminated:
done_ptr_r: ir.Value | None = getattr(Gen, '_coro_done_ptr', None)
if done_ptr_r is not None:
Gen._store(ir.Constant(ir.IntType(32), 1), done_ptr_r)
exit_bb_r: ir.Block | None = getattr(Gen, '_coro_exit_bb', None)
if exit_bb_r is not None:
Gen.builder.branch(exit_bb_r)
# ---- 各 except handler ----
for i, handler in enumerate(Node.handlers):
Gen.builder.position_at_start(handler_bbs[i])
if handler.name:
e_slot: ir.Value | None = Gen.variables.get(handler.name)
if e_slot is not None and exc_ptr is not None:
h_exc_val: ir.Value = Gen._load(exc_ptr, name='coro_exc_val')
Gen._store(h_exc_val, e_slot)
Gen._record_var_signedness(handler.name, False)
if exc_ptr is not None:
Gen._store(ir.Constant(ir.IntType(32), 0), exc_ptr)
self._HandleCoroSegment(handler.body, Gen)
if Gen.builder is not None and not Gen.builder.block.is_terminated:
Gen.builder.branch(merge_bb)
if not merge_bb.is_terminated:
Gen.builder.position_at_start(merge_bb)
else:
Gen.builder.position_at_end(merge_bb)
def _HandleCoroTryFinally(self, Node: ast.Try, Gen: LlvmCodeGenerator) -> None:
"""协程内 try/finally(无 except):正常/异常路径都执行 fbody;
异常时 finally 后重新传播(done=1 + br exit);finally 内暂不支持 await。"""
if any(isinstance(n, ast.Await) for s in Node.finalbody for n in ast.walk(s)):
# 注入行偏移还原:AST 行号含 _inject_auto_imports 注入的 N 行
_lineno: int = int(getattr(Node, 'lineno', 0) or 0)
_line_offset: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
if _line_offset > 0 and _lineno > _line_offset:
_lineno -= _line_offset
raise SyntaxError(
f"[coro-M7] finally 内暂不支持 await (line {_lineno})"
)
fin_bb: ir.Block = Gen.func.append_basic_block('coro_fin')
fin_exc_bb: ir.Block = Gen.func.append_basic_block('coro_fin_exc')
merge_bb: ir.Block = Gen.func.append_basic_block('coro_fin_merge')
if not getattr(Gen, '_coro_try_stack', None):
Gen._coro_try_stack = []
Gen._coro_try_stack.append(fin_bb)
self._HandleCoroSegment(Node.body, Gen)
if Gen.builder is not None and not Gen.builder.block.is_terminated:
Gen.builder.branch(fin_bb)
Gen._coro_try_stack.pop()
# fin_bb:记录异常标志,执行 fbody
Gen.builder.position_at_start(fin_bb)
exc_ptr_f: ir.Value | None = getattr(Gen, '_coro_exc_ptr', None)
if exc_ptr_f is not None:
was_exc: ir.Value = Gen.builder.icmp_signed(
'!=', Gen._load(exc_ptr_f, name='coro_fin_exc'),
ir.Constant(ir.IntType(32), 0), name='coro_fin_was_exc')
else:
was_exc = ir.Constant(ir.IntType(1), 0)
self._HandleCoroSegment(Node.finalbody, Gen)
if Gen.builder is not None and not Gen.builder.block.is_terminated:
Gen.builder.cbranch(was_exc, fin_exc_bb, merge_bb)
# fin_exc_bb:finally 后异常继续传播
Gen.builder.position_at_start(fin_exc_bb)
if not fin_exc_bb.is_terminated:
done_ptr_f: ir.Value | None = getattr(Gen, '_coro_done_ptr', None)
if done_ptr_f is not None:
Gen._store(ir.Constant(ir.IntType(32), 1), done_ptr_f)
exit_bb_f: ir.Block | None = getattr(Gen, '_coro_exit_bb', None)
if exit_bb_f is not None:
Gen.builder.branch(exit_bb_f)
if not merge_bb.is_terminated:
Gen.builder.position_at_start(merge_bb)
else:
Gen.builder.position_at_end(merge_bb)
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):
# 注入行偏移还原:AST 行号含 _inject_auto_imports 注入的 N 行
_lineno: int = int(getattr(Node, 'lineno', 0) or 0)
_line_offset: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
if _line_offset > 0 and _lineno > _line_offset:
_lineno -= _line_offset
raise SyntaxError(
f"[coro-M3] 协程内 For 仅支持 range 迭代(含 await)"
f"(line {_lineno})"
)
self._HandleCoroForRange(Node, Gen)
return
if any(isinstance(n, ast.Return) for st in Node.body for n in ast.walk(st)):
# 注入行偏移还原:AST 行号含 _inject_auto_imports 注入的 N 行
_lineno: int = int(getattr(Node, 'lineno', 0) or 0)
_line_offset: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
if _line_offset > 0 and _lineno > _line_offset:
_lineno -= _line_offset
raise SyntaxError(
f"[coro-M2] For 循环体内暂不支持 return(M3 实现)(line {_lineno})"
)
# 无 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 _HandleCoroGatherLlvm(self, Node: ast.Call, Gen: LlvmCodeGenerator) -> ir.Value:
"""coro.coro_gather(帧...):并发推进全部协程到完成(含 coro_sleep 轮询),返回完成数。"""
zero32: ir.Constant = ir.Constant(ir.IntType(32), 0)
count: int = 0
for arg in Node.args:
async_name: str | None = None
if isinstance(arg, ast.Name):
async_name = getattr(Gen, '_coro_var_async', {}).get(arg.id)
if not async_name:
continue
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:
continue
frame_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(arg)
if frame_val is None:
continue
if isinstance(frame_val.type, ir.PointerType):
frame_ptr: ir.Value = Gen.builder.bitcast(frame_val, ir.PointerType(frame_ty), name='gather_frame')
elif isinstance(frame_val.type, ir.IntType):
frame_ptr = Gen.builder.inttoptr(frame_val, ir.PointerType(frame_ty), name='gather_frame')
else:
continue
loop_bb: ir.Block = Gen.func.append_basic_block('gather_loop')
check_bb: ir.Block = Gen.func.append_basic_block('gather_wcheck')
after_bb: ir.Block = Gen.func.append_basic_block('gather_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'gather_resume_{async_name}')
done_cond: ir.Value = Gen.builder.icmp_signed('!=', status, zero32, name='gather_done_cond')
Gen.builder.cbranch(done_cond, after_bb, check_bb)
# SUSPEND:coro_sleep 唤醒轮询
Gen.builder.position_at_start(check_bb)
slot_vars: list[str] = getattr(Gen, '_coro_slot_vars', {}).get(async_name, [])
wake_idx: int | None = None
if '__coro_wake_us' in slot_vars:
wake_idx = 5 + slot_vars.index('__coro_wake_us')
if wake_idx is not None:
wsleep_bb: ir.Block = Gen.func.append_basic_block('gather_wsleep')
wdue_bb: ir.Block = Gen.func.append_basic_block('gather_wdue')
wake_ptr: ir.Value = Gen.builder.gep(
frame_ptr,
[ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), wake_idx)],
name='gather_wake_ptr',
)
wake_val: ir.Value = Gen._load(wake_ptr, name='gather_wake')
now_fn: ir.Function = self._GetWinFunc('GetTickCount64', Gen, ir.IntType(64))
now_val: ir.Value = Gen.builder.call(now_fn, [], name='gather_tick_now')
not_wake: ir.Value = Gen.builder.icmp_signed('==', wake_val, ir.Constant(ir.IntType(64), 0), name='gather_wake_zero')
due: ir.Value = Gen.builder.icmp_unsigned('>=', now_val, wake_val, name='gather_wake_due')
sleep_cond: ir.Value = Gen.builder.or_(not_wake, due, name='gather_continue_cond')
Gen.builder.cbranch(sleep_cond, wdue_bb, wsleep_bb)
Gen.builder.position_at_start(wsleep_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(wdue_bb)
Gen.builder.branch(loop_bb)
else:
Gen.builder.branch(loop_bb)
Gen.builder.position_at_start(after_bb)
count += 1
return ir.Constant(ir.IntType(32), count)
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')
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_idx: int | None = None
slot_vars: list[str] = getattr(Gen, '_coro_slot_vars', {}).get(async_name, [])
if '__coro_wake_us' in slot_vars:
wake_idx = 5 + slot_vars.index('__coro_wake_us')
if wake_idx is not None:
wake_wait_bb: ir.Block = Gen.func.append_basic_block('coro_wsleep')
wake_due_bb: ir.Block = Gen.func.append_basic_block('coro_wdue')
wake_ptr: ir.Value = Gen.builder.gep(
frame_ptr,
[ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), wake_idx)],
name='coro_wake_ptr',
)
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)
Gen.builder.branch(loop_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')