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:
1 parent
4640211e3c
commit
3acf24c7d0
4 files changed
+291
-68
No files matched your search
@@ -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
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in new issue
Block a user