feat(coro): M2——async 参数/嵌套 await 表达式/If-While 控制流
- 帧结构体增加参数槽与提升临时变量槽,create_<name> 带参数存入帧 - 嵌套 await(如 a = b + await f())提升为顶层临时赋值 __await_N,帧预留槽 - 协程版 If/While:条件求值 + 分支内 await 就地挂起/恢复(动态状态号恢复块) - For 循环委托现有 handler(仅支持无 await/return,M3 扩展) - CoroTest 用例覆盖参数/嵌套 await/while+await/if+await(期望 coro result = 30)
This commit is contained in:
1 parent
a775ec9932
commit
ff7c0457ad
2 files changed
+423
-123
No files matched your search
@@ -4,18 +4,25 @@ import stdio
|
||||
import coro
|
||||
|
||||
|
||||
async def leaf() -> int:
|
||||
return 7
|
||||
async def leaf(x: int) -> int:
|
||||
return x + 1
|
||||
|
||||
|
||||
async def task() -> int:
|
||||
a: int = await leaf()
|
||||
b: int = await leaf()
|
||||
return a + b
|
||||
async def task(base: int) -> int:
|
||||
a: int = await leaf(base)
|
||||
b: int = a * 2 + await leaf(a)
|
||||
s: int = 0
|
||||
i: int = 0
|
||||
while i < 3:
|
||||
s = s + await leaf(i)
|
||||
i = i + 1
|
||||
if s > 5:
|
||||
s = s + await leaf(10)
|
||||
return s + a + b
|
||||
|
||||
|
||||
def main() -> t.CInt:
|
||||
tt: coro.Coroutine = task()
|
||||
tt: coro.Coroutine = task(2)
|
||||
r: t.CInt = coro.coro_run(tt)
|
||||
stdio.printf("coro result = %d\n", r)
|
||||
return 0
|
||||
return 0
|
||||
@@ -10,20 +10,18 @@ from lib.includes import t
|
||||
|
||||
|
||||
class AsyncFunctionHandle(BaseHandle):
|
||||
"""语言内协程 M1:async def + await + coro_run 状态机翻译。
|
||||
"""语言内协程 M2:async def + await + coro_run 状态机翻译。
|
||||
|
||||
M1 语义约定:
|
||||
- async def 无参数、返回 i32/int。
|
||||
- 每个 async 函数生成 3 部分:
|
||||
1. 帧结构体 %Coro_<name> = type { i32, i32, i32, <跨 await 局部变量> }
|
||||
(前 3 槽:state, done, ret)
|
||||
2. create_<name>() -> %Coro_<name>*:stdlib.malloc 分配帧,state/done/ret 置 0
|
||||
3. resume_<name>(%Coro_<name>*) -> i32:0=SUSPEND 1=DONE;switch(state) 切分 await 点
|
||||
- await <async调用>:创建子帧 -> call resume(child)(M1 假设一次完成)
|
||||
-> 取子帧 ret -> 存父帧局部变量槽 -> 父挂起(state=下一切片、ret=0(SUSPEND))
|
||||
- return expr:写帧 ret + done=1 + br 完成块;函数体结尾隐式同 return 路径。
|
||||
- 普通函数调用 async 函数(如 main 里 task()):生成 create 调用(返回帧指针)。
|
||||
- coro.coro_run(帧):内联翻译为 resume 循环,返回帧 ret。
|
||||
M2 在 M1 基础上扩展:
|
||||
- async 函数参数:帧结构体加参数槽,create_<name> 带参数并存入帧。
|
||||
- 嵌套 await 表达式:`a = b + await leaf()` 提升为顶层临时赋值
|
||||
(`__await_N = await leaf(); a = b + __await_N`),帧预留临时变量槽。
|
||||
- 控制流:If/While 语句(含内部 await 就地挂起/恢复);For 仅支持无 await。
|
||||
- resume 采用动态状态号:每个 await 点分配恢复块(state{N}),switch 分发。
|
||||
|
||||
帧布局:%Coro_<name> = type { i32 state, i32 done, i32 ret, <参数槽>, <局部槽>, <提升临时槽> }
|
||||
状态机:create_<name>(args...) 分配帧 + 存参数;resume_<name>(frame) -> i32
|
||||
(0=SUSPEND 1=DONE)按 state 分发到主入口 state0 与各恢复块。
|
||||
"""
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
@@ -63,14 +61,15 @@ class AsyncFunctionHandle(BaseHandle):
|
||||
|
||||
def _EmitAsyncFunctionLlvm(self, Node: ast.AsyncFunctionDef, Gen: LlvmCodeGenerator) -> None:
|
||||
name: str = Node.name
|
||||
if Node.args.args:
|
||||
raise SyntaxError(
|
||||
f"[coro-M1] async 函数 '{name}' 暂不支持参数(M1 仅支持无参数 async def)"
|
||||
)
|
||||
# 防重复生成:模块可能被多次编译(泛型特化等触发),避免 create_/resume_ 重名
|
||||
if f'create_{name}' in Gen.functions or name in getattr(Gen, '_coro_frame_types', {}):
|
||||
return
|
||||
self._RegisterAsyncFunc(name, Node)
|
||||
# 预扫描嵌套 await,分配提升临时变量槽(帧布局需要)
|
||||
hoist_count: int = self._PreScanHoistedVars(Node, Gen)
|
||||
if not hasattr(Gen, '_coro_hoisted_count'):
|
||||
Gen._coro_hoisted_count = {}
|
||||
Gen._coro_hoisted_count[name] = hoist_count
|
||||
# 保存外层 Gen 状态(create/resume 生成期间会切换 builder/func/variables)
|
||||
saved_builder: ir.IRBuilder | None = Gen.builder
|
||||
saved_func: Any = Gen.func
|
||||
@@ -82,6 +81,8 @@ class AsyncFunctionHandle(BaseHandle):
|
||||
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),
|
||||
@@ -90,11 +91,15 @@ class AsyncFunctionHandle(BaseHandle):
|
||||
'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),
|
||||
}
|
||||
try:
|
||||
self.Trans.VarScopes.append({})
|
||||
frame_ty: ir.IdentifiedStructType = self._GetOrCreateFrameType(name, Node, Gen)
|
||||
self._EmitCreateFunction(name, frame_ty, Gen)
|
||||
frame_ty: ir.IdentifiedStructType = self._GetOrCreateFrameType(name, Node, Gen, hoist_count)
|
||||
Gen._coro_hoist_counter = 0
|
||||
self._EmitCreateFunction(name, Node, frame_ty, Gen)
|
||||
self._EmitResumeFunction(name, Node, frame_ty, Gen)
|
||||
# 符号表注册(普通名称),供 _HandleCallLlvm 的类型解析
|
||||
if not self.Trans.SymbolTable.has(name):
|
||||
@@ -107,6 +112,8 @@ class AsyncFunctionHandle(BaseHandle):
|
||||
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
|
||||
@@ -123,52 +130,146 @@ class AsyncFunctionHandle(BaseHandle):
|
||||
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']
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 帧结构体与局部变量收集
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _GetOrCreateFrameType(self, name: str, Node: ast.AsyncFunctionDef, Gen: LlvmCodeGenerator) -> ir.IdentifiedStructType:
|
||||
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.If, ast.While, ast.For)):
|
||||
_walk(stmt.body)
|
||||
if stmt.orelse:
|
||||
_walk(stmt.orelse)
|
||||
continue
|
||||
else:
|
||||
continue
|
||||
if target not in seen:
|
||||
seen.add(target)
|
||||
vars_.append((target, slot_ty))
|
||||
|
||||
_walk(Node.body)
|
||||
return vars_
|
||||
|
||||
def _GetOrCreateFrameType(self, name: str, Node: ast.AsyncFunctionDef, Gen: LlvmCodeGenerator, hoist_count: int) -> ir.IdentifiedStructType:
|
||||
if not hasattr(Gen, '_coro_frame_types'):
|
||||
Gen._coro_frame_types = {}
|
||||
if not hasattr(Gen, '_coro_local_vars'):
|
||||
Gen._coro_local_vars = {}
|
||||
if 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]
|
||||
local_names: list[str] = self._CollectLocalVars(Node)
|
||||
# 参数:名字 + 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}
|
||||
# 提升临时变量槽:__await_0 .. __await_{hoist_count-1}
|
||||
fields: list[ir.Type] = [
|
||||
ir.IntType(32), # 0: state
|
||||
ir.IntType(32), # 1: done
|
||||
ir.IntType(32), # 2: ret
|
||||
]
|
||||
for _ in local_names:
|
||||
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 i in range(hoist_count):
|
||||
fields.append(ir.IntType(32))
|
||||
slot_vars.append(f'__await_{i}')
|
||||
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_local_vars[name] = local_names
|
||||
Gen._coro_slot_vars[name] = slot_vars
|
||||
Gen._coro_param_vars[name] = params
|
||||
return frame_ty
|
||||
|
||||
def _CollectLocalVars(self, Node: ast.AsyncFunctionDef) -> list[str]:
|
||||
"""收集协程体内顶层 AnnAssign/Assign 的 Name 目标(M1 仅 i32 槽)。"""
|
||||
names: list[str] = []
|
||||
seen: set[str] = set()
|
||||
# ------------------------------------------------------------------
|
||||
# 预扫描:嵌套 await 提升(分配 __await_N 临时槽)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _PreScanHoistedVars(self, Node: ast.AsyncFunctionDef, Gen: LlvmCodeGenerator) -> int:
|
||||
"""统计需提升的嵌套 await 数量(与翻译端提取顺序一致)。"""
|
||||
counter: int = 0
|
||||
for stmt in Node.body:
|
||||
target: str | None = None
|
||||
if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.target, ast.Name):
|
||||
target = stmt.target.id
|
||||
elif (isinstance(stmt, ast.Assign)
|
||||
and len(stmt.targets) == 1
|
||||
and isinstance(stmt.targets[0], ast.Name)):
|
||||
target = stmt.targets[0].id
|
||||
if target is not None and target not in seen:
|
||||
seen.add(target)
|
||||
names.append(target)
|
||||
return names
|
||||
counter = self._CountNestedAwaitForStmt(stmt, counter, Gen)
|
||||
return counter
|
||||
|
||||
def _CountNestedAwaitForStmt(self, stmt: ast.stmt, counter: int, Gen: LlvmCodeGenerator) -> int:
|
||||
if isinstance(stmt, (ast.If, ast.While)):
|
||||
for s in stmt.body:
|
||||
counter = self._CountNestedAwaitForStmt(s, counter, Gen)
|
||||
if stmt.orelse:
|
||||
for s in stmt.orelse:
|
||||
counter = self._CountNestedAwaitForStmt(s, counter, Gen)
|
||||
return counter
|
||||
if isinstance(stmt, ast.For):
|
||||
if any(isinstance(n, ast.Await) for n in ast.walk(stmt)):
|
||||
raise SyntaxError(
|
||||
f"[coro-M2] For 循环暂不支持 await(M3 实现)(line {getattr(stmt, 'lineno', 0)})"
|
||||
)
|
||||
return counter
|
||||
# 顶层 await 赋值(value 直接是 Await)不提升
|
||||
if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.value, ast.Await):
|
||||
return counter
|
||||
if (isinstance(stmt, ast.Assign)
|
||||
and len(stmt.targets) == 1
|
||||
and isinstance(stmt.targets[0], ast.Name)
|
||||
and isinstance(stmt.value, ast.Await)):
|
||||
return counter
|
||||
for n in ast.walk(stmt):
|
||||
if isinstance(n, ast.Await):
|
||||
counter += 1
|
||||
return counter
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# create_<name>() -> %Coro_<name>*
|
||||
# create_<name>(args...) -> %Coro_<name>*
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _GetMalloc(self, Gen: LlvmCodeGenerator) -> ir.Function:
|
||||
@@ -187,10 +288,12 @@ class AsyncFunctionHandle(BaseHandle):
|
||||
if mangled == raw_name or raw_name not in Gen._export_extern_funcs:
|
||||
Gen.functions[raw_name] = fn
|
||||
|
||||
def _EmitCreateFunction(self, name: str, frame_ty: ir.IdentifiedStructType, Gen: LlvmCodeGenerator) -> None:
|
||||
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)
|
||||
create_ty: ir.FunctionType = ir.FunctionType(ir.PointerType(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')
|
||||
@@ -203,46 +306,26 @@ class AsyncFunctionHandle(BaseHandle):
|
||||
for i in range(3):
|
||||
slot_ptr: ir.Value = Gen.builder.gep(frame_ptr, [zero32, ir.Constant(ir.IntType(32), i)], name=f'init_slot{i}')
|
||||
Gen._store(zero32, slot_ptr)
|
||||
# 参数存入帧槽(3 + i)
|
||||
for i in range(len(params)):
|
||||
slot_ptr = Gen.builder.gep(frame_ptr, [zero32, ir.Constant(ir.IntType(32), 3 + i)], name=f'param{i}_slot')
|
||||
arg_val: ir.Argument = create_fn.args[i]
|
||||
arg_val.name = f'arg{i}'
|
||||
Gen._store(arg_val, slot_ptr)
|
||||
Gen.builder.ret(frame_ptr)
|
||||
Gen.builder = None
|
||||
Gen.func = None
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# resume_<name>(%Coro_<name>*) -> i32 状态机
|
||||
# resume_<name>(%Coro_<name>*) -> i32 状态机(动态状态号)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _SplitBody(self, body: list[ast.stmt]) -> list[list[ast.stmt]]:
|
||||
"""按顶层 await 切分函数体。
|
||||
|
||||
await 仅识别 AnnAssign.value / Assign.value(Name 目标)顶层形式;
|
||||
含 await 的语句作为所在段的最后一条(翻译后 br exit 挂起)。
|
||||
"""
|
||||
segments: list[list[ast.stmt]] = []
|
||||
current: list[ast.stmt] = []
|
||||
for stmt in body:
|
||||
has_await: bool = False
|
||||
if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.value, ast.Await):
|
||||
has_await = True
|
||||
elif (isinstance(stmt, ast.Assign)
|
||||
and len(stmt.targets) == 1
|
||||
and isinstance(stmt.targets[0], ast.Name)
|
||||
and isinstance(stmt.value, ast.Await)):
|
||||
has_await = True
|
||||
current.append(stmt)
|
||||
if has_await:
|
||||
segments.append(current)
|
||||
current = []
|
||||
if current:
|
||||
segments.append(current)
|
||||
return segments
|
||||
|
||||
def _EmitResumeFunction(self, name: str, Node: ast.AsyncFunctionDef, frame_ty: ir.IdentifiedStructType, Gen: LlvmCodeGenerator) -> None:
|
||||
resume_ty: ir.FunctionType = ir.FunctionType(ir.IntType(32), [ir.PointerType(frame_ty)])
|
||||
resume_fn: ir.Function = ir.Function(Gen.module, resume_ty, name=Gen._mangle_func_name(f'resume_{name}'))
|
||||
self._RegisterCoroFunction(Gen, f'resume_{name}', resume_fn)
|
||||
resume_fn.attributes.add('noredzone')
|
||||
Gen.func = resume_fn
|
||||
segments: list[list[ast.stmt]] = self._SplitBody(Node.body)
|
||||
entry: ir.Block = resume_fn.append_basic_block('entry')
|
||||
Gen.builder = ir.IRBuilder(entry)
|
||||
frame_arg: ir.Argument = resume_fn.args[0]
|
||||
@@ -253,9 +336,10 @@ class AsyncFunctionHandle(BaseHandle):
|
||||
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)
|
||||
# 槽指针 → Gen.variables(读取/写入自动走帧字段 GEP)
|
||||
local_slot_ptrs: dict[str, ir.Value] = {}
|
||||
for idx, var in enumerate(Gen._coro_local_vars.get(name, [])):
|
||||
slot_vars: list[str] = getattr(Gen, '_coro_slot_vars', {}).get(name, [])
|
||||
for idx, var in enumerate(slot_vars):
|
||||
slot_ptr: ir.Value = Gen.builder.gep(
|
||||
frame_arg,
|
||||
[zero32, ir.Constant(ir.IntType(32), 3 + idx)],
|
||||
@@ -270,19 +354,16 @@ class AsyncFunctionHandle(BaseHandle):
|
||||
Gen._coro_exit_bb = exit_bb
|
||||
Gen._coro_frame_ptr = frame_arg
|
||||
switch_instr: Any = Gen.builder.switch(state_val, exit_bb)
|
||||
state_bbs: list[ir.Block] = []
|
||||
for i in range(len(segments)):
|
||||
bb: ir.Block = resume_fn.append_basic_block(f'state{i}')
|
||||
state_bbs.append(bb)
|
||||
switch_instr.add_case(ir.Constant(ir.IntType(32), i), bb)
|
||||
# 逐段生成
|
||||
for i, seg in enumerate(segments):
|
||||
Gen.builder.position_at_start(state_bbs[i])
|
||||
Gen.variables = dict(local_slot_ptrs)
|
||||
Gen._coro_next_state = i + 1
|
||||
self._HandleCoroSegment(seg, Gen)
|
||||
if Gen.builder is not None and not Gen.builder.block.is_terminated:
|
||||
self._EmitCoroImplicitReturn(Gen)
|
||||
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')
|
||||
@@ -296,37 +377,116 @@ class AsyncFunctionHandle(BaseHandle):
|
||||
|
||||
def _HandleCoroSegment(self, stmts: list[ast.stmt], Gen: LlvmCodeGenerator) -> None:
|
||||
for stmt in stmts:
|
||||
if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.value, ast.Await):
|
||||
self._HandleCoroAwaitAnnAssign(stmt, Gen)
|
||||
if Gen.builder is None or Gen.builder.block.is_terminated:
|
||||
return
|
||||
Gen._set_node_info(stmt)
|
||||
if isinstance(stmt, ast.Return):
|
||||
self._HandleCoroReturn(stmt, Gen)
|
||||
continue
|
||||
if (isinstance(stmt, ast.AnnAssign)
|
||||
and isinstance(stmt.target, ast.Name)
|
||||
and isinstance(stmt.value, ast.Await)):
|
||||
self._HandleCoroAwaitAnnAssign(stmt, Gen)
|
||||
continue
|
||||
if (isinstance(stmt, ast.Assign)
|
||||
and len(stmt.targets) == 1
|
||||
and isinstance(stmt.targets[0], ast.Name)
|
||||
and isinstance(stmt.value, ast.Await)):
|
||||
self._HandleCoroAwaitAssign(stmt, Gen)
|
||||
return
|
||||
if isinstance(stmt, ast.Return):
|
||||
self._HandleCoroReturn(stmt, Gen)
|
||||
return
|
||||
# M1 防御:await 仅支持顶层(AnnAssign/Assign 的 value 直接是 Await)
|
||||
continue
|
||||
if isinstance(stmt, ast.If):
|
||||
self._HandleCoroIf(stmt, Gen)
|
||||
continue
|
||||
if isinstance(stmt, ast.While):
|
||||
self._HandleCoroWhile(stmt, Gen)
|
||||
continue
|
||||
if isinstance(stmt, ast.For):
|
||||
self._HandleCoroFor(stmt, Gen)
|
||||
continue
|
||||
if isinstance(stmt, ast.Break):
|
||||
if Gen.loop_break_targets:
|
||||
Gen.builder.branch(Gen.loop_break_targets[-1])
|
||||
continue
|
||||
if isinstance(stmt, ast.Continue):
|
||||
if Gen.loop_continue_targets:
|
||||
Gen.builder.branch(Gen.loop_continue_targets[-1])
|
||||
continue
|
||||
if isinstance(stmt, ast.Pass):
|
||||
continue
|
||||
# 语句内嵌套 await(非顶层)→ 提升
|
||||
if any(isinstance(n, ast.Await) for n in ast.walk(stmt)):
|
||||
raise SyntaxError(
|
||||
f"[coro-M1] await 仅支持顶层赋值形式 `var: int = await fn()` "
|
||||
f"(line {getattr(stmt, 'lineno', 0)})"
|
||||
)
|
||||
if isinstance(stmt, ast.AnnAssign):
|
||||
self.Trans.AnnAssignHandler._HandleAnnAssignLlvm(stmt)
|
||||
self._HandleNestedAwaitStmt(stmt, Gen)
|
||||
continue
|
||||
if isinstance(stmt, ast.Assign):
|
||||
self.Trans.AssignHandler._HandleAssignLlvm(stmt)
|
||||
continue
|
||||
if isinstance(stmt, ast.Expr):
|
||||
self.Trans.ExprHandler.HandleExprLlvm(stmt.value)
|
||||
continue
|
||||
raise SyntaxError(
|
||||
f"[coro-M1] async 函数体暂不支持语句: {type(stmt).__name__} "
|
||||
f"(line {getattr(stmt, 'lineno', 0)})"
|
||||
self._TranslateOrdinaryStmt(stmt, Gen)
|
||||
|
||||
def _TranslateOrdinaryStmt(self, stmt: ast.stmt, Gen: LlvmCodeGenerator) -> None:
|
||||
if isinstance(stmt, ast.AnnAssign):
|
||||
self.Trans.AnnAssignHandler._HandleAnnAssignLlvm(stmt)
|
||||
return
|
||||
if isinstance(stmt, ast.Assign):
|
||||
self.Trans.AssignHandler._HandleAssignLlvm(stmt)
|
||||
return
|
||||
if isinstance(stmt, ast.Expr):
|
||||
self.Trans.ExprHandler.HandleExprLlvm(stmt.value)
|
||||
return
|
||||
raise SyntaxError(
|
||||
f"[coro-M2] async 函数体暂不支持语句: {type(stmt).__name__} "
|
||||
f"(line {getattr(stmt, 'lineno', 0)})"
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 嵌套 await 提升:a = b + await f() → __await_N = await f(); a = b + __await_N
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _FindFirstAwait(self, node: ast.AST) -> ast.Await | None:
|
||||
for n in ast.walk(node):
|
||||
if isinstance(n, ast.Await):
|
||||
return n
|
||||
return None
|
||||
|
||||
def _ReplaceAwaitWithName(self, node: ast.AST, temp_name: str) -> bool:
|
||||
"""把语句树中第一个 Await 替换为 Name(temp_name, Load)(DFS 顺序)。"""
|
||||
for field in node._fields:
|
||||
val: Any = getattr(node, field, None)
|
||||
if isinstance(val, ast.Await):
|
||||
setattr(node, field, ast.Name(temp_name, ast.Load()))
|
||||
return True
|
||||
if isinstance(val, list):
|
||||
for i, item in enumerate(val):
|
||||
if isinstance(item, ast.Await):
|
||||
val[i] = ast.Name(temp_name, ast.Load())
|
||||
return True
|
||||
if isinstance(item, ast.AST):
|
||||
if self._ReplaceAwaitWithName(item, temp_name):
|
||||
return True
|
||||
elif isinstance(val, ast.AST):
|
||||
if self._ReplaceAwaitWithName(val, temp_name):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _HandleNestedAwaitStmt(self, stmt: ast.stmt, Gen: LlvmCodeGenerator) -> None:
|
||||
"""把语句中所有嵌套 await 提升为顶层临时赋值(与预扫描顺序一致)。"""
|
||||
counter: int = getattr(Gen, '_coro_hoist_counter', 0)
|
||||
while True:
|
||||
await_node: ast.Await | None = self._FindFirstAwait(stmt)
|
||||
if await_node is None:
|
||||
break
|
||||
temp_name: str = f'__await_{counter}'
|
||||
counter += 1
|
||||
hoisted: ast.Assign = ast.Assign(
|
||||
targets=[ast.Name(temp_name, ast.Store())],
|
||||
value=await_node,
|
||||
type_comment=None,
|
||||
)
|
||||
# 提升赋值挂起 + position 到恢复块
|
||||
self._HandleCoroAwaitAssign(hoisted, Gen)
|
||||
self._ReplaceAwaitWithName(stmt, temp_name)
|
||||
Gen._coro_hoist_counter = counter
|
||||
self._TranslateOrdinaryStmt(stmt, Gen)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# await 表达式翻译
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _HandleCoroAwaitAnnAssign(self, stmt: ast.AnnAssign, Gen: LlvmCodeGenerator) -> None:
|
||||
target: str = stmt.target.id
|
||||
@@ -353,13 +513,33 @@ class AsyncFunctionHandle(BaseHandle):
|
||||
async_name: str | None = self._GetAsyncCallName(call) if isinstance(call, ast.Call) else None
|
||||
if not async_name:
|
||||
raise SyntaxError(
|
||||
f"[coro-M1] await 目标必须是 async 函数调用 (line {getattr(await_node, 'lineno', 0)})"
|
||||
f"[coro-M2] await 目标必须是 async 函数调用 (line {getattr(await_node, 'lineno', 0)})"
|
||||
)
|
||||
self.Trans.ExprHandler.HandleExprLlvm(await_node) # → _HandleAwaitLlvm
|
||||
|
||||
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(M1 假设一次完成)-> 取子帧 ret -> 存父帧槽 -> 父挂起。
|
||||
创建子帧(含参数)-> resume 到 DONE -> 取子帧 ret -> 存父帧槽
|
||||
-> 父挂起(state=新恢复块编号、ret=0)-> position 到恢复块继续。
|
||||
"""
|
||||
zero32: ir.Constant = ir.Constant(ir.IntType(32), 0)
|
||||
call: Any = Node.value
|
||||
@@ -371,7 +551,16 @@ class AsyncFunctionHandle(BaseHandle):
|
||||
resume_fn: ir.Function | None = Gen._get_function(f'resume_{async_name}')
|
||||
if not frame_ty or not create_fn or not resume_fn:
|
||||
return zero32
|
||||
child: ir.Value = Gen.builder.call(create_fn, [], name=f'create_{async_name}')
|
||||
# 子协程参数
|
||||
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,
|
||||
@@ -383,16 +572,23 @@ class AsyncFunctionHandle(BaseHandle):
|
||||
slot: ir.Value | None = getattr(Gen, '_coro_await_slot_ptr', None)
|
||||
if slot is not None:
|
||||
Gen._store(child_ret, slot)
|
||||
# 父挂起:state = 下一切片,ret = 0(SUSPEND)
|
||||
# 父挂起:分配新恢复块(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), getattr(Gen, '_coro_next_state', 1)), state_ptr)
|
||||
Gen._store(ir.Constant(ir.IntType(32), state_no), state_ptr)
|
||||
ret_field_ptr: ir.Value | None = getattr(Gen, '_coro_ret_field_ptr', None)
|
||||
if ret_field_ptr is not None:
|
||||
Gen._store(zero32, ret_field_ptr)
|
||||
exit_bb: ir.Block | None = getattr(Gen, '_coro_exit_bb', None)
|
||||
if exit_bb is not None:
|
||||
Gen.builder.branch(exit_bb)
|
||||
Gen.builder.position_at_start(resume_bb)
|
||||
return child_ret
|
||||
|
||||
def _HandleCoroReturn(self, stmt: ast.Return, Gen: LlvmCodeGenerator) -> None:
|
||||
@@ -417,7 +613,96 @@ class AsyncFunctionHandle(BaseHandle):
|
||||
Gen.builder.branch(Gen._coro_exit_bb)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 普通函数调用 async 函数:task() -> create_task()(返回帧指针)
|
||||
# 控制流(协程版:body 内 await 就地挂起/恢复)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _HandleCoroIf(self, Node: ast.If, Gen: LlvmCodeGenerator) -> None:
|
||||
if any(isinstance(n, ast.Await) for n in ast.walk(Node.test)):
|
||||
raise SyntaxError(
|
||||
f"[coro-M2] if 条件中不支持 await (line {getattr(Node, 'lineno', 0)})"
|
||||
)
|
||||
Cond: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.test)
|
||||
if not Cond:
|
||||
return
|
||||
if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1:
|
||||
if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)):
|
||||
Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name='coro_ifcond')
|
||||
else:
|
||||
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name='coro_ifcond')
|
||||
ThenBB: ir.Block = Gen.func.append_basic_block(name='coro_then')
|
||||
ElseBB: ir.Block | None = Gen.func.append_basic_block(name='coro_else') if Node.orelse else None
|
||||
MergeBB: ir.Block = Gen.func.append_basic_block(name='coro_endif')
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.cbranch(Cond, ThenBB, ElseBB if ElseBB else MergeBB)
|
||||
Gen.builder.position_at_start(ThenBB)
|
||||
self._HandleCoroSegment(Node.body, Gen)
|
||||
if Gen.builder is not None and not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(MergeBB)
|
||||
if ElseBB:
|
||||
Gen.builder.position_at_start(ElseBB)
|
||||
self._HandleCoroSegment(Node.orelse, Gen)
|
||||
if Gen.builder is not None and not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(MergeBB)
|
||||
if not MergeBB.is_terminated:
|
||||
Gen.builder.position_at_start(MergeBB)
|
||||
else:
|
||||
Gen.builder.position_at_end(MergeBB)
|
||||
|
||||
def _HandleCoroWhile(self, Node: ast.While, Gen: LlvmCodeGenerator) -> None:
|
||||
if any(isinstance(n, ast.Await) for n in ast.walk(Node.test)):
|
||||
raise SyntaxError(
|
||||
f"[coro-M2] while 条件中不支持 await (line {getattr(Node, 'lineno', 0)})"
|
||||
)
|
||||
CondBB: ir.Block = Gen.func.append_basic_block(name='coro_wcond')
|
||||
BodyBB: ir.Block = Gen.func.append_basic_block(name='coro_wbody')
|
||||
ElseBB: ir.Block | None = Gen.func.append_basic_block(name='coro_welse') if Node.orelse else None
|
||||
AfterBB: ir.Block = Gen.func.append_basic_block(name='coro_wend')
|
||||
Gen.loop_break_targets.append(AfterBB)
|
||||
Gen.loop_continue_targets.append(CondBB)
|
||||
Gen.builder.branch(CondBB)
|
||||
Gen.builder.position_at_start(CondBB)
|
||||
Cond: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.test)
|
||||
if Cond:
|
||||
if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1:
|
||||
if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)):
|
||||
Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name='coro_wcond')
|
||||
else:
|
||||
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name='coro_wcond')
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB)
|
||||
else:
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(ElseBB if ElseBB else AfterBB)
|
||||
Gen.builder.position_at_start(BodyBB)
|
||||
self._HandleCoroSegment(Node.body, Gen)
|
||||
if Gen.builder is not None and not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(CondBB)
|
||||
Gen.loop_break_targets.pop()
|
||||
Gen.loop_continue_targets.pop()
|
||||
if ElseBB:
|
||||
Gen.builder.position_at_start(ElseBB)
|
||||
self._HandleCoroSegment(Node.orelse, Gen)
|
||||
if Gen.builder is not None and not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(AfterBB)
|
||||
if not AfterBB.is_terminated:
|
||||
Gen.builder.position_at_start(AfterBB)
|
||||
else:
|
||||
Gen.builder.position_at_end(AfterBB)
|
||||
|
||||
def _HandleCoroFor(self, Node: ast.For, Gen: LlvmCodeGenerator) -> None:
|
||||
if any(isinstance(n, ast.Await) for n in ast.walk(Node)):
|
||||
raise SyntaxError(
|
||||
f"[coro-M2] For 循环暂不支持 await(M3 实现)(line {getattr(Node, 'lineno', 0)})"
|
||||
)
|
||||
if any(isinstance(n, ast.Return) for n in ast.walk(Node.body)):
|
||||
raise SyntaxError(
|
||||
f"[coro-M2] For 循环体内暂不支持 return(M3 实现)(line {getattr(Node, 'lineno', 0)})"
|
||||
)
|
||||
# 无 await/return:委托现有 ForHandler(迭代索引等 alloca 不跨挂起,安全)
|
||||
self.Trans.ForHandler._HandleForLlvm(Node)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 普通函数调用 async 函数:task(...) -> create_task(...)(返回帧指针)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _HandleAsyncCreateCallLlvm(self, Node: ast.Call, FuncName: str) -> ir.Value:
|
||||
@@ -425,11 +710,19 @@ class AsyncFunctionHandle(BaseHandle):
|
||||
create_fn: ir.Function | None = Gen._get_function(f'create_{FuncName}')
|
||||
if not create_fn:
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
result: ir.Value = Gen.builder.call(create_fn, [], name=f'create_{FuncName}')
|
||||
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(帧) 内联翻译(M1)
|
||||
# coro.coro_run(帧) 内联翻译
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _HandleCoroRunLlvm(self, Node: ast.Call, Gen: LlvmCodeGenerator) -> ir.Value:
|
||||
|
||||
Reference in new issue
Block a user