feat(coro): M3——For 内 await、coro_sleep 挂起、coro_destroy 释放帧

- For 内 await:range 迭代变换为 While(__f_idx_N/__f_len_N 帧槽),复用协程版 While
  就地挂起/恢复;For 迭代目标进帧槽跨挂起存活;仅支持 range 1/2 参数
- coro_sleep(ms):帧加 __coro_wake_us(i64)唤醒槽,挂起后 coro_run 轮询
  GetTickCount64,未到点 Sleep(1) 续轮询,到点自动恢复
- coro_destroy(帧):coro.coro_destroy 内联翻译为 free 释放帧内存
- coro.vp 追加 coro_sleep/coro_destroy 占位;CoroTest 用例覆盖
  for+await/sleep/destroy(期望 coro result = 15)
This commit is contained in:
TermiNexus committed 2026-08-21 14:17:27 +08:00
1 parent 4640211e3c
commit 3acf24c7d0
4 files changed
+291 -68

No files matched your search

+5 -9
View File
@@ -9,20 +9,16 @@ async def leaf(x: int) -> int:
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:
for i in range(base):
s = s + await leaf(i)
i = i + 1
if s > 5:
s = s + await leaf(10)
return s + a + b
await coro_sleep(100)
return s
def main() -> t.CInt:
tt: coro.Coroutine = task(2)
tt: coro.Coroutine = task(5)
r: t.CInt = coro.coro_run(tt)
stdio.printf("coro result = %d\n", r)
coro.coro_destroy(tt)
return 0
+10
View File
@@ -26,3 +26,13 @@ def coro_run(c: Coroutine) -> t.CInt:
while s == 0:
s = coro_resume(c)
return coro_result(c)
def coro_sleep(ms: t.CInt) -> t.CInt:
# M3 占位:编译器将 await coro_sleep(ms) 内联翻译为帧 wake 槽挂起,
# 本函数不会被真正调用(仅保证模块可编译)。
return 0
def coro_destroy(c: Coroutine) -> t.CVoid:
# M3 占位:编译器将 coro.coro_destroy(帧) 内联翻译为 free。
return
+271 -58
View File
@@ -10,16 +10,15 @@ from lib.includes import t
class AsyncFunctionHandle(BaseHandle):
"""语言内协程 M2:async def + await + coro_run 状态机翻译。
"""语言内协程 M3:async def + await + coro_run 状态机翻译。
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 分发。
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, <参数槽>, <局部槽>, <提升临时槽> }
帧布局:%Coro_<name> = type { i32 state, i32 done, i32 ret, <参数槽>, <局部槽>, <额外槽(wake/for/await)> }
状态机:create_<name>(args...) 分配帧 + 存参数;resume_<name>(frame) -> i32
(0=SUSPEND 1=DONE)按 state 分发到主入口 state0 与各恢复块。
"""
@@ -65,11 +64,11 @@ class AsyncFunctionHandle(BaseHandle):
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
# 预扫描额外槽(嵌套 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
@@ -94,11 +93,14 @@ class AsyncFunctionHandle(BaseHandle):
'switch': getattr(Gen, '_coro_switch_instr', None),
'state_counter': getattr(Gen, '_coro_state_counter', None),
'hoist_counter': getattr(Gen, '_coro_hoist_counter', None),
'for_counter': getattr(Gen, '_coro_for_counter', None),
'wake_ptr': getattr(Gen, '_coro_wake_ptr', None),
}
try:
self.Trans.VarScopes.append({})
frame_ty: ir.IdentifiedStructType = self._GetOrCreateFrameType(name, Node, Gen, hoist_count)
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 的类型解析
@@ -133,6 +135,8 @@ class AsyncFunctionHandle(BaseHandle):
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']
# ------------------------------------------------------------------
# 帧结构体与局部变量收集
@@ -173,7 +177,18 @@ class AsyncFunctionHandle(BaseHandle):
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)):
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)
@@ -187,7 +202,7 @@ class AsyncFunctionHandle(BaseHandle):
_walk(Node.body)
return vars_
def _GetOrCreateFrameType(self, name: str, Node: ast.AsyncFunctionDef, Gen: LlvmCodeGenerator, hoist_count: int) -> ir.IdentifiedStructType:
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'):
@@ -204,7 +219,7 @@ class AsyncFunctionHandle(BaseHandle):
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}
# 额外槽:__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
@@ -219,9 +234,9 @@ class AsyncFunctionHandle(BaseHandle):
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}')
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
@@ -234,39 +249,59 @@ class AsyncFunctionHandle(BaseHandle):
# 预扫描:嵌套 await 提升(分配 __await_N 临时槽)
# ------------------------------------------------------------------
def _PreScanHoistedVars(self, Node: ast.AsyncFunctionDef, Gen: LlvmCodeGenerator) -> int:
"""统计需提升的嵌套 await 数量(与翻译端提取顺序一致)。"""
counter: int = 0
for stmt in Node.body:
counter = self._CountNestedAwaitForStmt(stmt, counter, Gen)
return counter
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 _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
def _walk(stmts: list[ast.stmt]) -> None:
for stmt in stmts:
if isinstance(stmt, (ast.If, ast.While)):
_walk(stmt.body)
if stmt.orelse:
_walk(stmt.orelse)
continue
if isinstance(stmt, ast.For):
if not any(isinstance(n, ast.Await) for n in ast.walk(stmt)):
continue # 无 await:委托 ForHandler,不需额外槽
if not self._IsRangeFor(stmt):
raise SyntaxError(
f"[coro-M3] 协程内 For 仅支持 range 迭代(含 await)"
f"(line {getattr(stmt, 'lineno', 0)})"
)
slots.append(f'__f_idx_{for_counter}')
slots.append(f'__f_len_{for_counter}')
for_counter += 1
_walk(stmt.body)
continue
# 顶层 await(value 直接是 Await)不提升,但仍检测 coro_sleep
if (isinstance(stmt, ast.AnnAssign) and isinstance(stmt.value, ast.Await)) or (
isinstance(stmt, ast.Assign)
and len(stmt.targets) == 1
and isinstance(stmt.targets[0], ast.Name)
and isinstance(stmt.value, ast.Await)) or (
isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Await)):
for _n in ast.walk(stmt):
if isinstance(_n, ast.Call) and self._IsCoroSleepCall(_n):
uses_sleep[0] = True
continue
for n in ast.walk(stmt):
if isinstance(n, ast.Await):
slots.append(f'__await_{await_counter}')
await_counter += 1
if isinstance(n, ast.Call) and self._IsCoroSleepCall(n):
uses_sleep[0] = True
_walk(Node.body)
if uses_sleep[0]:
slots.insert(0, '__coro_wake_us')
return slots
# ------------------------------------------------------------------
# create_<name>(args...) -> %Coro_<name>*
@@ -346,6 +381,8 @@ class AsyncFunctionHandle(BaseHandle):
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
@@ -394,6 +431,9 @@ class AsyncFunctionHandle(BaseHandle):
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
@@ -508,15 +548,109 @@ class AsyncFunctionHandle(BaseHandle):
def _HandleCoroAwaitCommon(self, target: str, await_node: ast.Await, Gen: LlvmCodeGenerator) -> None:
"""await 顶层翻译:设置目标槽后调用 _HandleAwaitLlvm(生成子帧/resume/挂起)。"""
Gen._coro_await_slot_ptr = Gen.variables.get(target)
# 校验 await 目标必须是 async 函数调用,且子协程已生成
# 校验 await 目标:async 函数调用 或 coro_sleep(ms)
call: Any = await_node.value
if isinstance(call, ast.Call) and self._IsCoroSleepCall(call):
self.Trans.ExprHandler.HandleExprLlvm(await_node) # → _HandleAwaitLlvm(sleep)
return
async_name: str | None = self._GetAsyncCallName(call) if isinstance(call, ast.Call) else None
if not async_name:
raise SyntaxError(
f"[coro-M2] await 目标必须是 async 函数调用 (line {getattr(await_node, 'lineno', 0)})"
f"[coro-M3] await 目标必须是 async 函数调用或 coro_sleep(ms) "
f"(line {getattr(await_node, 'lineno', 0)})"
)
self.Trans.ExprHandler.HandleExprLlvm(await_node) # → _HandleAwaitLlvm
def _IsCoroSleepCall(self, call: ast.Call) -> bool:
return (isinstance(call.func, ast.Name) and call.func.id == 'coro_sleep') or (
isinstance(call.func, ast.Attribute)
and call.func.attr == 'coro_sleep'
and isinstance(call.func.value, ast.Name)
and self._IsCoroModule(call.func.value.id)
)
def _GetWinFunc(self, name: str, Gen: LlvmCodeGenerator, ret_ty: ir.Type,
args: list[ir.Type] | None = None) -> ir.Function:
fn: ir.Function | None = Gen._get_function(name)
if fn is not None:
return fn
fn = ir.Function(Gen.module, ir.FunctionType(ret_ty, args or []), name=name)
Gen.functions[name] = fn
return fn
def _GetFree(self, Gen: LlvmCodeGenerator) -> ir.Function:
for fn in Gen.module.global_values:
if getattr(fn, 'name', None) == 'free':
return fn
fn = ir.Function(Gen.module, ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]), name='free')
Gen.functions['free'] = fn
return fn
def _HandleAwaitSleepLlvm(self, call: ast.Call, Gen: LlvmCodeGenerator) -> ir.Value:
"""await coro_sleep(ms):wake = GetTickCount64() + ms 存帧,挂起(coro_run 轮询续跑)。"""
zero32: ir.Constant = ir.Constant(ir.IntType(32), 0)
ms_val: ir.Value = ir.Constant(ir.IntType(64), 0)
if call.args:
ms_v: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(call.args[0])
if ms_v is not None and isinstance(ms_v.type, ir.IntType):
if ms_v.type.width < 64:
ms_val = Gen.builder.zext(ms_v, ir.IntType(64), name='zext_sleep_ms')
elif ms_v.type.width > 64:
ms_val = Gen.builder.trunc(ms_v, ir.IntType(64), name='trunc_sleep_ms')
else:
ms_val = ms_v
now_fn: ir.Function = self._GetWinFunc('GetTickCount64', Gen, ir.IntType(64))
now_val: ir.Value = Gen.builder.call(now_fn, [], name='tick_now')
wake_val: ir.Value = Gen.builder.add(now_val, ms_val, name='coro_wake_us')
wake_ptr: ir.Value | None = getattr(Gen, '_coro_wake_ptr', None)
if wake_ptr is not None:
Gen._store(wake_val, wake_ptr)
# 挂起:分配恢复块 + state + ret=0 + br exit + position 恢复块
state_no: int = getattr(Gen, '_coro_state_counter', 1)
Gen._coro_state_counter = state_no + 1
resume_bb: ir.Block = Gen.func.append_basic_block(f'state{state_no}')
switch_instr: Any = getattr(Gen, '_coro_switch_instr', None)
if switch_instr is not None:
switch_instr.add_case(ir.Constant(ir.IntType(32), state_no), resume_bb)
state_ptr: ir.Value | None = getattr(Gen, '_coro_state_ptr', None)
if state_ptr is not None:
Gen._store(ir.Constant(ir.IntType(32), state_no), state_ptr)
ret_field_ptr: ir.Value | None = getattr(Gen, '_coro_ret_field_ptr', None)
if ret_field_ptr is not None:
Gen._store(zero32, ret_field_ptr)
exit_bb: ir.Block | None = getattr(Gen, '_coro_exit_bb', None)
if exit_bb is not None:
Gen.builder.branch(exit_bb)
Gen.builder.position_at_start(resume_bb)
return zero32
def _HandleCoroDestroyLlvm(self, Node: ast.Call, Gen: LlvmCodeGenerator) -> ir.Value:
"""coro.coro_destroy(帧):释放帧内存(free)。"""
if not Node.args:
return ir.Constant(ir.IntType(32), 0)
arg: ast.expr = Node.args[0]
async_name: str | None = None
if isinstance(arg, ast.Name):
async_name = getattr(Gen, '_coro_var_async', {}).get(arg.id)
if not async_name:
return ir.Constant(ir.IntType(32), 0)
frame_ty: ir.IdentifiedStructType | None = getattr(Gen, '_coro_frame_types', {}).get(async_name)
if not frame_ty:
return ir.Constant(ir.IntType(32), 0)
frame_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(arg)
if frame_val is None:
return ir.Constant(ir.IntType(32), 0)
if isinstance(frame_val.type, ir.PointerType):
frame_ptr: ir.Value = Gen.builder.bitcast(frame_val, ir.PointerType(frame_ty), name='coro_frame')
elif isinstance(frame_val.type, ir.IntType):
frame_ptr = Gen.builder.inttoptr(frame_val, ir.PointerType(frame_ty), name='coro_frame')
else:
return ir.Constant(ir.IntType(32), 0)
free_fn: ir.Function = self._GetFree(Gen)
raw: ir.Value = Gen.builder.bitcast(frame_ptr, ir.IntType(8).as_pointer(), name='coro_free_ptr')
Gen.builder.call(free_fn, [raw])
return ir.Constant(ir.IntType(32), 0)
def _CoerceArg(self, v: ir.Value | None, target_ty: ir.Type, Gen: LlvmCodeGenerator, name: str = 'arg') -> ir.Value:
"""实参转换到 create 形参类型(int 宽转换 / 指针 bitcast)。"""
if v is None:
@@ -543,6 +677,9 @@ class AsyncFunctionHandle(BaseHandle):
"""
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
@@ -691,9 +828,13 @@ class AsyncFunctionHandle(BaseHandle):
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 not self._IsRangeFor(Node):
raise SyntaxError(
f"[coro-M3] 协程内 For 仅支持 range 迭代(含 await)"
f"(line {getattr(Node, 'lineno', 0)})"
)
self._HandleCoroForRange(Node, Gen)
return
if any(isinstance(n, ast.Return) for n in ast.walk(Node.body)):
raise SyntaxError(
f"[coro-M2] For 循环体内暂不支持 return(M3 实现)(line {getattr(Node, 'lineno', 0)})"
@@ -701,6 +842,57 @@ class AsyncFunctionHandle(BaseHandle):
# 无 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(...)(返回帧指针)
# ------------------------------------------------------------------
@@ -749,11 +941,32 @@ class AsyncFunctionHandle(BaseHandle):
return ir.Constant(ir.IntType(32), 0)
loop_bb: ir.Block = Gen.func.append_basic_block('coro_loop')
after_bb: ir.Block = Gen.func.append_basic_block('coro_after')
check_bb: ir.Block = Gen.func.append_basic_block('coro_wcheck')
wake_wait_bb: ir.Block = Gen.func.append_basic_block('coro_wsleep')
wake_due_bb: ir.Block = Gen.func.append_basic_block('coro_wdue')
Gen.builder.branch(loop_bb)
Gen.builder.position_at_start(loop_bb)
status: ir.Value = Gen.builder.call(resume_fn, [frame_ptr], name=f'resume_{async_name}')
done_cond: ir.Value = Gen.builder.icmp_signed('!=', status, ir.Constant(ir.IntType(32), 0), name='coro_done_cond')
Gen.builder.cbranch(done_cond, after_bb, loop_bb)
Gen.builder.cbranch(done_cond, after_bb, check_bb)
# SUSPEND:若 coro_sleep 唤醒槽存在且未到点,Sleep(1) 后继续轮询
Gen.builder.position_at_start(check_bb)
wake_ptr: ir.Value | None = getattr(Gen, '_coro_wake_ptr', None)
if wake_ptr is not None:
wake_val: ir.Value = Gen._load(wake_ptr, name='coro_wake')
now_fn: ir.Function = self._GetWinFunc('GetTickCount64', Gen, ir.IntType(64))
now_val: ir.Value = Gen.builder.call(now_fn, [], name='tick_now')
not_wake: ir.Value = Gen.builder.icmp_signed('==', wake_val, ir.Constant(ir.IntType(64), 0), name='coro_wake_zero')
due: ir.Value = Gen.builder.icmp_unsigned('>=', now_val, wake_val, name='coro_wake_due')
sleep_cond: ir.Value = Gen.builder.or_(not_wake, due, name='coro_continue_cond')
Gen.builder.cbranch(sleep_cond, wake_due_bb, wake_wait_bb)
Gen.builder.position_at_start(wake_wait_bb)
sleep_fn: ir.Function = self._GetWinFunc('Sleep', Gen, ir.VoidType(), [ir.IntType(32)])
Gen.builder.call(sleep_fn, [ir.Constant(ir.IntType(32), 1)])
Gen.builder.branch(loop_bb)
Gen.builder.position_at_start(wake_due_bb)
else:
Gen.builder.branch(loop_bb)
Gen.builder.position_at_start(after_bb)
ret_ptr: ir.Value = Gen.builder.gep(
frame_ptr,
+5 -1
View File
@@ -274,10 +274,14 @@ class ExprCallHandle(BaseHandle):
def _HandleCallLlvm(self, Node: ast.Call) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
# M1 协程:coro.coro_run(帧) 内联翻译为 resume 循环
# 协程:coro.coro_run(帧) 内联翻译为 resume 循环
if isinstance(Node.func, ast.Attribute) and Node.func.attr == 'coro_run':
if isinstance(Node.func.value, ast.Name) and self.Trans.AsyncHandler._IsCoroModule(Node.func.value.id):
return self.Trans.AsyncHandler._HandleCoroRunLlvm(Node, Gen)
# 协程:coro.coro_destroy(帧) 内联翻译为 free
if isinstance(Node.func, ast.Attribute) and Node.func.attr == 'coro_destroy':
if isinstance(Node.func.value, ast.Name) and self.Trans.AsyncHandler._IsCoroModule(Node.func.value.id):
return self.Trans.AsyncHandler._HandleCoroDestroyLlvm(Node, Gen)
FuncAttr: str | None = None
ModulePath: str | None = None
if isinstance(Node.func, ast.Name):