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 口径等历史改动一并入库
1472 lines
78 KiB
Python
1472 lines
78 KiB
Python
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')
|