diff --git a/Test/CoroTest/App/main.vp b/Test/CoroTest/App/main.vp index 5f77b7b..a9270e3 100644 --- a/Test/CoroTest/App/main.vp +++ b/Test/CoroTest/App/main.vp @@ -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 \ No newline at end of file diff --git a/includes/coro.vp b/includes/coro.vp index f0e1e0e..3cfa02a 100644 --- a/includes/coro.vp +++ b/includes/coro.vp @@ -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 diff --git a/lib/core/Handles/HandlesAsyncFunctions.py b/lib/core/Handles/HandlesAsyncFunctions.py index 216a734..00699c7 100644 --- a/lib/core/Handles/HandlesAsyncFunctions.py +++ b/lib/core/Handles/HandlesAsyncFunctions.py @@ -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_ 带参数并存入帧。 - - 嵌套 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_ = type { i32 state, i32 done, i32 ret, <参数槽>, <局部槽>, <提升临时槽> } + 帧布局:%Coro_ = type { i32 state, i32 done, i32 ret, <参数槽>, <局部槽>, <额外槽(wake/for/await)> } 状态机:create_(args...) 分配帧 + 存参数;resume_(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_(args...) -> %Coro_* @@ -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; ; __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, diff --git a/lib/core/Handles/HandlesExprCall.py b/lib/core/Handles/HandlesExprCall.py index 7bfa2ce..65df6b4 100644 --- a/lib/core/Handles/HandlesExprCall.py +++ b/lib/core/Handles/HandlesExprCall.py @@ -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):