feat(gen): 控制流汇合 Meet(M2.2)

- VarGenMixin:life_capture/life_restore/life_join(作用域链快照,池上 [count,(entry,life)…] 数组)。 - StmtGenCifMixin.translate_if:进分支前快照、then 末快照、else 前复位、出口按 min 合并。 - StmtGenMixin:while/for 统一在语句分派处 capture→run→join(一处覆盖全部迭代形态与解糖,含 0 次迭代路径)。
This commit is contained in:
TermiNexus committed 2026-10-08 12:35:59 +08:00
1 parent ec47401151
commit a6e1957768
3 files changed
+79 -2

No files matched your search

+12
View File
@@ -708,6 +708,9 @@ novirtual class StmtGenCifMixin:
if has_else == 1: mlirlite.build_cond_br(builder, cond_i1, then_bb, else_bb)
else: mlirlite.build_cond_br(builder, cond_i1, then_bb, merge_bb)
# 生命期汇合:进入分支前快照(else 分支需从该状态重新开始,见 §11 控制流 Meet)
life_snap0: sizet* = self.Gen.VarGen.life_capture(trans)
# 5. translate the then body; reset the merge-reachable flag first (nested control flow
# overwrites it, so the branch-tail check must not see a stale value from before this If).
trans._ctrl_merge_reachable = 1
@@ -730,9 +733,14 @@ novirtual class StmtGenCifMixin:
mlirlite.build_br(builder, merge_bb)
then_branches_merge = 1
# then 末状态快照(供两端 Meet:先复位到 if 前状态,再与 then 末状态合并)
life_snap1: sizet* = self.Gen.VarGen.life_capture(trans)
# 6. translate the else body (if any)
else_branches_merge: int = 0
if has_else == 1:
# 复位到 if 前状态,让 else 分支从同一基线出发(否则会看到 then 分支写入的 Life)
self.Gen.VarGen.life_restore(life_snap0)
# as in then: reset the flag to avoid stale values from the then branch
trans._ctrl_merge_reachable = 1
mlirlite.position_at_end(builder, else_bb)
@@ -748,6 +756,10 @@ novirtual class StmtGenCifMixin:
mlirlite.build_br(builder, merge_bb)
else_branches_merge = 1
# 生命期汇合:有 else → 与 then 末状态 Meet;无 else → 与 if 前状态 Meet(else 路径=跳过)
if has_else == 1: self.Gen.VarGen.life_join(life_snap1)
else: self.Gen.VarGen.life_join(life_snap0)
# 7. merge reachability (used by tail-flow checks): without else cond_br always reaches
# merge; with else, any branch br reaching merge suffices; only all-return is unreachable.
trans._ctrl_merge_reachable = 1
+12 -2
View File
@@ -51,9 +51,19 @@ novirtual class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
return self.Gen.FuncGen.translate_nested_function_def(trans, node)
elif k == ast.ASTKind.Return: return self.Gen.StmtGenCif.translate_return(trans, node)
elif k == ast.ASTKind.If: return self.Gen.StmtGenCif.translate_if(trans, node)
elif k == ast.ASTKind.While: return self.Gen.StmtGenCif.translate_while(trans, node)
elif k == ast.ASTKind.While:
# 循环生命期汇合:循环可能 0 次执行,出口状态须与进入前状态 Meet(见 §11 控制流 Meet)
snap_wh: sizet* = self.Gen.VarGen.life_capture(trans)
rc_wh: int = self.Gen.StmtGenCif.translate_while(trans, node)
self.Gen.VarGen.life_join(snap_wh)
return rc_wh
elif k == ast.ASTKind.AugAssign: return self.Gen.AssignGen.translate_augassign(trans, node)
elif k == ast.ASTKind.For: return self.Gen.StmtGenCif.translate_for(trans, node)
elif k == ast.ASTKind.For:
# 同上:for 的各迭代形态(range/指针/数组/容器/解糖)统一在此收口
snap_fr: sizet* = self.Gen.VarGen.life_capture(trans)
rc_fr: int = self.Gen.StmtGenCif.translate_for(trans, node)
self.Gen.VarGen.life_join(snap_fr)
return rc_fr
elif k == ast.ASTKind.ClassDef: return self.Gen.ClassGenDef.translate_class_def(trans, node)
elif k == ast.ASTKind.Import: return self.Gen.ImportsGen.translate_import(trans, node)
elif k == ast.ASTKind.ImportFrom:
+55
View File
@@ -204,6 +204,61 @@ novirtual class VarGenMixin:
"""Meet of two life tags (min); used where branches join"""
return a if a < b else b
# life_capture - 快照当前作用域链上所有变量的 LifeTag(供控制流汇合 Meet)。
# 返回池上数组:buf[0]=count,其后每项 (entry_ptr, life) 各占一个 sizet 槽;失败返回 None。
def life_capture(self, trans: HT.Translator*) -> sizet*:
"""Snapshot every in-scope variable's LifeTag (control-flow merge support)"""
if trans is None or trans.SymTab is None: return None
pool: memhub.MemBuddy* = trans.Pool
if pool is None: return None
cnt: sizet = 0
sc_c: GenTypes.Scope* = trans.SymTab.Current
while sc_c is not None:
cnt += sizet(sc_c.VarCount)
sc_c = sc_c.Parent
buf: sizet* = sizet*(pool.alloc(8 * (2 * cnt + 2)))
if buf is None: return None
buf[0] = cnt
idx: sizet = 1
esz: uint64 = uint64(GenTypes.VarEntry.__sizeof__())
sc: GenTypes.Scope* = trans.SymTab.Current
while sc is not None:
if sc.Vars is not None and sc.VarCount > 0:
j: int = 0
while j < sc.VarCount:
ent: GenTypes.VarEntry* = GenTypes.VarEntry*(uint64(sc.Vars) + uint64(j) * esz)
buf[idx * 2] = sizet(uint64(ent))
buf[idx * 2 + 1] = sizet(ent.Life)
idx += 1
j += 1
sc = sc.Parent
return buf
# life_restore - 把快照写回各变量(让 else 分支从 if 之前的状态开始)。
def life_restore(self, buf: sizet*) -> int:
"""Restore LifeTag values from a snapshot; 0=ok / 1=no snapshot"""
if buf is None: return 1
cnt: sizet = buf[0]
i: sizet = 1
while i <= cnt:
ent: GenTypes.VarEntry* = GenTypes.VarEntry*(uint64(buf[i * 2]))
if ent is not None: ent.Life = int(buf[i * 2 + 1])
i += 1
return 0
# life_join - 当前值与快照逐项 Meet(汇合:任一路径为短命即取短命)。
def life_join(self, buf: sizet*) -> int:
"""Meet the current LifeTags with a snapshot; 0=ok / 1=no snapshot"""
if buf is None: return 1
cnt: sizet = buf[0]
i: sizet = 1
while i <= cnt:
ent: GenTypes.VarEntry* = GenTypes.VarEntry*(uint64(buf[i * 2]))
if ent is not None:
ent.Life = self.life_meet(ent.Life, int(buf[i * 2 + 1]))
i += 1
return 0
# add_var - add a variable to the variable table
# ============================================================
def add_var(self, vars_ptr: GenTypes.VarEntry*, var_count: int, name: str, alloca: mlirlite.Value*) -> int: