回滚 13080f6 的 110 处访问器调用,恢复裸字段访问 `x.Next`。
理由:该批访问器是把访问移到定义模块内执行,**绕开**了"继承字段名解析",
属于规避而非修复;缺陷本体在 TPC 侧(导入侧继承展平把泛型基类的继承字段
记成 __inherited_N 占位名,名字丢失)。TPC 已按语义修正:
· e6451a07 继承展平沿继承链取真实字段名(泛型特化回退模板名),
展平表直接落 `[("Next", <槽位类型>), ...]`,属性访问是普通表命中;
· 3ca46c01 顺带修掉 _get_or_create_struct 里"同名枚举成员遮蔽类定义"的 i32 出口。
因此源码侧恢复为唯一写法(裸字段访问),由编译器负责解析。
注:本 commit 只回滚访问器;13080f6 里夹带的 CallGenProp.vp 续行合并(非访问器改动)
已在工作区保留(未提交)。
2633 lines
137 KiB
Plaintext
2633 lines
137 KiB
Plaintext
import lib.core.Gen.GenTypes as GenTypes
|
||
import lib.core.Gen.Generator as Generator
|
||
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdlib
|
||
import stdio
|
||
import viperlib
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Gen.Translator as HT
|
||
import lib.core.Gen.Type.TypeSpec as TSpec
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
import lib.Projectrans.Config as Config
|
||
import lib.core.Gen.GenApi as GenApi
|
||
|
||
|
||
# ============================================================
|
||
# StmtGenCifMixin - CIf 编译期求值 + NewXxxHandle 工厂
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# StmtGenCifMixin - CIf 求值 + 工厂(最底层父类)
|
||
# ============================================================
|
||
novirtual class StmtGenCifMixin:
|
||
"""CIf 编译期求值 + NewXxxHandle 工厂(StmtGen 拆分 1/3,最底层)"""
|
||
|
||
# --- 编译期 CIf 求值状态(原 HandlesIf._g_cif_eval_ok) ---
|
||
# 用 8 字节类型:Mixin 独立布局与 Generator 组合布局的字段对齐必须一致
|
||
# (i32 首字段在组合布局中导致 EnumTable 相对偏移 4 vs 独立布局 8 的错位,
|
||
# this_adjust 无法同时修正,枚举表错位到相邻字段被覆盖——ASTCtx 丢失根因)。
|
||
Gen: Generator.Generator*
|
||
CifEvalOk: sizet
|
||
|
||
# --- 枚举注册表(原 HandlesEnum._enum_table/_enum_count) ---
|
||
EnumTable: rawptr[GenTypes.EnumEntry]
|
||
EnumCount: int
|
||
|
||
# --- OOM 语句级诊断计数(translate_stmt 限频打印 used) ---
|
||
DiagStmtCount: int
|
||
|
||
# ============================================================
|
||
# 簇 B:编译期 CIf 宏求值(迁移自 HandlesIf.vp 模块级函数)
|
||
# ============================================================
|
||
|
||
def _is_cif_attr(self, attr: str) -> int:
|
||
"""检查方法名是否为 CIf 系(CIf/CIfdef/CIfndef)"""
|
||
if attr is None:
|
||
return 0
|
||
if string.strcmp(attr, "CIf") == 0: return 1
|
||
if string.strcmp(attr, "CIfdef") == 0: return 1
|
||
if string.strcmp(attr, "CIfndef") == 0: return 1
|
||
return 0
|
||
|
||
def _is_cif_call(self, node: ast.AST*) -> int:
|
||
"""检查 test 是否为 c.CIf(...)/c.CIfdef(...)/c.CIfndef(...)(或裸 CIf 系)调用"""
|
||
if node is None or node.kind() != ast.ASTKind.Call:
|
||
return 0
|
||
cl: ast.Call* = ast.Call*(node)
|
||
if cl.func is None:
|
||
return 0
|
||
fk: int = cl.func.kind()
|
||
if fk == ast.ASTKind.Attribute:
|
||
at: ast.Attribute* = ast.Attribute*(cl.func)
|
||
if at.attr is None:
|
||
return 0
|
||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||
vn: ast.Name* = ast.Name*(at.value)
|
||
if vn.id is not None and string.strcmp(vn.id, "c") == 0:
|
||
return self._is_cif_attr(at.attr)
|
||
return 0
|
||
if fk == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(cl.func)
|
||
if nm.id is not None and self._is_cif_attr(nm.id) != 0:
|
||
return 1
|
||
return 0
|
||
|
||
def _get_platform_macro_value(self, name: str) -> int:
|
||
"""平台内置宏值(从目标三元组推导,对齐 TPC HandlesIf._get_platform_macros)。
|
||
|
||
命中置 self.CifEvalOk=1;未命中置 0 返回 0。
|
||
"""
|
||
self.CifEvalOk = 0
|
||
if name is None:
|
||
return 0
|
||
triple: str = Config.TargetTriple
|
||
if triple is None:
|
||
triple = "x86_64-pc-windows-gnu"
|
||
is_win: int = 0
|
||
is_linux: int = 0
|
||
is_x64: int = 0
|
||
if string.strstr(triple, "windows") is not None \
|
||
or string.strstr(triple, "win32") is not None \
|
||
or string.strstr(triple, "mingw") is not None \
|
||
or string.strstr(triple, "msvc") is not None:
|
||
is_win = 1
|
||
if string.strstr(triple, "linux") is not None:
|
||
is_linux = 1
|
||
if string.strstr(triple, "x86_64") is not None:
|
||
is_x64 = 1
|
||
# 简化:本编译目标为 x86_64 Windows(_WIN64/WIN64 恒与 is_win 一致)
|
||
if string.strcmp(name, "_WIN32") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0
|
||
if string.strcmp(name, "WIN32") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0
|
||
if string.strcmp(name, "_WIN64") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0
|
||
if string.strcmp(name, "WIN64") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0
|
||
if string.strcmp(name, "__linux__") == 0: self.CifEvalOk = is_linux; return 1 if is_linux else 0
|
||
if string.strcmp(name, "__x86_64__") == 0: self.CifEvalOk = is_x64; return 1 if is_x64 else 0
|
||
if string.strcmp(name, "__x86_64") == 0: self.CifEvalOk = is_x64; return 1 if is_x64 else 0
|
||
if string.strcmp(name, "_M_X64") == 0: self.CifEvalOk = is_x64; return 1 if is_x64 else 0
|
||
if string.strcmp(name, "SIZEOF_VOID_P") == 0: self.CifEvalOk = 1; return 8 if is_x64 else 4
|
||
if string.strcmp(name, "__SIZEOF_POINTER__") == 0: self.CifEvalOk = 1; return 8 if is_x64 else 4
|
||
if string.strcmp(name, "NDEBUG") == 0: self.CifEvalOk = 1; return 0
|
||
return 0
|
||
|
||
def _cif_name_value(self, pool: memhub.MemBuddy*,
|
||
trans: HT.Translator*,
|
||
name: str) -> int:
|
||
"""查宏名值: 本地 CDefine → 跨模块 CDefine → 平台宏。
|
||
|
||
命中置 self.CifEvalOk=1(值 0 也算命中,如 DISABLED=0);未命中置 0。
|
||
"""
|
||
self.CifEvalOk = 0
|
||
if name is None or trans is None:
|
||
return 0
|
||
v: int = self.Gen.TypeGenCDef.lookup_cdefine_constant(name)
|
||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||
self.CifEvalOk = 1
|
||
return v
|
||
v2: int = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(pool, name, trans._from_imports, trans._imported_modules)
|
||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||
self.CifEvalOk = 1
|
||
return v2
|
||
pv: int = self._get_platform_macro_value(name)
|
||
if self.CifEvalOk != 0:
|
||
return pv
|
||
return 0
|
||
|
||
def _cif_attr_value(self, pool: memhub.MemBuddy*,
|
||
trans: HT.Translator*,
|
||
at: ast.Attribute*) -> int:
|
||
"""Attribute 宏值: platmacro.IS_WINDOWS → 本地 CDefine(attr) → 跨模块 CDefine。
|
||
|
||
命中置 self.CifEvalOk=1;未命中置 0。
|
||
"""
|
||
self.CifEvalOk = 0
|
||
if at is None or at.attr is None or at.value is None or trans is None:
|
||
return 0
|
||
if at.value.kind() != ast.ASTKind.Name:
|
||
return 0
|
||
vn: ast.Name* = ast.Name*(at.value)
|
||
if vn.id is None:
|
||
return 0
|
||
v: int = self.Gen.TypeGenCDef.lookup_cdefine_constant(at.attr)
|
||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||
self.CifEvalOk = 1
|
||
return v
|
||
# 跨模块: 确定真实模块名(解析 from_imports 别名)
|
||
real_mod: str = vn.id
|
||
if trans._from_imports is not None:
|
||
resolved: str = self.Gen.ImportsGen.lookup_from_import(trans._from_imports, vn.id, 0)
|
||
if resolved is not None:
|
||
rm_len: sizet = 0
|
||
while resolved[rm_len] != ' ' and resolved[rm_len] != '\0' and resolved[rm_len] != ':':
|
||
rm_len += 1
|
||
rm_buf: str = pool.alloc(rm_len + 1)
|
||
if rm_buf is not None:
|
||
for rm_i in range(rm_len):
|
||
rm_buf[rm_i] = resolved[rm_i]
|
||
rm_buf[rm_len] = '\0'
|
||
real_mod = rm_buf
|
||
fi_len: sizet = string.strlen(at.attr) + string.strlen(real_mod) + 2
|
||
fi: str = pool.alloc(fi_len)
|
||
if fi is None:
|
||
return 0
|
||
viperlib.snprintf(fi, fi_len, "%s:%s", at.attr, real_mod)
|
||
v2: int = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(pool, at.attr, fi)
|
||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||
self.CifEvalOk = 1
|
||
return v2
|
||
return 0
|
||
|
||
def _cif_eval_node(self, pool: memhub.MemBuddy*,
|
||
trans: HT.Translator*,
|
||
node: ast.AST*) -> int:
|
||
"""递归常量求值 CIf 表达式。
|
||
|
||
支持: Constant(int) / Name(CDefine/跨模块/平台宏) / Attribute(跨模块 CDefine)
|
||
/ BinOp(+ - * // % & | ^ << >>) / Compare(== != < > <= >=)
|
||
/ BoolOp(and/or) / UnaryOp(not - + ~)。
|
||
成功置 self.CifEvalOk=1;失败(含运行时变量)置 0 返回 0。
|
||
"""
|
||
if node is None:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.Constant:
|
||
cn: ast.Constant* = ast.Constant*(node)
|
||
if cn.const_kind == ast.CONST_INT:
|
||
self.CifEvalOk = 1
|
||
return cn.int_val
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
if k == ast.ASTKind.Call:
|
||
return self._cif_eval_call(pool, trans, node)
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(node)
|
||
if nm.id is None:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
return self._cif_name_value(pool, trans, nm.id)
|
||
if k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute* = ast.Attribute*(node)
|
||
return self._cif_attr_value(pool, trans, at)
|
||
if k == ast.ASTKind.UnaryOp:
|
||
uop: ast.UnaryOp* = ast.UnaryOp*(node)
|
||
if uop.operand is None:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
ov: int = self._cif_eval_node(pool, trans, uop.operand)
|
||
if self.CifEvalOk == 0:
|
||
return 0
|
||
if uop.op == ast.OpKind.Not: return 1 if ov == 0 else 0
|
||
if uop.op == ast.OpKind.USub: return -ov
|
||
if uop.op == ast.OpKind.UAdd: return ov
|
||
if uop.op == ast.OpKind.Invert: return ~ov
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
if k == ast.ASTKind.BoolOp:
|
||
bo: rawptr[ast.BoolOp] = rawptr[ast.BoolOp](node)
|
||
vals: list[ast.AST*]* = bo.values
|
||
if vals is None:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
bn: sizet = len(vals)
|
||
if bo.op == ast.OpKind.And:
|
||
for bi in range(bn):
|
||
rv: int = self._cif_eval_node(pool, trans, vals.get(bi))
|
||
if self.CifEvalOk == 0:
|
||
return 0
|
||
if rv == 0:
|
||
return 0
|
||
return 1
|
||
if bo.op == ast.OpKind.Or:
|
||
for bi in range(bn):
|
||
rv: int = self._cif_eval_node(pool, trans, vals.get(bi))
|
||
if self.CifEvalOk == 0:
|
||
return 0
|
||
if rv != 0:
|
||
return 1
|
||
return 0
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
if k == ast.ASTKind.Compare:
|
||
cmp: rawptr[ast.Compare] = rawptr[ast.Compare](node)
|
||
lv: int = self._cif_eval_node(pool, trans, cmp.left)
|
||
if self.CifEvalOk == 0:
|
||
return 0
|
||
ops_list: list[int] | t.CPtr = (list[int] | t.CPtr)(cmp.ops)
|
||
comps: list[ast.AST*]* = cmp.comparators
|
||
if ops_list is None or comps is None:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
cc: sizet = len(comps)
|
||
ci: sizet
|
||
for ci in range(cc):
|
||
rv: int = self._cif_eval_node(pool, trans, comps.get(ci))
|
||
if self.CifEvalOk == 0:
|
||
return 0
|
||
op_id: int = ops_list.get(ci)
|
||
ok_cmp: int = 0
|
||
if op_id == ast.OpKind.Eq: ok_cmp = 1 if lv == rv else 0
|
||
elif op_id == ast.OpKind.Ne: ok_cmp = 1 if lv != rv else 0
|
||
elif op_id == ast.OpKind.Lt: ok_cmp = 1 if lv < rv else 0
|
||
elif op_id == ast.OpKind.Le: ok_cmp = 1 if lv <= rv else 0
|
||
elif op_id == ast.OpKind.Gt: ok_cmp = 1 if lv > rv else 0
|
||
elif op_id == ast.OpKind.Ge: ok_cmp = 1 if lv >= rv else 0
|
||
else:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
if ok_cmp == 0:
|
||
return 0
|
||
lv = rv
|
||
return 1
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp* = ast.BinOp*(node)
|
||
lv: int = self._cif_eval_node(pool, trans, bop.left)
|
||
if self.CifEvalOk == 0:
|
||
return 0
|
||
rv: int = self._cif_eval_node(pool, trans, bop.right)
|
||
if self.CifEvalOk == 0:
|
||
return 0
|
||
if bop.op == ast.OpKind.Add: return lv + rv
|
||
if bop.op == ast.OpKind.Sub: return lv - rv
|
||
if bop.op == ast.OpKind.Mult: return lv * rv
|
||
if bop.op == ast.OpKind.Div:
|
||
# 整数常量除法:与 FloorDiv 一致(对齐 TPC ConstEvaluator L354-355)
|
||
if rv == 0:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
return lv // rv
|
||
if bop.op == ast.OpKind.FloorDiv:
|
||
if rv == 0:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
return lv // rv
|
||
if bop.op == ast.OpKind.Mod:
|
||
if rv == 0:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
return lv % rv
|
||
if bop.op == ast.OpKind.BitAnd: return lv & rv
|
||
if bop.op == ast.OpKind.BitOr: return lv | rv
|
||
if bop.op == ast.OpKind.BitXor: return lv ^ rv
|
||
if bop.op == ast.OpKind.LShift: return lv << rv
|
||
if bop.op == ast.OpKind.RShift: return lv >> rv
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
|
||
def _eval_ctraits_isptr(self, symtab: rawptr[GenTypes.SymbolTable],
|
||
name: str) -> int:
|
||
"""ctraits.isptr(name) 编译期求值。
|
||
|
||
按变量实际存储类型判断是否指针:alloca 的 pointee 为 Ptr 即指针
|
||
(与 TPC ConstEvaluator._eval_compile_time_call 的 LLVM 类型判断一致)。
|
||
返回: 1=指针 0=非指针 -1=无法求值(变量不存在/无类型信息)。
|
||
"""
|
||
if name is None or symtab is None:
|
||
return -1
|
||
v: llvmlite.Value* = self.Gen.VarGen.lookup_var(symtab, name)
|
||
if v is None or v.Ty is None:
|
||
return -1
|
||
pointee: llvmlite.LLVMType* = v.Ty.Pointee
|
||
if pointee is not None and self.Gen.ExprGenBase.is_ptr_type(pointee) != 0:
|
||
return 1
|
||
return 0
|
||
|
||
def _cif_eval_call(self, pool: memhub.MemBuddy*,
|
||
trans: HT.Translator*,
|
||
node: ast.AST*) -> int:
|
||
"""编译期函数调用求值:ctraits.isptr(x)。
|
||
|
||
命中置 self.CifEvalOk=1 返回 1/0;未识别调用置 0 返回 0。
|
||
"""
|
||
self.CifEvalOk = 0
|
||
if node is None or trans is None:
|
||
return 0
|
||
cl: ast.Call* = ast.Call*(node)
|
||
if cl is None or cl.func is None:
|
||
return 0
|
||
fk: int = cl.func.kind()
|
||
if fk != ast.ASTKind.Attribute:
|
||
return 0
|
||
at: ast.Attribute* = ast.Attribute*(cl.func)
|
||
if at.value is None or at.attr is None:
|
||
return 0
|
||
if at.value.kind() != ast.ASTKind.Name:
|
||
return 0
|
||
vn: ast.Name* = ast.Name*(at.value)
|
||
if vn.id is None:
|
||
return 0
|
||
if string.strcmp(vn.id, "ctraits") != 0 or string.strcmp(at.attr, "isptr") != 0:
|
||
return 0
|
||
cargs: list[ast.AST*]* = cl.args
|
||
if cargs is None or len(cargs) < 1:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
arg0: ast.AST* = cargs.get(0)
|
||
if arg0 is None or arg0.kind() != ast.ASTKind.Name:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
nm0: ast.Name* = ast.Name*(arg0)
|
||
if nm0.id is None:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
r: int = self._eval_ctraits_isptr(trans.SymTab, nm0.id)
|
||
if r < 0:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
self.CifEvalOk = 1
|
||
return r
|
||
|
||
def _evaluate_cif_test(self, pool: memhub.MemBuddy*,
|
||
trans: HT.Translator*,
|
||
test: ast.AST*) -> int:
|
||
"""求值 CIf 调用(test 必须是 c.CIf 系调用)。
|
||
|
||
成功: 置 self.CifEvalOk=1,返回条件值(0/1)
|
||
失败(运行时变量/未知结构): 置 self.CifEvalOk=0,返回 0
|
||
"""
|
||
self.CifEvalOk = 0
|
||
cl: ast.Call* = ast.Call*(test)
|
||
if cl is None or cl.func is None:
|
||
return 0
|
||
kind: str = None
|
||
fk: int = cl.func.kind()
|
||
if fk == ast.ASTKind.Attribute:
|
||
at: ast.Attribute* = ast.Attribute*(cl.func)
|
||
kind = at.attr
|
||
elif fk == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(cl.func)
|
||
kind = nm.id
|
||
if kind is None:
|
||
return 0
|
||
cargs: list[ast.AST*]* = cl.args
|
||
if cargs is None or len(cargs) < 1:
|
||
return 0
|
||
arg0: ast.AST* = cargs.get(0)
|
||
if string.strcmp(kind, "CIf") == 0:
|
||
v: int = self._cif_eval_node(pool, trans, arg0)
|
||
if self.CifEvalOk == 0:
|
||
return 0
|
||
return 1 if v != 0 else 0
|
||
# CIfdef / CIfndef: 判定宏名是否已定义
|
||
defined: int = 0
|
||
if arg0 is not None and arg0.kind() == ast.ASTKind.Name:
|
||
nm0: ast.Name* = ast.Name*(arg0)
|
||
if nm0.id is None:
|
||
return 0
|
||
self._cif_name_value(pool, trans, nm0.id)
|
||
defined = self.CifEvalOk
|
||
elif arg0 is not None and arg0.kind() == ast.ASTKind.Constant:
|
||
cn0: ast.Constant* = ast.Constant*(arg0)
|
||
if cn0.const_kind == ast.CONST_STR and cn0.str_val is not None:
|
||
self._cif_name_value(pool, trans, cn0.str_val)
|
||
defined = self.CifEvalOk
|
||
else:
|
||
return 0
|
||
elif arg0 is not None and arg0.kind() == ast.ASTKind.Attribute:
|
||
at0: ast.Attribute* = ast.Attribute*(arg0)
|
||
self._cif_attr_value(pool, trans, at0)
|
||
defined = self.CifEvalOk
|
||
else:
|
||
return 0
|
||
# 定义判定本身成功(未定义名特判:不报错,defined=0 走 else)
|
||
self.CifEvalOk = 1
|
||
if string.strcmp(kind, "CIfdef") == 0:
|
||
return 1 if defined != 0 else 0
|
||
# CIfndef
|
||
return 0 if defined != 0 else 1
|
||
|
||
# ============================================================
|
||
# translate_return - Return 语句翻译(迁移自 HandlesReturn.ReturnHandle.Handle)
|
||
#
|
||
# 翻译返回值(若有)并生成 ret 指令;裸 return 按函数返回类型生成
|
||
# 默认零值(void→ret void,ptr→null,float→0.0,其余→零值)。
|
||
# ============================================================
|
||
def translate_return(self, trans: HT.Translator*,
|
||
node: ast.AST*) -> int:
|
||
"""翻译 Return 语句"""
|
||
rt: rawptr[ast.Return] = rawptr[ast.Return](node)
|
||
if rt is None:
|
||
return 0
|
||
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
mod: llvmlite.LLVMModule* = trans.Module
|
||
|
||
val: llvmlite.Value* = None
|
||
if rt.value is not None:
|
||
# f-string 逃逸(return f"..."):f-string 指向当前函数的栈缓冲,函数返回即
|
||
# 失效,返回该指针会让调用方读到已弹栈的帧(历史事故:ASan
|
||
# stack-buffer-underflow in vsnprintf)。需要带出函数时先显式拷贝,
|
||
# 见 GenApi.escape_fstring_copy。
|
||
GenApi.fail_if_fstring_escape(rt.value, "函数返回值")
|
||
# return a, b → 打包匿名 struct 值(多返回值,函数返回类型 tuple[T1,T2])
|
||
if rt.value.kind() == ast.ASTKind.Tuple:
|
||
rtp: ast.Tuple* = ast.Tuple*(rt.value)
|
||
rtp_elts: list[ast.AST*]* = rtp.elts
|
||
rt_n: sizet = 0
|
||
if rtp_elts is not None:
|
||
rt_n = len(rtp_elts)
|
||
if rt_n > 0 and rt_n <= 16:
|
||
rt_vals: sizet* = pool.alloc(8 * 16)
|
||
if rt_vals is not None:
|
||
rt_val_ok: int = 1
|
||
rt_head: llvmlite.ParamNode* = None
|
||
rt_tail: llvmlite.ParamNode* = None
|
||
rvi: sizet
|
||
for rvi in range(rt_n):
|
||
ev_i: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, rtp_elts.get(rvi),
|
||
trans._funcs, trans._func_count, trans)
|
||
if ev_i is None:
|
||
rt_val_ok = 0
|
||
break
|
||
rt_vals[rvi] = sizet(ev_i)
|
||
if rt_val_ok != 0:
|
||
# 构建匿名 struct 类型(字段类型 = 元素值类型)
|
||
rvi2: sizet
|
||
for rvi2 in range(rt_n):
|
||
rv_i: llvmlite.Value* = llvmlite.Value*((rt_vals[rvi2]))
|
||
if rv_i is None or rv_i.Ty is None:
|
||
rt_val_ok = 0
|
||
break
|
||
rn: llvmlite.ParamNode* = llvmlite.new_param_node(pool, rv_i.Ty)
|
||
if rn is None:
|
||
rt_val_ok = 0
|
||
break
|
||
if rt_head is None:
|
||
rt_head = rn
|
||
else:
|
||
llvmlite.paramnode_set_next(rt_tail, rn)
|
||
rt_tail = rn
|
||
rt_struct_ty: llvmlite.LLVMType* = None
|
||
if rt_val_ok != 0 and rt_head is not None:
|
||
rt_struct_ty = llvmlite.Struct(pool, rt_head, rt_n, None)
|
||
rt_tmp: llvmlite.Value* = None
|
||
if rt_struct_ty is not None:
|
||
rt_tmp = llvmlite.build_alloca(builder, rt_struct_ty)
|
||
if rt_tmp is not None:
|
||
rvi3: sizet
|
||
for rvi3 in range(rt_n):
|
||
rv3: llvmlite.Value* = llvmlite.Value*(rt_vals[rvi3])
|
||
rfp: llvmlite.Value* = llvmlite.build_gep_struct(builder, rt_struct_ty, rv3.Ty, rt_tmp, rvi3)
|
||
if rfp is None:
|
||
rt_val_ok = 0
|
||
break
|
||
llvmlite.build_store(builder, rv3, rfp)
|
||
if rt_val_ok != 0:
|
||
val = llvmlite.build_load(builder, rt_struct_ty, rt_tmp)
|
||
# return self: 返回 self 指针本身(Ptr(StructTy)),而非结构体值
|
||
# translate_value 会 load 得到结构体值,但 return self 需要指针
|
||
# 注意: lookup_var 返回的是存储 self 的 alloca (Ptr(Ptr(StructTy)))
|
||
# 需要 load 得到实际的 self 指针 (Ptr(StructTy))
|
||
if rt.value.kind() == ast.ASTKind.Name:
|
||
ret_nm: ast.Name* = ast.Name*(rt.value)
|
||
if ret_nm is not None and ret_nm.id is not None \
|
||
and string.strcmp(ret_nm.id, "self") == 0:
|
||
self_ptr: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, "self")
|
||
if self_ptr is not None:
|
||
# 检查 self_ptr 是否是 Ptr(Ptr(...))(alloca 存储指针)
|
||
self_pointee_ty: llvmlite.LLVMType* = None
|
||
match self_ptr.Ty:
|
||
case llvmlite.LLVMType.Ptr(inner_ty):
|
||
self_pointee_ty = inner_ty
|
||
if self_pointee_ty is not None and self.Gen.ExprGenBase.is_ptr_type(self_pointee_ty) != 0:
|
||
# Ptr(Ptr(StructTy)) → load 得到 Ptr(StructTy)
|
||
val = llvmlite.build_load(builder, self_pointee_ty, self_ptr)
|
||
else:
|
||
val = self_ptr
|
||
if val is None:
|
||
# P1-A(上下文位宽传播):把当前函数的返回类型作为 target_ty 传入,
|
||
# 使 `return 12345`(-> uint64)直接物化 i64 常量,与 `return u64(12345)`
|
||
# 一致,并省去下方返回类型对齐生成的 zext。
|
||
ret_val_ty: llvmlite.LLVMType* = None
|
||
cur_func_rv: llvmlite.Function* = trans._cur_func
|
||
if cur_func_rv is not None:
|
||
ret_val_ty = llvmlite.function_get_ret_ty(cur_func_rv)
|
||
# [C①] 返回注解上下文:记录本次 return 的直接值节点,供裸名泛型
|
||
# 构造(`-> Stack[int]` 里 `return Stack()`)用 CurFuncRetAnnot
|
||
# 里的类型实参特化;仅该直接值生效(identity 判定在 CallGenCtor)。
|
||
trans.CurRetNode = rt.value
|
||
val = self.Gen.ExprGen.translate_value(builder, pool, mod, rt.value,
|
||
trans._funcs, trans._func_count, trans, ret_val_ty, "返回注解")
|
||
trans.CurRetNode = None
|
||
|
||
# val 为 None 时(裸 return):检查当前函数返回类型
|
||
# void 函数(如 __init__/__before_init__)生成 ret void,
|
||
# ptr 函数生成 ret ptr null,浮点函数生成 ConstFloat(0.0),
|
||
# 否则 ret i32 0(浮点漏处理会报 llc: value doesn't match function result type)
|
||
if val is None:
|
||
cur_func: llvmlite.Function* = trans._cur_func
|
||
is_void_ret: int = 0
|
||
is_ptr_ret: int = 0
|
||
is_float_ret: int = 0
|
||
ret_ty: llvmlite.LLVMType* = None
|
||
if cur_func is not None:
|
||
ret_ty = llvmlite.function_get_ret_ty(cur_func)
|
||
if ret_ty is not None:
|
||
match ret_ty:
|
||
case llvmlite.LLVMType.Void():
|
||
is_void_ret = 1
|
||
case llvmlite.LLVMType.Ptr(_pe):
|
||
is_ptr_ret = 1
|
||
case llvmlite.LLVMType.Float(_fb):
|
||
is_float_ret = 1
|
||
if is_void_ret != 0:
|
||
llvmlite.build_ret_void(builder)
|
||
return 0
|
||
if is_ptr_ret != 0:
|
||
null_val: llvmlite.Value* = llvmlite.ConstNull(pool, ret_ty, "null")
|
||
llvmlite.build_ret(builder, null_val)
|
||
return 0
|
||
if is_float_ret != 0:
|
||
zero_f: llvmlite.Value* = llvmlite.ConstFloat(pool, ret_ty, 0.0)
|
||
llvmlite.build_ret(builder, zero_f)
|
||
return 0
|
||
if ret_ty is None:
|
||
# fail-fast: 裸 return 无法确定函数返回类型,禁止硬编码 i32 零值兜底
|
||
self.Gen.TypeGenErr.fatal_error(rt, "函数返回类型无法确定", "TypeError")
|
||
val = llvmlite.ConstZero(pool, ret_ty)
|
||
if val is None:
|
||
# fail-fast: 无法按返回类型构造零值
|
||
self.Gen.TypeGenErr.fatal_error(rt, "函数返回类型无法确定", "TypeError")
|
||
|
||
# 类型转换:确保 val 类型与函数返回类型匹配
|
||
# 处理 i1(bool 比较结果)→ i8(t.CBool)等情况
|
||
# i1 → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF)
|
||
# 注意:当 val 是整数而 ret_ty 是 ptr 时(即使 bits 相同,如 i64 vs ptr),
|
||
# 也必须 inttoptr 转换,否则 llc 报 "value doesn't match function result type"
|
||
cur_func_rt: llvmlite.Function* = trans._cur_func
|
||
ret_ty_rt: llvmlite.LLVMType* = None
|
||
if cur_func_rt is not None and val is not None and val.Ty is not None:
|
||
ret_ty_rt = llvmlite.function_get_ret_ty(cur_func_rt)
|
||
# void 函数 return <expr>:丢弃值 + ret void(Python 语义合法;此前
|
||
# 直接 build_ret(val) 生成 ret i32 与 define void 冲突 → llc "value
|
||
# doesn't match function result type 'void'"——GenApi.add_global_name
|
||
# `return g.TranslatorGen.add_global_name(...)` 委托调用根因)。
|
||
if ret_ty_rt is not None and val is not None:
|
||
rv_void: int = 0
|
||
match ret_ty_rt:
|
||
case llvmlite.LLVMType.Void():
|
||
rv_void = 1
|
||
if rv_void != 0:
|
||
llvmlite.build_ret_void(builder)
|
||
return 0
|
||
if ret_ty_rt is not None:
|
||
val_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty)
|
||
ret_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(ret_ty_rt)
|
||
val_is_ptr: int = self.Gen.ExprGenBase.is_ptr_type(val.Ty)
|
||
ret_is_ptr: int = self.Gen.ExprGenBase.is_ptr_type(ret_ty_rt)
|
||
# ptr 类型不一致性:val 是整数但 ret 是 ptr(或反之),必须转换
|
||
if val_is_ptr != ret_is_ptr:
|
||
# [FIX 2026-08-30] __new__ 返回类型是类指针(T | t.CPtr 语义):
|
||
# 返回的实例存储指针来自跨模块调用(如 pool.alloc),Phase A
|
||
# 依赖未就绪时其返回类型退化为默认 i32。此时 int→ptr 是退化
|
||
# 指针重建而非隐式转换错误——允许 inttoptr,文件保持 pending
|
||
# 不写盘,下遍依赖就绪后多遍收敛精确解析(否则 fail-fast 硬
|
||
# 中断多遍收敛,memhub↔_list 环永不求解)。
|
||
fn_nm_ret: str = None
|
||
if cur_func_rt is not None:
|
||
fn_nm_ret = llvmlite.function_get_name(cur_func_rt)
|
||
if fn_nm_ret is not None and string.strstr(fn_nm_ret, "__new__") is not None \
|
||
and val_is_ptr == 0 and ret_is_ptr != 0:
|
||
val = llvmlite.build_inttoptr(builder, val, ret_ty_rt)
|
||
else:
|
||
# 传 trans:Phase A 依赖未就绪(_deps_pending)时,跨模块调用
|
||
# 返回类型退化为默认 i32,int→ptr 是退化指针重建而非隐式转换
|
||
# 错误,须跳过 fail-fast(与 AssignGenMixin/ExprGenBase 的
|
||
# _deps_pending 兜底一致)。否则 return 跨模块指针构造函数
|
||
# (如 SSAValue)误报"整数隐式转指针已禁止"。
|
||
val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node, trans)
|
||
elif val_is_ptr != 0 and ret_is_ptr != 0:
|
||
# 指针 → 指针且元素类型不同(如 t\.CVoid(x, CPtr) 得到 i8*,
|
||
# 函数返回类型是类指针 Circle* 时)需 bitcast 回,
|
||
# 否则 llc 报 "value doesn't match function result type"。
|
||
val_pointee: llvmlite.LLVMType* = None
|
||
ret_pointee: llvmlite.LLVMType* = None
|
||
match val.Ty:
|
||
case llvmlite.LLVMType.Ptr(v_inner):
|
||
val_pointee = v_inner
|
||
match ret_ty_rt:
|
||
case llvmlite.LLVMType.Ptr(r_inner):
|
||
ret_pointee = r_inner
|
||
if val_pointee is not None and ret_pointee is not None \
|
||
and uint64(val_pointee) != uint64(ret_pointee):
|
||
val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node)
|
||
elif val_bits != 0 and ret_bits != 0 and val_bits != ret_bits:
|
||
if val_bits == 1 and val_bits < ret_bits:
|
||
val = llvmlite.build_zext(builder, val, ret_ty_rt)
|
||
else:
|
||
# 传 trans:无符号源类型(uint16/uint32/CSizeT 等)扩展用 zext,
|
||
# 缺 trans 时 _node_type_unsigned 查不到变量注解 → 误 sext
|
||
val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node, trans)
|
||
elif self.Gen.ExprGenBase.get_llvm_float_bits(val.Ty) != 0 \
|
||
or self.Gen.ExprGenBase.get_llvm_float_bits(ret_ty_rt) != 0:
|
||
# Float alignment: SpecTypeBits reports 0 for Float/Double, so the
|
||
# integer branch above never runs and a double literal returned from a
|
||
# `-> float` function would emit `ret double` (llc: value doesn't match
|
||
# function result type 'float'). Coerce here (fpext/fptrunc/si2fp/fptosi),
|
||
# same as TPC's emit_return.
|
||
val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node, trans)
|
||
llvmlite.build_ret(builder, val)
|
||
return 0
|
||
|
||
# ============================================================
|
||
# translate_if - if/elif/else 语句翻译(迁移自 HandlesIf.IfHandle.Handle)
|
||
#
|
||
# 编译期宏条件: if c.CIf(...) / c.CIfdef(...) / c.CIfndef(...)
|
||
# 求值成功 → 只编译命中的分支(剪枝,不发射运行时 IR),elif 递归
|
||
# 求值失败(运行时变量等)→ 回退运行时翻译。
|
||
# 运行时翻译 if 语句为 LLVM IR 控制流:
|
||
# br i1 %cond, label %then, label %else
|
||
# then:
|
||
# ... body ...
|
||
# br label %end
|
||
# else:
|
||
# ... orelse ...
|
||
# br label %end
|
||
# end:
|
||
# ============================================================
|
||
def translate_if(self, trans: HT.Translator*,
|
||
node: ast.AST*) -> int:
|
||
"""翻译 if/elif/else 语句"""
|
||
if node is None:
|
||
return 0
|
||
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
func: llvmlite.Function* = trans._cur_func
|
||
|
||
if builder is None or func is None:
|
||
return 0
|
||
|
||
if_node: rawptr[ast.If] = rawptr[ast.If](node)
|
||
|
||
# 0. 编译期宏条件: if c.CIf(...) / c.CIfdef(...) / c.CIfndef(...)
|
||
# 求值成功 → 只编译命中的分支(剪枝,不发射运行时 IR),elif 递归
|
||
# 求值失败(运行时变量等)→ 回退运行时翻译
|
||
if self._is_cif_call(if_node.test) == 1:
|
||
cif_val: int = self._evaluate_cif_test(pool, trans, if_node.test)
|
||
if self.CifEvalOk != 0:
|
||
if cif_val != 0:
|
||
body_cif: list[ast.AST*]* = if_node.children
|
||
if body_cif is not None:
|
||
bc_cif: sizet = len(body_cif)
|
||
bi_cif: sizet
|
||
for bi_cif in range(bc_cif):
|
||
stmt_cif: ast.AST* = body_cif.get(bi_cif)
|
||
if stmt_cif is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt_cif)
|
||
else:
|
||
orelse_cif: list[ast.AST*]* = if_node.orelse
|
||
if orelse_cif is not None and len(orelse_cif) == 1:
|
||
sub_cif: ast.AST* = orelse_cif.get(0)
|
||
if sub_cif is not None and sub_cif.kind() == ast.ASTKind.If:
|
||
# elif: 递归(子 If 的 test 仍会走 CIf 判定或运行时翻译)
|
||
self.translate_if(trans, sub_cif)
|
||
elif sub_cif is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, sub_cif)
|
||
elif orelse_cif is not None:
|
||
oc_cif: sizet = len(orelse_cif)
|
||
oi_cif: sizet
|
||
for oi_cif in range(oc_cif):
|
||
stmt_cif2: ast.AST* = orelse_cif.get(oi_cif)
|
||
if stmt_cif2 is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt_cif2)
|
||
return 0
|
||
|
||
# 1. 求值条件表达式
|
||
cond_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, if_node.test,
|
||
trans._funcs, trans._func_count, trans)
|
||
|
||
# 2. 转换为 i1 条件
|
||
# Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较
|
||
if cond_val is None:
|
||
# fail-fast: if 条件表达式翻译失败
|
||
self.Gen.TypeGenErr.fatal_error(if_node.test, "if 条件表达式翻译失败", "TypeError")
|
||
cond_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cond_val.Ty)
|
||
if cond_bits == 1:
|
||
cond_i1: llvmlite.Value* = cond_val
|
||
elif self.Gen.ExprGenBase.is_ptr_type(cond_val.Ty) != 0:
|
||
# 指针类型:与 null 比较(不能用整数 0,否则 llc 报 "integer constant must have integer type")
|
||
null_cond: llvmlite.Value* = llvmlite.ConstNull(pool, cond_val.Ty, "null")
|
||
cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, null_cond)
|
||
else:
|
||
zero: llvmlite.Value* = llvmlite.const_int32(pool, 0)
|
||
cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, zero)
|
||
|
||
# 3. 创建基本块(使用 trans._label_counter 生成唯一标签名,不与 SSA 名共享)
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
|
||
name_buf: str = pool.alloc(32)
|
||
viperlib.snprintf(name_buf, 32, "if.then.%d", cnt)
|
||
then_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "if.end.%d", cnt)
|
||
merge_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
# 检查是否有 else 分支
|
||
has_else: int = 0
|
||
orelse_list: list[ast.AST*]* = if_node.orelse
|
||
if orelse_list is not None:
|
||
if len(orelse_list) > 0:
|
||
has_else = 1
|
||
|
||
else_bb: rawptr[llvmlite.BasicBlock] = None
|
||
if has_else == 1:
|
||
viperlib.snprintf(name_buf, 32, "if.else.%d", cnt)
|
||
else_bb = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
# 4. 发射条件分支
|
||
if has_else == 1:
|
||
llvmlite.build_cond_br(builder, cond_i1, then_bb, else_bb)
|
||
else:
|
||
llvmlite.build_cond_br(builder, cond_i1, then_bb, merge_bb)
|
||
|
||
# 5. 翻译 then body
|
||
# 重置 merge 可达标志:分支内嵌套控制流会覆盖该标志,分支末尾判定依据
|
||
# "分支最后语句的控制流状态",须防进入本 If 前的残留值污染(append90
|
||
# 末句 If 全 return 被 fail-fast 误判"流程掉出末尾"的根因链一环)
|
||
trans._ctrl_merge_reachable = 1
|
||
llvmlite.position_at_end(builder, then_bb)
|
||
body: list[ast.AST*]* = if_node.children
|
||
if body is not None:
|
||
body_count: sizet = len(body)
|
||
for bi in range(body_count):
|
||
stmt: ast.AST* = body.get(bi)
|
||
if stmt is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||
|
||
# then 块未终止则跳到 merge(记录 then 是否 br 到 merge)
|
||
then_branches_merge: int = 0
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||
if trans._ctrl_merge_reachable == 0:
|
||
# 分支末尾是嵌套控制流且 merge 结构性不可达(全分支 return):
|
||
# 当前块是嵌套的 merge(无 terminator),补 unreachable 收尾。
|
||
# 不补 br merge——否则外层 If 的"分支是否 br merge"判定把不可达
|
||
# 分支当可达,函数末句 If 全 return 被误判"流程掉出末尾"
|
||
# (vipermath.vp atan2 根因;对齐 FuncGenDef append90 unreachable)
|
||
llvmlite.build_unreachable(builder)
|
||
else:
|
||
llvmlite.build_br(builder, merge_bb)
|
||
then_branches_merge = 1
|
||
|
||
# 6. 翻译 else body(若有)
|
||
else_branches_merge: int = 0
|
||
if has_else == 1:
|
||
# 同 then:重置标志防残留(else 是普通语句时不被 then 的嵌套控制流值污染)
|
||
trans._ctrl_merge_reachable = 1
|
||
llvmlite.position_at_end(builder, else_bb)
|
||
else_count: sizet = len(orelse_list)
|
||
for ei in range(else_count):
|
||
stmt: ast.AST* = orelse_list.get(ei)
|
||
if stmt is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||
if trans._ctrl_merge_reachable == 0:
|
||
# 嵌套控制流全分支 return:补 unreachable,不 br merge(同 then 分支)
|
||
llvmlite.build_unreachable(builder)
|
||
else:
|
||
llvmlite.build_br(builder, merge_bb)
|
||
else_branches_merge = 1
|
||
|
||
# 7. merge 块可达性(末句控制流收尾判定用):无 else 时 cond_br 直接跳 merge(恒可达);
|
||
# 有 else 时任一分支 br 到 merge 即可达;全分支 return(无 br)才结构性不可达。
|
||
# 经 HandlesBase 模块级全局传递(避免依赖 Translator 字段表)。
|
||
trans._ctrl_merge_reachable = 1
|
||
if has_else == 1 and then_branches_merge == 0 and else_branches_merge == 0:
|
||
trans._ctrl_merge_reachable = 0
|
||
|
||
# 8. 定位到 merge 块继续后续代码
|
||
llvmlite.position_at_end(builder, merge_bb)
|
||
return 0
|
||
|
||
# ============================================================
|
||
# translate_while - while 循环语句翻译(迁移自 HandlesWhile.WhileHandle.Handle)
|
||
#
|
||
# 翻译 while 语句为 LLVM IR 控制流:
|
||
# br label %cond
|
||
# cond:
|
||
# %t = <test>
|
||
# %c = icmp ne i32 %t, 0
|
||
# br i1 %c, label %body, label %end
|
||
# body:
|
||
# ... body ...
|
||
# br label %cond
|
||
# end:
|
||
# ============================================================
|
||
def translate_while(self, trans: HT.Translator*,
|
||
node: ast.AST*) -> int:
|
||
"""翻译 while 循环语句"""
|
||
if node is None:
|
||
return 0
|
||
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
func: llvmlite.Function* = trans._cur_func
|
||
|
||
if builder is None or func is None:
|
||
return 0
|
||
|
||
while_node: rawptr[ast.While] = rawptr[ast.While](node)
|
||
|
||
# 1. 创建基本块: cond / body / end(使用 trans._label_counter,不与 SSA 名共享)
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
|
||
name_buf: str = pool.alloc(32)
|
||
viperlib.snprintf(name_buf, 32, "while.cond.%d", cnt)
|
||
cond_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "while.body.%d", cnt)
|
||
body_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "while.end.%d", cnt)
|
||
end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
# 2. 跳转到 cond 块
|
||
llvmlite.build_br(builder, cond_bb)
|
||
|
||
# 3. cond 块: 求值条件,条件分支
|
||
llvmlite.position_at_end(builder, cond_bb)
|
||
cond_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, while_node.test,
|
||
trans._funcs, trans._func_count, trans)
|
||
if cond_val is None:
|
||
# fail-fast: while 条件表达式翻译失败
|
||
self.Gen.TypeGenErr.fatal_error(while_node.test, "while 条件表达式翻译失败", "TypeError")
|
||
|
||
# Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较
|
||
cond_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cond_val.Ty)
|
||
if cond_bits == 1:
|
||
cond_i1: llvmlite.Value* = cond_val
|
||
elif self.Gen.ExprGenBase.is_ptr_type(cond_val.Ty) != 0:
|
||
# 指针类型:与 null 比较(不能用整数 0,否则 llc 报 "integer constant must have integer type")
|
||
null_cond: llvmlite.Value* = llvmlite.ConstNull(pool, cond_val.Ty, "null")
|
||
cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, null_cond)
|
||
else:
|
||
zero: llvmlite.Value* = llvmlite.const_int32(pool, 0)
|
||
cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, zero)
|
||
llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb)
|
||
|
||
# 4. body 块: 翻译循环体,跳回 cond
|
||
llvmlite.position_at_end(builder, body_bb)
|
||
|
||
# 保存旧循环上下文,设置 break/continue 目标
|
||
old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||
old_continue: rawptr[llvmlite.BasicBlock] = trans._continue_bb
|
||
trans._break_bb = end_bb
|
||
trans._continue_bb = cond_bb
|
||
|
||
body: list[ast.AST*]* = while_node.children
|
||
if body is not None:
|
||
body_count: sizet = len(body)
|
||
for bi in range(body_count):
|
||
stmt: ast.AST* = body.get(bi)
|
||
if stmt is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||
|
||
# 恢复旧循环上下文
|
||
trans._break_bb = old_break
|
||
trans._continue_bb = old_continue
|
||
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||
llvmlite.build_br(builder, cond_bb)
|
||
|
||
# 5. 定位到 end 块
|
||
llvmlite.position_at_end(builder, end_bb)
|
||
# 追加90:while 的 cond_br 恒引用 end_bb → merge 恒可达(需正常收尾)
|
||
trans._ctrl_merge_reachable = 1
|
||
# 无限循环(条件常量真 1/True)且循环体无本层 break → 运行时无任何边
|
||
# 到达 end 块(merge 结构性不可达)→ 置 0,函数收尾对末句 While 生成
|
||
# unreachable(追加90:无 br 到达 merge 时才安全;否则 llc O2 把
|
||
# br-to-unreachable 优化为 fall-through → 双分支执行崩溃)。
|
||
# 修复 vrandom.gammavariate 的 while True 全 return 被误判"流程掉出末尾"。
|
||
if self._IsConstTrue(while_node.test) != 0 and self._StmtHasBreak(body) == 0:
|
||
trans._ctrl_merge_reachable = 0
|
||
return 0
|
||
|
||
# ============================================================
|
||
# 无限循环判定辅助(merge 可达性,迁移自 HandlesWhile 模块级函数)
|
||
#
|
||
# _IsConstTrue: while 条件为常量真(CONST_INT 非 0 / CONST_BOOL 真)
|
||
# _NodeHasBreak / _StmtHasBreak: 扫描本层 break(跳过嵌套 While/For
|
||
# 子树——嵌套循环的 break 归内层,不影响外层 merge 可达性)
|
||
# ============================================================
|
||
def _IsConstTrue(self, test: ast.AST*) -> int:
|
||
"""while 条件为常量真(1 / True)返回 1"""
|
||
if test is None:
|
||
return 0
|
||
if test.kind() == ast.ASTKind.Constant:
|
||
cn: ast.Constant* = ast.Constant*(test)
|
||
if cn.const_kind == ast.CONST_INT and cn.int_val != 0:
|
||
return 1
|
||
if cn.const_kind == ast.CONST_BOOL and cn.int_val != 0:
|
||
return 1
|
||
return 0
|
||
|
||
def _NodeHasBreak(self, node: ast.AST*) -> int:
|
||
"""递归扫描节点子树(跳过嵌套 While/For 子树),含 Break 返回 1"""
|
||
if node is None:
|
||
return 0
|
||
ch: list[ast.AST*]* = node.children
|
||
if ch is not None:
|
||
n: sizet = len(ch)
|
||
for bi in range(n):
|
||
c: ast.AST* = ch.get(bi)
|
||
if c is None:
|
||
continue
|
||
k: int = c.kind()
|
||
if k == ast.ASTKind.Break:
|
||
return 1
|
||
if k == ast.ASTKind.While or k == ast.ASTKind.For:
|
||
continue
|
||
if self._NodeHasBreak(c) != 0:
|
||
return 1
|
||
return 0
|
||
|
||
def _StmtHasBreak(self, body: list[ast.AST*]*) -> int:
|
||
"""语句列表是否含本层 break(嵌套循环的 break 归内层)"""
|
||
if body is None:
|
||
return 0
|
||
n: sizet = len(body)
|
||
for bi in range(n):
|
||
s: ast.AST* = body.get(bi)
|
||
if s is None:
|
||
continue
|
||
k: int = s.kind()
|
||
if k == ast.ASTKind.Break:
|
||
return 1
|
||
if k == ast.ASTKind.While or k == ast.ASTKind.For:
|
||
continue
|
||
if self._NodeHasBreak(s) != 0:
|
||
return 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# translate_for - for 循环语句翻译(迁移自 HandlesFor.ForHandle.Handle)
|
||
#
|
||
# 支持 for i in range(start, stop, step) 模式:
|
||
# %i = alloca i32
|
||
# store i32 start, i32* %i
|
||
# br label %cond
|
||
# cond:
|
||
# %cur = load i32, i32* %i
|
||
# %cmp = icmp slt i32 %cur, stop
|
||
# br i1 %cmp, label %body, label %end
|
||
# body:
|
||
# ... body ...
|
||
# br label %incr
|
||
# incr:
|
||
# %cur2 = load i32, i32* %i
|
||
# %next = add i32 %cur2, step
|
||
# store i32 %next, i32* %i
|
||
# br label %cond
|
||
# end:
|
||
# ============================================================
|
||
def translate_for(self, trans: HT.Translator*,
|
||
node: ast.AST*) -> int:
|
||
"""翻译 for i in range(...) 循环语句"""
|
||
if node is None:
|
||
return 0
|
||
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
func: llvmlite.Function* = trans._cur_func
|
||
|
||
if builder is None or func is None:
|
||
return 0
|
||
|
||
for_node: ast.For* = ast.For*(node)
|
||
|
||
# 1. 获取循环变量(Name 单变量 / Tuple 多变量)
|
||
target: ast.AST* = for_node.target
|
||
if target is None:
|
||
return 0
|
||
tk: int = target.kind()
|
||
if tk != ast.ASTKind.Name and tk != ast.ASTKind.Tuple:
|
||
return 0
|
||
var_name: str = None
|
||
if tk == ast.ASTKind.Name:
|
||
target_nm: ast.Name* = ast.Name*(target)
|
||
var_name = target_nm.id
|
||
if var_name is None:
|
||
return 0
|
||
|
||
# 2. 解析迭代器:支持 range() 和指针迭代
|
||
iter_node: ast.AST* = for_node.iter
|
||
if iter_node is None:
|
||
return 0
|
||
|
||
# 检查是否是 range() 调用
|
||
is_range_iter: int = 0
|
||
if iter_node.kind() == ast.ASTKind.Call:
|
||
call_pre: ast.Call* = ast.Call*(iter_node)
|
||
fn_pre: str = self.Gen.ExprGenBase.get_func_name(call_pre.func)
|
||
if fn_pre is not None:
|
||
if string.strcmp(fn_pre, "range") == 0:
|
||
is_range_iter = 1
|
||
elif string.strcmp(fn_pre, "enumerate") == 0 or string.strcmp(fn_pre, "zip") == 0:
|
||
pass # 多变量迭代,在下方非 range 分支处理
|
||
else:
|
||
err_msg: str = pool.alloc(256)
|
||
if err_msg is not None:
|
||
viperlib.snprintf(err_msg, 256, "仅支持 range()/enumerate()/zip() 或指针迭代,got call '%s'", fn_pre)
|
||
self.Gen.TypeGenErr.fatal_error(iter_node, err_msg)
|
||
self.Gen.TypeGenErr.fatal_error(iter_node, "仅支持 range()/enumerate()/zip() 或指针迭代")
|
||
|
||
# 非范围迭代:走指针/数组/列表字面量/容器/多变量迭代路径
|
||
if is_range_iter == 0:
|
||
# 列表字面量:按元素顺序迭代(for x in [1, 2, 3])
|
||
if iter_node.kind() == ast.ASTKind.List:
|
||
return self._handle_list_literal_iter(trans, for_node, var_name, iter_node)
|
||
# enumerate(x):for i, v in enumerate(x)(多变量迭代)
|
||
if iter_node.kind() == ast.ASTKind.Call:
|
||
call_mi: ast.Call* = ast.Call*(iter_node)
|
||
fn_mi: str = self.Gen.ExprGenBase.get_func_name(call_mi.func)
|
||
if fn_mi is not None and string.strcmp(fn_mi, "enumerate") == 0:
|
||
if tk != ast.ASTKind.Tuple:
|
||
self.Gen.TypeGenErr.fatal_error(iter_node, "enumerate 迭代需要两个循环变量 (for i, v in enumerate(x))")
|
||
tup_ie: ast.Tuple* = ast.Tuple*(target)
|
||
t1_buf_ie: bytes = pool.alloc(128)
|
||
t2_buf_ie: bytes = pool.alloc(128)
|
||
if t1_buf_ie is None or t2_buf_ie is None:
|
||
return 0
|
||
t1_buf_ie[0] = '\0'
|
||
t2_buf_ie[0] = '\0'
|
||
if self._extract_tuple_names(tup_ie, t1_buf_ie, t2_buf_ie) == 0:
|
||
self.Gen.TypeGenErr.fatal_error(iter_node, "enumerate 迭代变量必须是简单名称")
|
||
return self._handle_enumerate_iter(trans, for_node, t1_buf_ie, t2_buf_ie, call_mi)
|
||
if fn_mi is not None and string.strcmp(fn_mi, "zip") == 0:
|
||
if tk != ast.ASTKind.Tuple:
|
||
self.Gen.TypeGenErr.fatal_error(iter_node, "zip 迭代需要两个循环变量 (for a, b in zip(...))")
|
||
tup_iz: ast.Tuple* = ast.Tuple*(target)
|
||
t1_buf_iz: bytes = pool.alloc(128)
|
||
t2_buf_iz: bytes = pool.alloc(128)
|
||
if t1_buf_iz is None or t2_buf_iz is None:
|
||
return 0
|
||
t1_buf_iz[0] = '\0'
|
||
t2_buf_iz[0] = '\0'
|
||
if self._extract_tuple_names(tup_iz, t1_buf_iz, t2_buf_iz) == 0:
|
||
self.Gen.TypeGenErr.fatal_error(iter_node, "zip 迭代变量必须是简单名称")
|
||
return self._handle_zip_iter(trans, for_node, t1_buf_iz, t2_buf_iz, call_mi)
|
||
# list[T] 容器变量:按 __count__ 动态长度迭代
|
||
if iter_node.kind() == ast.ASTKind.Name and trans is not None:
|
||
nm_lst: ast.Name* = ast.Name*(iter_node)
|
||
if nm_lst.id is not None:
|
||
ve_lst: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm_lst.id)
|
||
lst_annot: str = self.Gen.VarGen.var_annot_class_name(ve_lst)
|
||
if lst_annot is not None:
|
||
# dict 容器变量:按 __count__/__keys__ 布局迭代(__iter__ 协议内联)
|
||
# [S4] 容器基名精确比较(SpecTypeNameBaseIs):原 strstr("dict") 子串匹配
|
||
# 会误命中任何含 "dict" 的类名(如 MyDictHelper)。
|
||
if TSpec.SpecTypeNameBaseIs(lst_annot, "dict") != 0:
|
||
lst_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, iter_node,
|
||
trans._funcs, trans._func_count, trans)
|
||
if lst_val is not None and lst_val.Ty is not None \
|
||
and self.Gen.ExprGenBase.is_ptr_type(lst_val.Ty) != 0:
|
||
return self._handle_dict_iter(trans, for_node, var_name, lst_val)
|
||
# [S4] 同上:原 strstr("list") 会误命中 playlist / GSList 等;
|
||
# 非 list 基名的用户类改由下方 OOP __iter__/__next__ 路径处理(更正确)。
|
||
if TSpec.SpecTypeNameBaseIs(lst_annot, "list") != 0:
|
||
lst_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, iter_node, trans._funcs, trans._func_count, trans)
|
||
if lst_val is not None and lst_val.Ty is not None \
|
||
and self.Gen.ExprGenBase.is_ptr_type(lst_val.Ty) != 0:
|
||
return self._handle_list_iter(trans, for_node, var_name, lst_val)
|
||
# OOP iter 协议:迭代源是类对象且类有 __iter__/__next__ 方法 →
|
||
# 走 __iter__/__next__ 调用迭代(对齐 TPC HandlesFor.py L142-166
|
||
# _HandleForIterLlvm)。dict/list 是内置泛型容器已在上方内联处理。
|
||
ov_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, iter_node,
|
||
trans._funcs, trans._func_count, trans)
|
||
if ov_val is not None and ov_val.Ty is not None \
|
||
and self.Gen.ExprGenBase.is_ptr_type(ov_val.Ty) != 0:
|
||
ov_st: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(ov_val)
|
||
if ov_st is not None:
|
||
ov_cn: str = self.Gen.StructGen.get_class_name_by_type(pool, ov_st)
|
||
if ov_cn is not None:
|
||
oi_lookup: str = pool.alloc(128)
|
||
if oi_lookup is not None:
|
||
viperlib.snprintf(oi_lookup, 128, "%s.__iter__", ov_cn)
|
||
oi_fn: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(trans.Module, oi_lookup)
|
||
if oi_fn is not None:
|
||
on_lookup: str = pool.alloc(128)
|
||
if on_lookup is not None:
|
||
viperlib.snprintf(on_lookup, 128, "%s.__next__", ov_cn)
|
||
on_fn: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(trans.Module, on_lookup)
|
||
if on_fn is not None:
|
||
return self._handle_oop_iter(trans, for_node, var_name, ov_cn, ov_val)
|
||
# 其它不支持的字面量:fast-fail 显式报错,
|
||
# 避免 translate_value 触发 list[T] 特化崩溃或语义歧义。
|
||
ik: int = iter_node.kind()
|
||
if ik == ast.ASTKind.Constant:
|
||
cn_ik: ast.Constant* = ast.Constant*(iter_node)
|
||
if cn_ik.const_kind != ast.CONST_STR:
|
||
self.Gen.TypeGenErr.fatal_error(iter_node, "for 迭代不支持该常量(仅支持字符串、数组、列表字面量、range())")
|
||
elif ik == ast.ASTKind.Dict or ik == ast.ASTKind.Set or ik == ast.ASTKind.Tuple \
|
||
or ik == ast.ASTKind.SetComp or ik == ast.ASTKind.DictComp:
|
||
self.Gen.TypeGenErr.fatal_error(iter_node, "for 迭代不支持字典/集合/元组字面量,请使用 range()、t.CArray 数组或列表字面量")
|
||
return self._handle_ptr_iter(trans, for_node, var_name)
|
||
|
||
call: ast.Call* = ast.Call*(iter_node)
|
||
|
||
# 3. 解析 range 参数: range(stop) / range(start, stop) / range(start, stop, step)
|
||
args: list[ast.AST*]* = call.args
|
||
if args is None:
|
||
return 0
|
||
arg_count: sizet = len(args)
|
||
|
||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
start_val: llvmlite.Value* = llvmlite.const_int32(pool, 0)
|
||
stop_val: llvmlite.Value* = None
|
||
step_val: llvmlite.Value* = llvmlite.const_int32(pool, 1)
|
||
|
||
if arg_count == 0:
|
||
# fail-fast: range 无参数,立即终止
|
||
self.Gen.TypeGenErr.fatal_error(call, "range 需要至少一个参数", "SyntaxError")
|
||
elif arg_count == 1:
|
||
stop_val = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, args.get(0), trans._funcs, trans._func_count, trans)
|
||
if stop_val is None:
|
||
# fail-fast: range 参数翻译失败
|
||
self.Gen.TypeGenErr.fatal_error(args.get(0), "range 参数翻译失败", "TypeError")
|
||
elif arg_count >= 2:
|
||
start_val = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, args.get(0), trans._funcs, trans._func_count, trans)
|
||
if start_val is None:
|
||
# fail-fast: range 参数翻译失败
|
||
self.Gen.TypeGenErr.fatal_error(args.get(0), "range 参数翻译失败", "TypeError")
|
||
stop_val = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, args.get(1), trans._funcs, trans._func_count, trans)
|
||
if stop_val is None:
|
||
# fail-fast: range 参数翻译失败
|
||
self.Gen.TypeGenErr.fatal_error(args.get(1), "range 参数翻译失败", "TypeError")
|
||
if arg_count >= 3:
|
||
step_val = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, args.get(2), trans._funcs, trans._func_count, trans)
|
||
if step_val is None:
|
||
# fail-fast: range 参数翻译失败
|
||
self.Gen.TypeGenErr.fatal_error(args.get(2), "range 参数翻译失败", "TypeError")
|
||
# step 为负数字面量时循环条件反转(对齐 TPC HandlesFor.py L86-94):
|
||
# range(a, b, -1) → i > stop;range(a, b, +1) → i < stop。
|
||
# TPC 仅识别负数字面量(UnaryOp USub 常量 / 负常量);变量 step 保守按正。
|
||
# 修复 _find_provider 的 range(top-1, -1, -1) 循环体不执行(i < -1 恒假)。
|
||
step_neg_const: int = 0
|
||
if arg_count >= 3:
|
||
step_arg_node: ast.AST* = args.get(2)
|
||
if step_arg_node is not None:
|
||
skn: int = step_arg_node.kind()
|
||
if skn == ast.ASTKind.UnaryOp:
|
||
uop_r: ast.UnaryOp* = ast.UnaryOp*(step_arg_node)
|
||
if uop_r.op == ast.OpKind.USub and uop_r.operand is not None:
|
||
if uop_r.operand.kind() == ast.ASTKind.Constant:
|
||
uoc_r: ast.Constant* = ast.Constant*(uop_r.operand)
|
||
if uoc_r.int_val > 0:
|
||
step_neg_const = 1
|
||
elif skn == ast.ASTKind.Constant:
|
||
skc_r: ast.Constant* = ast.Constant*(step_arg_node)
|
||
if skc_r.int_val < 0:
|
||
step_neg_const = 1
|
||
|
||
# 3.5 循环变量存储位宽随 range 参数类型(uint64→i64 / uint16→i16 / uint8→i8 / 其余→i32),
|
||
# 不固定 i32:固定 i32 alloca 会截断 uint64 上界(range(heap_end, new_end, 4096)
|
||
# 生成 trunc i64→i32 → 高 32 位丢失 → 映射地址错误)。仅当循环变量尚未声明时生效;
|
||
# 已声明变量沿用其 alloca 元素类型(见下方 loop_var_ty 解引用)。
|
||
loop_store_ty: llvmlite.LLVMType* = i32_ty
|
||
range_arg_bits: int = 0
|
||
if arg_count == 1:
|
||
if stop_val is not None and stop_val.Ty is not None:
|
||
range_arg_bits = self.Gen.ExprGenBase.get_llvm_type_bits(stop_val.Ty)
|
||
else:
|
||
start_bits_rt: int = 0
|
||
stop_bits_rt: int = 0
|
||
if start_val is not None and start_val.Ty is not None:
|
||
start_bits_rt = self.Gen.ExprGenBase.get_llvm_type_bits(start_val.Ty)
|
||
if stop_val is not None and stop_val.Ty is not None:
|
||
stop_bits_rt = self.Gen.ExprGenBase.get_llvm_type_bits(stop_val.Ty)
|
||
range_arg_bits = start_bits_rt if start_bits_rt > stop_bits_rt else stop_bits_rt
|
||
if range_arg_bits == 64:
|
||
loop_store_ty = llvmlite.Int64(pool)
|
||
elif range_arg_bits == 16:
|
||
loop_store_ty = llvmlite.Int16(pool)
|
||
elif range_arg_bits == 8:
|
||
loop_store_ty = llvmlite.Int8(pool)
|
||
|
||
# 3.6 循环无符号性:循环变量注解或任一 range 边界为无符号整型 →
|
||
# icmp ult/ugt 而非 slt/sgt(复用 ExprGenOps._node_type_unsigned:
|
||
# Name 查 SymTab 注解 / Call 转换目标 / Subscript 元素 / BinOp 递归)。
|
||
# syscall 的 va 未声明,靠边界 heap_end/new_end(uint64)判定;
|
||
# fat32 的 i/s 已声明 uint32/uint8,靠循环变量注解判定。
|
||
loop_unsigned: int = 0
|
||
if tk == ast.ASTKind.Name:
|
||
if self.Gen.ExprGenOps._node_type_unsigned(pool, target, trans) != 0:
|
||
loop_unsigned = 1
|
||
if loop_unsigned == 0:
|
||
args_u: sizet
|
||
for args_u in range(arg_count):
|
||
if self.Gen.ExprGenOps._node_type_unsigned(pool, args.get(args_u), trans) != 0:
|
||
loop_unsigned = 1
|
||
break
|
||
|
||
# 3.7 stop 边界为负数字面量(-1 / -N)→ 撤回无符号谓词,必须用有符号比较。
|
||
# 倒序循环条件为 i > stop;stop = -1 在无符号域里是 UINT_MAX,任何 i
|
||
# 都 ugt 不过它 → 条件恒假 → 循环体整段变死代码。TPC 的 for 条件只按
|
||
# 循环变量注解定符号性(HandlesFor.py L218 `Gen._is_var_unsigned`),
|
||
# 未声明循环变量的 range(top - 1, -1, -1) 走有符号 sgt 可正常执行;
|
||
# 边界推导(上文 3.6)把「start 边界无符号」也算成无符号,覆盖了负步长的
|
||
# SGT(即 step_neg_const 处注释里「修复 _find_provider 的
|
||
# range(top-1,-1,-1) 循环体不执行」失效)→ _find_provider 恒返回 NULL
|
||
# → with 上下文的 __mbuddy__ 注入不上(FakeDuckTest Test 9 FAIL +
|
||
# 后续 _str.upper 解引用 NULL 崩溃)。负数字面量语义上属有符号域,
|
||
# 此处无条件退回有符号谓词(slt/sgt),与 3.6 的无符号优化不冲突。
|
||
stop_neg_const: int = 0
|
||
if arg_count >= 2:
|
||
stop_arg_node: ast.AST* = args.get(1)
|
||
if stop_arg_node is not None:
|
||
stn_k: int = stop_arg_node.kind()
|
||
if stn_k == ast.ASTKind.UnaryOp:
|
||
stop_uop: ast.UnaryOp* = ast.UnaryOp*(stop_arg_node)
|
||
if stop_uop.op == ast.OpKind.USub and stop_uop.operand is not None:
|
||
if stop_uop.operand.kind() == ast.ASTKind.Constant:
|
||
stop_uc: ast.Constant* = ast.Constant*(stop_uop.operand)
|
||
if stop_uc.int_val > 0:
|
||
stop_neg_const = 1
|
||
elif stn_k == ast.ASTKind.Constant:
|
||
stop_c: ast.Constant* = ast.Constant*(stop_arg_node)
|
||
if stop_c.int_val < 0:
|
||
stop_neg_const = 1
|
||
if stop_neg_const != 0:
|
||
loop_unsigned = 0
|
||
|
||
# 4. 创建/查找循环变量 alloca
|
||
# 必须用 lookup_current(仅当前作用域):闭包内 lookup_var 会跨函数
|
||
# 命中父函数同名变量(如父函数自己的循环计数器 i)→ 循环计数写到
|
||
# 父函数存储 → 跨函数 SSA 错乱(llc "instruction expected to be
|
||
# numbered",Terminal _cmd_cd 的 for i in range(1,64) 根因)。
|
||
var_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_current(trans.SymTab, var_name)
|
||
new_vars: int = 0
|
||
if var_alloca is None:
|
||
# 用 _alloca_at_entry:alloca 放函数入口块,保证支配性
|
||
# (内联 build_alloca 若 preheader 是分支块(如 if.then),
|
||
# 循环三块跨块使用 → llc "Instruction does not dominate all
|
||
# uses!",Terminal _cmd_cd 的 for i in range(1,64) 根因)。
|
||
# 闭包跨函数命中父函数变量的根因已由 lookup_current 修复,
|
||
# 故 entry 插入路径安全。
|
||
# 位宽随 range 参数类型(loop_store_ty),不再固定 i32:
|
||
# uint64 上界 → i64 alloca,避免 trunc i64→i32 丢失高位。
|
||
var_alloca = self.Gen.VarGen._alloca_at_entry(builder, loop_store_ty)
|
||
if self.Gen.VarGen.define_var(trans.SymTab, var_name, var_alloca) == 0:
|
||
new_vars = 1
|
||
|
||
# 获取循环变量的实际元素类型(alloca 是指针类型,需解引用 Pointee)
|
||
# 当循环变量已声明为 i64(如 sizet),使用 i64 而非硬编码 i32
|
||
# 避免 load i32, i64* / store i32, i64* 类型不匹配
|
||
loop_var_ty: llvmlite.LLVMType* = i32_ty
|
||
if var_alloca is not None and var_alloca.Ty is not None:
|
||
match var_alloca.Ty:
|
||
case llvmlite.LLVMType.Ptr(pointee_ty):
|
||
if pointee_ty is not None:
|
||
loop_var_ty = pointee_ty
|
||
loop_var_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(loop_var_ty)
|
||
|
||
# 5. 存储初始值 (类型对齐: start_val 可能是 i32/i64,需对齐到 loop_var_ty)
|
||
init_val: llvmlite.Value* = start_val
|
||
if start_val is not None and start_val.Ty is not None:
|
||
start_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(start_val.Ty)
|
||
if start_bits != 0 and start_bits != loop_var_bits:
|
||
if start_bits < loop_var_bits:
|
||
init_val = llvmlite.build_sext(builder, start_val, loop_var_ty)
|
||
else:
|
||
init_val = llvmlite.build_trunc(builder, start_val, loop_var_ty)
|
||
llvmlite.build_store(builder, init_val, var_alloca)
|
||
|
||
# 6. 创建基本块: cond / body / incr / end(使用 trans._label_counter,不与 SSA 名共享)
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
|
||
name_buf: str = pool.alloc(32)
|
||
viperlib.snprintf(name_buf, 32, "for.cond.%d", cnt)
|
||
cond_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "for.body.%d", cnt)
|
||
body_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "for.incr.%d", cnt)
|
||
incr_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "for.end.%d", cnt)
|
||
end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
# 7. 跳转到 cond 块
|
||
llvmlite.build_br(builder, cond_bb)
|
||
|
||
# 8. cond 块: load i, icmp slt i, stop, cond_br body/end
|
||
llvmlite.position_at_end(builder, cond_bb)
|
||
cur_i: llvmlite.Value* = llvmlite.build_load(builder, loop_var_ty, var_alloca)
|
||
# 类型对齐: stop_val 可能是 i64 (如 range(strlen(s))),需将 cur_i 提升到 stop_val 类型
|
||
cmp_lhs: llvmlite.Value* = cur_i
|
||
cmp_rhs: llvmlite.Value* = stop_val
|
||
if stop_val is not None and stop_val.Ty is not None:
|
||
stop_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(stop_val.Ty)
|
||
cur_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cur_i.Ty)
|
||
if stop_bits != 0 and cur_bits != 0 and stop_bits != cur_bits:
|
||
if cur_bits < stop_bits:
|
||
cmp_lhs = llvmlite.build_sext(builder, cur_i, stop_val.Ty)
|
||
else:
|
||
# 循环变量位宽 > stop 位宽(如 sizet 循环变量 + range(i32)):应把 cur_i 截断到
|
||
# stop_val 类型(低向高才 sext/zext,高向低用 trunc)。反过来把小的 stop_val
|
||
# 扩宽会生成非法 IR(llc "invalid cast opcode for cast from 'i32' to 'i64'")。
|
||
cmp_lhs = llvmlite.build_trunc(builder, cur_i, stop_val.Ty)
|
||
# 有符号基准谓词:step 为负时条件反转(i > stop,SGT);正/缺省 i < stop(SLT)
|
||
range_cmp_op: int = llvmlite.ICMP_SLT
|
||
if step_neg_const != 0:
|
||
range_cmp_op = llvmlite.ICMP_SGT
|
||
# 无符号循环:改用无符号谓词(正步长 ult / 负步长 ugt)
|
||
if loop_unsigned != 0:
|
||
if step_neg_const != 0:
|
||
range_cmp_op = llvmlite.ICMP_UGT
|
||
else:
|
||
range_cmp_op = llvmlite.ICMP_ULT
|
||
cond_i1: llvmlite.Value* = llvmlite.build_icmp(builder, range_cmp_op, cmp_lhs, cmp_rhs)
|
||
llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb)
|
||
|
||
# 9. body 块: 翻译循环体,跳到 incr
|
||
llvmlite.position_at_end(builder, body_bb)
|
||
|
||
# 保存旧循环上下文,设置 break/continue 目标
|
||
old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||
old_continue: rawptr[llvmlite.BasicBlock] = trans._continue_bb
|
||
trans._break_bb = end_bb
|
||
trans._continue_bb = incr_bb
|
||
|
||
body: list[ast.AST*]* = for_node.children
|
||
if body is not None:
|
||
body_count: sizet = len(body)
|
||
for bi in range(body_count):
|
||
stmt: ast.AST* = body.get(bi)
|
||
if stmt is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||
|
||
# 恢复旧循环上下文
|
||
trans._break_bb = old_break
|
||
trans._continue_bb = old_continue
|
||
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||
llvmlite.build_br(builder, incr_bb)
|
||
|
||
# 10. incr 块: i = i + step, 跳回 cond
|
||
llvmlite.position_at_end(builder, incr_bb)
|
||
cur_i2: llvmlite.Value* = llvmlite.build_load(builder, loop_var_ty, var_alloca)
|
||
# 类型对齐: step_val 可能是 i32/i64,需对齐到 loop_var_ty 与 cur_i2 类型一致
|
||
incr_step: llvmlite.Value* = step_val
|
||
if step_val is not None and step_val.Ty is not None:
|
||
step_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(step_val.Ty)
|
||
cur2_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cur_i2.Ty)
|
||
if step_bits != 0 and cur2_bits != 0 and step_bits != cur2_bits:
|
||
if step_bits > cur2_bits:
|
||
incr_step = llvmlite.build_trunc(builder, step_val, loop_var_ty)
|
||
else:
|
||
incr_step = llvmlite.build_sext(builder, step_val, loop_var_ty)
|
||
next_i: llvmlite.Value* = llvmlite.build_add(builder, cur_i2, incr_step)
|
||
llvmlite.build_store(builder, next_i, var_alloca)
|
||
llvmlite.build_br(builder, cond_bb)
|
||
|
||
# 11. 定位到 end 块
|
||
llvmlite.position_at_end(builder, end_bb)
|
||
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
|
||
trans._ctrl_merge_reachable = 1
|
||
return new_vars
|
||
|
||
# ============================================================
|
||
# 多变量迭代辅助(enumerate / zip,迁移自 ForHandleBase)
|
||
#
|
||
# 支持迭代源: range(start, stop, step) / 字符串(常量|变量) / list[T]
|
||
# enumerate(x) → for i, v in enumerate(x):i 为序号,v 为元素
|
||
# zip(a, b) → for x, y in zip(a, b):任一源耗尽即终止
|
||
# ============================================================
|
||
def _extract_tuple_names(self, tup: ast.Tuple*,
|
||
out1: str, out2: str) -> int:
|
||
"""从 Tuple target 提取前两个 Name 变量名,写入 out1/out2,成功返回 1"""
|
||
if tup is None or tup.elts is None or out1 is None or out2 is None:
|
||
return 0
|
||
elts: list[ast.AST*]* = tup.elts
|
||
n: sizet = len(elts)
|
||
if n < 2:
|
||
return 0
|
||
e0: ast.AST* = elts.get(0)
|
||
e1: ast.AST* = elts.get(1)
|
||
if e0 is None or e1 is None:
|
||
return 0
|
||
if e0.kind() != ast.ASTKind.Name or e1.kind() != ast.ASTKind.Name:
|
||
return 0
|
||
n0: ast.Name* = ast.Name*(e0)
|
||
n1: ast.Name* = ast.Name*(e1)
|
||
if n0.id is None or n1.id is None:
|
||
return 0
|
||
string.strcpy(out1, n0.id)
|
||
string.strcpy(out2, n1.id)
|
||
return 1
|
||
|
||
def _seq_kind(self, trans: HT.Translator*,
|
||
src: ast.AST*) -> int:
|
||
"""判断迭代源类型: SEQ_KIND_RANGE / STR / LIST,不支持返回 0"""
|
||
if src is None:
|
||
return 0
|
||
k: int = src.kind()
|
||
if k == ast.ASTKind.Call:
|
||
cl_s: ast.Call* = ast.Call*(src)
|
||
fn_s: str = self.Gen.ExprGenBase.get_func_name(cl_s.func)
|
||
if fn_s is not None and string.strcmp(fn_s, "range") == 0:
|
||
return GenTypes.SEQ_KIND_RANGE
|
||
return 0
|
||
if k == ast.ASTKind.Constant:
|
||
cn_s: ast.Constant* = ast.Constant*(src)
|
||
if cn_s is not None and cn_s.const_kind == ast.CONST_STR:
|
||
return GenTypes.SEQ_KIND_STR
|
||
return 0
|
||
if k == ast.ASTKind.Name:
|
||
nm_s: ast.Name* = ast.Name*(src)
|
||
if nm_s.id is not None and trans is not None:
|
||
ve_s: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm_s.id)
|
||
sq_annot: str = self.Gen.VarGen.var_annot_class_name(ve_s)
|
||
if sq_annot is not None:
|
||
# [S4] 容器基名精确比较(原 strstr("list") 子串匹配会误命中 playlist 等)
|
||
if TSpec.SpecTypeNameBaseIs(sq_annot, "list") != 0:
|
||
return GenTypes.SEQ_KIND_LIST
|
||
return GenTypes.SEQ_KIND_STR
|
||
return 0
|
||
|
||
def _build_seq_loop(self, trans: HT.Translator*,
|
||
for_node: ast.For*,
|
||
t1: str, t2: str,
|
||
src1: ast.AST*,
|
||
src2: ast.AST*,
|
||
n_srcs: int) -> int:
|
||
"""生成序列迭代循环(enumerate: n_srcs=1 / zip: n_srcs=2)
|
||
|
||
循环变量 alloca 自动创建或复用;元素类型由源类型决定
|
||
(RANGE→i32, STR→i8, LIST→i8*)。索引内部统一 i64。
|
||
"""
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
func: llvmlite.Function* = trans._cur_func
|
||
|
||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
|
||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||
|
||
# ---- 源 1 准备 ----
|
||
kind1: int = self._seq_kind(trans, src1)
|
||
if kind1 == 0:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: 源 1 类型不支持")
|
||
r1_start: llvmlite.Value* = None
|
||
r1_stop: llvmlite.Value* = None
|
||
r1_step: llvmlite.Value* = None
|
||
s1_ptr: llvmlite.Value* = None
|
||
l1_count: llvmlite.Value* = None
|
||
l1_data: llvmlite.Value* = None
|
||
l1_esize: llvmlite.Value* = None
|
||
elem1_ty: llvmlite.LLVMType* = i8_ptr_ty
|
||
if kind1 == GenTypes.SEQ_KIND_RANGE:
|
||
elem1_ty = i32_ty
|
||
r1_start = llvmlite.const_int64(pool, 0)
|
||
r1_step = llvmlite.const_int64(pool, 1)
|
||
r1_stop = llvmlite.const_int64(pool, 0)
|
||
# 先赋中间变量再取 args(cast 链式属性访问会推断错字段偏移)
|
||
call_src1: ast.Call* = ast.Call*(src1)
|
||
cargs1: list[ast.AST*]* = call_src1.args
|
||
if cargs1 is not None:
|
||
n1: sizet = len(cargs1)
|
||
if n1 >= 1:
|
||
sv: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, cargs1.get(0),
|
||
trans._funcs, trans._func_count, trans)
|
||
if sv is None:
|
||
# fail-fast: range 参数翻译失败
|
||
self.Gen.TypeGenErr.fatal_error(cargs1.get(0), "range 参数翻译失败", "TypeError")
|
||
r1_stop = self.Gen.ExprGenBase.coerce_to_type(builder, sv, i64_ty, cargs1.get(0))
|
||
if n1 >= 2:
|
||
sv2: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, cargs1.get(1), trans._funcs, trans._func_count, trans)
|
||
if sv2 is None:
|
||
# fail-fast: range 参数翻译失败
|
||
self.Gen.TypeGenErr.fatal_error(cargs1.get(1), "range 参数翻译失败", "TypeError")
|
||
r1_start = self.Gen.ExprGenBase.coerce_to_type(builder, sv2, i64_ty, cargs1.get(1))
|
||
if n1 >= 3:
|
||
sv3: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, cargs1.get(2), trans._funcs, trans._func_count, trans)
|
||
if sv3 is None:
|
||
# fail-fast: range 参数翻译失败
|
||
self.Gen.TypeGenErr.fatal_error(cargs1.get(2), "range 参数翻译失败", "TypeError")
|
||
r1_step = self.Gen.ExprGenBase.coerce_to_type(builder, sv3, i64_ty, cargs1.get(2))
|
||
elif kind1 == GenTypes.SEQ_KIND_STR:
|
||
elem1_ty = i8_ty
|
||
s1_ptr = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, src1, trans._funcs, trans._func_count, trans)
|
||
if s1_ptr is None:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: 字符串源翻译失败")
|
||
elif kind1 == GenTypes.SEQ_KIND_LIST:
|
||
elem1_ty = i8_ptr_ty
|
||
l1_obj: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, src1, trans._funcs, trans._func_count, trans)
|
||
if l1_obj is None or l1_obj.Ty is None or self.Gen.ExprGenBase.is_ptr_type(l1_obj.Ty) == 0:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: list 源不是指针类型")
|
||
l1_count = llvmlite.build_load(builder, i64_ty, llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 1)))
|
||
l1_data = llvmlite.build_load(builder, i8_ptr_ty, llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 0)))
|
||
l1_esize = llvmlite.build_load(builder, i64_ty, llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 4)))
|
||
|
||
# ---- 源 2 准备(zip)----
|
||
kind2: int = 0
|
||
elem2_ty: llvmlite.LLVMType* = elem1_ty
|
||
s2_ptr: llvmlite.Value* = None
|
||
l2_count: llvmlite.Value* = None
|
||
l2_data: llvmlite.Value* = None
|
||
l2_esize: llvmlite.Value* = None
|
||
r2_start: llvmlite.Value* = None
|
||
r2_stop: llvmlite.Value* = None
|
||
r2_step: llvmlite.Value* = None
|
||
if n_srcs >= 2:
|
||
kind2 = self._seq_kind(trans, src2)
|
||
if kind2 == 0:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: 源 2 类型不支持")
|
||
if kind2 == GenTypes.SEQ_KIND_RANGE:
|
||
elem2_ty = i32_ty
|
||
r2_start = llvmlite.const_int64(pool, 0)
|
||
r2_step = llvmlite.const_int64(pool, 1)
|
||
r2_stop = llvmlite.const_int64(pool, 0)
|
||
# 先赋中间变量再取 args(cast 链式属性访问会推断错字段偏移)
|
||
call_src2: ast.Call* = ast.Call*(src2)
|
||
cargs2: list[ast.AST*]* = call_src2.args
|
||
if cargs2 is not None:
|
||
n2: sizet = len(cargs2)
|
||
if n2 >= 1:
|
||
svz: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, cargs2.get(0), trans._funcs, trans._func_count, trans)
|
||
if svz is None:
|
||
# fail-fast: range 参数翻译失败
|
||
self.Gen.TypeGenErr.fatal_error(cargs2.get(0), "range 参数翻译失败", "TypeError")
|
||
r2_stop = self.Gen.ExprGenBase.coerce_to_type(builder, svz, i64_ty, cargs2.get(0))
|
||
if n2 >= 2:
|
||
svz2: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, cargs2.get(1), trans._funcs, trans._func_count, trans)
|
||
if svz2 is None:
|
||
# fail-fast: range 参数翻译失败
|
||
self.Gen.TypeGenErr.fatal_error(cargs2.get(1), "range 参数翻译失败", "TypeError")
|
||
r2_start = self.Gen.ExprGenBase.coerce_to_type(builder, svz2, i64_ty, cargs2.get(1))
|
||
if n2 >= 3:
|
||
svz3: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, cargs2.get(2), trans._funcs, trans._func_count, trans)
|
||
if svz3 is None:
|
||
# fail-fast: range 参数翻译失败
|
||
self.Gen.TypeGenErr.fatal_error(cargs2.get(2), "range 参数翻译失败", "TypeError")
|
||
r2_step = self.Gen.ExprGenBase.coerce_to_type(builder, svz3, i64_ty, cargs2.get(2))
|
||
elif kind2 == GenTypes.SEQ_KIND_STR:
|
||
elem2_ty = i8_ty
|
||
s2_ptr = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, src2, trans._funcs, trans._func_count, trans)
|
||
if s2_ptr is None:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: 字符串源 2 翻译失败")
|
||
elif kind2 == GenTypes.SEQ_KIND_LIST:
|
||
elem2_ty = i8_ptr_ty
|
||
l2_obj: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, src2, trans._funcs, trans._func_count, trans)
|
||
if l2_obj is None or l2_obj.Ty is None or self.Gen.ExprGenBase.is_ptr_type(l2_obj.Ty) == 0:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: list 源 2 不是指针类型")
|
||
l2_count = llvmlite.build_load(builder, i64_ty, llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 1)))
|
||
l2_data = llvmlite.build_load(builder, i8_ptr_ty, llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 0)))
|
||
l2_esize = llvmlite.build_load(builder, i64_ty, llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 4)))
|
||
|
||
# ---- 循环变量 alloca ----
|
||
# t1: enumerate → 序号 (i32);zip → 源 1 元素
|
||
t1_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, t1)
|
||
new_vars: int = 0
|
||
if t1_alloca is None:
|
||
if n_srcs == 1:
|
||
t1_alloca = self.Gen.VarGen._alloca_at_entry(builder, i32_ty)
|
||
else:
|
||
t1_alloca = self.Gen.VarGen._alloca_at_entry(builder, elem1_ty)
|
||
if t1_alloca is not None:
|
||
if self.Gen.VarGen.define_var(trans.SymTab, t1, t1_alloca) == 0:
|
||
new_vars += 1
|
||
# t2: 源 2 元素(enumerate 时 = 源 1 元素)
|
||
t2_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, t2)
|
||
if t2_alloca is None:
|
||
t2_alloca = self.Gen.VarGen._alloca_at_entry(builder, elem2_ty)
|
||
if t2_alloca is not None:
|
||
if self.Gen.VarGen.define_var(trans.SymTab, t2, t2_alloca) == 0:
|
||
new_vars += 1
|
||
|
||
# 隐式 index 变量 (i64)
|
||
idx_alloca: llvmlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, i64_ty)
|
||
llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca)
|
||
|
||
# 基本块: cond / body / incr / end
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
|
||
name_buf: str = pool.alloc(32)
|
||
viperlib.snprintf(name_buf, 32, "seq.cond.%d", cnt)
|
||
cond_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "seq.body.%d", cnt)
|
||
body_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "seq.incr.%d", cnt)
|
||
incr_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "seq.end.%d", cnt)
|
||
end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
llvmlite.build_br(builder, cond_bb)
|
||
|
||
# cond 块: 源 1 done 检查(zip 需源 2 也 done)
|
||
llvmlite.position_at_end(builder, cond_bb)
|
||
cur_idx: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, idx_alloca)
|
||
done1: llvmlite.Value* = None
|
||
if kind1 == GenTypes.SEQ_KIND_RANGE:
|
||
done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, r1_stop)
|
||
elif kind1 == GenTypes.SEQ_KIND_STR:
|
||
ch_ptr1: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, s1_ptr, cur_idx)
|
||
ch1: llvmlite.Value* = llvmlite.build_load(builder, i8_ty, ch_ptr1)
|
||
zero1: llvmlite.Value* = llvmlite.const_int(pool, 8, 0)
|
||
done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, ch1, zero1)
|
||
elif kind1 == GenTypes.SEQ_KIND_LIST:
|
||
done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, l1_count)
|
||
cont: llvmlite.Value* = done1
|
||
if n_srcs >= 2:
|
||
done2: llvmlite.Value* = None
|
||
if kind2 == GenTypes.SEQ_KIND_RANGE:
|
||
done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, r2_stop)
|
||
elif kind2 == GenTypes.SEQ_KIND_STR:
|
||
ch_ptr2: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, s2_ptr, cur_idx)
|
||
ch2: llvmlite.Value* = llvmlite.build_load(builder, i8_ty, ch_ptr2)
|
||
zero2: llvmlite.Value* = llvmlite.const_int(pool, 8, 0)
|
||
done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, ch2, zero2)
|
||
elif kind2 == GenTypes.SEQ_KIND_LIST:
|
||
done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, l2_count)
|
||
cont = llvmlite.build_and(builder, done1, done2)
|
||
llvmlite.build_cond_br(builder, cont, body_bb, end_bb)
|
||
|
||
# body 块: 获取元素 → store → 循环体
|
||
llvmlite.position_at_end(builder, body_bb)
|
||
# 源 1 元素
|
||
v1: llvmlite.Value* = None
|
||
if kind1 == GenTypes.SEQ_KIND_RANGE:
|
||
step1: llvmlite.Value* = llvmlite.build_mul(builder, cur_idx, r1_step)
|
||
v1 = llvmlite.build_add(builder, r1_start, step1)
|
||
elif kind1 == GenTypes.SEQ_KIND_STR:
|
||
ch_ptr1b: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, s1_ptr, cur_idx)
|
||
v1 = llvmlite.build_load(builder, i8_ty, ch_ptr1b)
|
||
elif kind1 == GenTypes.SEQ_KIND_LIST:
|
||
off1: llvmlite.Value* = llvmlite.build_mul(builder, cur_idx, l1_esize)
|
||
addr1: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, l1_data, off1)
|
||
v1 = llvmlite.build_load(builder, i8_ptr_ty, addr1)
|
||
# store t1 / t2
|
||
if t1_alloca is not None and t1_alloca.Ty is not None:
|
||
t1_ty: llvmlite.LLVMType* = t1_alloca.Ty.Pointee
|
||
if n_srcs == 1:
|
||
# enumerate: t1 = 序号(trunc i64 → i32)
|
||
idx32: llvmlite.Value* = llvmlite.build_trunc(builder, cur_idx, i32_ty)
|
||
llvmlite.build_store(builder, idx32, t1_alloca)
|
||
if t2_alloca is not None and t2_alloca.Ty is not None and v1 is not None:
|
||
t2_ty: llvmlite.LLVMType* = t2_alloca.Ty.Pointee
|
||
v1c: llvmlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, v1, t2_ty, src1)
|
||
llvmlite.build_store(builder, v1c, t2_alloca)
|
||
else:
|
||
if v1 is not None:
|
||
v1c: llvmlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, v1, t1_ty, src1)
|
||
llvmlite.build_store(builder, v1c, t1_alloca)
|
||
# 源 2 元素 → t2
|
||
v2: llvmlite.Value* = None
|
||
if kind2 == GenTypes.SEQ_KIND_RANGE:
|
||
step2: llvmlite.Value* = llvmlite.build_mul(builder, cur_idx, r2_step)
|
||
v2 = llvmlite.build_add(builder, r2_start, step2)
|
||
elif kind2 == GenTypes.SEQ_KIND_STR:
|
||
ch_ptr2b: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, s2_ptr, cur_idx)
|
||
v2 = llvmlite.build_load(builder, i8_ty, ch_ptr2b)
|
||
elif kind2 == GenTypes.SEQ_KIND_LIST:
|
||
off2: llvmlite.Value* = llvmlite.build_mul(builder, cur_idx, l2_esize)
|
||
addr2: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, l2_data, off2)
|
||
v2 = llvmlite.build_load(builder, i8_ptr_ty, addr2)
|
||
if t2_alloca is not None and t2_alloca.Ty is not None and v2 is not None:
|
||
t2_ty2: llvmlite.LLVMType* = t2_alloca.Ty.Pointee
|
||
v2c: llvmlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, v2, t2_ty2, src2)
|
||
llvmlite.build_store(builder, v2c, t2_alloca)
|
||
|
||
# 保存旧循环上下文,设置 break/continue 目标
|
||
old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||
old_continue: rawptr[llvmlite.BasicBlock] = trans._continue_bb
|
||
trans._break_bb = end_bb
|
||
trans._continue_bb = incr_bb
|
||
|
||
body: list[ast.AST*]* = for_node.children
|
||
if body is not None:
|
||
body_count: sizet = len(body)
|
||
for bi in range(body_count):
|
||
stmt: ast.AST* = body.get(bi)
|
||
if stmt is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||
|
||
trans._break_bb = old_break
|
||
trans._continue_bb = old_continue
|
||
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||
llvmlite.build_br(builder, incr_bb)
|
||
|
||
# incr 块: index++
|
||
llvmlite.position_at_end(builder, incr_bb)
|
||
one_val: llvmlite.Value* = llvmlite.const_int64(pool, 1)
|
||
next_idx: llvmlite.Value* = llvmlite.build_add(builder, cur_idx, one_val)
|
||
llvmlite.build_store(builder, next_idx, idx_alloca)
|
||
llvmlite.build_br(builder, cond_bb)
|
||
|
||
# 定位到 end 块
|
||
llvmlite.position_at_end(builder, end_bb)
|
||
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
|
||
trans._ctrl_merge_reachable = 1
|
||
return new_vars
|
||
|
||
# ============================================================
|
||
# _handle_ptr_iter - 指针迭代: for x in ptr:(迁移自 ForHandleIter)
|
||
# 遍历指针,依赖隐式 index,直到解引用为空(null 终止符)
|
||
#
|
||
# 生成 IR 结构:
|
||
# %idx = alloca i32
|
||
# store i32 0, i32* %idx
|
||
# br label %cond
|
||
# cond:
|
||
# %i = load i32, i32* %idx
|
||
# %ep = getelementptr elem_ty, ptr_ty %ptr, i32 %i
|
||
# %ev = load elem_ty, elem_ty* %ep
|
||
# %null = icmp eq elem_ty %ev, 0
|
||
# br i1 %null, label %end, label %body
|
||
# body:
|
||
# store elem_ty %ev, elem_ty* %var
|
||
# ... 循环体 ...
|
||
# br label %incr
|
||
# incr:
|
||
# %next = add i32 %i, 1
|
||
# store i32 %next, i32* %idx
|
||
# br label %cond
|
||
# end:
|
||
# ============================================================
|
||
def _handle_ptr_iter(self, trans: HT.Translator*,
|
||
for_node: ast.For*,
|
||
var_name: str) -> int:
|
||
"""指针迭代: for x in ptr: 直到解引用为空"""
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
func: llvmlite.Function* = trans._cur_func
|
||
|
||
# 翻译迭代器表达式,获取指针值
|
||
ptr_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, for_node.iter, trans._funcs, trans._func_count, trans)
|
||
if ptr_val is None:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 无法翻译迭代器表达式")
|
||
|
||
# 检查迭代器类型
|
||
if self.Gen.ExprGenBase.is_ptr_type(ptr_val.Ty) == 0:
|
||
# 数组迭代:for k in arr(定长数组按长度迭代,元素可为任意类型)
|
||
if self.Gen.ExprGenBase.is_array_type(ptr_val.Ty) != 0:
|
||
return self._handle_array_iter(trans, for_node, var_name, ptr_val)
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 迭代器不是指针类型")
|
||
|
||
# 获取元素类型
|
||
elem_ty: llvmlite.LLVMType* = ptr_val.Ty.Pointee
|
||
if elem_ty is None:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 无法获取元素类型")
|
||
|
||
# 元素类型是数组(Ptr([N x T]),如 t.CArray 变量退化指针):
|
||
# load 出数组值后走数组迭代(按长度,非 null 终止)
|
||
if self.Gen.ExprGenBase.is_array_type(elem_ty) != 0:
|
||
arr_v2: llvmlite.Value* = llvmlite.build_load(builder, elem_ty, ptr_val)
|
||
if arr_v2 is not None:
|
||
return self._handle_array_iter(trans, for_node, var_name, arr_v2)
|
||
|
||
# 元素类型决定"空值"判定(用户语义:解引用后为空即终止):
|
||
# 整数 → ==0;指针(如 i8** 遍历的元素 i8*)→ ==null;浮点 → ==0.0
|
||
elem_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(elem_ty)
|
||
elem_is_ptr2: int = self.Gen.ExprGenBase.is_ptr_type(elem_ty)
|
||
elem_fbits2: int = self.Gen.ExprGenBase.get_llvm_float_bits(elem_ty)
|
||
if elem_bits == 0 and elem_is_ptr2 == 0 and elem_fbits2 == 0:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 元素类型不是整数/指针/浮点,无法检查空终止符")
|
||
|
||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
|
||
# 创建循环变量 alloca(存储元素值)
|
||
var_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, var_name)
|
||
new_vars: int = 0
|
||
if var_alloca is None:
|
||
var_alloca = self.Gen.VarGen._alloca_at_entry(builder, elem_ty)
|
||
if self.Gen.VarGen.define_var(trans.SymTab, var_name, var_alloca) == 0:
|
||
new_vars = 1
|
||
|
||
# 创建隐式 index 变量,初始为 0
|
||
idx_alloca: llvmlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, i32_ty)
|
||
llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca)
|
||
|
||
# 创建基本块: cond / body / incr / end
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
|
||
name_buf: str = pool.alloc(32)
|
||
viperlib.snprintf(name_buf, 32, "ptr.cond.%d", cnt)
|
||
cond_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "ptr.body.%d", cnt)
|
||
body_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "ptr.incr.%d", cnt)
|
||
incr_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "ptr.end.%d", cnt)
|
||
end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
# 跳转到 cond
|
||
llvmlite.build_br(builder, cond_bb)
|
||
|
||
# cond 块: load index, GEP, load elem, 空值判定(整数==0 / 指针==null / 浮点==0.0)
|
||
llvmlite.position_at_end(builder, cond_bb)
|
||
cur_idx: llvmlite.Value* = llvmlite.build_load(builder, i32_ty, idx_alloca)
|
||
elem_ptr: llvmlite.Value* = llvmlite.build_gep(builder, elem_ty, ptr_val, cur_idx)
|
||
cur_elem: llvmlite.Value* = llvmlite.build_load(builder, elem_ty, elem_ptr)
|
||
is_null: llvmlite.Value* = None
|
||
if elem_is_ptr2 != 0:
|
||
null_p: llvmlite.Value* = llvmlite.ConstNull(pool, elem_ty, "null")
|
||
if null_p is not None:
|
||
is_null = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, cur_elem, null_p)
|
||
elif elem_fbits2 != 0:
|
||
zero_f2: llvmlite.Value* = llvmlite.ConstFloat(pool, elem_ty, 0.0)
|
||
if zero_f2 is not None:
|
||
is_null = llvmlite.build_fcmp(builder, llvmlite.FCMP_OEQ, cur_elem, zero_f2)
|
||
else:
|
||
null_val: llvmlite.Value* = llvmlite.const_int(pool, elem_bits, 0)
|
||
is_null = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, cur_elem, null_val)
|
||
if is_null is None:
|
||
is_null = llvmlite.const_int(pool, 1, 0)
|
||
llvmlite.build_cond_br(builder, is_null, end_bb, body_bb)
|
||
|
||
# body 块: store elem to var, 翻译循环体
|
||
llvmlite.position_at_end(builder, body_bb)
|
||
llvmlite.build_store(builder, cur_elem, var_alloca)
|
||
|
||
# 保存旧循环上下文,设置 break/continue 目标
|
||
old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||
old_continue: rawptr[llvmlite.BasicBlock] = trans._continue_bb
|
||
trans._break_bb = end_bb
|
||
trans._continue_bb = incr_bb
|
||
|
||
body: list[ast.AST*]* = for_node.children
|
||
if body is not None:
|
||
body_count: sizet = len(body)
|
||
for bi in range(body_count):
|
||
stmt: ast.AST* = body.get(bi)
|
||
if stmt is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||
|
||
# 恢复旧循环上下文
|
||
trans._break_bb = old_break
|
||
trans._continue_bb = old_continue
|
||
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||
llvmlite.build_br(builder, incr_bb)
|
||
|
||
# incr 块: index++, br cond
|
||
llvmlite.position_at_end(builder, incr_bb)
|
||
one_val: llvmlite.Value* = llvmlite.const_int32(pool, 1)
|
||
next_idx: llvmlite.Value* = llvmlite.build_add(builder, cur_idx, one_val)
|
||
llvmlite.build_store(builder, next_idx, idx_alloca)
|
||
llvmlite.build_br(builder, cond_bb)
|
||
|
||
# 定位到 end 块
|
||
llvmlite.position_at_end(builder, end_bb)
|
||
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
|
||
trans._ctrl_merge_reachable = 1
|
||
return new_vars
|
||
|
||
# ============================================================
|
||
# _handle_array_iter - 数组迭代: for x in arr:(迁移自 ForHandleIter)
|
||
# 定长数组按长度迭代(元素可为任意类型,不做 null 终止符检查)
|
||
#
|
||
# 数组值是数组类型而非指针(如局部 t.CArray 修复后),
|
||
# 先拷到临时 alloca 获得地址,再按 [0, N) 迭代。
|
||
#
|
||
# 生成 IR 结构:
|
||
# %tmp = alloca [N x elem_ty]
|
||
# store [N x elem_ty] %arr_val, [N x elem_ty]* %tmp
|
||
# %idx = alloca i32 ; store 0
|
||
# br %cond
|
||
# cond:
|
||
# %i = load i32, i32* %idx
|
||
# %c = icmp slt i32 %i, N
|
||
# br i1 %c, %body, %end
|
||
# body:
|
||
# %ep = getelementptr [N x elem_ty], [N x elem_ty]* %tmp, i32 0, i32 %i
|
||
# %ev = load elem_ty, elem_ty* %ep
|
||
# store elem_ty %ev, elem_ty* %var
|
||
# ... 循环体 ...
|
||
# br %incr
|
||
# incr:
|
||
# %n = add i32 %i, 1 ; store %n ; br %cond
|
||
# end:
|
||
# ============================================================
|
||
def _handle_array_iter(self, trans: HT.Translator*,
|
||
for_node: ast.For*,
|
||
var_name: str,
|
||
array_val: llvmlite.Value*) -> int:
|
||
"""数组迭代: for x in arr: 按数组长度迭代"""
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
func: llvmlite.Function* = trans._cur_func
|
||
|
||
# 解析数组类型 [N x elem_ty]
|
||
arr_ty: llvmlite.LLVMType* = array_val.Ty
|
||
elem_ty: llvmlite.LLVMType* = None
|
||
elem_count: int = 0
|
||
match arr_ty:
|
||
case llvmlite.LLVMType.Array(et, n):
|
||
elem_ty = et
|
||
elem_count = n
|
||
if elem_ty is None or elem_count <= 0:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "数组迭代: 无法解析数组类型")
|
||
|
||
# 数组值 → 临时 alloca(数组值不是指针,需拷贝后 GEP 迭代)
|
||
# 必须在 entry 块创建:非 entry alloca 会被 LLVM 当动态 alloca → 运行时 sub rsp 大数组,
|
||
# 调用栈深时 rsp 骤降踩未映射页 → 概率性 #PF。
|
||
arr_tmp: llvmlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, arr_ty)
|
||
if arr_tmp is None:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "数组迭代: 临时存储分配失败")
|
||
llvmlite.build_store(builder, array_val, arr_tmp)
|
||
|
||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
|
||
# 循环变量 alloca(存储元素值)
|
||
var_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, var_name)
|
||
new_vars: int = 0
|
||
if var_alloca is None:
|
||
var_alloca = self.Gen.VarGen._alloca_at_entry(builder, elem_ty)
|
||
if self.Gen.VarGen.define_var(trans.SymTab, var_name, var_alloca) == 0:
|
||
new_vars = 1
|
||
|
||
# 隐式 index 变量,初始为 0
|
||
idx_alloca: llvmlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, i32_ty)
|
||
llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca)
|
||
|
||
# 基本块: cond / body / incr / end
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
|
||
name_buf: str = pool.alloc(32)
|
||
viperlib.snprintf(name_buf, 32, "arr.cond.%d", cnt)
|
||
cond_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "arr.elem.%d", cnt)
|
||
elem_check_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "arr.body.%d", cnt)
|
||
body_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "arr.incr.%d", cnt)
|
||
incr_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "arr.end.%d", cnt)
|
||
end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
llvmlite.build_br(builder, cond_bb)
|
||
|
||
# cond 块: 先查越界(idx < count,越界时不能 GEP+load 判空)
|
||
llvmlite.position_at_end(builder, cond_bb)
|
||
cur_idx: llvmlite.Value* = llvmlite.build_load(builder, i32_ty, idx_alloca)
|
||
count_val: llvmlite.Value* = llvmlite.const_int32(pool, elem_count)
|
||
in_bounds: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, count_val)
|
||
llvmlite.build_cond_br(builder, in_bounds, elem_check_bb, end_bb)
|
||
|
||
# elem_check 块: GEP(0, idx) → load elem → 空值判定(NULL 终止)
|
||
# 用户语义:整数/指针/浮点元素按"解引用为空"提前终止(如 split 尾哨兵
|
||
# 的 str 数组),同时保留长度上限防越界读;聚合元素只按长度迭代。
|
||
llvmlite.position_at_end(builder, elem_check_bb)
|
||
elem_ptr: llvmlite.Value* = llvmlite.build_gep_array(builder, arr_ty, elem_ty, arr_tmp, cur_idx)
|
||
cur_elem: llvmlite.Value* = llvmlite.build_load(builder, elem_ty, elem_ptr)
|
||
elem_bits_a: int = self.Gen.ExprGenBase.get_llvm_type_bits(elem_ty)
|
||
elem_ptr_a: int = self.Gen.ExprGenBase.is_ptr_type(elem_ty)
|
||
elem_fbits_a: int = self.Gen.ExprGenBase.get_llvm_float_bits(elem_ty)
|
||
if elem_bits_a != 0 or elem_ptr_a != 0 or elem_fbits_a != 0:
|
||
is_empty_a: llvmlite.Value* = None
|
||
if elem_ptr_a != 0:
|
||
null_ap: llvmlite.Value* = llvmlite.ConstNull(pool, elem_ty, "null")
|
||
if null_ap is not None:
|
||
is_empty_a = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, cur_elem, null_ap)
|
||
elif elem_fbits_a != 0:
|
||
zero_af: llvmlite.Value* = llvmlite.ConstFloat(pool, elem_ty, 0.0)
|
||
if zero_af is not None:
|
||
is_empty_a = llvmlite.build_fcmp(builder, llvmlite.FCMP_OEQ, cur_elem, zero_af)
|
||
else:
|
||
zero_ai: llvmlite.Value* = llvmlite.const_int(pool, elem_bits_a, 0)
|
||
is_empty_a = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, cur_elem, zero_ai)
|
||
if is_empty_a is not None:
|
||
llvmlite.build_cond_br(builder, is_empty_a, end_bb, body_bb)
|
||
else:
|
||
llvmlite.build_br(builder, body_bb)
|
||
else:
|
||
llvmlite.build_br(builder, body_bb)
|
||
|
||
# body 块: store elem to var → 循环体
|
||
llvmlite.position_at_end(builder, body_bb)
|
||
llvmlite.build_store(builder, cur_elem, var_alloca)
|
||
|
||
old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||
old_continue: rawptr[llvmlite.BasicBlock] = trans._continue_bb
|
||
trans._break_bb = end_bb
|
||
trans._continue_bb = incr_bb
|
||
|
||
body: list[ast.AST*]* = for_node.children
|
||
if body is not None:
|
||
body_count: sizet = len(body)
|
||
for bi in range(body_count):
|
||
stmt: ast.AST* = body.get(bi)
|
||
if stmt is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||
|
||
trans._break_bb = old_break
|
||
trans._continue_bb = old_continue
|
||
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||
llvmlite.build_br(builder, incr_bb)
|
||
|
||
# incr 块: index++
|
||
llvmlite.position_at_end(builder, incr_bb)
|
||
one_val: llvmlite.Value* = llvmlite.const_int32(pool, 1)
|
||
next_idx: llvmlite.Value* = llvmlite.build_add(builder, cur_idx, one_val)
|
||
llvmlite.build_store(builder, next_idx, idx_alloca)
|
||
llvmlite.build_br(builder, cond_bb)
|
||
|
||
# 定位到 end 块
|
||
llvmlite.position_at_end(builder, end_bb)
|
||
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
|
||
trans._ctrl_merge_reachable = 1
|
||
return new_vars
|
||
|
||
# ============================================================
|
||
# _handle_list_literal_iter - 列表字面量迭代: for x in [a, b, c]:(迁移自 ForHandleIter)
|
||
# 把列表字面量转成定长数组值,再复用数组迭代(按长度迭代)。
|
||
#
|
||
# 元素类型取第一个元素的值类型,其余元素 coerce 到该类型。
|
||
# ============================================================
|
||
def _handle_list_literal_iter(self, trans: HT.Translator*,
|
||
for_node: ast.For*,
|
||
var_name: str,
|
||
list_node: ast.AST*) -> int:
|
||
"""列表字面量迭代: for x in [a, b, c]: 按元素顺序迭代"""
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
|
||
lst: ast.List* = ast.List*(list_node)
|
||
if lst is None or lst.elts is None:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 空列表")
|
||
elts: list[ast.AST*]* = lst.elts
|
||
elts_count: sizet = len(elts)
|
||
if elts_count <= 0:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 空列表")
|
||
|
||
# 翻译第一个元素,确定元素类型
|
||
first_el: ast.AST* = elts.get(0)
|
||
# 显式判空(本仓硬约定:指针判空一律 `is None`;整型字面量 0 比较不是本仓判空写法
|
||
# ——`x == 0` 实测同样编译为 `icmp eq <ptr>, null`,逐字证据见
|
||
# AssignGenMixin.vp:1126-1145 记录的反例现场):
|
||
# 列表元素计数 > 实际填充 ⇒ 该槽为裸 0 ⇒ 上层某处产生了空 AST 元素。
|
||
# 不给下游 translate_value 的守卫吞掉(那会静默跳过 store、产出错值),此处响亮失败。
|
||
if first_el is None:
|
||
self.Gen.TypeGenErr.fatal_error(for_node,
|
||
f"列表字面量迭代遇到空 AST 元素:第 0 个元素为裸空指针(0),"
|
||
f"但元素计数为 {elts_count}(元素与计数不一致);上层某处产生了空 AST 元素,已终止编译。",
|
||
"ValueError")
|
||
# 对象有效性校验(vptr 非 0,硬约定与证据见 AssignGenMixin.vp:1174-1183):
|
||
# @t.CVTable 类对象首字即 vptr,为 0 时下游任意虚调用(kind()/dump())都会
|
||
# `load [0+slot]` ⇒ ASan READ at 0x0。读首字的唯一可用写法是 c.Deref((uint64*)(p))。
|
||
if c.Deref((uint64*)(first_el)) == 0:
|
||
self.Gen.TypeGenErr.fatal_error(for_node,
|
||
f"列表字面量迭代遇到【对象无效】的 AST 元素(vptr 为 0):第 0 个元素指针非 0"
|
||
f"(地址 {uint64(first_el)})但其对象首字(vtable 指针)为 0,元素计数 {elts_count};"
|
||
f"上层某处产生了「未初始化 vptr 的 AST 节点」(典型源:深拷贝只搬字段未搬 vptr),已终止编译。",
|
||
"ValueError")
|
||
first_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, first_el,
|
||
trans._funcs, trans._func_count, trans)
|
||
if first_val is None or first_val.Ty is None:
|
||
self.Gen.TypeGenErr.fatal_error(first_el, "列表字面量迭代: 无法确定元素类型")
|
||
elem_ty: llvmlite.LLVMType* = first_val.Ty
|
||
|
||
# 构建 [N x elem_ty] 数组值:临时 alloca 逐元素写入后 load
|
||
# 同样必须在 entry 块创建,避免非 entry alloca 被降为动态 alloca(见 _handle_array_iter)
|
||
arr_ty: llvmlite.LLVMType* = llvmlite.Array(pool, elem_ty, elts_count)
|
||
tmp_alloca: llvmlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, arr_ty)
|
||
if tmp_alloca is None:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 临时数组分配失败")
|
||
first_ptr: llvmlite.Value* = llvmlite.build_gep_array(builder, arr_ty, elem_ty, tmp_alloca, llvmlite.const_int32(pool, 0))
|
||
if first_ptr is not None:
|
||
llvmlite.build_store(builder, first_val, first_ptr)
|
||
# 写其余元素(coerce 到 elem_ty)
|
||
i: sizet = 1
|
||
while i < elts_count:
|
||
el_node: ast.AST* = elts.get(i)
|
||
# 显式判空(同上,用 `is None`):不得让空元素被 translate_value 的 None 守卫静默吞掉。
|
||
if el_node is None:
|
||
self.Gen.TypeGenErr.fatal_error(for_node,
|
||
f"列表字面量迭代遇到空 AST 元素:第 {i} 个元素为裸空指针(0),"
|
||
f"但元素计数为 {elts_count}(元素与计数不一致);上层某处产生了空 AST 元素,已终止编译。",
|
||
"ValueError")
|
||
# 对象有效性校验(vptr 非 0),同第 0 元素处:同族"取元素后即用"路径。
|
||
if c.Deref((uint64*)(el_node)) == 0:
|
||
self.Gen.TypeGenErr.fatal_error(for_node,
|
||
f"列表字面量迭代遇到【对象无效】的 AST 元素(vptr 为 0):第 {i} 个元素指针非 0"
|
||
f"(地址 {uint64(el_node)})但其对象首字(vtable 指针)为 0,元素计数 {elts_count};"
|
||
f"上层某处产生了「未初始化 vptr 的 AST 节点」(典型源:深拷贝只搬字段未搬 vptr),已终止编译。",
|
||
"ValueError")
|
||
el_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, el_node, trans._funcs, trans._func_count, trans)
|
||
if el_val is not None:
|
||
el_val = self.Gen.ExprGenBase.coerce_to_type(builder, el_val, elem_ty, el_node)
|
||
el_ptr: llvmlite.Value* = llvmlite.build_gep_array(builder, arr_ty, elem_ty, tmp_alloca, llvmlite.const_int32(pool, i))
|
||
if el_ptr is not None:
|
||
llvmlite.build_store(builder, el_val, el_ptr)
|
||
i += 1
|
||
# load 回数组值,复用数组迭代
|
||
arr_val: llvmlite.Value* = llvmlite.build_load(builder, arr_ty, tmp_alloca)
|
||
if arr_val is None:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 数组加载失败")
|
||
return self._handle_array_iter(trans, for_node, var_name, arr_val)
|
||
|
||
# ============================================================
|
||
# _handle_list_iter - list[T] 容器迭代: for v in lst:(迁移自 ForHandleIter)
|
||
# 按 __count__ 动态长度迭代(元素任意类型,不做 null 终止符检查)
|
||
#
|
||
# list 结构布局 (6 字段 × 8 字节):
|
||
# __data__(0) __count__(8) __capacity__(16) __pool__(24)
|
||
# __elem_size__(32) __iter_index__(40)
|
||
#
|
||
# 生成 IR 结构:
|
||
# %count = load __count__
|
||
# %idx = alloca i64 ; store 0
|
||
# br %cond
|
||
# cond:
|
||
# %i = load i64, %idx
|
||
# %c = icmp slt i64 %i, %count
|
||
# br i1 %c, %body, %end
|
||
# body:
|
||
# %data = load __data__ (i8*)
|
||
# %es = load __elem_size__ (i64)
|
||
# %off = mul i64 %i, %es
|
||
# %addr = getelementptr i8, i8* %data, i64 %off
|
||
# %el = load i8*, i8** %addr
|
||
# store i8* %el, i8** %var
|
||
# ... 循环体 ...
|
||
# br %incr
|
||
# incr:
|
||
# %n = add i64 %i, 1 ; store ; br %cond
|
||
# end:
|
||
# ============================================================
|
||
def _handle_list_iter(self, trans: HT.Translator*,
|
||
for_node: ast.For*,
|
||
var_name: str,
|
||
list_val: llvmlite.Value*) -> int:
|
||
"""list[T] 容器迭代: for v in lst: 按 __count__ 动态长度迭代"""
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
func: llvmlite.Function* = trans._cur_func
|
||
|
||
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
|
||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||
|
||
# 读取 __count__ (偏移 8, GEP index 1)
|
||
cnt_ptr: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, list_val, llvmlite.const_int64(pool, 1))
|
||
if cnt_ptr is None:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "list 迭代: 无法定位 __count__")
|
||
count_val: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, cnt_ptr)
|
||
|
||
# 循环变量 alloca(元素类型 i8*,与 list.get 内联一致)
|
||
var_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, var_name)
|
||
new_vars: int = 0
|
||
if var_alloca is None:
|
||
var_alloca = self.Gen.VarGen._alloca_at_entry(builder, i8_ptr_ty)
|
||
if self.Gen.VarGen.define_var(trans.SymTab, var_name, var_alloca) == 0:
|
||
new_vars = 1
|
||
|
||
# 隐式 index 变量 (i64,与 __count__ 类型对齐)
|
||
idx_alloca: llvmlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, i64_ty)
|
||
llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca)
|
||
|
||
# 基本块: cond / body / incr / end
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
|
||
name_buf: str = pool.alloc(32)
|
||
viperlib.snprintf(name_buf, 32, "lst.cond.%d", cnt)
|
||
cond_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "lst.body.%d", cnt)
|
||
body_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "lst.incr.%d", cnt)
|
||
incr_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "lst.end.%d", cnt)
|
||
end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
llvmlite.build_br(builder, cond_bb)
|
||
|
||
# cond 块: load index, icmp slt idx, count
|
||
llvmlite.position_at_end(builder, cond_bb)
|
||
cur_idx: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, idx_alloca)
|
||
in_bounds: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, count_val)
|
||
llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb)
|
||
|
||
# body 块: __data__ + idx*__elem_size__ → load 元素 → store to var
|
||
llvmlite.position_at_end(builder, body_bb)
|
||
dpp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, list_val, llvmlite.const_int64(pool, 0))
|
||
data_ptr: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, dpp)
|
||
epp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, list_val, llvmlite.const_int64(pool, 4))
|
||
esize: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, epp)
|
||
offset: llvmlite.Value* = llvmlite.build_mul(builder, cur_idx, esize)
|
||
elem_addr: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, data_ptr, offset)
|
||
cur_elem: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, elem_addr)
|
||
llvmlite.build_store(builder, cur_elem, var_alloca)
|
||
|
||
# 保存旧循环上下文,设置 break/continue 目标
|
||
old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||
old_continue: rawptr[llvmlite.BasicBlock] = trans._continue_bb
|
||
trans._break_bb = end_bb
|
||
trans._continue_bb = incr_bb
|
||
|
||
body: list[ast.AST*]* = for_node.children
|
||
if body is not None:
|
||
body_count: sizet = len(body)
|
||
for bi in range(body_count):
|
||
stmt: ast.AST* = body.get(bi)
|
||
if stmt is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||
|
||
trans._break_bb = old_break
|
||
trans._continue_bb = old_continue
|
||
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||
llvmlite.build_br(builder, incr_bb)
|
||
|
||
# incr 块: index++
|
||
llvmlite.position_at_end(builder, incr_bb)
|
||
one_val: llvmlite.Value* = llvmlite.const_int64(pool, 1)
|
||
next_idx: llvmlite.Value* = llvmlite.build_add(builder, cur_idx, one_val)
|
||
llvmlite.build_store(builder, next_idx, idx_alloca)
|
||
llvmlite.build_br(builder, cond_bb)
|
||
|
||
# 定位到 end 块
|
||
llvmlite.position_at_end(builder, end_bb)
|
||
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
|
||
trans._ctrl_merge_reachable = 1
|
||
return new_vars
|
||
|
||
def _handle_dict_iter(self, trans: HT.Translator*,
|
||
for_node: ast.For*,
|
||
var_name: str,
|
||
dict_val: llvmlite.Value*) -> int:
|
||
"""dict 容器迭代: for key in d: 按 __count__/__keys__ 布局迭代
|
||
|
||
_dict.vp 布局(8 字节槽):__keys__@0, __values__@1, __count__@2,
|
||
__capacity__@3, __mbuddy__@4, __iter_index__@5。
|
||
__iter__ 协议(__iter__ 重置 iter_index + __next__ 取 key)内联为
|
||
循环:iter_idx < __count__ → key = __keys__[iter_idx]。
|
||
"""
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
func: llvmlite.Function* = trans._cur_func
|
||
|
||
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
|
||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||
|
||
# 读取 __count__(槽 2,字节偏移 16)
|
||
cnt_ptr: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, dict_val, llvmlite.const_int64(pool, 2))
|
||
if cnt_ptr is None:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "dict 迭代: 无法定位 __count__")
|
||
count_val: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, cnt_ptr)
|
||
|
||
# 循环变量 alloca(元素类型 i8*,与 dict.__next__ 返回 str 一致)
|
||
var_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, var_name)
|
||
new_vars: int = 0
|
||
if var_alloca is None:
|
||
var_alloca = self.Gen.VarGen._alloca_at_entry(builder, i8_ptr_ty)
|
||
if self.Gen.VarGen.define_var(trans.SymTab, var_name, var_alloca) == 0:
|
||
new_vars = 1
|
||
|
||
# 隐式 index 变量 (i64,与 __count__ 类型对齐)
|
||
idx_alloca: llvmlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, i64_ty)
|
||
llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca)
|
||
|
||
# 基本块: cond / body / incr / end
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
|
||
name_buf: str = pool.alloc(32)
|
||
viperlib.snprintf(name_buf, 32, "dict.cond.%d", cnt)
|
||
cond_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "dict.body.%d", cnt)
|
||
body_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "dict.incr.%d", cnt)
|
||
incr_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
viperlib.snprintf(name_buf, 32, "dict.end.%d", cnt)
|
||
end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
llvmlite.build_br(builder, cond_bb)
|
||
|
||
# cond 块: load index, icmp slt idx, count
|
||
llvmlite.position_at_end(builder, cond_bb)
|
||
cur_idx: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, idx_alloca)
|
||
in_bounds: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, count_val)
|
||
llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb)
|
||
|
||
# body 块: __keys__ + idx*8 → load key (i8*) → store to var
|
||
llvmlite.position_at_end(builder, body_bb)
|
||
kpp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, dict_val, llvmlite.const_int64(pool, 0))
|
||
keys_ptr: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, kpp)
|
||
eight_val: llvmlite.Value* = llvmlite.const_int64(pool, 8)
|
||
key_offset: llvmlite.Value* = llvmlite.build_mul(builder, cur_idx, eight_val)
|
||
key_addr: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, keys_ptr, key_offset)
|
||
cur_key: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, key_addr)
|
||
llvmlite.build_store(builder, cur_key, var_alloca)
|
||
|
||
# 保存旧循环上下文,设置 break/continue 目标
|
||
old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||
old_continue: rawptr[llvmlite.BasicBlock] = trans._continue_bb
|
||
trans._break_bb = end_bb
|
||
trans._continue_bb = incr_bb
|
||
|
||
body: list[ast.AST*]* = for_node.children
|
||
if body is not None:
|
||
body_count: sizet = len(body)
|
||
for bi in range(body_count):
|
||
stmt: ast.AST* = body.get(bi)
|
||
if stmt is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||
|
||
trans._break_bb = old_break
|
||
trans._continue_bb = old_continue
|
||
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||
llvmlite.build_br(builder, incr_bb)
|
||
|
||
# incr 块: index++
|
||
llvmlite.position_at_end(builder, incr_bb)
|
||
one_val: llvmlite.Value* = llvmlite.const_int64(pool, 1)
|
||
next_idx: llvmlite.Value* = llvmlite.build_add(builder, cur_idx, one_val)
|
||
llvmlite.build_store(builder, next_idx, idx_alloca)
|
||
llvmlite.build_br(builder, cond_bb)
|
||
|
||
# 定位到 end 块
|
||
llvmlite.position_at_end(builder, end_bb)
|
||
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
|
||
trans._ctrl_merge_reachable = 1
|
||
return new_vars
|
||
|
||
# ============================================================
|
||
# _handle_oop_iter - OOP 迭代协议: for x in obj:(迁移自 ForHandleIter)
|
||
# obj 的类有 __iter__/__next__ 方法时调用协议迭代
|
||
# (对齐 TPC HandlesFor.py _HandleForIterLlvm L599-663)
|
||
#
|
||
# 生成 IR 结构:
|
||
# %it = call {Class}.__iter__(obj)
|
||
# %flag = alloca i1 ; store 0
|
||
# br %cond
|
||
# cond:
|
||
# store 0, %flag
|
||
# %v = call {Class}.__next__(%it, %flag)
|
||
# %stop = load i1, %flag
|
||
# br i1 %stop==0, %body, %end
|
||
# body:
|
||
# store %v, %var
|
||
# ... 循环体 ...
|
||
# br %step
|
||
# step:
|
||
# br %cond
|
||
# end:
|
||
#
|
||
# __next__ 的隐藏参数 __stop_iter_flag__(i1*)由 ClassGenMixin
|
||
# _translate_method 注入,raise StopIteration 时置 1(translate_raise);
|
||
# VpiReader stub 声明同步该参数(_inject_method_declare)。
|
||
# ============================================================
|
||
def _handle_oop_iter(self, trans: HT.Translator*,
|
||
for_node: ast.For*,
|
||
var_name: str,
|
||
class_name: str,
|
||
obj_val: llvmlite.Value*) -> int:
|
||
"""OOP iter 协议: for x in obj: 调用 __iter__/__next__ 迭代"""
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
func: llvmlite.Function* = trans._cur_func
|
||
mod: llvmlite.LLVMModule* = trans.Module
|
||
|
||
if builder is None or func is None or mod is None:
|
||
return 0
|
||
if obj_val is None or obj_val.Ty is None:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "OOP 迭代: 迭代源对象类型未知")
|
||
if self.Gen.ExprGenBase.is_ptr_type(obj_val.Ty) == 0:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "OOP 迭代: 迭代源对象不是指针类型")
|
||
|
||
# 1. 查找 {Class}.__iter__ 并调用,得到迭代器
|
||
iter_lookup: str = pool.alloc(128)
|
||
if iter_lookup is None:
|
||
return 0
|
||
viperlib.snprintf(iter_lookup, 128, "%s.__iter__", class_name)
|
||
iter_fn: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, iter_lookup)
|
||
if iter_fn is None:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, f"OOP 迭代: 类 '{class_name}' 没有 __iter__ 方法")
|
||
iter_ret_ty: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(iter_fn)
|
||
iter_fn_name: str = llvmlite.function_get_name(iter_fn)
|
||
if iter_ret_ty is None or iter_fn_name is None:
|
||
return 0
|
||
# self 参数按 __iter__ 首参类型对齐(stub 声明 self 可能是 i8*)
|
||
iter_self: llvmlite.Value* = obj_val
|
||
iter_first: llvmlite.Param* = llvmlite.function_get_param_head(iter_fn)
|
||
if iter_first is not None:
|
||
iter_self_ty: llvmlite.LLVMType* = llvmlite.param_get_ty(iter_first)
|
||
if iter_self_ty is not None:
|
||
iter_self = llvmlite.build_bitcast(builder, obj_val, iter_self_ty)
|
||
if iter_self is None:
|
||
return 0
|
||
iter_self.Next = None
|
||
iter_result: llvmlite.Value* = llvmlite.build_call(builder, iter_fn_name, iter_self, 1, iter_ret_ty, 0)
|
||
if iter_result is None:
|
||
return 0
|
||
|
||
# 2. 查找 {Class}.__next__(带隐藏 __stop_iter_flag__ i1* 参数)
|
||
next_lookup: str = pool.alloc(128)
|
||
if next_lookup is None:
|
||
return 0
|
||
viperlib.snprintf(next_lookup, 128, "%s.__next__", class_name)
|
||
next_fn: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, next_lookup)
|
||
if next_fn is None:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, f"OOP 迭代: 类 '{class_name}' 没有 __next__ 方法")
|
||
next_ret_ty: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(next_fn)
|
||
next_fn_name: str = llvmlite.function_get_name(next_fn)
|
||
if next_ret_ty is None or next_fn_name is None:
|
||
return 0
|
||
|
||
# 3. 循环变量 alloca(元素类型 = __next__ 返回类型)
|
||
var_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, var_name)
|
||
new_vars: int = 0
|
||
if var_alloca is None:
|
||
var_alloca = self.Gen.VarGen._alloca_at_entry(builder, next_ret_ty)
|
||
if var_alloca is not None:
|
||
if self.Gen.VarGen.define_var(trans.SymTab, var_name, var_alloca) == 0:
|
||
new_vars = 1
|
||
|
||
# 4. stop flag alloca(i1,初始 0)
|
||
i1_ty: llvmlite.LLVMType* = llvmlite.Int1(pool)
|
||
flag_alloca: llvmlite.Value* = llvmlite.build_alloca(builder, i1_ty)
|
||
if flag_alloca is None:
|
||
return 0
|
||
flag_zero: llvmlite.Value* = llvmlite.ConstInt(pool, i1_ty, 0, "0")
|
||
if flag_zero is not None:
|
||
llvmlite.build_store(builder, flag_zero, flag_alloca)
|
||
|
||
# 5. 创建基本块: cond / body / step / end
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
name_buf: str = pool.alloc(32)
|
||
viperlib.snprintf(name_buf, 32, "oop.cond.%d", cnt)
|
||
cond_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
viperlib.snprintf(name_buf, 32, "oop.body.%d", cnt)
|
||
body_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
viperlib.snprintf(name_buf, 32, "oop.step.%d", cnt)
|
||
step_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
viperlib.snprintf(name_buf, 32, "oop.end.%d", cnt)
|
||
end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
if cond_bb is None or body_bb is None or step_bb is None or end_bb is None:
|
||
return 0
|
||
|
||
llvmlite.build_br(builder, cond_bb)
|
||
|
||
# 6. cond 块: 重置 flag → 调 __next__(iter, flag) → 检查 flag 判结束
|
||
llvmlite.position_at_end(builder, cond_bb)
|
||
if flag_zero is not None:
|
||
llvmlite.build_store(builder, flag_zero, flag_alloca)
|
||
# __next__ 参数 1:迭代器(按首参类型 bitcast)
|
||
next_self: llvmlite.Value* = iter_result
|
||
next_first: llvmlite.Param* = llvmlite.function_get_param_head(next_fn)
|
||
if next_first is not None:
|
||
next_self_ty: llvmlite.LLVMType* = llvmlite.param_get_ty(next_first)
|
||
if next_self_ty is not None and iter_result.Ty is not None:
|
||
next_self = llvmlite.build_bitcast(builder, iter_result, next_self_ty)
|
||
if next_self is None:
|
||
return 0
|
||
# 参数链表: arg1(iter).Next = arg2(flag);flag 独立 null 结尾防自链接
|
||
next_self.Next = flag_alloca
|
||
flag_alloca.Next = None
|
||
next_val: llvmlite.Value* = llvmlite.build_call(builder, next_fn_name, next_self, 2, next_ret_ty, 0)
|
||
if next_val is None:
|
||
return 0
|
||
stop_val: llvmlite.Value* = llvmlite.build_load(builder, i1_ty, flag_alloca)
|
||
if stop_val is None:
|
||
return 0
|
||
flag_zero2: llvmlite.Value* = llvmlite.ConstInt(pool, i1_ty, 0, "0")
|
||
continue_i1: llvmlite.Value* = None
|
||
if flag_zero2 is not None:
|
||
continue_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, stop_val, flag_zero2)
|
||
if continue_i1 is None:
|
||
return 0
|
||
llvmlite.build_cond_br(builder, continue_i1, body_bb, end_bb)
|
||
|
||
# 7. body 块: store 元素 → 翻译循环体 → br step
|
||
llvmlite.position_at_end(builder, body_bb)
|
||
if var_alloca is not None:
|
||
llvmlite.build_store(builder, next_val, var_alloca)
|
||
old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||
old_continue: rawptr[llvmlite.BasicBlock] = trans._continue_bb
|
||
trans._break_bb = end_bb
|
||
trans._continue_bb = step_bb
|
||
body: list[ast.AST*]* = for_node.children
|
||
if body is not None:
|
||
body_count: sizet = len(body)
|
||
for bi in range(body_count):
|
||
stmt: ast.AST* = body.get(bi)
|
||
if stmt is not None:
|
||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||
trans._break_bb = old_break
|
||
trans._continue_bb = old_continue
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||
llvmlite.build_br(builder, step_bb)
|
||
|
||
# 8. step 块 → cond;定位到 end 块
|
||
llvmlite.position_at_end(builder, step_bb)
|
||
llvmlite.build_br(builder, cond_bb)
|
||
llvmlite.position_at_end(builder, end_bb)
|
||
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
|
||
trans._ctrl_merge_reachable = 1
|
||
return new_vars
|
||
|
||
def _handle_enumerate_iter(self, trans: HT.Translator*,
|
||
for_node: ast.For*,
|
||
t1: str, t2: str,
|
||
call: ast.Call*) -> int:
|
||
"""enumerate 迭代: for i, v in enumerate(x)"""
|
||
if call is None or call.args is None:
|
||
return 0
|
||
cargs: list[ast.AST*]* = call.args
|
||
if len(cargs) < 1:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "enumerate 需要至少一个参数")
|
||
return self._build_seq_loop(trans, for_node, t1, t2, cargs.get(0), None, 1)
|
||
|
||
def _handle_zip_iter(self, trans: HT.Translator*,
|
||
for_node: ast.For*,
|
||
t1: str, t2: str,
|
||
call: ast.Call*) -> int:
|
||
"""zip 迭代: for a, b in zip(x, y)"""
|
||
if call is None or call.args is None:
|
||
# fail-fast: zip 参数缺失
|
||
self.Gen.TypeGenErr.fatal_error(call, "zip 参数缺失", "SyntaxError")
|
||
cargs: list[ast.AST*]* = call.args
|
||
if len(cargs) < 2:
|
||
self.Gen.TypeGenErr.fatal_error(for_node, "zip 需要至少两个参数")
|
||
return self._build_seq_loop(trans, for_node, t1, t2, cargs.get(0), cargs.get(1), 2)
|
||
|
||
|
||
def InitStmtGen(self) -> int:
|
||
"""初始化 StmtGen 族字段(构造时由 Generator 调用)"""
|
||
if self is None:
|
||
return 1
|
||
self.CifEvalOk = 0
|
||
self.EnumTable = None
|
||
self.EnumCount = 0
|
||
self.DiagStmtCount = 0
|
||
return 0
|