diff --git a/App/lib/core/Gen/CallGenBase.vp b/App/lib/core/Gen/CallGenBase.vp new file mode 100644 index 0000000..e2e1603 --- /dev/null +++ b/App/lib/core/Gen/CallGenBase.vp @@ -0,0 +1,1085 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesFunctions as HandlesFunctions +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign +import lib.core.CompilerFactory as CompilerFactory + + + +# ============================================================ +# CallGenBase - CallGenMixin 拆分 1/9(最底层父类):模块符号查找 + +# 返回类型解析基础设施 +# +# 按功能域从 CallGenMixin.vp 拆出(500~1500 行/文件架构重构): +# 字段(15 个)+ InitCallGen + 模块符号查找(sha1/cexport/vpi/reexport/find_func_in_module) +# + 返回类型解析链(_ensure_method_declare/_LookupMethodRetTyFromTextLL/_dep_text_ll_exists 等) +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 +# ============================================================ + + +# ============================================================ +# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug) +# ============================================================ +GLOBAL_FUNC_MAX: t.CDefine = 8192 +GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 +_CEXPORT_MAX: t.CDefine = 256 +ASM_MAX_OPERANDS: t.CDefine = 16 +ASM_TEXT_BUF_SIZE: t.CDefine = 2048 +ASM_CONST_BUF_SIZE: t.CDefine = 512 +ASM_ARGS_BUF_SIZE: t.CDefine = 512 +ASM_LINE_BUF_SIZE: t.CDefine = 4096 +LLVMIR_MAX_OPS: t.CDefine = 16 +LLVMIR_TEMPLATE_BUF: t.CDefine = 512 +# 闭包名表大小(原 HandlesExprCall 模块级常量) +MAX_CLOSURE_NAMES: t.CDefine = 128 +# 函数指针签名表大小(原 HandlesExprCall 模块级常量) +MAX_FUNC_PTR_SIGS: t.CDefine = 64 +# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32) +ISINSTANCE_CLASS_MAX: t.CDefine = 64 + + +# ============================================================ +# CallGenBase - 最底层父类(字段 + 模块查找 + 返回类型解析) +# ============================================================ +@t.NoVTable +class CallGenBase: + """调用分派最底层父类(字段 + 模块符号查找 + 返回类型解析基础设施)""" + + # --- c.cexport 注册表(原 _g_cexport_sha1_arr/_g_cexport_func_arr/_g_cexport_count) --- + CexportSha1Arr: bytes + CexportFuncArr: bytes + CexportCount: int + + # --- LLVMIR 寄存器序号(原 _g_llvmir_reg_seq) --- + LLVMIRRegSeq: int + + # --- temp 目录(原 _g_temp_dir/_g_temp_dir_len) --- + TempDir: str + TempDirLen: t.CSizeT + + # --- 闭包名表(原 _g_closure_names/_g_closure_count) --- + ClosureNames: str + ClosureCount: int + + # --- 函数指针签名表(原 _g_funcptr_names/_g_funcptr_rets/_g_funcptr_count) --- + FuncptrNames: str + FuncptrRets: t.CUInt64T | t.CPtr + FuncptrCount: int + + # --- 全局函数注册表(原 _global_funcs/_global_func_count) --- + GlobalFuncs: HandlesExprCall.FuncEntry | t.CPtr + GlobalFuncCount: int + + # --- 全局默认参数表(原 _global_defaults/_global_defaults_count) --- + GlobalDefaults: HandlesExprCall.FuncDefaultsEntry | t.CPtr + GlobalDefaultsCount: int + + def InitCallGen(self) -> int: + """初始化调用 Mixin 字段(子类构造时内联调用,规避 NoVTable 继承符号不转发)""" + if self is None: + return 1 + self.CexportSha1Arr = None + self.CexportFuncArr = None + self.CexportCount = 0 + self.LLVMIRRegSeq = 0 + self.TempDir = None + self.TempDirLen = 0 + self.ClosureNames = None + self.ClosureCount = 0 + self.FuncptrNames = None + self.FuncptrRets = None + self.FuncptrCount = 0 + self.GlobalFuncs = None + self.GlobalFuncCount = 0 + self.GlobalDefaults = None + self.GlobalDefaultsCount = 0 + return 0 + + # ============================================================ + # P4 簇 1+2 迁移方法(函数体来自 HandlesExprCall.vp: + # 模块 SHA1 查询/CExport 注册表/c.* 系列/内联汇编/LLVMIR) + # 本模块函数调用改 self.,外部模块调用保留模块前缀 + # ============================================================ + + + # ============================================================ + # P4 簇 1+2 迁移方法(函数体来自 HandlesExprCall.vp: + # 模块 SHA1 查询/CExport 注册表/c.* 系列/内联汇编/LLVMIR) + # 本模块函数调用改 self.,外部模块调用保留模块前缀 + # ============================================================ + + def _lookup_module_sha1(self, mod_name: str) -> str: + """查找模块名对应的 SHA1,找不到返回 None + + 委托给 StubMerger.LookupSha1ByModName(精确匹配 + 包名回退)。 + """ + return StubMerger.LookupSha1ByModName(mod_name) + + + def _lookup_module_sha1_suffix(self, mod_suffix: str) -> str: + """后缀匹配查找模块 SHA1,如 mod_suffix="__types" 匹配 "llvmlite.__types" + + 用于 from .X import Y 的相对导入:impf.module 是 ".X"(带前导点), + 去掉前导点后为 "X",SHA1 映射表中键是 "pkg.X",需要后缀匹配。 + 委托给 StubMerger.LookupSha1ByModNameSuffix(精确 + 后缀 + 反向后缀)。 + """ + return StubMerger.LookupSha1ByModNameSuffix(mod_suffix) + + + def _module_package_from_sha1(self, pool: memhub.MemBuddy | t.CPtr, + mod_sha1: str) -> str: + """从 SHA1 存储器的 rel_path 计算模块所属包名(目录部分,'/' → '.')""" + if pool is None or mod_sha1 is None: + return None + rel_arr_ptr: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr() + sha1_arr_ptr: bytes | t.CPtr = StubMerger.GetSha1StoreArrPtr() + count: int = StubMerger.GetSha1StoreCount() + if rel_arr_ptr is None or sha1_arr_ptr is None or count <= 0: + return None + for i in range(count): + sidx: t.CSizeT = t.CSizeT(i) * 17 + if string.strcmp(sha1_arr_ptr + sidx, mod_sha1) != 0: + continue + ridx: t.CSizeT = t.CSizeT(i) * StubMerger.MAX_REL_PATH_LEN + rel: str = rel_arr_ptr + ridx + last_slash: str = string.strrchr(rel, 47) # 47 = ord('/') + if last_slash is None: + return None + pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(last_slash) - t.CUInt64T(rel)) + if pkg_len == 0: + return None + pkg_buf: str = pool.alloc(pkg_len + 1) + if pkg_buf is None: + return None + for pi in range(pkg_len): + if rel[pi] == '/': + pkg_buf[pi] = '.' + else: + pkg_buf[pi] = rel[pi] + pkg_buf[pkg_len] = '\0' + return pkg_buf + return None + + + def _lookup_reexport_from_vpi(self, pool: memhub.MemBuddy | t.CPtr, + mod_sha1: str, func_name: str) -> str: + """re-export 表未命中时,从模块 .vpi 按需解析 from-import 定位定义模块 + + includes 模块(如 llvmlite/__init__)的 stub/text 已存在时不会被按需 + 全量翻译(Phase2 3.5 仅在 stub/text 缺失时翻译),而 re-export 表只在 + declare_only=0 的全量翻译中注册(HandleImportFromNames),因此表可能为空。 + 本函数解析该模块 .vpi 的 "from .X import ... func_name ..." 语句, + 返回定义模块名(如 llvmlite/__init__ 的 .__builder → "llvmlite.__builder")。 + """ + if pool is None or mod_sha1 is None or func_name is None: + return None + temp_dir: str = HandlesType.get_temp_dir() + if temp_dir is None: + return None + td_len: t.CSizeT = string.strlen(temp_dir) + vpi_path: str = StubMerger._sliced_path(temp_dir, td_len, mod_sha1, "vpi") + if vpi_path is None: + return None + READ_SZ: t.CSizeT = 1048576 + buf: bytes = stdlib.malloc(READ_SZ) + if buf is None: + stdlib.free(vpi_path) + return None + vf: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R) + stdlib.free(vpi_path) + if vf.closed: + stdlib.free(buf) + return None + nrd: LONG = vf.read_all(buf, READ_SZ) + vf.close() + if nrd <= 0: + stdlib.free(buf) + return None + if nrd < READ_SZ: + buf[nrd] = 0 + else: + buf[READ_SZ - 1] = 0 + name_len: t.CSizeT = string.strlen(func_name) + total: t.CSizeT = string.strlen(buf) + pos: t.CSizeT = 0 + while pos < total: + ls: t.CSizeT = pos + while pos < total and buf[pos] != '\n': + pos += 1 + ll: t.CSizeT = pos - ls + if pos < total: + pos += 1 + # 行必须以 "from " 开头 + if ll < 6: + continue + if buf[ls] != 'f' or buf[ls + 1] != 'r' or buf[ls + 2] != 'o' or buf[ls + 3] != 'm' or buf[ls + 4] != ' ': + continue + # 找 " import " 分隔符 + imp_pos: t.CSizeT = ls + 5 + while imp_pos + 7 <= ls + ll: + if buf[imp_pos] == ' ' and buf[imp_pos + 1] == 'i' and buf[imp_pos + 2] == 'm' and \ + buf[imp_pos + 3] == 'p' and buf[imp_pos + 4] == 'o' and buf[imp_pos + 5] == 'r' and \ + buf[imp_pos + 6] == 't' and buf[imp_pos + 7] == ' ': + break + imp_pos += 1 + if imp_pos + 7 > ls + ll: + continue + mod_start: t.CSizeT = ls + 5 + mod_end: t.CSizeT = imp_pos + # 名称列表从 "import " 之后(逗号分隔,含 "A as B" 取原名 A) + nm_start: t.CSizeT = imp_pos + 8 + scan: t.CSizeT = nm_start + while scan < ls + ll: + while scan < ls + ll and (buf[scan] == ' ' or buf[scan] == ','): + scan += 1 + if scan >= ls + ll: + break + n_end: t.CSizeT = scan + while n_end < ls + ll and buf[n_end] != ',' and buf[n_end] != ' ': + n_end += 1 + cand_start: t.CSizeT = scan + cand_len: t.CSizeT = n_end - scan + as_pos: t.CSizeT = scan + while as_pos + 4 <= n_end: + if buf[as_pos] == ' ' and buf[as_pos + 1] == 'a' and buf[as_pos + 2] == 's' and buf[as_pos + 3] == ' ': + cand_start = as_pos + 4 + cand_len = n_end - cand_start + break + as_pos += 1 + if cand_len == name_len: + m_ok: int = 1 + for ki in range(name_len): + if buf[cand_start + ki] != func_name[ki]: + m_ok = 0 + break + if m_ok == 1: + # 命中:解析模块名(前导点 → 相对导入,补包前缀) + has_dot: int = 0 + if buf[mod_start] == '.': + has_dot = 1 + mod_buf: str = pool.alloc(mod_end - mod_start + 1) + if mod_buf is None: + stdlib.free(buf) + return None + mi: t.CSizeT = 0 + while mod_start + mi < mod_end: + mod_buf[mi] = buf[mod_start + mi] + mi += 1 + mod_buf[mi] = '\0' + while mod_buf[0] == '.': + mod_buf = mod_buf + 1 + if string.strlen(mod_buf) == 0: + stdlib.free(buf) + return None + if has_dot != 0: + pkg: str = self._module_package_from_sha1(pool, mod_sha1) + if pkg is None: + stdlib.free(buf) + return None + rl: t.CSizeT = string.strlen(pkg) + string.strlen(mod_buf) + 2 + res: str = pool.alloc(rl) + if res is None: + stdlib.free(buf) + return None + viperlib.snprintf(res, rl, "%s.%s", pkg, mod_buf) + stdlib.free(buf) + return res + stdlib.free(buf) + return mod_buf + scan = n_end + stdlib.free(buf) + return None + + + def register_cexport_func(self, sha1: str, func_name: str) -> int: + """注册 CExport 函数到全局表(sha1+func_name 二元组)""" + if sha1 is None or func_name is None: + return 0 + if self.CexportSha1Arr is None: + self.CexportSha1Arr = CompilerFactory.get_perm_pool().alloc(_CEXPORT_MAX * 17) + self.CexportFuncArr = CompilerFactory.get_perm_pool().alloc(_CEXPORT_MAX * 64) + if self.CexportSha1Arr is None or self.CexportFuncArr is None: + return 0 + string.memset(self.CexportSha1Arr, 0, _CEXPORT_MAX * 17) + string.memset(self.CexportFuncArr, 0, _CEXPORT_MAX * 64) + if self.CexportCount < _CEXPORT_MAX: + idx: t.CSizeT = t.CSizeT(self.CexportCount) * 17 + # 槽位定长 17/64 字节,strcpy 无界会越界写相邻槽(stdlib 堆区) + string.strncpy(self.CexportSha1Arr + idx, sha1, 16) + self.CexportSha1Arr[idx + 16] = '\0' + idx2: t.CSizeT = t.CSizeT(self.CexportCount) * 64 + string.strncpy(self.CexportFuncArr + idx2, func_name, 63) + self.CexportFuncArr[idx2 + 63] = '\0' + self.CexportCount += 1 + return 1 + return 0 + + + def is_cexport_func(self, sha1: str, func_name: str) -> int: + """检查 (sha1, func_name) 是否是 CExport 函数""" + if sha1 is None or func_name is None: + return 0 + if self.CexportSha1Arr is None: + return 0 + for i in range(self.CexportCount): + idx: t.CSizeT = t.CSizeT(i) * 17 + if string.strcmp(self.CexportSha1Arr + idx, sha1) == 0: + idx2: t.CSizeT = t.CSizeT(i) * 64 + if string.strcmp(self.CexportFuncArr + idx2, func_name) == 0: + return 1 + return 0 + + + def _is_state_func_from_vpi(self, pool: memhub.MemBuddy | t.CPtr, + sha1: str, func_name: str) -> int: + """vpi 返回注解含 t.State → 外部 C 函数(定义端用裸名,跨模块调用无 sha1 头) + + t.State(同 t.CExtern/t.CExport)是外部函数标记:定义端生成裸名 + @PyList_Size(链接外部库 libpython),跨模块调用若生成 @{sha1}.PyList_Size + → ld.lld undefined symbol(CPythonTest PyList_Size 根因)。CExport 走 + is_cexport_func 注册表,State 函数未注册 → 按需解析 vpi 返回注解判断。 + """ + if pool is None or sha1 is None or func_name is None: + return 0 + import lib.StubGen.VpiReader as VpiReader + if self.TempDir is not None and self.TempDirLen > 0: + VpiReader._ensure_vpi_ret_annot_loaded(sha1, self.TempDir) + state_annot: str = VpiReader._lookup_vpi_ret_annot(sha1, None, func_name) + if state_annot is None: + return 0 + # 返回注解含 "State"(如 "t.CSizeT | t.State")→ 外部 C 函数 + if string.strstr(state_annot, "State") is not None: + return 1 + return 0 + + + def _lookup_mod_sha1(self, pool: memhub.MemBuddy | t.CPtr, + from_imports: str, class_name: str, + allow_star_fallback: int = 1) -> str: + """从 from_imports 查找类所属模块的 SHA1,返回 None=未找到 + + allow_star_fallback: 传 0 禁用 star import 回退(用于明确模块名/函数名查找) + """ + mod_name_raw: str = HandlesImports.lookup_from_import( + from_imports, class_name, allow_star_fallback) + if mod_name_raw is None: + return None + return self._lookup_sha1_from_modname_raw(pool, mod_name_raw) + + + def _lookup_sha1_from_modname_raw(self, pool: memhub.MemBuddy | t.CPtr, + mod_name_raw: str) -> str: + """从原始模块名查找 SHA1,返回 None=未找到""" + # 手动找到模块名结束位置(空格、null、或 ':' 别名分隔符),复制到新缓冲区 + mod_len: t.CSizeT = 0 + while mod_name_raw[mod_len] != ' ' and mod_name_raw[mod_len] != '\0' and mod_name_raw[mod_len] != ':': + mod_len += 1 + mod_name_buf: str = pool.alloc(mod_len + 1) + if mod_name_buf is None: + return None + for mi in range(mod_len): + mod_name_buf[mi] = mod_name_raw[mi] + mod_name_buf[mod_len] = '\0' + # 去掉相对导入的前导点 + base_mod: str = mod_name_buf + while base_mod[0] == '.': + base_mod = base_mod + 1 + sha1: str = self._lookup_module_sha1(base_mod) + if sha1 is None: + sha1 = self._lookup_module_sha1_suffix(base_mod) + return sha1 + + + def find_func_in_module(self, mod: llvmlite.LLVMModule | t.CPtr, + name: str) -> llvmlite.Function | t.CPtr: + """在模块的函数链表中按名称查找函数 + + 查找策略: + 1. 精确匹配(如 "strlen" 匹配 @strlen,有 t.CExport 的函数) + 2. 后缀匹配(如 "atoi" 匹配 @"83210a72e829a086.atoi",无 t.CExport 的函数) + + 使用 llvmlite.function_get_name/next 访问器绕过 stub 类型限制 + (stub 类型字段不足且字段类型可能错误,直接字段访问会被静默跳过)。 + """ + if mod is None or name is None: + return None + name_len: t.CSizeT = string.strlen(name) + cur: llvmlite.Function | t.CPtr = mod.FuncHead + # 第一遍:精确匹配 + while cur is not None: + cur_name: str = llvmlite.function_get_name(cur) + if cur_name is not None: + if string.strcmp(cur_name, name) == 0: + return cur + cur = llvmlite.function_get_next(cur) + # 第二遍:后缀匹配(.name) + # 不跳过 declare:方法 stub 也是 declare,需要通过后缀匹配找到 + # 调用处(translate_call 等)负责判断 IsDeclared 并决定使用裸名还是 sha1 前缀名 + # + # 修复:本模块 define 优先于跨模块 stub declare。 + # 根因:跨模块同名函数(如 lexer.vp 的 _advance 与 parser.vp 的 _advance) + # 的 stub declare 在 stub 注入时排在 FuncHead 前面,裸名调用 _advance 后缀 + # 匹配按链表顺序先命中跨模块 declare → 参数按 Lexer* coerce → Parser* 被 + # bitcast 成 Lexer* → lexer 版 _advance 按 Lexer 布局操作 Parser 指针, + # cur 永不推进 → parse 无限循环。本模块同名 define 必须优先。 + cur = mod.FuncHead + while cur is not None: + cur_name2: str = llvmlite.function_get_name(cur) + if cur_name2 is not None: + cur_len: t.CSizeT = string.strlen(cur_name2) + if cur_len > name_len + 1: + suffix_start: t.CSizeT = cur_len - name_len + if cur_name2[suffix_start - 1] == '.': + match: int = 1 + for i in range(name_len): + if cur_name2[suffix_start + i] != name[i]: + match = 0 + break + if match == 1: + if cur.IsDeclared == 0: + return cur + cur = llvmlite.function_get_next(cur) + # 本模块无同名 define:回退到 stub declare(跨模块方法/函数调用) + cur = mod.FuncHead + while cur is not None: + cur_name3: str = llvmlite.function_get_name(cur) + if cur_name3 is not None: + cur_len3: t.CSizeT = string.strlen(cur_name3) + if cur_len3 > name_len + 1: + suffix_start3: t.CSizeT = cur_len3 - name_len + if cur_name3[suffix_start3 - 1] == '.': + match3: int = 1 + for i in range(name_len): + if cur_name3[suffix_start3 + i] != name[i]: + match3 = 0 + break + if match3 == 1: + return cur + cur = llvmlite.function_get_next(cur) + return None + + + # ============================================================ + # _ensure_method_declare - 为跨模块方法调用创建 declare 声明 + # + # 当 found_func 为 None(stub 未注入或跨模块调用)时, + # 在当前模块中创建函数声明,避免 llc 报 undefined value。 + # ============================================================ + def _ensure_method_declare(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + call_name: str, + ret_ty: llvmlite.LLVMType | t.CPtr, + param_head: llvmlite.ParamNode | t.CPtr, + param_count: int): + """为跨模块方法调用创建 declare 声明 + + 若模块中已存在同名 declare 且参数数量较少(例如 File.__init__ 的 + stub 仅 3 个参数,而实际调用传入 4 个),则向现有 declare 追加缺失 + 参数,避免 llc 报 `argument invalid for parameter type` 之类的错误。 + 已存在的 define 不修改(其参数由定义决定)。 + """ + if pool is None or mod is None or call_name is None: + return + # 检查模块中是否已有同名函数(declare 或 define) + existing: llvmlite.Function | t.CPtr = mod.FuncHead + while existing is not None: + if existing.Name is not None: + if string.strcmp(existing.Name, call_name) == 0: + # 已存在:仅当是 declare 且参数数量不足时追加缺失参数 + if existing.IsDeclared == 1: + # 变长函数(*args,IsVarArg=1)不追加参数:多余实参由 + # 变参机制(...)承接,追加有类型参数会导致调用侧把变参 + # 强转为追加的类型(如 i8 → i64),%d/%x 等格式读错。 + if existing.IsVarArg == 1: + return + # 遍历现有参数链表计数(避免依赖 GSList.Count 字段的类型推断) + cur_count: int = 0 + cur_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(existing) + while cur_p is not None: + cur_count += 1 + cur_p = cur_p.Next + # 只追加缺失的参数(cur_count < param_count 时) + if cur_count < param_count: + # 定位到 param_head 的第 cur_count 个节点开始追加 + pnode2: llvmlite.ParamNode | t.CPtr = param_head + pi2: int = 0 + # 跳过已有的 cur_count 个参数 + while pnode2 is not None and pi2 < cur_count: + pnode2 = pnode2.Next + pi2 += 1 + # 追加剩余参数 + while pnode2 is not None and pi2 < param_count: + if pnode2.Ty is not None: + param2: llvmlite.Param | t.CPtr = llvmlite.new_param(pool, pnode2.Ty, None) + if param2 is not None: + llvmlite.function_add_param(existing, param2) + pnode2 = pnode2.Next + pi2 += 1 + return + existing = existing.Next + # 创建函数声明 + func: llvmlite.Function | t.CPtr = llvmlite.new_function(pool, call_name, ret_ty) + if func is None: + return + func.IsDeclared = 1 + # 添加参数(declare 中参数名无意义,设为 None 只输出类型) + pnode: llvmlite.ParamNode | t.CPtr = param_head + pi: int = 0 + while pnode is not None and pi < param_count: + if pnode.Ty is not None: + param: llvmlite.Param | t.CPtr = llvmlite.new_param(pool, pnode.Ty, None) + if param is not None: + llvmlite.function_add_param(func, param) + pnode = pnode.Next + pi += 1 + llvmlite.module_add_function(mod, func) + + # ============================================================ + # _lookup_method_ret_ty_via_vpi - 从 vpi stub 返回注解缓存精确获取方法返回类型 + # + # 方法定义处(.vpi stub)的返回注解(如 json.JsonValue._pool_alloc → + # "str")在 stub 注入时由 VpiReader 缓存(_cache_vpi_return_annots_text)。 + # 此函数按 模块SHA1 + 类名 + 方法名 查缓存并纯字符串解析为 LLVMType。 + # 无需硬编码白名单——返回类型始终来自方法定义处。 + # ============================================================ + + # ============================================================ + # _lookup_method_ret_ty_via_vpi - 从 vpi stub 返回注解缓存精确获取方法返回类型 + # + # 方法定义处(.vpi stub)的返回注解(如 json.JsonValue._pool_alloc → + # "str")在 stub 注入时由 VpiReader 缓存(_cache_vpi_return_annots_text)。 + # 此函数按 模块SHA1 + 类名 + 方法名 查缓存并纯字符串解析为 LLVMType。 + # 无需硬编码白名单——返回类型始终来自方法定义处。 + # ============================================================ + def _lookup_method_ret_ty_via_vpi(self, pool: memhub.MemBuddy | t.CPtr, + cls_sha1: str, + cls_name: str, + method_name: str) -> llvmlite.LLVMType | t.CPtr: + """从 vpi stub 返回注解缓存获取方法返回类型,未命中返回 None""" + if pool is None or cls_sha1 is None or method_name is None: + return None + # 函数内懒 import:VpiReader imports HandlesExprCall,顶层 import 会成环 + import lib.StubGen.VpiReader as VpiReader + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + # 按需加载:缓存未命中时直接读 {temp_dir}/{sha1[0:2]}/{sha1}.vpi + # 覆盖"模块自身翻译时 stub 尚未注入"(同模块方法调用,定义在后)的场景 + if self.TempDir is not None and self.TempDirLen > 0: + VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, self.TempDir) + annot: str = VpiReader._lookup_vpi_ret_annot(cls_sha1, cls_name, method_name) + if annot is None: + return None + return VpiReader._resolve_vpi_ret_annot_str(pool, annot, i32_ty, i8_ptr_ty) + + # ============================================================ + # _special_method_ret_ty - 编译器内置特殊方法的固定返回类型 + # + # __before_init__ / __init__:编译器生成/约定返回 void + # __new__:返回 Ptr(StructTy)(存储空间指针) + # + # 这些方法不存在于源码(vpi stub 无条目),跨模块调用时 + # found_func/text.ll/vpi 缓存必然未命中,但返回类型是编译器 + # 确定性语义(与 HandlesClassDef._translate_method 3543-3548 一致), + # 在此直接固定,不触发 fail-fast 误报。非特殊方法返回 None。 + # ============================================================ + + # ============================================================ + # _special_method_ret_ty - 编译器内置特殊方法的固定返回类型 + # + # __before_init__ / __init__:编译器生成/约定返回 void + # __new__:返回 Ptr(StructTy)(存储空间指针) + # + # 这些方法不存在于源码(vpi stub 无条目),跨模块调用时 + # found_func/text.ll/vpi 缓存必然未命中,但返回类型是编译器 + # 确定性语义(与 HandlesClassDef._translate_method 3543-3548 一致), + # 在此直接固定,不触发 fail-fast 误报。非特殊方法返回 None。 + # ============================================================ + def _special_method_ret_ty(self, pool: memhub.MemBuddy | t.CPtr, + class_name: str, + method_name: str) -> llvmlite.LLVMType | t.CPtr: + """编译器内置特殊方法的固定返回类型;非特殊返回 None""" + if pool is None or method_name is None: + return None + if string.strcmp(method_name, "__before_init__") == 0 or \ + string.strcmp(method_name, "__init__") == 0: + return llvmlite.Void(pool) + if string.strcmp(method_name, "__new__") == 0: + if class_name is not None: + sp_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name) + if sp_struct_ty is not None: + return llvmlite.Ptr(pool, sp_struct_ty) + return None + return None + + # ============================================================ + # _fail_method_ret_ty - 方法返回类型无法精确获取时 fail-fast + # + # 返回类型来源(按序):当前模块函数 → text.ll define → vpi stub 返回注解缓存。 + # 全部未命中时立即 ERROR + 错误堆栈终止,绝不按名推断白名单/静默默认 i32。 + # + # node: 调用点 AST 节点(可选,用于 ERROR 堆栈定位) + # ============================================================ + + # ============================================================ + # _fail_method_ret_ty - 方法返回类型无法精确获取时 fail-fast + # + # 返回类型来源(按序):当前模块函数 → text.ll define → vpi stub 返回注解缓存。 + # 全部未命中时立即 ERROR + 错误堆栈终止,绝不按名推断白名单/静默默认 i32。 + # + # node: 调用点 AST 节点(可选,用于 ERROR 堆栈定位) + # ============================================================ + def _fail_method_ret_ty(self, method_name: str, + node: ast.AST | t.CPtr = None) -> llvmlite.LLVMType | t.CPtr: + """方法返回类型无法精确获取时 fail-fast(ERROR + 错误堆栈) + + 返回类型来源(按序):当前模块函数 → text.ll define → vpi stub 返回注解缓存。 + 全部未命中说明方法定义缺失或 stub 损坏,立即终止暴露,绝不静默默认 i32。 + """ + VLogger.error( + f"方法返回类型无法精确获取(函数/text.ll/vpi stub 均未命中): {method_name}", + "HandlesExprCall") + HandlesType.fatal_error( + node, + f"方法返回类型无法精确获取,默认 i32 会截断指针/i64: {method_name}", + "TypeError") + return None + + # ============================================================ + # SetTempDir - 设置 temp 目录路径 + # + # 在 Phase2.py 的 Phase A 翻译前调用,使 CallGenMixin + # 能够读取依赖模块的 text.ll 文件。 + # ============================================================ + + # ============================================================ + # SetTempDir - 设置 temp 目录路径 + # + # 在 Phase2.py 的 Phase A 翻译前调用,使 CallGenMixin + # 能够读取依赖模块的 text.ll 文件。 + # ============================================================ + def SetTempDir(self, temp_dir: str): + """设置 temp 目录路径(供跨模块方法返回类型查找使用)""" + self.TempDir = temp_dir + if temp_dir is not None: + self.TempDirLen = string.strlen(temp_dir) + else: + self.TempDirLen = 0 + + # ============================================================ + # _ParseLLVMRetTyStr - 将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType + # + # 从 define 行中提取的返回类型字符串(define 与 @ 之间的内容), + # 转换为 llvmlite.LLVMType 对象。 + # + # 支持的类型: + # void → Void + # i8/i16/i32/i64 → Int8/Int16/Int32/Int64 + # double → Double, float → Float + # 任何含 * 的类型 → Ptr(Int8)(通用指针,保留 64 位地址) + # + # Args: + # pool: 内存池 + # buf: 包含类型字符串的缓冲区 + # start: 类型字符串起始位置 + # end: 类型字符串结束位置(不含) + # + # Returns: + # LLVM 类型对象,或 None(无法解析) + # ============================================================ + + # ============================================================ + # _ParseLLVMRetTyStr - 将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType + # + # 从 define 行中提取的返回类型字符串(define 与 @ 之间的内容), + # 转换为 llvmlite.LLVMType 对象。 + # + # 支持的类型: + # void → Void + # i8/i16/i32/i64 → Int8/Int16/Int32/Int64 + # double → Double, float → Float + # 任何含 * 的类型 → Ptr(Int8)(通用指针,保留 64 位地址) + # + # Args: + # pool: 内存池 + # buf: 包含类型字符串的缓冲区 + # start: 类型字符串起始位置 + # end: 类型字符串结束位置(不含) + # + # Returns: + # LLVM 类型对象,或 None(无法解析) + # ============================================================ + def _ParseLLVMRetTyStr(self, pool: memhub.MemBuddy | t.CPtr, + buf: bytes, + start: t.CSizeT, + end: t.CSizeT) -> llvmlite.LLVMType | t.CPtr: + """将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType""" + if pool is None or buf is None or start >= end: + return None + + # 去除前导空白 + s: t.CSizeT = start + while s < end: + c: int = buf[s] + if c != ' ' and c != '\t': + break + s += 1 + # 去除尾部空白 + e: t.CSizeT = end + while e > s: + c2: int = buf[e - 1] + if c2 != ' ' and c2 != '\t': + break + e -= 1 + + ty_len: t.CSizeT = e - s + if ty_len == 0: + return None + + # struct 字面量 {T1, T2, ...}(tuple 打包返回类型,如 b2a_hqx -> + # tuple[str, t.CUnsignedShort] 编译为 {i8*, i16})。必须在 * 检查 + # 之前——否则 "{i8*, i16}" 内含 * 会被误判为 i8*(b2a_hqx 调用侧 + # 返回类型退化 i8* → HandlesAssign tuple 解包静默跳过 → free 未初始化 + # 指针崩溃,HashLibTest hqx 段)。 + if s < e and buf[s] == '{': + th_st: llvmlite.ParamNode | t.CPtr = None + tt_st: llvmlite.ParamNode | t.CPtr = None + tc_st: int = 0 + ps_st: t.CSizeT = s + 1 + while ps_st < e and buf[ps_st] != '}': + while ps_st < e and (buf[ps_st] == ' ' or buf[ps_st] == ','): + ps_st += 1 + if ps_st >= e or buf[ps_st] == '}': + break + es_st: t.CSizeT = ps_st + while ps_st < e and buf[ps_st] != ',' and buf[ps_st] != '}': + ps_st += 1 + ee_st: t.CSizeT = ps_st + if ee_st > es_st: + et_st: llvmlite.LLVMType | t.CPtr = self._ParseLLVMRetTyStr( + pool, buf, es_st, ee_st) + if et_st is None: + return None + en_st: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node( + pool, et_st) + if en_st is None: + return None + if th_st is None: + th_st = en_st + else: + llvmlite.paramnode_set_next(tt_st, en_st) + tt_st = en_st + tc_st += 1 + if th_st is None or tc_st == 0: + return None + st_ty_st: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, th_st, tc_st, None) + # 指针到 struct({i32, i8}*):返回 Ptr(Struct);纯 tuple 打包 + # ({i8*, i16})无尾部 *,返回 Struct 本身。 + if ps_st < e and buf[ps_st] == '*': + return llvmlite.Ptr(pool, st_ty_st) + return st_ty_st + + # 检查是否含 * (指针类型) → 返回 i8* (通用指针) + # 包括 i8*, i32*, %"name"*, { i32, i8 }* 等 + ci: t.CSizeT = s + while ci < e: + if buf[ci] == '*': + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + ci += 1 + + # void + if ty_len == 4 and string.strncmp(buf + s, "void", 4) == 0: + return llvmlite.Void(pool) + + # double + if ty_len == 6 and string.strncmp(buf + s, "double", 6) == 0: + return llvmlite.Double(pool) + + # float + if ty_len == 5 and string.strncmp(buf + s, "float", 5) == 0: + return llvmlite.Float(pool) + + # iN (i8, i16, i32, i64) + if ty_len >= 2 and buf[s] == 'i': + bits: int = 0 + di: t.CSizeT = s + 1 + valid: int = 1 + while di < e: + d: int = buf[di] + if d >= '0' and d <= '9': + bits = bits * 10 + (d - '0') + else: + valid = 0 + break + di += 1 + if valid != 0 and bits > 0: + if bits == 8: + return llvmlite.Int8(pool) + if bits == 16: + return llvmlite.Int16(pool) + if bits == 32: + return llvmlite.Int32(pool) + if bits == 64: + return llvmlite.Int64(pool) + + # 无法解析 + return None + + # ============================================================ + # _LookupMethodRetTyFromTextLL - 从依赖模块的 text.ll 查找方法返回类型 + # + # 读取 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll (level=1),搜索 + # define 行中包含 "{sha1}.{class_name}.{method_name}" 的函数, + # 提取返回类型并转换为 llvmlite.LLVMType。 + # + # 解决问题: 旧实现 _infer_method_ret_ty(已移除)默认返回 i32,导致指针返回值 + # 被 inttoptr 截断为 32 位(coerce_to_type line 238-239)。 + # 本函数从 text.ll 获取实际返回类型,避免截断。 + # + # Args: + # pool: 内存池 + # class_sha1: 类所属模块的 SHA1 + # class_name: 类名 + # method_name: 方法名 + # + # Returns: + # LLVM 类型对象,或 None(未找到/text.ll 不存在) + # ============================================================ + + # ============================================================ + # _LookupMethodRetTyFromTextLL - 从依赖模块的 text.ll 查找方法返回类型 + # + # 读取 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll (level=1),搜索 + # define 行中包含 "{sha1}.{class_name}.{method_name}" 的函数, + # 提取返回类型并转换为 llvmlite.LLVMType。 + # + # 解决问题: 旧实现 _infer_method_ret_ty(已移除)默认返回 i32,导致指针返回值 + # 被 inttoptr 截断为 32 位(coerce_to_type line 238-239)。 + # 本函数从 text.ll 获取实际返回类型,避免截断。 + # + # Args: + # pool: 内存池 + # class_sha1: 类所属模块的 SHA1 + # class_name: 类名 + # method_name: 方法名 + # + # Returns: + # LLVM 类型对象,或 None(未找到/text.ll 不存在) + # ============================================================ + def _LookupMethodRetTyFromTextLL(self, pool: memhub.MemBuddy | t.CPtr, + class_sha1: str, + class_name: str, + method_name: str, + use_bare: int = 0) -> llvmlite.LLVMType | t.CPtr: + """从依赖模块的 text.ll 中查找方法返回类型 + + use_bare: 1=按模块级函数查找(搜索 "{sha1}.{method_name}" define, + 用于 new_lexer/tokenize 等模块函数;class_name 忽略)。 + """ + if pool is None or class_sha1 is None or method_name is None: + return None + if self.TempDir is None or self.TempDirLen == 0: + return None + + sha1_len: t.CSizeT = string.strlen(class_sha1) + if sha1_len < 2: + return None + + # 构造 text.ll 路径 (level=1): {temp_dir}/{sha1[0:2]}/{sha1}.text.ll + # 使用 subdir 缓冲区避免 %c 格式化问题(与 StubMerger._sliced_path 一致) + path_len: t.CSizeT = self.TempDirLen + sha1_len + 14 + path_buf: bytes = stdlib.malloc(path_len) + if path_buf is None: + return None + subdir_buf: bytes = stdlib.malloc(3) + if subdir_buf is None: + stdlib.free(path_buf) + return None + subdir_buf[0] = class_sha1[0] + subdir_buf[1] = class_sha1[1] + subdir_buf[2] = '\0' + viperlib.snprintf(path_buf, path_len, "%s/%s/%s.text.ll", + self.TempDir, subdir_buf, class_sha1) + stdlib.free(subdir_buf) + + # 读取 text.ll(按文件实际大小分配:固定 _TEXT_LL_READ_BUF_SIZE(256KB) + # 会截断大模块的 text.ll,末尾方法定义查不到 → 误报"方法返回类型无法 + # 精确获取"(追加80b 根因,同追加74 _read_source_line 截断)。64MB 上限 + # 防御异常超大文件整体读取。) + tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R) + if tf.closed: + stdlib.free(path_buf) + return None + tfsize: LONGLONG = tf.size() + if tfsize <= 0 or tfsize > 67108864: + tf.close() + stdlib.free(path_buf) + return None + read_size: t.CSizeT = t.CSizeT(tfsize) + read_buf: bytes = stdlib.malloc(read_size + 1) + if read_buf is None: + tf.close() + stdlib.free(path_buf) + return None + text_len: t.CInt64T = tf.read_all(read_buf, ULONG(read_size + 1)) + tf.close() + stdlib.free(path_buf) + + if text_len <= 0: + stdlib.free(read_buf) + return None + read_buf[text_len] = '\0' + + # 构造搜索模式: "{sha1}.{class_name}.{method_name}" 或 bare 模式 "{sha1}.{method_name}" + cls_len: t.CSizeT = 0 + if class_name is not None: + cls_len = string.strlen(class_name) + meth_len: t.CSizeT = string.strlen(method_name) + search_len: t.CSizeT = sha1_len + meth_len + 2 + if use_bare == 0: + search_len = sha1_len + cls_len + meth_len + 4 + search_buf: bytes = stdlib.malloc(search_len) + if search_buf is None: + stdlib.free(read_buf) + return None + if use_bare != 0: + viperlib.snprintf(search_buf, search_len, "%s.%s", + class_sha1, method_name) + else: + viperlib.snprintf(search_buf, search_len, "%s.%s.%s", + class_sha1, class_name, method_name) + search_str_len: t.CSizeT = string.strlen(search_buf) + + # 在 text.ll 中搜索 define 行包含 search_buf + buf_len: t.CSizeT = string.strlen(read_buf) + pos: t.CSizeT = 0 + result_ty: llvmlite.LLVMType | t.CPtr = None + + while pos < buf_len and result_ty is None: + ls: t.CSizeT = pos + le: t.CSizeT = pos + while le < buf_len: + if read_buf[le] == '\n': + break + le += 1 + ll: t.CSizeT = le - ls + + # 检查是否是 define 行 + if ll >= 7 and string.strncmp(read_buf + ls, "define ", 7) == 0: + # 找 @ 符号 + at_pos: t.CSizeT = ls + 7 + while at_pos < ls + ll: + if read_buf[at_pos] == '@': + break + at_pos += 1 + if at_pos < ls + ll: + # 跳过可选引号 + name_start: t.CSizeT = at_pos + 1 + if name_start < ls + ll and read_buf[name_start] == '"': + name_start += 1 + # 检查是否匹配 search_buf + if name_start + search_str_len <= ls + ll: + if string.strncmp(read_buf + name_start, search_buf, search_str_len) == 0: + # 函数名边界检查:search 后必须是 '"'(带引号名)、'('(参数表)或行尾, + # 否则 "sha1.func" 会误匹配 "sha1.func_helper" 等前缀同名函数 + name_end: t.CSizeT = name_start + search_str_len + end_ch: int = 0 + if name_end < ls + ll: + end_ch = read_buf[name_end] + if end_ch == 34 or end_ch == 40 or end_ch == 0: + # 匹配!提取返回类型: [ls+7, at_pos) + result_ty = self._ParseLLVMRetTyStr(pool, read_buf, ls + 7, at_pos) + + pos = le + 1 + + stdlib.free(search_buf) + stdlib.free(read_buf) + return result_ty + + # ============================================================ + # _dep_text_ll_exists - 探测依赖模块 text.ll 是否已生成 + # + # 用于区分跨模块返回类型精确解析失败的两种场景: + # 1. text.ll 存在但函数未命中 → 真错误(依赖已编译,函数缺失) + # 2. text.ll 不存在 → 依赖模块尚未翻译(Phase A 按文件顺序翻译, + # main.vp 先于其 import 的 mbuddytest.vp),标记重试待下遍 + # ============================================================ + + # ============================================================ + # _dep_text_ll_exists - 探测依赖模块 text.ll 是否已生成 + # + # 用于区分跨模块返回类型精确解析失败的两种场景: + # 1. text.ll 存在但函数未命中 → 真错误(依赖已编译,函数缺失) + # 2. text.ll 不存在 → 依赖模块尚未翻译(Phase A 按文件顺序翻译, + # main.vp 先于其 import 的 mbuddytest.vp),标记重试待下遍 + # ============================================================ + def _dep_text_ll_exists(self, pool: memhub.MemBuddy | t.CPtr, + sha1: str) -> int: + """探测 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll 是否存在,1=存在""" + if self.TempDir is None or self.TempDirLen == 0 or sha1 is None: + return 0 + sha1_len: t.CSizeT = string.strlen(sha1) + if sha1_len < 2: + return 0 + path_len: t.CSizeT = self.TempDirLen + sha1_len + 14 + path_buf: bytes = stdlib.malloc(path_len) + subdir_buf: bytes = stdlib.malloc(3) + if path_buf is None or subdir_buf is None: + if path_buf is not None: + stdlib.free(path_buf) + if subdir_buf is not None: + stdlib.free(subdir_buf) + return 0 + subdir_buf[0] = sha1[0] + subdir_buf[1] = sha1[1] + subdir_buf[2] = '\0' + viperlib.snprintf(path_buf, path_len, "%s/%s/%s.text.ll", + self.TempDir, subdir_buf, sha1) + stdlib.free(subdir_buf) + tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R) + exists: int = 0 + if not tf.closed: + tf.close() + exists = 1 + stdlib.free(path_buf) + return exists + + # ============================================================ + # 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助 + # + # 元数据表由 HandlesClassDef 在类翻译/预注册阶段填充, + # 这里负责把 obj.prop / obj.prop=v / del obj.prop / Class.method() + # 翻译为对应的 {sha1}.ClassName.prop 系列函数调用。 + # ============================================================ + + # ============================================================ + # _translate_property_call — 翻译属性方法调用 + # + # 与 _translate_method_call 的调用名/返回类型解析逻辑一致: + # 1. 优先用模块中已有的函数(精确/后缀匹配,来自 stub 注入) + # 2. 否则用类所属模块的 SHA1 构造 "{sha1}.ClassName.method" 调用名 + # 3. 返回类型:函数实类型 → text.ll 查找 → 按方法名推断(默认 i32) + # + # call_head/call_count: 已构建好的参数链表(如 getter 只有 obj 一个参数) + # ============================================================ diff --git a/App/lib/core/Gen/CallGenCBuiltin.vp b/App/lib/core/Gen/CallGenCBuiltin.vp new file mode 100644 index 0000000..8ce1c4d --- /dev/null +++ b/App/lib/core/Gen/CallGenCBuiltin.vp @@ -0,0 +1,1370 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesFunctions as HandlesFunctions +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase + + +# ============================================================ +# CallGenCBuiltin - CallGenMixin 拆分 2/9:c.* 内建 + asm + llvmir +# +# 按功能域从 CallGenMixin.vp 拆出(500~1500 行/文件架构重构): +# translate_c_deref/derefas/set/addr/load + c.Asm 全套 + c.LLVMIR。 +# 继承 CallGenBase。 +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 +# ============================================================ + + +# ============================================================ +# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug) +# ============================================================ +GLOBAL_FUNC_MAX: t.CDefine = 8192 +GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 +_CEXPORT_MAX: t.CDefine = 256 +ASM_MAX_OPERANDS: t.CDefine = 16 +ASM_TEXT_BUF_SIZE: t.CDefine = 2048 +ASM_CONST_BUF_SIZE: t.CDefine = 512 +ASM_ARGS_BUF_SIZE: t.CDefine = 512 +ASM_LINE_BUF_SIZE: t.CDefine = 4096 +LLVMIR_MAX_OPS: t.CDefine = 16 +LLVMIR_TEMPLATE_BUF: t.CDefine = 512 +# 闭包名表大小(原 HandlesExprCall 模块级常量) +MAX_CLOSURE_NAMES: t.CDefine = 128 +# 函数指针签名表大小(原 HandlesExprCall 模块级常量) +MAX_FUNC_PTR_SIGS: t.CDefine = 64 +# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32) +ISINSTANCE_CLASS_MAX: t.CDefine = 64 + + +# ============================================================ +# CallGenCBuiltin - c.*/asm/llvmir 内建 +# ============================================================ +@t.NoVTable +class CallGenCBuiltin(CallGenBase.CallGenBase): + """c.* 内建 + 内联汇编 + LLVMIR 翻译(继承 Base)""" + + + def translate_c_deref(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.Deref(ptr) → load 按 ptr 的 pointee 类型""" + if cl is None: + return None + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or len(cargs) < 1: + return None + + ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cargs.get(0), None, 0, trans) + if ptr_val is None: + return None + + # 按 pointee 类型读取;非指针参数默认按 i8(保持向后兼容) + if HandlesExpr.is_ptr_type(ptr_val.Ty) != 0: + pointee: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee + if pointee is not None: + # i8*(void*)时按赋值目标类型推断读取宽度(对齐 TPC + # HandlesSpecialCall._infer_deref_target_type): + # v: int = c.Deref(p) → bitcast i32* 后 load 4 字节。 + # 背景:DictTest d3[key5]=500 读出 -12——固定按 i8 读 1 字节 + + # sext 截断(0xF4 → 0xFFFFFFF4);Test 1 的小值(10)恰好正确 + # 掩盖了缺陷。 + match pointee: + case llvmlite.LLVMType.Int(pointee_width): + # 仅当 c.Deref 是赋值语句的直接 RHS(如 v: int = c.Deref(p)) + # 时才用注解推断读取宽度(对齐 TPC _infer_deref_target_type + # 的直接 RHS 检查);嵌套在 while 条件/比较/binop/类型转换 + # 调用中(如 while c.Deref(p) != 0、total += t.CInt(c.Deref(p))) + # 不推断,否则 i8* 会被残留 CurAssignAnnot 误判为 i32* + # 读 4 字节 → StringIterTest ASCII sum/manual strcmp 失败。 + if pointee_width == 8 and trans is not None \ + and trans.CurAssignAnnot is not None \ + and trans.CurAssignNode is not None \ + and t.CUInt64T(cl) == t.CUInt64T(trans.CurAssignNode): + dref_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + trans.Pool, trans.CurAssignAnnot, + trans._imported_modules, trans._from_imports, trans) + if dref_ty is not None: + dref_bits: int = HandlesExpr.get_llvm_type_bits(dref_ty) + dref_fbits: int = HandlesExpr.get_llvm_float_bits(dref_ty) + # 仅整数/浮点目标(struct 值目标不推断,保持 i8 读) + dref_ptr: llvmlite.Value | t.CPtr = None + if (dref_bits != 0 or dref_fbits != 0) and dref_bits != 8: + dref_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, dref_ty) + dref_ptr = llvmlite.build_bitcast( + builder, ptr_val, dref_ptr_ty) + if dref_ptr is not None: + return llvmlite.build_load(builder, dref_ty, dref_ptr) + case _: + pass + return llvmlite.build_load(builder, pointee, ptr_val) + # 非指针参数即类型推断退化:fail-fast,绝不按 i8 兜底读取(会读到垃圾宽度) + HandlesType.fatal_error(cl, "c.Deref 参数不是指针类型(类型推断退化)", "TypeError") + return None + + + def translate_c_derefas(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.DerefAs(ptr, val) → store val to ptr(bitcast 后 store)""" + if cl is None: + return None + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or len(cargs) < 2: + return None + + ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cargs.get(0), None, 0, trans) + val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cargs.get(1), None, 0, trans) + if ptr_val is None or val is None: + return None + + # 两端均为指向同一结构体类型的指针时执行结构体拷贝(*ptr = *val), + # 而非存储指针值。这对 REnum 变体构造(c.DerefAs(ptr, LLVMType.Int(32)))至关重要: + # LLVMType.Int(32) 构造返回 alloca 指针(Ptr(LLVMType)),若直接 store 指针值, + # 只写入 8 字节指针(tag 字段仍是 0x0),导致运行时读 tag 错乱。 + # 对应 TPC HandlesExprCall.py:3696-3701 的 struct 拷贝逻辑。 + if HandlesExpr.is_ptr_type(ptr_val.Ty) != 0 and HandlesExpr.is_ptr_type(val.Ty) != 0: + ptr_pointee: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee + val_pointee: llvmlite.LLVMType | t.CPtr = val.Ty.Pointee + if ptr_pointee is not None and val_pointee is not None: + # ptr_pointee 是已注册结构体类型(用 find_struct_by_type 判断) + if HandlesStruct.find_struct_by_type(ptr_pointee) is not None: + if ptr_pointee is val_pointee: + # 同一结构体类型:load 值再 store(结构体拷贝) + loaded: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, val_pointee, val) + if loaded is not None: + # bitcast ptr 到结构体指针再 store + struct_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, ptr_pointee) + casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, ptr_val, struct_ptr_ty) + if casted_ptr is not None: + llvmlite.build_store(builder, loaded, casted_ptr) + return val + + # bitcast ptr 到 val.Ty* 再 store + val_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, val.Ty) + casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ptr_val, val_ptr_ty) + if casted_ptr is None: + return None + llvmlite.build_store(builder, val, casted_ptr) + return val + + + def translate_c_set(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.Set(a, b) → a = b(赋值语义,a 为左值)""" + if cl is None: + return None + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or len(cargs) < 2: + return None + a_node: ast.AST | t.CPtr = cargs.get(0) + b_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cargs.get(1), None, 0, trans) + if b_val is None: + return None + + # 形态 1: c.Set(c.Deref(ptr), b) → *ptr = b + if a_node is not None and a_node.kind() == ast.ASTKind.Call: + d_call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(a_node) + if d_call.func is not None and d_call.func.kind() == ast.ASTKind.Attribute: + d_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(d_call.func) + if d_at.attr is not None and string.strcmp(d_at.attr, "Deref") == 0: + d_args: list[ast.AST | t.CPtr] | t.CPtr = d_call.args + if d_args is not None and len(d_args) >= 1: + ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, d_args.get(0), None, 0, trans) + if ptr_val is not None: + val_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, b_val.Ty) + casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, ptr_val, val_ptr_ty) + if casted_ptr is not None: + llvmlite.build_store(builder, b_val, casted_ptr) + return b_val + # 其他 Call 形态不可作左值 + return b_val + + # 形态 2: Name 变量赋值 + if a_node is not None and a_node.kind() == ast.ASTKind.Name and trans is not None: + nm_set: ast.Name | t.CPtr = (ast.Name | t.CPtr)(a_node) + if nm_set.id is not None: + if HT.is_global_name(trans, nm_set.id) != 0: + mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( + trans.SymTab, nm_set.id) + if mod_alloca is not None: + tg_ty: llvmlite.LLVMType | t.CPtr = None + if mod_alloca.Ty is not None: + tg_ty = mod_alloca.Ty.Pointee + sv: llvmlite.Value | t.CPtr = b_val + if tg_ty is not None: + sv = HandlesExpr.coerce_to_type(builder, b_val, tg_ty, a_node) + llvmlite.build_store(builder, sv, mod_alloca) + return b_val + if HT.is_nonlocal_name(trans, nm_set.id) != 0: + nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr( + trans, nm_set.id) + if nl_ptr is not None: + nl_ty: llvmlite.LLVMType | t.CPtr = None + if nl_ptr.Ty is not None: + nl_ty = nl_ptr.Ty.Pointee + sv2: llvmlite.Value | t.CPtr = b_val + if nl_ty is not None: + sv2 = HandlesExpr.coerce_to_type(builder, b_val, nl_ty, a_node) + llvmlite.build_store(builder, sv2, nl_ptr) + return b_val + alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym( + trans.SymTab, pool, builder, nm_set.id, b_val.Ty) + if alloca is not None: + ac_ty: llvmlite.LLVMType | t.CPtr = None + if alloca.Ty is not None: + ac_ty = alloca.Ty.Pointee + sv3: llvmlite.Value | t.CPtr = b_val + if ac_ty is not None: + sv3 = HandlesExpr.coerce_to_type(builder, b_val, ac_ty, a_node) + llvmlite.build_store(builder, sv3, alloca) + return b_val + return b_val + + # 形态 3: Attribute 字段赋值 + if a_node is not None and a_node.kind() == ast.ASTKind.Attribute: + field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( + builder, pool, mod, a_node, trans) + if field_ptr is not None: + fd_ty: llvmlite.LLVMType | t.CPtr = None + if field_ptr.Ty is not None: + fd_ty = field_ptr.Ty.Pointee + sv4: llvmlite.Value | t.CPtr = b_val + if fd_ty is not None: + sv4 = HandlesExpr.coerce_to_type(builder, b_val, fd_ty, a_node) + llvmlite.build_store(builder, sv4, field_ptr) + return b_val + + return b_val + + + def translate_c_addr(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.Addr(var) → 返回变量的 alloca 指针(不 load)""" + if cl is None: + return None + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or len(cargs) < 1: + return None + + arg0: ast.AST | t.CPtr = cargs.get(0) + if arg0 is None: + return None + + # Name 形式: c.Addr(var) → 返回变量的 alloca 指针(不 load) + if arg0.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0) + if nm.id is None: + return None + if trans is not None: + # self/cls 对象引用:c.Addr(self) 返回对象指针本身(Ptr(Struct)), + # 而非指针变量的地址(Ptr(Ptr(Struct)))。方法与 Attribute 分支 + # (c.Addr(self.field) 先 load self)语义一致,供 + # return t.CVoid(c.Addr(self), CPtr) 返回 this 使用。 + if string.strcmp(nm.id, "self") == 0 or string.strcmp(nm.id, "cls") == 0: + self_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, nm.id) + if self_entry is not None and self_entry.Alloca is not None and self_entry.Alloca.Ty is not None: + match self_entry.Alloca.Ty: + case llvmlite.LLVMType.Ptr(inner1): + match inner1: + case llvmlite.LLVMType.Ptr(inner2): + obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, inner2) + return llvmlite.build_load(builder, obj_ty, self_entry.Alloca) + case _: + pass + case _: + pass + return_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) + if return_var is not None and return_var.Ty is not None: + # 对象指针变量(如 lit_tree = zhuff.zhuff_tree(),alloca 是 + # Ptr(Ptr(Struct)),存对象指针):c.Addr(对象变量) 应返回对象 + # 指针本身(load 一次),对齐 self/cls 分支与 c.Addr(self.field) + # (GEP 后对象地址)。此前直接返回 &变量(Ptr(Ptr(Struct)))→ + # 调用端 bitcast 成 Ptr(Struct) 后 ht 指向指针变量存储 → 字段 + # 读到指针值/垃圾 → build_decode_tree 越界崩溃 + # (zinflate inflate_block_fixed 的 c.Addr(lit_tree) 根因)。 + match return_var.Ty: + case llvmlite.LLVMType.Ptr(addr_inner1): + match addr_inner1: + case llvmlite.LLVMType.Ptr(addr_inner2): + match addr_inner2: + case llvmlite.LLVMType.Struct(_, _, _): + addr_obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, addr_inner2) + return llvmlite.build_load(builder, addr_obj_ty, return_var) + case _: + pass + case _: + pass + case _: + pass + return return_var + + # Attribute 形式: c.Addr(self.field) → 取字段地址(GEP 到字段,不 load) + # 用于 atom.__atomic_test_and_set(c.Addr(self.lock_val), ...) 等锁操作 + if arg0.kind() == ast.ASTKind.Attribute: + if trans is None: + return None + at_addr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg0) + if at_addr is None or at_addr.attr is None or at_addr.value is None: + return None + # 解析 self(Name)→ 查找 alloca + if at_addr.value.kind() != ast.ASTKind.Name: + return None + self_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_addr.value) + if self_nm.id is None: + return None + self_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, self_nm.id) + if self_alloca is None or self_alloca.Ty is None: + return None + # 从 self 类型提取结构体类型(Ptr(Struct) 或 Ptr(Ptr(Struct))) + struct_ty: llvmlite.LLVMType | t.CPtr = None + self_is_ptr_ptr: int = 0 + match self_alloca.Ty: + case llvmlite.LLVMType.Ptr(inner1): + match inner1: + case llvmlite.LLVMType.Ptr(inner2): + struct_ty = inner2 + self_is_ptr_ptr = 1 + case _: + struct_ty = inner1 + case _: + return None + # 查找字段 + fe_addr: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( + struct_ty, at_addr.attr) + if fe_addr is None: + return None + # self_alloca 是 Ptr(Ptr(Struct)) 时先 load 成 Ptr(Struct) 对象指针 + obj_ptr: llvmlite.Value | t.CPtr = self_alloca + if self_is_ptr_ptr == 1: + self_obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) + obj_ptr = llvmlite.build_load(builder, self_obj_ty, self_alloca) + if obj_ptr is None: + return None + # GEP 到字段地址 + return llvmlite.build_gep_struct( + builder, struct_ty, fe_addr.Ty, obj_ptr, fe_addr.Index) + + # Subscript 形式: c.Addr(arr[i]) → 数组元素地址(GEP 数组,不 load) + # 用于 self.root_directory = c.Addr(directories[directory_count]) 等。 + # 此前只支持 Name/Attribute,Subscript 落到函数末尾返回 None → + # 赋值右侧为 None(devfs.vp:159 根因)。 + if arg0.kind() == ast.ASTKind.Subscript: + if trans is None: + return None + sub_addr: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(arg0) + if sub_addr is None or sub_addr.value is None or sub_addr.slice is None: + return None + arr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, sub_addr.value, None, 0, trans) + if arr_val is None or arr_val.Ty is None: + return None + idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, sub_addr.slice, None, 0, trans) + if idx_val is None: + return None + # 数组基址 pointee 是 Array(elem_ty, N) → GEP 得元素指针 + arr_pointee_ca: llvmlite.LLVMType | t.CPtr = None + if HandlesExpr.is_ptr_type(arr_val.Ty) != 0: + arr_pointee_ca = arr_val.Ty.Pointee + if arr_pointee_ca is not None: + match arr_pointee_ca: + case llvmlite.LLVMType.Array(arr_et_ca, _): + return llvmlite.build_gep_array( + builder, arr_pointee_ca, arr_et_ca, arr_val, idx_val) + case _: + pass + return None + + + def translate_c_load(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.Load(a, b) → *a = *b(加载 b 的值,存储到 a)""" + if cl is None: + return None + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or len(cargs) < 2: + return None + + dst_ptr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cargs.get(0), None, 0, trans) + src_ptr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cargs.get(1), None, 0, trans) + if dst_ptr is None or src_ptr is None: + return None + + # 确定 pointee 类型(优先用 src 的 pointee,回退到 dst 的 pointee) + pointee: llvmlite.LLVMType | t.CPtr = None + if src_ptr.Ty is not None: + pointee = src_ptr.Ty.Pointee + if pointee is None and dst_ptr.Ty is not None: + pointee = dst_ptr.Ty.Pointee + if pointee is None: + return None + + # bitcast src 到 pointee* 并 load + target_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, pointee) + src_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, src_ptr, target_ptr_ty) + if src_cast is None: + return None + loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, pointee, src_cast) + if loaded is None: + return None + + # bitcast dst 到 pointee* 并 store + dst_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, dst_ptr, target_ptr_ty) + if dst_cast is None: + return None + llvmlite.build_store(builder, loaded, dst_cast) + return loaded + + + def _asm_append_cstr(self, dst: str, dst_size: t.CSizeT, + src: str): + """将 C 字符串 src 追加到 dst 末尾""" + if dst is None or src is None: + return + dlen: t.CSizeT = string.strlen(dst) + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: + return + i: t.CSizeT = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' + + + def _asm_escape_for_ir(self, pool: memhub.MemBuddy | t.CPtr, + src: str) -> str: + """转义汇编文本用于 LLVM IR 字符串字面量""" + if src is None: + return None + slen: t.CSizeT = string.strlen(src) + buf: str = pool.alloc(slen * 4 + 8) + if buf is None: + return None + pos: t.CSizeT = 0 + for ch in src: + if ch == '\n': + buf[pos] = '\\' + pos += 1 + buf[pos] = '0' + pos += 1 + buf[pos] = 'A' + pos += 1 + elif ch == '"': + buf[pos] = '\\' + pos += 1 + buf[pos] = '2' + pos += 1 + buf[pos] = '2' + pos += 1 + elif ch == '\\': + buf[pos] = '\\' + pos += 1 + buf[pos] = '5' + pos += 1 + buf[pos] = 'C' + pos += 1 + else: + buf[pos] = ch + pos += 1 + buf[pos] = '\0' + return buf + + + def _resolve_register(self, attr_name: str) -> str: + """将 t.ASM_DESCR.XXX 的属性名映射到约束字符串值""" + if attr_name is None: + return "" + + # Clobber 破坏描述符 + if string.strcmp(attr_name, "CLOBBER_MEMORY") == 0: return "memory" + if string.strcmp(attr_name, "CLOBBER_CC") == 0: return "cc" + if string.strcmp(attr_name, "CLOBBER_RAX") == 0: return "rax" + if string.strcmp(attr_name, "CLOBBER_RBX") == 0: return "rbx" + if string.strcmp(attr_name, "CLOBBER_RCX") == 0: return "rcx" + if string.strcmp(attr_name, "CLOBBER_RDX") == 0: return "rdx" + if string.strcmp(attr_name, "CLOBBER_RSI") == 0: return "rsi" + if string.strcmp(attr_name, "CLOBBER_RDI") == 0: return "rdi" + if string.strcmp(attr_name, "CLOBBER_RBP") == 0: return "rbp" + if string.strcmp(attr_name, "CLOBBER_RSP") == 0: return "rsp" + if string.strcmp(attr_name, "CLOBBER_R8") == 0: return "r8" + if string.strcmp(attr_name, "CLOBBER_R9") == 0: return "r9" + if string.strcmp(attr_name, "CLOBBER_R10") == 0: return "r10" + if string.strcmp(attr_name, "CLOBBER_R11") == 0: return "r11" + if string.strcmp(attr_name, "CLOBBER_R12") == 0: return "r12" + if string.strcmp(attr_name, "CLOBBER_R13") == 0: return "r13" + if string.strcmp(attr_name, "CLOBBER_R14") == 0: return "r14" + if string.strcmp(attr_name, "CLOBBER_R15") == 0: return "r15" + if string.strcmp(attr_name, "CLOBBER_EAX") == 0: return "eax" + if string.strcmp(attr_name, "CLOBBER_EBX") == 0: return "ebx" + if string.strcmp(attr_name, "CLOBBER_ECX") == 0: return "ecx" + if string.strcmp(attr_name, "CLOBBER_EDX") == 0: return "edx" + if string.strcmp(attr_name, "CLOBBER_ESI") == 0: return "esi" + if string.strcmp(attr_name, "CLOBBER_EDI") == 0: return "edi" + if string.strcmp(attr_name, "CLOBBER_DX") == 0: return "dx" + if string.strcmp(attr_name, "CLOBBER_AX") == 0: return "ax" + if string.strcmp(attr_name, "CLOBBER_CX") == 0: return "cx" + if string.strcmp(attr_name, "CLOBBER_SI") == 0: return "si" + if string.strcmp(attr_name, "CLOBBER_DI") == 0: return "di" + + # Output 输出约束 + if string.strcmp(attr_name, "OUTPUT_REG") == 0: return "=r" + if string.strcmp(attr_name, "OUTPUT_MEM") == 0: return "=m" + if string.strcmp(attr_name, "OUTPUT_EAX") == 0: return "=a" + if string.strcmp(attr_name, "OUTPUT_EBX") == 0: return "=b" + if string.strcmp(attr_name, "OUTPUT_ECX") == 0: return "=c" + if string.strcmp(attr_name, "OUTPUT_EDX") == 0: return "=d" + if string.strcmp(attr_name, "OUTPUT_ESI") == 0: return "=S" + if string.strcmp(attr_name, "OUTPUT_EDI") == 0: return "=D" + if string.strcmp(attr_name, "OUTPUT_RAX") == 0: return "=a" + if string.strcmp(attr_name, "OUTPUT_RBX") == 0: return "=b" + if string.strcmp(attr_name, "OUTPUT_RCX") == 0: return "=c" + if string.strcmp(attr_name, "OUTPUT_RDX") == 0: return "=d" + if string.strcmp(attr_name, "OUTPUT_RSI") == 0: return "=S" + if string.strcmp(attr_name, "OUTPUT_RDI") == 0: return "=D" + + # Input/Register 输入约束 + if string.strcmp(attr_name, "REG_ANY") == 0: return "r" + if string.strcmp(attr_name, "REG_EAX") == 0: return "a" + if string.strcmp(attr_name, "REG_EBX") == 0: return "b" + if string.strcmp(attr_name, "REG_ECX") == 0: return "c" + if string.strcmp(attr_name, "REG_EDX") == 0: return "d" + if string.strcmp(attr_name, "REG_ESI") == 0: return "S" + if string.strcmp(attr_name, "REG_EDI") == 0: return "D" + if string.strcmp(attr_name, "REG_RAX") == 0: return "a" + if string.strcmp(attr_name, "REG_RBX") == 0: return "b" + if string.strcmp(attr_name, "REG_RCX") == 0: return "c" + if string.strcmp(attr_name, "REG_RDX") == 0: return "d" + if string.strcmp(attr_name, "REG_RSI") == 0: return "S" + if string.strcmp(attr_name, "REG_RDI") == 0: return "D" + + if string.strcmp(attr_name, "INPUT_REG") == 0: return "r" + if string.strcmp(attr_name, "INPUT_MEM") == 0: return "m" + if string.strcmp(attr_name, "INPUT_EAX") == 0: return "a" + if string.strcmp(attr_name, "INPUT_EBX") == 0: return "b" + if string.strcmp(attr_name, "INPUT_ECX") == 0: return "c" + if string.strcmp(attr_name, "INPUT_EDX") == 0: return "d" + if string.strcmp(attr_name, "INPUT_ESI") == 0: return "S" + if string.strcmp(attr_name, "INPUT_EDI") == 0: return "D" + if string.strcmp(attr_name, "INPUT_RAX") == 0: return "a" + if string.strcmp(attr_name, "INPUT_RBX") == 0: return "b" + if string.strcmp(attr_name, "INPUT_RCX") == 0: return "c" + if string.strcmp(attr_name, "INPUT_RDX") == 0: return "d" + if string.strcmp(attr_name, "INPUT_RSI") == 0: return "S" + if string.strcmp(attr_name, "INPUT_RDI") == 0: return "D" + + return "" + + + def _resolve_asm_descr(self, pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr) -> str: + """递归解析约束表达式,返回约束字符串""" + if node is None: + return "" + + k: int = node.kind() + + # BinOp with BitOr: 拼接左右 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if bop.op == ast.OpKind.BitOr: + left_str: str = self._resolve_asm_descr(pool, bop.left) + right_str: str = self._resolve_asm_descr(pool, bop.right) + llen: t.CSizeT = string.strlen(left_str) + rlen: t.CSizeT = string.strlen(right_str) + buf: str = pool.alloc(llen + rlen + 1) + if buf is None: + return "" + string.strcpy(buf, left_str) + for i in range(rlen): + buf[llen + i] = right_str[i] + buf[llen + rlen] = '\0' + return buf + return "" + + # Attribute: t.ASM_DESCR.XXX 或 t.XXX + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + # t.ASM_DESCR.XXX + if at.value is not None and at.value.kind() == ast.ASTKind.Attribute: + inner: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value) + if inner.value is not None and inner.value.kind() == ast.ASTKind.Name: + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner.value) + if mod_nm.id is not None and string.strcmp(mod_nm.id, "t") == 0: + if inner.attr is not None and string.strcmp(inner.attr, "ASM_DESCR") == 0: + return self._resolve_register(at.attr) + # t.XXX 简化形式 + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + mod_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if mod_nm2.id is not None and string.strcmp(mod_nm2.id, "t") == 0: + return self._resolve_register(at.attr) + return "" + + # Constant: 字符串常量 + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn.const_kind == ast.CONST_STR: + return cn.str_val + return "" + + return "" + + + def _asm_get_operand(self, base: HandlesExprCall.AsmOperand | t.CPtr, + idx: int) -> HandlesExprCall.AsmOperand | t.CPtr: + """获取操作数数组中第 idx 个元素的指针""" + entry_size: t.CSizeT = HandlesExprCall.AsmOperand.__sizeof__() + entry_addr: t.CUInt64T = t.CUInt64T(base) + idx * entry_size + return (HandlesExprCall.AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + + + def _asm_is_c_call(self, node: ast.Call | t.CPtr) -> str: + """检查 Call 节点是否是 c.XXX 调用,返回属性名或 None""" + if node is None or node.func is None: + return None + if node.func.kind() != ast.ASTKind.Attribute: + return None + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node.func) + if at.value is None or at.value.kind() != ast.ASTKind.Name: + return None + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if mod_nm.id is None or string.strcmp(mod_nm.id, "c") != 0: + return None + return at.attr + + + def _asm_add_operand(self, operands: HandlesExprCall.AsmOperand | t.CPtr, + count: int, + val: llvmlite.Value | t.CPtr, + constraint: str, + is_output: int) -> int: + """添加操作数到数组,返回新计数(失败返回原计数) + + 去重:f-string 模板内嵌的 AsmOut/AsmInp 与 out=/inp= 声明指向 + 同一变量时会重复收集(如 vrandom.vp 的 c.Asm(f"...{AsmOut(v)}", + out=[AsmOut(v)])),同一 (Value, IsOutput) 只保留第一个, + 避免约束数多于 asm 返回元素数(llc: output constraints mismatch)。 + """ + if count >= ASM_MAX_OPERANDS: + return count + if val is not None: + for ei in range(count): + eop: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, ei) + if eop is not None and eop.Value == val and eop.IsOutput == is_output: + return count + op: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, count) + op.Value = val + op.Constraint = constraint + op.IsOutput = is_output + return count + 1 + + + def translate_c_asm(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译 c.Asm 内联汇编,返回结果 Value(无输出时返回 None)""" + if cl is None: + return None + + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or len(cargs) < 1: + return None + + # 分配操作数数组 + operand_size: t.CSizeT = HandlesExprCall.AsmOperand.__sizeof__() + operands: HandlesExprCall.AsmOperand | t.CPtr = pool.alloc(operand_size * ASM_MAX_OPERANDS) + if operands is None: + return None + string.memset(operands, 0, operand_size * ASM_MAX_OPERANDS) + + # 分配 clobber 名数组 + clobbers: str | t.CPtr = pool.alloc(8 * ASM_MAX_OPERANDS) + if clobbers is None: + return None + string.memset(clobbers, 0, 8 * ASM_MAX_OPERANDS) + + # 分配 asm 文本缓冲区 + asm_text: str = pool.alloc(ASM_TEXT_BUF_SIZE) + if asm_text is None: + return None + asm_text[0] = '\0' + + operand_count: int = 0 + clobber_count: int = 0 + fv_count: int = 0 + + # 分配 fv 索引数组(记录每个 FormattedValue 对应的操作数原始索引) + fv_orig_indices: int | t.CPtr = pool.alloc(4 * ASM_MAX_OPERANDS) + if fv_orig_indices is None: + return None + string.memset(fv_orig_indices, 0, 4 * ASM_MAX_OPERANDS) + + # ============================================================ + # 1. 解析汇编模板(JoinedStr 或 Constant)— 第一遍:收集操作数 + # 不生成 asm 文本(占位符 $N 需在重排后才能确定编号) + # ============================================================ + tmpl_node: ast.AST | t.CPtr = cargs.get(0) + if tmpl_node is not None: + tk: int = tmpl_node.kind() + + if tk == ast.ASTKind.JoinedStr: + js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node) + jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values + if jvalues is not None: + jvlen: t.CSizeT = len(jvalues) + for vi in range(jvlen): + part: ast.AST | t.CPtr = jvalues.get(vi) + if part is None: + continue + pk: int = part.kind() + + if pk == ast.ASTKind.FormattedValue: + fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part) + fexpr: ast.AST | t.CPtr = fv.value + if fexpr is None or fexpr.kind() != ast.ASTKind.Call: + continue + fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr) + attr_nm: str = self._asm_is_c_call(fcall) + if attr_nm is None: + continue + + is_out: int = 0 + if string.strcmp(attr_nm, "AsmOut") == 0: + is_out = 1 + elif string.strcmp(attr_nm, "AsmInp") == 0: + is_out = 0 + else: + continue + + fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args + if fargs is None or len(fargs) < 1: + continue + + val_node: ast.AST | t.CPtr = fargs.get(0) + cons_str: str = "" + if len(fargs) >= 2: + cons_str = self._resolve_asm_descr(pool, fargs.get(1)) + + if is_out != 0: + # 输出:获取变量 alloca + if val_node is None or val_node.kind() != ast.ASTKind.Name: + continue + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node) + if nm.id is None: + continue + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) + if alloca is None: + continue + operand_count = self._asm_add_operand( + operands, operand_count, alloca, cons_str, 1) + else: + # 输入:翻译值 + ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, val_node, None, 0, trans) + if ival is None: + continue + operand_count = self._asm_add_operand( + operands, operand_count, ival, cons_str, 0) + + # 记录 fv 的原始操作数索引 + if fv_count < ASM_MAX_OPERANDS: + fv_orig_indices[fv_count] = operand_count - 1 + fv_count += 1 + + # ============================================================ + # 2. 解析关键字参数 out=/inp=/op=/clobber= + # ============================================================ + keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords + if keywords is not None: + kwlen: t.CSizeT = len(keywords) + for ki in range(kwlen): + kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) + if kw is None or kw.arg is None or kw.value is None: + continue + kwk: int = kw.value.kind() + + if string.strcmp(kw.arg, "out") == 0: + # 输出操作数列表 + if kwk != ast.ASTKind.List: + continue + out_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) + out_elts: list[ast.AST | t.CPtr] | t.CPtr = out_lst.elts + if out_elts is None: + continue + oelen: t.CSizeT = len(out_elts) + for oi in range(oelen): + oelt: ast.AST | t.CPtr = out_elts.get(oi) + if oelt is None or oelt.kind() != ast.ASTKind.Call: + continue + ocall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(oelt) + oattr: str = self._asm_is_c_call(ocall) + if oattr is None or string.strcmp(oattr, "AsmOut") != 0: + continue + oargs: list[ast.AST | t.CPtr] | t.CPtr = ocall.args + if oargs is None or len(oargs) < 1: + continue + oval_node: ast.AST | t.CPtr = oargs.get(0) + ocons: str = "" + if len(oargs) >= 2: + ocons = self._resolve_asm_descr(pool, oargs.get(1)) + if oval_node is None or oval_node.kind() != ast.ASTKind.Name: + continue + onm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(oval_node) + if onm.id is None: + continue + oalloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, onm.id) + if oalloca is None: + continue + operand_count = self._asm_add_operand( + operands, operand_count, oalloca, ocons, 1) + + elif string.strcmp(kw.arg, "inp") == 0 or string.strcmp(kw.arg, "inputs") == 0: + # 输入操作数列表 + if kwk != ast.ASTKind.List: + continue + in_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) + in_elts: list[ast.AST | t.CPtr] | t.CPtr = in_lst.elts + if in_elts is None: + continue + ielen: t.CSizeT = len(in_elts) + for ii in range(ielen): + ielt: ast.AST | t.CPtr = in_elts.get(ii) + if ielt is None or ielt.kind() != ast.ASTKind.Call: + continue + icall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(ielt) + iattr: str = self._asm_is_c_call(icall) + if iattr is None or string.strcmp(iattr, "AsmInp") != 0: + continue + iargs: list[ast.AST | t.CPtr] | t.CPtr = icall.args + if iargs is None or len(iargs) < 1: + continue + ival_node: ast.AST | t.CPtr = iargs.get(0) + icons: str = "" + if len(iargs) >= 2: + icons = self._resolve_asm_descr(pool, iargs.get(1)) + ival2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, ival_node, None, 0, trans) + if ival2 is None: + continue + operand_count = self._asm_add_operand( + operands, operand_count, ival2, icons, 0) + + elif string.strcmp(kw.arg, "op") == 0 or string.strcmp(kw.arg, "clobber") == 0: + # 破坏列表 + if kwk != ast.ASTKind.List: + continue + cl_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) + cl_elts: list[ast.AST | t.CPtr] | t.CPtr = cl_lst.elts + if cl_elts is None: + continue + clen: t.CSizeT = len(cl_elts) + for ci in range(clen): + celt: ast.AST | t.CPtr = cl_elts.get(ci) + if celt is None: + continue + cstr: str = self._resolve_asm_descr(pool, celt) + if cstr is None or cstr[0] == '\0': + continue + if clobber_count < ASM_MAX_OPERANDS: + cl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8 + cl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(cl_addr, t.CPtr)) + cl_ptr[0] = cstr + clobber_count += 1 + + # ============================================================ + # 3. 解析第二个位置参数作为破坏列表 + # ============================================================ + if len(cargs) >= 2: + pos_node: ast.AST | t.CPtr = cargs.get(1) + if pos_node is not None and pos_node.kind() == ast.ASTKind.List: + pos_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(pos_node) + pos_elts: list[ast.AST | t.CPtr] | t.CPtr = pos_lst.elts + if pos_elts is not None: + plen: t.CSizeT = len(pos_elts) + for pi in range(plen): + pelt: ast.AST | t.CPtr = pos_elts.get(pi) + if pelt is None: + continue + pstr: str = self._resolve_asm_descr(pool, pelt) + if pstr is None or pstr[0] == '\0': + continue + if clobber_count < ASM_MAX_OPERANDS: + pcl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8 + pcl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(pcl_addr, t.CPtr)) + pcl_ptr[0] = pstr + clobber_count += 1 + + # ============================================================ + # 4. 统计输出/输入数量,确定返回类型 + # ============================================================ + output_count: int = 0 + input_count: int = 0 + first_output_idx: int = -1 + for oi2 in range(operand_count): + op2: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi2) + if op2.IsOutput != 0: + if first_output_idx < 0: + first_output_idx = oi2 + output_count += 1 + else: + input_count += 1 + + # 确定返回类型 + # 多输出(如 vrandom rdrand*_step 的 val+ok 两个 AsmOut)返回 + # 匿名 struct {ty1, ty2, ...},元素数 = 输出操作数(LLVM asm + # 要求输出约束数 = 返回 struct 元素数)。 + ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + if output_count > 0 and first_output_idx >= 0: + if output_count > 1: + out_pn_head: llvmlite.ParamNode | t.CPtr = None + out_pn_last: llvmlite.ParamNode | t.CPtr = None + out_pn_n: int = 0 + for oi5 in range(operand_count): + op5: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi5) + if op5 is None or op5.IsOutput == 0: + continue + if op5.Value is not None and op5.Value.Ty is not None \ + and op5.Value.Ty.Pointee is not None: + pn5: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node( + pool, op5.Value.Ty.Pointee) + if pn5 is not None: + if out_pn_head is None: + out_pn_head = pn5 + else: + out_pn_last.Next = pn5 + out_pn_last = pn5 + out_pn_n += 1 + if out_pn_head is not None and out_pn_n > 0: + ret_ty = llvmlite.Struct(pool, out_pn_head, out_pn_n, None) + else: + HandlesType.fatal_error( + cl, "c.Asm 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError") + ret_ty = llvmlite.Int32(pool) + else: + out_op: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, first_output_idx) + if out_op.Value is not None and out_op.Value.Ty is not None: + # alloca 的类型是指针,Pointee 是目标类型 + if out_op.Value.Ty.Pointee is not None: + ret_ty = out_op.Value.Ty.Pointee + else: + HandlesType.fatal_error( + cl, "c.Asm 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError") + ret_ty = llvmlite.Int32(pool) + + # 判断 void — 直接基于 output_count 判断,避免 match 类型匹配问题 + is_void: int = 1 + if output_count > 0: + is_void = 0 + + # ============================================================ + # 4.5 重排操作数:输出在前,输入在后(LLVM IR 要求) + # + # new_order[new_idx] = orig_idx — 新位置对应原索引 + # orig_to_new[orig_idx] = new_idx — 原索引映射到新位置(用于占位符编号) + # ============================================================ + new_order: int | t.CPtr = pool.alloc(4 * (operand_count + 1)) + orig_to_new: int | t.CPtr = pool.alloc(4 * (operand_count + 1)) + if new_order is None or orig_to_new is None: + return None + + new_idx: int = 0 + # 先放输出 + for oi3 in range(operand_count): + op3: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi3) + if op3.IsOutput != 0: + new_order[new_idx] = oi3 + new_idx += 1 + # 再放输入 + for oi4 in range(operand_count): + op4: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi4) + if op4.IsOutput == 0: + new_order[new_idx] = oi4 + new_idx += 1 + # 建立映射 orig -> new + for ni2 in range(operand_count): + orig_to_new[new_order[ni2]] = ni2 + + # ============================================================ + # 4.6 生成汇编文本(第二遍遍历 f-string,用重排后的索引生成占位符) + # 项目约定使用 Intel 语法,通过 IR 的 inteldialect 关键字启用 + # ============================================================ + if tmpl_node is not None: + tk2: int = tmpl_node.kind() + if tk2 == ast.ASTKind.JoinedStr: + js2: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node) + jvalues2: list[ast.AST | t.CPtr] | t.CPtr = js2.values + if jvalues2 is not None: + jvlen2: t.CSizeT = len(jvalues2) + fv_fi: int = 0 + for vi2 in range(jvlen2): + part2: ast.AST | t.CPtr = jvalues2.get(vi2) + if part2 is None: + continue + pk2: int = part2.kind() + if pk2 == ast.ASTKind.Constant: + cn3: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part2) + if cn3.const_kind == ast.CONST_STR and cn3.str_val is not None: + self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn3.str_val) + elif pk2 == ast.ASTKind.FormattedValue: + if fv_fi < fv_count: + orig_idx2: int = fv_orig_indices[fv_fi] + new_idx2: int = orig_to_new[orig_idx2] + ph_buf2: str = pool.alloc(16) + if ph_buf2 is not None: + viperlib.snprintf(ph_buf2, 16, "$%d", new_idx2) + self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, ph_buf2) + fv_fi += 1 + elif tk2 == ast.ASTKind.Constant: + cn4: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(tmpl_node) + if cn4.const_kind == ast.CONST_STR and cn4.str_val is not None: + self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn4.str_val) + + # ============================================================ + # 5. 构建约束字符串(按重排后的顺序:输出在前,输入在后) + # ============================================================ + const_buf: str = pool.alloc(ASM_CONST_BUF_SIZE) + if const_buf is None: + return None + const_buf[0] = '\0' + + first_const: int = 1 + for ci2 in range(operand_count): + orig_i: int = new_order[ci2] + cop: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, orig_i) + cons_val: str = cop.Constraint + if cons_val is None: + cons_val = "r" + + if first_const == 0: + self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",") + first_const = 0 + + if cop.IsOutput != 0: + # 输出约束:确保以 = 开头 + if cons_val[0] != '=': + self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "=") + self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val) + else: + self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val) + + # 追加 clobber 约束 ~{name} + for cidx in range(clobber_count): + cl_addr2: t.CUInt64T = t.CUInt64T(clobbers) + cidx * 8 + cname: str = (str | t.CPtr)(t.CVoid(cl_addr2, t.CPtr))[0] + if cname is None or cname[0] == '\0': + continue + if first_const == 0: + self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",") + first_const = 0 + self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "~{") + self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cname) + self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "}") + + # ============================================================ + # 6. 构建参数列表文本(仅输入操作数) + # ============================================================ + args_buf: str = pool.alloc(ASM_ARGS_BUF_SIZE) + if args_buf is None: + return None + args_buf[0] = '\0' + + first_arg: int = 1 + for ai3 in range(operand_count): + orig_i2: int = new_order[ai3] + aop: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, orig_i2) + if aop.IsOutput != 0: + continue + aval: llvmlite.Value | t.CPtr = aop.Value + if aval is None or aval.Ty is None or aval.Name is None: + continue + + if first_arg == 0: + self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ", ") + first_arg = 0 + + # 类型文本 + ty_buf: str = pool.alloc(64) + if ty_buf is not None: + ty_buf[0] = '\0' + llvmlite.TypePrint(ty_buf, 64, aval.Ty, pool) + self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ty_buf) + self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, " ") + self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, aval.Name) + + # ============================================================ + # 7. 转义汇编文本 + # ============================================================ + escaped_asm: str = self._asm_escape_for_ir(pool, asm_text) + if escaped_asm is None: + return None + + # ============================================================ + # 8. 生成 IR 行并发射 + # ============================================================ + line: str = pool.alloc(ASM_LINE_BUF_SIZE) + if line is None: + return None + line[0] = '\0' + + ssa_name: str = None + if is_void == 0: + ssa_name = pool.alloc(16) + if ssa_name is not None: + viperlib.snprintf(ssa_name, 16, "%%%d", builder.Counter) + builder.Counter += 1 + + # 获取返回类型文本 + ret_ty_buf: str = pool.alloc(64) + if ret_ty_buf is not None: + ret_ty_buf[0] = '\0' + llvmlite.TypePrint(ret_ty_buf, 64, ret_ty, pool) + + if is_void == 1: + viperlib.snprintf(line, ASM_LINE_BUF_SIZE, + "call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)", + ret_ty_buf, escaped_asm, const_buf, args_buf) + else: + viperlib.snprintf(line, ASM_LINE_BUF_SIZE, + "%s = call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)", + ssa_name, ret_ty_buf, escaped_asm, const_buf, args_buf) + + # 发射 IR 到当前块 + llvmlite.block_append_text(pool, builder.CurBlock, line) + + # ============================================================ + # 9. 处理输出:存储结果到输出变量 + # ============================================================ + if is_void == 0 and first_output_idx >= 0: + result_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, ret_ty, ssa_name) + out_emit_idx: int = 0 + for oi_out in range(operand_count): + orig_o: int = new_order[oi_out] + oo: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, orig_o) + if oo is None or oo.IsOutput == 0: + continue + if output_count > 1: + # 多输出:extractvalue 取第 out_emit_idx 个元素后 store + if oo.Value is not None and oo.Value.Ty is not None \ + and oo.Value.Ty.Pointee is not None: + ev_name: str = pool.alloc(32) + ev_line: str = pool.alloc(ASM_LINE_BUF_SIZE) + if ev_name is not None and ev_line is not None: + # ssa_name 形如 "%N"(纯数字 ID),构造唯一名 + # "%asm.N.e{i}"(字母开头,避免 %N.e{i} 被解析为 + # 数字 ID + 非法后缀导致 "expected '=' after id") + viperlib.snprintf(ev_name, 32, "%%asm.%s.e%d", ssa_name + 1, out_emit_idx) + viperlib.snprintf(ev_line, ASM_LINE_BUF_SIZE, + "%s = extractvalue %s %s, %d", + ev_name, ret_ty_buf, ssa_name, out_emit_idx) + llvmlite.block_append_text(pool, builder.CurBlock, ev_line) + ev_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, oo.Value.Ty.Pointee, ev_name) + llvmlite.build_store(builder, ev_val, oo.Value) + else: + if oo.Value is not None: + llvmlite.build_store(builder, result_val, oo.Value) + out_emit_idx += 1 + return result_val + + return None + + + def translate_c_llvmir(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.LLVMIR 内联 LLVM IR:无返回值,直接嵌入原始 IR 文本 + + 不做指令解析,模板文本(c.LInp/c.LOut 替换后)用 block_append_text + 嵌入当前基本块。c.LOut 变量由唯一 SSA 寄存器 %llvmirN 接收结果, + 嵌入后自动追加 store 写回变量 alloca。返回 None(无返回值)。 + """ + if cl is None or builder is None or pool is None or trans is None: + return None + + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or len(cargs) < 1: + HandlesType.fatal_error(cl, "c.LLVMIR 缺少模板参数", "TypeError") + + # LOut 写回记录(alloca 指针 + 寄存器名),最多 LLVMIR_MAX_OPS 个 + out_alloca: t.CSizeT | t.CPtr = pool.alloc(8 * LLVMIR_MAX_OPS) + out_regname: t.CSizeT | t.CPtr = pool.alloc(8 * LLVMIR_MAX_OPS) + if out_alloca is None or out_regname is None: + return None + string.memset(out_alloca, 0, 8 * LLVMIR_MAX_OPS) + string.memset(out_regname, 0, 8 * LLVMIR_MAX_OPS) + out_count: int = 0 + + # 模板文本缓冲区 + text: str = pool.alloc(LLVMIR_TEMPLATE_BUF) + if text is None: + return None + text[0] = '\0' + + # ============================================================ + # 1. 解析 IR 模板(JoinedStr 或 Constant)— 替换 LInp/LOut/表达式为值文本 + # ============================================================ + first_arg: ast.AST | t.CPtr = cargs.get(0) + if first_arg is None: + return None + + tk: int = first_arg.kind() + + if tk == ast.ASTKind.JoinedStr: + js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(first_arg) + jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values + if jvalues is not None: + jvlen: t.CSizeT = len(jvalues) + for vi in range(jvlen): + part: ast.AST | t.CPtr = jvalues.get(vi) + if part is None: + continue + pk: int = part.kind() + + if pk == ast.ASTKind.Constant: + # 字符串字面量片段 + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part) + if cn.str_val is not None: + self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, cn.str_val) + + elif pk == ast.ASTKind.FormattedValue: + fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part) + fexpr: ast.AST | t.CPtr = fv.value + if fexpr is None: + continue + # 检测 c.LInp / c.LOut + if fexpr.kind() == ast.ASTKind.Call: + fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr) + attr_nm: str = self._asm_is_c_call(fcall) + if attr_nm is not None: + fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args + if fargs is None or len(fargs) < 1: + continue + val_node: ast.AST | t.CPtr = fargs.get(0) + + if string.strcmp(attr_nm, "LInp") == 0: + # 输入操作数:翻译值,替换为 LLVM 值引用文本(%x 或常量文本) + inp_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, val_node, None, 0, trans) + if inp_val is not None and inp_val.Name is not None: + self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, inp_val.Name) + + elif string.strcmp(attr_nm, "LOut") == 0: + # 输出操作数:为变量分配唯一 SSA 寄存器 %llvmirN, + # 记录写回(模板嵌入后 store 到变量 alloca) + if val_node is not None and val_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node) + if nm.id is not None: + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, nm.id) + if alloca is None or out_count >= LLVMIR_MAX_OPS: + HandlesType.fatal_error( + fcall, + f"c.LOut 变量 '{nm.id}' 未定义或输出数超过 {LLVMIR_MAX_OPS}", + "TypeError") + self.LLVMIRRegSeq += 1 + reg_buf: str = pool.alloc(32) + if reg_buf is not None: + viperlib.snprintf(reg_buf, 32, "%%llvmir_%d", self.LLVMIRRegSeq) + self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, reg_buf) + out_alloca[out_count] = t.CSizeT(alloca) + out_regname[out_count] = t.CSizeT(reg_buf) + out_count += 1 + continue + # 非 c.LInp/c.LOut 的 f-string 表达式:翻译值并嵌入值文本 + ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, fexpr, None, 0, trans) + if ival is not None and ival.Name is not None: + self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, ival.Name) + + elif tk == ast.ASTKind.Constant: + cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(first_arg) + if cn2.str_val is not None: + # 裸 strcpy 无界:模板常量串 ≥ LLVMIR_TEMPLATE_BUF 会越界写 pool 块, + # 改用与 JoinedStr 分支一致的有界追加 + self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, cn2.str_val) + + # ============================================================ + # 2. 直接嵌入模板文本(不做指令解析)+ LOut 写回 + # ============================================================ + llvmlite.block_append_text(pool, builder.CurBlock, text) + + # LOut 写回: store %llvmirN, * %var + oi: int + for oi in range(out_count): + oa: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(t.CVoid(out_alloca[oi], t.CPtr)) + rn: str = (str)(t.CVoid(out_regname[oi], t.CPtr)) + if oa is None or oa.Ty is None or oa.Ty.Pointee is None or rn is None: + continue + reg_val: llvmlite.Value | t.CPtr = llvmlite.new_value(pool) + if reg_val is None: + continue + reg_val.Ty = oa.Ty.Pointee + reg_val.Name = rn + reg_val.IsConst = 0 + llvmlite.build_store(builder, reg_val, oa) + + return None + + # ============================================================ + # _apply_struct_defaults — 应用结构体字段的默认值 + # + # 在 zeroinitializer 之后、显式参数之前调用 + # 遍历所有字段,对有默认值的字段翻译并 store + # 显式参数(位置/关键字)后续会覆盖默认值 + # ============================================================ diff --git a/App/lib/core/Gen/CallGenLeafKit.vp b/App/lib/core/Gen/CallGenLeafKit.vp new file mode 100644 index 0000000..64fb670 --- /dev/null +++ b/App/lib/core/Gen/CallGenLeafKit.vp @@ -0,0 +1,1343 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesFunctions as HandlesFunctions +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenCBuiltin as CallGenCBuiltin + + +# ============================================================ +# CallGenLeafKit - CallGenMixin 拆分 3/9:EH/isinstance/闭包/print/函数表 +# +# 按功能域从 CallGenMixin.vp 拆出(500~1500 行/文件架构重构): +# EH 防护 + isinstance + 闭包/函数指针 + printf/print + 全局函数表/默认参数表。 +# 继承 CallGenCBuiltin。 +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 +# ============================================================ + + +# ============================================================ +# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug) +# ============================================================ +GLOBAL_FUNC_MAX: t.CDefine = 8192 +GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 +_CEXPORT_MAX: t.CDefine = 256 +ASM_MAX_OPERANDS: t.CDefine = 16 +ASM_TEXT_BUF_SIZE: t.CDefine = 2048 +ASM_CONST_BUF_SIZE: t.CDefine = 512 +ASM_ARGS_BUF_SIZE: t.CDefine = 512 +ASM_LINE_BUF_SIZE: t.CDefine = 4096 +LLVMIR_MAX_OPS: t.CDefine = 16 +LLVMIR_TEMPLATE_BUF: t.CDefine = 512 +# 闭包名表大小(原 HandlesExprCall 模块级常量) +MAX_CLOSURE_NAMES: t.CDefine = 128 +# 函数指针签名表大小(原 HandlesExprCall 模块级常量) +MAX_FUNC_PTR_SIGS: t.CDefine = 64 +# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32) +ISINSTANCE_CLASS_MAX: t.CDefine = 64 + + +# ============================================================ +# CallGenLeafKit - EH/isinstance/闭包/print/函数表 +# ============================================================ +@t.NoVTable +class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin): + """EH 防护 + isinstance + 闭包 + print + 全局函数表(继承 CBuiltin)""" + + + # ============================================================ + # _func_has_eh_params - 被调函数签名是否含 try-except EH 输出参数 + # + # EH 参数(%__eh_msg_out__/__eh_code_out__)由 translate_function_def/ + # _translate_method 在含 raise 的函数签名末尾注入(main 除外)。 + # ============================================================ + def _func_has_eh_params(self, func: llvmlite.Function | t.CPtr) -> int: + """返回 1=函数带 EH 输出参数 / 0=不带""" + if func is None: + return 0 + cur_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) + while cur_p is not None: + pn: str = llvmlite.param_get_name(cur_p) + if pn is not None and string.strcmp(pn, "%__eh_msg_out__") == 0: + return 1 + cur_p = llvmlite.param_get_next(cur_p) + return 0 + + # ============================================================ + # _emit_eh_guarded_call - 调用侧 try-except EH 检测(对齐 TPC + # HandlesExprCall._append_eh_msg_out_arg + _check_eh_return) + # + # 被调函数带 EH 输出参数时: + # 1. 确定 msg/code 输出指针: + # - 当前在 try(trans._eh_dispatch_bb 非空):复用 try 的 + # eh_message/exception_code alloca——被调函数直接写入,检查 + # 路径读同一 alloca 即得异常,无需搬运 + # - 当前函数有 EH 输出参数:复用本函数 out 参数(异常直接写进 + # 本函数输出,检查命中后仅返回,由调用方接管传播) + # - 两者皆无:局部 null alloca(异常被吞) + # 2. 调用前清零输出指针(复用 alloca 必须复位,防上次残留误判) + # 3. 追加 msg/code 两个实参(count+2) + # 4. 调用后检查 msg != null:命中 → err 块(try 内分支 DispatchBB; + # 否则仅返回默认值);未命中 → ok 块继续 + # ============================================================ + + # ============================================================ + # _emit_eh_guarded_call - 调用侧 try-except EH 检测(对齐 TPC + # HandlesExprCall._append_eh_msg_out_arg + _check_eh_return) + # + # 被调函数带 EH 输出参数时: + # 1. 确定 msg/code 输出指针: + # - 当前在 try(trans._eh_dispatch_bb 非空):复用 try 的 + # eh_message/exception_code alloca——被调函数直接写入,检查 + # 路径读同一 alloca 即得异常,无需搬运 + # - 当前函数有 EH 输出参数:复用本函数 out 参数(异常直接写进 + # 本函数输出,检查命中后仅返回,由调用方接管传播) + # - 两者皆无:局部 null alloca(异常被吞) + # 2. 调用前清零输出指针(复用 alloca 必须复位,防上次残留误判) + # 3. 追加 msg/code 两个实参(count+2) + # 4. 调用后检查 msg != null:命中 → err 块(try 内分支 DispatchBB; + # 否则仅返回默认值);未命中 → ok 块继续 + # ============================================================ + def _emit_eh_guarded_call(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + func: llvmlite.Function | t.CPtr, + call_name: str, + head: llvmlite.Value | t.CPtr, + count: int, + ret_ty: llvmlite.LLVMType | t.CPtr, + is_variadic: int) -> llvmlite.Value | t.CPtr: + """带 try-except EH 检测的函数调用,返回 call 结果(检查后位于 ok 块)""" + if trans is None or self._func_has_eh_params(func) == 0: + return llvmlite.build_call(builder, call_name, head, count, ret_ty, is_variadic) + # ---- 1. 确定输出指针 ---- + i8_ty_g: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty_g: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_g) + i32_ty_g: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if i8_ty_g is None or i8_ptr_ty_g is None or i32_ty_g is None: + return llvmlite.build_call(builder, call_name, head, count, ret_ty, is_variadic) + msg_ptr: llvmlite.Value | t.CPtr = None + code_ptr: llvmlite.Value | t.CPtr = None + if trans._eh_msg_ptr is not None and trans._eh_code_ptr is not None: + msg_ptr = trans._eh_msg_ptr + code_ptr = trans._eh_code_ptr + elif trans._cur_func_has_eh != 0 and trans._eh_msg_out_param is not None \ + and trans._eh_code_out_param is not None: + msg_ptr = trans._eh_msg_out_param + code_ptr = trans._eh_code_out_param + if msg_ptr is None: + msg_ptr = llvmlite.build_alloca(builder, i8_ptr_ty_g) + code_ptr = llvmlite.build_alloca(builder, i32_ty_g) + # ---- 2. 调用前清零 ---- + null_msg_g: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty_g, "null") + zero_code_g: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + if null_msg_g is not None: + llvmlite.build_store(builder, null_msg_g, msg_ptr) + if zero_code_g is not None: + llvmlite.build_store(builder, zero_code_g, code_ptr) + # ---- 3. 追加实参(链表末尾 + count+2)---- + msg_ptr.Next = code_ptr + code_ptr.Next = None + if head is None: + head = msg_ptr + else: + tail_g: llvmlite.Value | t.CPtr = head + while tail_g.Next is not None: + tail_g = tail_g.Next + tail_g.Next = msg_ptr + count = count + 2 + # ---- 4. 调用 + 检查 ---- + result: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, call_name, head, count, ret_ty, is_variadic) + cur_func_g: llvmlite.Function | t.CPtr = trans._cur_func + if cur_func_g is None or null_msg_g is None: + return result + msg_val_g: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty_g, msg_ptr) + if msg_val_g is None: + return result + is_err_g: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, msg_val_g, null_msg_g) + if is_err_g is None: + return result + lc_g: int = trans._label_counter + trans._label_counter = lc_g + 1 + bb_buf_g: str = pool.alloc(64) + if bb_buf_g is None: + return result + viperlib.snprintf(bb_buf_g, 64, "eh.err.%d", lc_g) + err_bb_g: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, cur_func_g, bb_buf_g) + viperlib.snprintf(bb_buf_g, 64, "eh.ok.%d", lc_g) + ok_bb_g: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, cur_func_g, bb_buf_g) + if err_bb_g is None or ok_bb_g is None: + return result + llvmlite.build_cond_br(builder, is_err_g, err_bb_g, ok_bb_g) + # err 块 + llvmlite.position_at_end(builder, err_bb_g) + if trans._eh_dispatch_bb is not None: + # try 内:异常已写入 try 的 alloca(code_ptr 即 try 的 alloca), + # 分支 DispatchBB 交给 except 链 + llvmlite.build_br(builder, trans._eh_dispatch_bb) + else: + # 非 try:异常已写入本函数 out 参数(复用)或局部 alloca(吞掉), + # 仅返回默认值,由调用方检测本函数 out 参数 + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + ret_ty_g2: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty( + cur_func_g) + if ret_ty_g2 is not None: + match ret_ty_g2: + case llvmlite.LLVMType.Void(): + llvmlite.build_ret_void(builder) + case llvmlite.LLVMType.Ptr(_pg): + nv_g: llvmlite.Value | t.CPtr = llvmlite.ConstNull( + pool, ret_ty_g2, "null") + if nv_g is not None: + llvmlite.build_ret(builder, nv_g) + case llvmlite.LLVMType.Float(_fg): + zf_g: llvmlite.Value | t.CPtr = llvmlite.ConstFloat( + pool, ret_ty_g2, 0.0) + if zf_g is not None: + llvmlite.build_ret(builder, zf_g) + case _: + zv_g: llvmlite.Value | t.CPtr = llvmlite.ConstZero( + pool, ret_ty_g2) + if zv_g is not None: + llvmlite.build_ret(builder, zv_g) + # ok 块:继续 + llvmlite.position_at_end(builder, ok_bb_g) + return result + + # ============================================================ + # isinstance - 运行时 vtable 子类集合比较(2026-08-10) + # + # CVTable 对象头部 vtable 指针唯一标识对象实际类。isinstance(obj, Cls) + # 语义 = Cls 是实际类的祖先(实际类 == Cls 或继承自 Cls)。运行时只能 + # 拿到实际类 vtable 地址,无法向上推导祖先链,因此在编译期沿 + # StructEntry.ParentNames 反向 BFS 枚举 Cls 的全部已知子类(含自身), + # 运行时比较 obj->vtable ∈ {Cls 子类 vtable 地址集合}。 + # NoVTable / 未知类回退编译时静态判断(obj 静态类型 MRO 判断)。 + # ============================================================ + + + # ============================================================ + # isinstance - 运行时 vtable 子类集合比较(2026-08-10) + # + # CVTable 对象头部 vtable 指针唯一标识对象实际类。isinstance(obj, Cls) + # 语义 = Cls 是实际类的祖先(实际类 == Cls 或继承自 Cls)。运行时只能 + # 拿到实际类 vtable 地址,无法向上推导祖先链,因此在编译期沿 + # StructEntry.ParentNames 反向 BFS 枚举 Cls 的全部已知子类(含自身), + # 运行时比较 obj->vtable ∈ {Cls 子类 vtable 地址集合}。 + # NoVTable / 未知类回退编译时静态判断(obj 静态类型 MRO 判断)。 + # ============================================================ + + def _translate_isinstance(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + obj_node: ast.AST | t.CPtr, + cls_node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """isinstance(obj, Cls):运行时 vtable 子类集合比较,返回 i1""" + if obj_node is None or cls_node is None: + # 参数缺失即调用错误:fail-fast,绝不返回 True 掩盖 + HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") + obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, obj_node, None, 0, trans) + if obj_val is None or obj_val.Ty is None: + # obj 类型推断失败:fail-fast,绝不返回 True 掩盖 + HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") + # 对象指针规整:二级指针(变量 alloca / 联合 Class|t.CPtr)先 load + obj_ptr: llvmlite.Value | t.CPtr = obj_val + match obj_val.Ty: + case llvmlite.LLVMType.Ptr(inner_ty): + match inner_ty: + case llvmlite.LLVMType.Ptr(_): + loaded: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, inner_ty, obj_val) + if loaded is not None: + obj_ptr = loaded + case _: + pass + obj_is_ptr: int = HandlesExpr.is_ptr_type(obj_ptr.Ty) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) + # 对象 vtable 指针惰性读取(首个 CVTable 类比较时执行一次) + vtable_ptr: llvmlite.Value | t.CPtr = None + vtable_ready: int = 0 + res: llvmlite.Value | t.CPtr = None + cls_names: t.CSizeT | t.CPtr = self._extract_isinstance_class_names(pool, cls_node) + if cls_names is None: + # 类名提取失败:fail-fast,绝不返回 True 掩盖 + HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") + ci: int = 0 + while cls_names[ci] != 0: + cn: str = (str | t.CPtr)(t.CVoid(cls_names[ci], t.CPtr)) + if cn is not None: + if HandlesStruct.is_novtable_by_name(cn) != 0 \ + or HandlesStruct.has_vtable_by_name(cn) == 0: + # NoVTable / 未知类 → 编译时静态判断(obj 静态类型 MRO) + st: int = self._isinstance_compile_time(pool, obj_ptr, cn) + c1: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 1, 1 if st > 0 else 0) + if res is None: + res = c1 + else: + res = llvmlite.build_or(builder, res, c1) + elif obj_is_ptr != 0: + # CVTable → 运行时 vtable 比较(读对象头部 vtable 指针) + if vtable_ready == 0: + vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, obj_ptr, i8_ptr_ptr_ty) + if vtable_slot is not None: + vtable_ptr = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot) + vtable_ready = 1 + if vtable_ptr is not None: + subs: t.CSizeT | t.CPtr = self._collect_subclass_vtable_classes(pool, cn) + if subs is not None: + k: int = 0 + while subs[k] != 0: + scn: str = (str | t.CPtr)(t.CVoid(subs[k], t.CPtr)) + if scn is not None: + sub_i8: llvmlite.Value | t.CPtr = self._make_vtable_ref_i8( + pool, builder, mod, scn, trans) + if sub_i8 is not None: + cmp: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_EQ, vtable_ptr, sub_i8) + if cmp is not None: + if res is None: + res = cmp + else: + res = llvmlite.build_or(builder, res, cmp) + k += 1 + ci += 1 + if res is None: + # 未产生任何比较结果(obj 非指针且类全部为 CVTable):推断失败,fail-fast + HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") + return res + + + def _extract_isinstance_class_names(self, pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr) -> t.CSizeT | t.CPtr: + """从 isinstance 第二参数提取类名数组(Name→id / Attribute→attr / Tuple→遍历)""" + arr: t.CSizeT | t.CPtr = pool.alloc(8 * 16) + if arr is None: + return None + # 全数组清零:pool 分配内存非零时,未初始化槽位会被 while cls_names[ci]!=0 + # 误当类名指针解引用 → 段错误 + string.memset(arr, 0, 8 * 16) + arr[0] = 0 + if node is None: + return arr + count: int = 0 + k: int = node.kind() + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is not None: + arr[0] = t.CSizeT(nm.id) + elif k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.attr is not None: + arr[0] = t.CSizeT(at.attr) + elif k == ast.ASTKind.Tuple: + tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node) + elts: list[ast.AST | t.CPtr] | t.CPtr = tp.elts + if elts is not None: + n: t.CSizeT = len(elts) + for i in range(n): + if count >= 15: + break + elt: ast.AST | t.CPtr = elts.get(i) + if elt is None: + continue + ek: int = elt.kind() + if ek == ast.ASTKind.Name: + enm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(elt) + if enm.id is not None: + arr[count] = t.CSizeT(enm.id) + count += 1 + elif ek == ast.ASTKind.Attribute: + eat: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(elt) + if eat.attr is not None: + arr[count] = t.CSizeT(eat.attr) + count += 1 + arr[count] = 0 + return arr + + + def _collect_subclass_vtable_classes(self, pool: memhub.MemBuddy | t.CPtr, + class_name: str) -> t.CSizeT | t.CPtr: + """反向 BFS 收集目标类及全部子类(含自身,仅 HasVTable==1),返回 0 结尾数组""" + if class_name is None: + return None + names: t.CSizeT | t.CPtr = pool.alloc(8 * (ISINSTANCE_CLASS_MAX + 1)) + queue: t.CSizeT | t.CPtr = pool.alloc(8 * ISINSTANCE_CLASS_MAX) + visited: t.CSizeT | t.CPtr = pool.alloc(8 * ISINSTANCE_CLASS_MAX) + if names is None or queue is None or visited is None: + return None + string.memset(names, 0, 8 * (ISINSTANCE_CLASS_MAX + 1)) + string.memset(queue, 0, 8 * ISINSTANCE_CLASS_MAX) + string.memset(visited, 0, 8 * ISINSTANCE_CLASS_MAX) + qcount: int = 0 + outcount: int = 0 + vcount: int = 0 + queue[0] = t.CSizeT(class_name) + qcount = 1 + while qcount > 0: + qcount -= 1 + cur_addr: t.CSizeT = queue[qcount] + cur: str = (str | t.CPtr)(t.CVoid(cur_addr, t.CPtr)) + if cur is None: + continue + dup: int = 0 + for vi in range(vcount): + va: t.CSizeT = visited[vi] + if va != 0: + vn: str = (str | t.CPtr)(t.CVoid(va, t.CPtr)) + if vn is not None and string.strcmp(vn, cur) == 0: + dup = 1 + break + if dup != 0: + continue + if vcount < ISINSTANCE_CLASS_MAX: + visited[vcount] = t.CSizeT(cur) + vcount += 1 + centry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(cur) + if centry is not None and centry.HasVTable != 0: + if outcount < ISINSTANCE_CLASS_MAX: + names[outcount] = t.CSizeT(cur) + outcount += 1 + # 子类入队:遍历全部已注册 struct,ParentNames 含 cur 者 + scnt: int = HandlesStruct.get_struct_count() + for i in range(scnt): + e2: HandlesStruct.StructEntry | t.CPtr = HandlesStruct._get_struct_entry(i) + if e2 is None or e2.Name is None: + continue + if e2.ParentCount > 0 and e2.ParentNames is not None: + parr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(e2.ParentNames, t.CPtr)) + for j in range(e2.ParentCount): + pa: t.CSizeT = parr[j] + if pa != 0: + pn: str = (str | t.CPtr)(t.CVoid(pa, t.CPtr)) + if pn is not None and string.strcmp(pn, cur) == 0: + if qcount < ISINSTANCE_CLASS_MAX: + queue[qcount] = t.CSizeT(e2.Name) + qcount += 1 + break + names[outcount] = 0 + return names + + + def _make_vtable_ref_i8(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """构造类 vtable 地址引用(i8*):本模块已定义直接引用,跨模块声明 external""" + if class_name is None: + return None + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + buf: str = pool.alloc(256) + if buf is None: + return None + viperlib.snprintf(buf, 256, "%s.vtable", class_name) + vn: str = (str | t.CPtr)(buf) + sha1: str = HandlesStruct.get_struct_sha1(class_name) + if sha1 is None: + if trans is None: + return None + sha1 = trans.ModuleSha1 + if sha1 is None: + return None + mangled: str = HandlesFunctions._mangle_name_with_sha1(sha1, vn) + ref_name: str = pool.alloc(256) + if ref_name is None: + return None + # vtable 名含 sha1 点号前缀,一律 @"..." 引号形式 + viperlib.snprintf(ref_name, 256, "@\"%s\"", mangled) + gv: llvmlite.GlobalVariable | t.CPtr = HandlesExpr.find_global_in_module(mod, mangled) + ref_ty: llvmlite.LLVMType | t.CPtr = None + if gv is not None: + # 本模块已定义 vtable(constant {i8* x N})→ 引用类型 Ptr(struct) + ref_ty = llvmlite.Ptr(pool, gv.Ty) + else: + # 跨模块:声明 @mangled = external global i8*,引用类型 i8** + gv2: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable( + pool, mangled, i8_ptr_ty) + if gv2 is None: + return None + llvmlite.module_add_global(mod, gv2) + ref_ty = llvmlite.Ptr(pool, i8_ptr_ty) + ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, ref_ty, ref_name) + if ref is None: + return None + return llvmlite.build_bitcast(builder, ref, i8_ptr_ty) + + + def _isinstance_compile_time(self, pool: memhub.MemBuddy | t.CPtr, + obj_ptr: llvmlite.Value | t.CPtr, + class_name: str) -> int: + """编译时静态判断:obj 静态类型 == class_name 或 class_name 在其 MRO 中""" + if obj_ptr is None or obj_ptr.Ty is None or class_name is None: + return 0 + match obj_ptr.Ty: + case llvmlite.LLVMType.Ptr(obj_struct_ty): + sname: str = HandlesStruct.get_class_name_by_type(pool, obj_struct_ty) + if sname is not None: + if string.strcmp(sname, class_name) == 0: + return 1 + mro: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, sname) + if mro is not None: + k: int = 0 + while mro[k] != 0: + mn: str = (str | t.CPtr)(t.CVoid(mro[k], t.CPtr)) + if mn is not None and string.strcmp(mn, class_name) == 0: + return 1 + k += 1 + case _: + pass + return 0 + + # ============================================================ + # P4 簇 5+6 迁移方法(函数体来自 HandlesExprCall.vp: + # 闭包调用/函数指针/printf/print/stdarg 糖/变长参数提升/函数表/全局注册表) + # 本模块函数调用改 self.,外部模块调用保留模块前缀,全局变量改 self 字段 + # ============================================================ + + + # ============================================================ + # P4 簇 5+6 迁移方法(函数体来自 HandlesExprCall.vp: + # 闭包调用/函数指针/printf/print/stdarg 糖/变长参数提升/函数表/全局注册表) + # 本模块函数调用改 self.,外部模块调用保留模块前缀,全局变量改 self 字段 + # ============================================================ + + def translate_closure_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + closure_alloca: llvmlite.Value | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """通过闭包指针间接调用(支持带参 lambda:i32(i8*, args...))""" + if builder is None or closure_alloca is None: + return None + + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 1. 加载闭包指针 (i8*) + closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, closure_alloca) + if closure_ptr is None: + return None + + # 2. 加载 fn_ptr (offset 0): bitcast to i8**, load i8* + fn_ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty)) + if fn_ptr_addr is None: + return None + fn_raw: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, fn_ptr_addr) + if fn_raw is None: + return None + + # 3. 加载 env_ptr (offset 8): GEP i8, closure, 8; load i8* + eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8) + env_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, closure_ptr, eight_val) + if env_addr is None: + return None + env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_addr) + if env_ptr is None: + return None + + # 4. 构建参数:env 头 + 实参尾(带参 lambda 时翻译实参) + total_args: int = 1 + arg_head: llvmlite.Value | t.CPtr = env_ptr + arg_tail: llvmlite.Value | t.CPtr = env_ptr + param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) + pn_tail: llvmlite.ParamNode | t.CPtr = param_node + if can > 0 and cargs is not None and trans is not None: + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None or arg_val.Ty is None: + continue + arg_val.Next = None + if arg_tail is not None: + arg_tail.Next = arg_val + arg_tail = arg_val + pn_new: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, arg_val.Ty) + if pn_new is not None: + pn_tail.Next = pn_new + pn_tail = pn_new + total_args += 1 + if total_args == 1: + env_ptr.Next = None + + # 5. bitcast fn_raw 到函数指针类型 i32(i8*, [args...])* + func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, param_node, total_args) + func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty) + fn_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, fn_raw, func_ptr_ty) + if fn_typed is None: + return None + + # 6. 间接调用: call i32 %fn_typed(env, args...) + return llvmlite.build_call_indirect(builder, fn_typed, arg_head, total_args, i32_ty) + + + def _is_func_ptr_alloca(self, alloca: llvmlite.Value | t.CPtr) -> int: + """判断 alloca 是否为函数指针变量(类型 Ptr(Ptr(i8))),1=是 / 0=否""" + if alloca is None or alloca.Ty is None: + return 0 + if HandlesExpr.is_ptr_type(alloca.Ty) == 0: + return 0 + pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if pointee is None or HandlesExpr.is_ptr_type(pointee) == 0: + return 0 + inner: llvmlite.LLVMType | t.CPtr = pointee.Pointee + if inner is None or HandlesExpr.is_ptr_type(inner) != 0: + return 0 + return 1 + + + def _ensure_closure_names(self) -> int: + """确保闭包名表已分配,0 失败""" + if self.ClosureNames is not None: + return 1 + self.ClosureNames = CompilerFactory.get_perm_pool().alloc(64 * MAX_CLOSURE_NAMES) + if self.ClosureNames is None: + return 0 + string.memset(self.ClosureNames, 0, 64 * MAX_CLOSURE_NAMES) + return 1 + + + def register_closure_name(self, name: str) -> int: + """注册嵌套函数(闭包变量)名,0 成功""" + if name is None: + return 1 + if self._ensure_closure_names() == 0: + return 1 + if self.ClosureCount >= MAX_CLOSURE_NAMES: + return 1 + idx: t.CSizeT = t.CSizeT(self.ClosureCount) * 64 + string.strncpy(self.ClosureNames + idx, name, 63) + self.ClosureCount += 1 + return 0 + + + def is_closure_name(self, name: str) -> int: + """检查 name 是否已注册为闭包变量名,1=是 / 0=否""" + if name is None or self.ClosureNames is None: + return 0 + i: t.CSizeT + for i in range(self.ClosureCount): + if string.strcmp(self.ClosureNames + i * 64, name) == 0: + return 1 + return 0 + + + def _ensure_funcptr_sigs(self) -> int: + """确保函数指针签名表已分配(stdlib.malloc,懒初始化)""" + if self.FuncptrNames is not None: + return 1 + self.FuncptrNames = CompilerFactory.get_perm_pool().alloc(64 * MAX_FUNC_PTR_SIGS) + self.FuncptrRets = CompilerFactory.get_perm_pool().alloc(8 * MAX_FUNC_PTR_SIGS) + if self.FuncptrNames is None or self.FuncptrRets is None: + return 0 + string.memset(self.FuncptrNames, 0, 64 * MAX_FUNC_PTR_SIGS) + return 1 + + + def register_func_ptr_sig(self, name: str, + ret_ty: llvmlite.LLVMType | t.CPtr) -> int: + """注册函数指针变量的返回类型签名,0 成功""" + if name is None or ret_ty is None: + return 1 + if self._ensure_funcptr_sigs() == 0: + return 1 + if self.FuncptrCount >= MAX_FUNC_PTR_SIGS: + return 1 + idx: t.CSizeT = t.CSizeT(self.FuncptrCount) * 64 + # 槽位定长 64 字节,与 register_closure_name 一致用 strncpy 钳制防越界 + string.strncpy(self.FuncptrNames + idx, name, 63) + # ret_ty 是调用方 pool 分配的裸 LLVMType,1a 每文件 reset 后悬空; + # 深拷贝到 perm_pool(lookup_func_ptr_ret 跨文件读取) + ret_copy_fp: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( + CompilerFactory.get_perm_pool(), ret_ty) + if ret_copy_fp is not None: + self.FuncptrRets[self.FuncptrCount] = t.CUInt64T(ret_copy_fp) + else: + self.FuncptrRets[self.FuncptrCount] = t.CUInt64T(ret_ty) + self.FuncptrCount += 1 + return 0 + + + def lookup_func_ptr_ret(self, name: str) -> llvmlite.LLVMType | t.CPtr: + """查函数指针变量的返回类型,None=未注册(调用时默认 i32)""" + if name is None or self.FuncptrNames is None: + return None + for i in range(self.FuncptrCount): + idx: t.CSizeT = t.CSizeT(i) * 64 + if string.strcmp(self.FuncptrNames + idx, name) == 0: + return (llvmlite.LLVMType | t.CPtr)( + t.CVoid(self.FuncptrRets[i], t.CPtr)) + return None + + + def _translate_func_ptr_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + fp_alloca: llvmlite.Value | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """函数指针变量间接调用,返回结果 Value""" + if builder is None or fp_alloca is None: + return None + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 1. load 函数地址 (i8*) + fn_i8: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, fp_alloca) + if fn_i8 is None: + return None + + # 2. 翻译实参并链接为 Value 链表 + head: llvmlite.Value | t.CPtr = None + tail: llvmlite.Value | t.CPtr = None + arg_count: int = 0 + ai: t.CSizeT + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is not None: + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is not None: + arg_val.Next = None + if head is None: + head = arg_val + else: + tail.Next = arg_val + tail = arg_val + arg_count += 1 + + # 3. 按实参类型 + 注册的返回类型构造签名(未注册即 t.Callable 注解缺失,fail-fast) + ret_ty: llvmlite.LLVMType | t.CPtr = self.lookup_func_ptr_ret(func_name) + if ret_ty is None: + HandlesType.fatal_error( + None, + f"函数指针变量 '{func_name}' 的返回类型未注册(t.Callable 注解缺失)", + "TypeError") + ret_ty = i32_ty + fp_first: llvmlite.ParamNode | t.CPtr = None + fp_prev: llvmlite.ParamNode | t.CPtr = None + cur_v: llvmlite.Value | t.CPtr = head + for pi in range(arg_count): + if cur_v is None: + break + cur_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(cur_v) + pn2: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, cur_ty) + if pn2 is not None: + if fp_first is None: + fp_first = pn2 + if fp_prev is not None: + llvmlite.paramnode_set_next(fp_prev, pn2) + fp_prev = pn2 + cur_v = llvmlite.value_get_next(cur_v) + + func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, ret_ty, fp_first, arg_count) + if func_ty is None: + return None + func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty) + + # 4. bitcast i8* → 函数指针类型,间接调用 + fn_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, fn_i8, func_ptr_ty) + if fn_typed is None: + return None + return llvmlite.build_call_indirect(builder, fn_typed, head, arg_count, ret_ty) + + + def translate_printf_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None): + """翻译 printf 调用(特殊处理格式字符串)""" + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None: + return + can: t.CSizeT = len(cargs) + if can == 0: + return + + arg0: ast.AST | t.CPtr = cargs.get(0) + if arg0 is None: + return + + fmt_str: str = None + arg0_kind: int = arg0.kind() + if arg0_kind == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg0) + if cn.const_kind == ast.CONST_STR: + fmt_str = cn.str_val + + if fmt_str is None: + return + + fmt_ptr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string( + builder, pool, mod, fmt_str, trans) + if fmt_ptr is None: + return + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 翻译额外参数并链接 + prev: llvmlite.Value | t.CPtr = fmt_ptr + for ai in range(1, can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is not None: + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is not None: + # C ABI integer promotion: i8/i16 → i32(printf 变参函数要求) + arg_bits: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty) + if arg_bits != 0 and arg_bits < 32: + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, i32_ty, arg) + # C ABI float promotion: float → double(printf 变参函数要求) + arg_fbits: int = HandlesExpr.get_llvm_float_bits(arg_val.Ty) + if arg_fbits != 0 and arg_fbits < 64: + double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, double_ty, arg) + arg_val.Next = None + prev.Next = arg_val + prev = arg_val + prev.Next = None + + # is_variadic=1: 生成带显式函数类型签名的 call(如 call i32 (i8*, ...) @printf), + # 让 llc 识别为 variadic 调用,生成正确的 Win64 ABI 代码(浮点参数同时传 XMM 和整数寄存器) + llvmlite.build_call(builder, "printf", fmt_ptr, can, i32_ty, 1) + + + def translate_print_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None): + """翻译 print 调用(类型感知格式化 + 默认换行)""" + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None: + return + + FMT_BUF_SIZE: t.CSizeT = 256 + fmt_buf: bytes = stdlib.malloc(FMT_BUF_SIZE) + if fmt_buf is None: + return + fmt_buf[0] = '\0' + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + dbl_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) + + can: t.CSizeT = len(cargs) + arg_head: llvmlite.Value | t.CPtr = None + arg_tail: llvmlite.Value | t.CPtr = None + arg_count: int = 1 # 格式串本身是第 1 个 printf 参数 + + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None or arg_val.Ty is None: + # fail-fast:print 参数翻译失败必须终止编译,绝不在格式串写 + # 误导为数据问题而非编译器 bug。 + fb_pp: str = VLogger.fmt_buf() + if fb_pp is not None: + viperlib.snprintf(fb_pp, 1024, "print 参数翻译失败(表达式返回 None): [arg=%d]", ai) + VLogger.error(fb_pp, "PRINT") + HandlesType.fatal_error(arg, "print 参数翻译失败(表达式返回 None)", "TypeError") + return + + # 数组名(如 print(l),l: t.CArray[t.CChar, N]): + # translate_value 会 load 出数组值([N x T]),print 无法格式化; + # 按数组退化语义取数组 alloca 地址——字符数组 → %s(打印字符串内容), + # 其他元素类型 → 0x%llx(打印数组地址)。 + array_ptr: llvmlite.Value | t.CPtr = None + array_elem_bits: int = 0 + if arg.kind() == ast.ASTKind.Name and trans is not None: + anm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg) + if anm.id is not None: + arr_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, anm.id) + if arr_alloca is not None and arr_alloca.Ty is not None \ + and HandlesExpr.is_ptr_type(arr_alloca.Ty) != 0: + arr_pointee: llvmlite.LLVMType | t.CPtr = arr_alloca.Ty.Pointee + if arr_pointee is not None: + match arr_pointee: + case llvmlite.LLVMType.Array(arr_et, arr_n): + array_ptr = arr_alloca + array_elem_bits = HandlesExpr.get_llvm_type_bits(arr_et) + case _: + pass + + token: str = None + chain_arg: int = 1 # 1=该 token 消耗一个参数,0=纯文本 + arg_bits: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty) + arg_fbits: int = HandlesExpr.get_llvm_float_bits(arg_val.Ty) + + if array_ptr is not None: + # 数组退化:字符数组 → %s(bitcast [N x i8]* 到 i8*);其他 → 0x%llx + if array_elem_bits == 8: + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + token = "%s" + arg_val = llvmlite.build_bitcast(builder, array_ptr, i8_ptr_ty) + else: + token = "0x%llx" + arg_val = llvmlite.build_ptrtoint(builder, array_ptr, i64_ty) + elif HandlesExpr.is_ptr_type(arg_val.Ty) != 0: + # i8*(str/bytes)→ %s;其他指针 → 0x%llx + pointee: llvmlite.LLVMType | t.CPtr = arg_val.Ty.Pointee + if pointee is not None and HandlesExpr.get_llvm_type_bits(pointee) == 8: + token = "%s" + else: + token = "0x%llx" + arg_val = llvmlite.build_ptrtoint(builder, arg_val, i64_ty) + elif arg_bits != 0: + if arg_bits == 1: + token = "%d" + arg_val = llvmlite.build_zext(builder, arg_val, i32_ty) + elif arg_bits == 8: + token = "%d" + arg_val = llvmlite.build_sext(builder, arg_val, i32_ty) + elif arg_bits == 16: + token = "%d" + arg_val = llvmlite.build_sext(builder, arg_val, i32_ty) + elif arg_bits == 32: + token = "%d" + else: + token = "%lld" + elif arg_fbits != 0: + token = "%f" + if arg_fbits < 64: + arg_val = llvmlite.build_fpext(builder, arg_val, dbl_ty) + else: + # 结构体值/数组/函数等 → "(unknown)",不传参 + token = "(unknown)" + chain_arg = 0 + + # 追加格式 token + if string.strlen(fmt_buf) < FMT_BUF_SIZE - 16: + viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 16, "%s", token) + # 链接参数 + if chain_arg != 0: + arg_val.Next = None + if arg_tail is None: + arg_head = arg_val + else: + arg_tail.Next = arg_val + arg_tail = arg_val + arg_count += 1 + + # 追加默认换行(Python print 默认 end="\n") + if string.strlen(fmt_buf) < FMT_BUF_SIZE - 2: + viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 2, "\n") + + fmt_ptr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string( + builder, pool, mod, fmt_buf, trans) + stdlib.free(fmt_buf) + if fmt_ptr is None: + return + fmt_ptr.Next = arg_head + # is_variadic=1: 带显式函数类型签名(C ABI 变参调用) + llvmlite.build_call(builder, "printf", fmt_ptr, arg_count, i32_ty, 1) + + + def init_func_table(self, pool: memhub.MemBuddy | t.CPtr, + max_count: int) -> HandlesExprCall.FuncEntry | t.CPtr: + """分配并清零函数表数组""" + size: t.CSizeT = max_count * HandlesExprCall.FuncEntry.__sizeof__() + funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = pool.alloc(size) + if funcs_ptr is not None: + string.memset(funcs_ptr, 0, size) + return funcs_ptr + + + def find_func_in_table(self, funcs: HandlesExprCall.FuncEntry | t.CPtr, + func_count: int, + name: str) -> llvmlite.Function | t.CPtr: + """在函数表中按名称查找,返回 Function 指针或 None""" + if name is None or funcs is None: + return None + entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__() + for i in range(func_count): + entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size + entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + return entry.Func + return None + + + def add_func_to_table(self, funcs: HandlesExprCall.FuncEntry | t.CPtr, + func_count: int, + name: str, + func: llvmlite.Function | t.CPtr, + max_count: int, + defaults: t.CVoid | t.CPtr = None, + default_count: int = 0, + param_count: int = 0, + pool: memhub.MemBuddy | t.CPtr = None) -> int: + """添加函数到函数表,返回 0 成功 + + Args: + defaults: ast.Arguments.defaults 列表节点指针,None=无默认值 + default_count: 默认值数量(len(defaults)) + param_count: 形参数量(不含 self,len(args.args)) + pool: 内存池(用于生成 TypeStr;None 时 TypeStr 为空,vtable 回退读 Func 对象) + """ + if name is None or func is None or funcs is None: + return 1 + if func_count >= max_count: + return 1 + entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__() + entry_addr: t.CUInt64T = t.CUInt64T(funcs) + func_count * entry_size + entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + entry.Name = name + entry.Func = func + entry.Defaults = defaults + entry.DefaultCount = default_count + entry.ParamCount = param_count + # 同时注册到全局函数表(供跨模块 vtable 初始化查找) + self._register_global_func(name, func, pool) + # 同时注册到全局默认参数表(供跨模块调用时填充默认值) + if default_count > 0: + self._register_global_defaults(name, defaults, default_count, param_count) + return 0 + + + def _init_global_func_table(self) -> int: + """初始化全局函数表(用 stdlib.malloc 分配,生命周期=整个程序)""" + if self.GlobalFuncs is not None: + return 1 + size: t.CSizeT = GLOBAL_FUNC_MAX * HandlesExprCall.FuncEntry.__sizeof__() + self.GlobalFuncs = CompilerFactory.get_perm_pool().alloc(size) + if self.GlobalFuncs is None: + return 0 + string.memset(self.GlobalFuncs, 0, size) + self.GlobalFuncCount = 0 + return 1 + + + def _build_func_type_str(self, pool: memhub.MemBuddy | t.CPtr, + func: llvmlite.Function | t.CPtr) -> str: + """生成函数类型文本(stdlib 分配)""" + if func is None: + return None + # 类型文本可能较长(SHA1 限定命名结构体 + 多参数),用 1024 缓冲 + ty_buf: str = pool.alloc(1024) + if ty_buf is None: + return None + ty_buf[0] = '\0' + + # 返回类型 + ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func) + ret_part: str = pool.alloc(512) + if ret_part is not None and ret_ty is not None: + ret_part[0] = '\0' + llvmlite.TypePrint(ret_part, 512, ret_ty, pool) + self._asm_append_cstr(ty_buf, 1024, ret_part) + self._asm_append_cstr(ty_buf, 1024, " (") + + # 参数类型(全部经 _asm_append_cstr 有界追加,防止 strcat 无界写穿 1024 缓冲) + cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) + first: int = 1 + param_part: str = pool.alloc(512) + while cur is not None: + if first == 0: + self._asm_append_cstr(ty_buf, 1024, ", ") + if param_part is not None: + param_part[0] = '\0' + param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur) + if param_ty is not None: + llvmlite.TypePrint(param_part, 512, param_ty, pool) + self._asm_append_cstr(ty_buf, 1024, param_part) + cur = llvmlite.param_get_next(cur) + first = 0 + self._asm_append_cstr(ty_buf, 1024, ")") + + # 深拷贝到 stdlib 区(TypeStr 跨文件永久存活) + ts_len: t.CSizeT = string.strlen(ty_buf) + ts_copy: str = CompilerFactory.get_perm_pool().alloc(ts_len + 1) + if ts_copy is None: + return None + string.strcpy(ts_copy, ty_buf) + return ts_copy + + + def _register_global_func(self, name: str, func: llvmlite.Function | t.CPtr, + pool: memhub.MemBuddy | t.CPtr = None) -> int: + """注册函数到全局表(已存在则跳过),返回 0 成功 + + 直接操作全局表,不调用 add_func_to_table,避免递归。 + pool 用于生成 TypeStr(None 时 TypeStr 为空)。 + """ + if name is None or func is None: + return 1 + if self._init_global_func_table() == 0: + return 1 + # 已存在则跳过(避免重复) + if self.find_func_in_table(self.GlobalFuncs, self.GlobalFuncCount, name) is not None: + return 0 + if self.GlobalFuncCount >= GLOBAL_FUNC_MAX: + return 1 + # 直接写入全局表(不调用 add_func_to_table,避免递归) + entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__() + entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalFuncs) + self.GlobalFuncCount * entry_size + entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + # Name 深拷贝到 stdlib 区:全局表跨文件永久存活,pool 内名字会被 1b 每文件 + # reset_to(mark1) 回收导致悬空(vtable 生成 find_func_global 后 strcmp 崩溃) + name_len: t.CSizeT = string.strlen(name) + name_copy: str = CompilerFactory.get_perm_pool().alloc(name_len + 1) + if name_copy is None: + return 1 + string.strcpy(name_copy, name) + entry.Name = name_copy + entry.Func = func + # TypeStr 不在此生成:函数参数在 add_func_to_table 之后才添加, + # 需由调用方在参数添加完成后调用 update_global_func_typestr 补全。 + self.GlobalFuncCount += 1 + return 0 + + + def update_global_func_typestr(self, pool: memhub.MemBuddy | t.CPtr, + name: str, + func: llvmlite.Function | t.CPtr) -> int: + """更新全局函数表的 TypeStr(在函数参数全部添加完成后调用) + + 调用时机:add_func_to_table 注册后、llvmlite.add_param 全部执行完。 + 生成 ret_ty (param1_ty, ...) 类型文本(stdlib 深拷贝), + 供 vtable 生成在 func 被 1b reset 后使用。 + """ + if name is None or func is None: + return 1 + entry: HandlesExprCall.FuncEntry | t.CPtr = self.find_func_entry_global(name) + if entry is None: + return 1 + entry.TypeStr = self._build_func_type_str(pool, func) + return 0 + + + def find_func_global(self, name: str) -> llvmlite.Function | t.CPtr: + """在全局函数表中按名称查找,返回 Function 指针或 None""" + if name is None or self.GlobalFuncs is None: + return None + return self.find_func_in_table(self.GlobalFuncs, self.GlobalFuncCount, name) + + + def find_func_entry_global(self, name: str) -> HandlesExprCall.FuncEntry | t.CPtr: + """在全局函数表中按名称查找,返回完整 FuncEntry(含 TypeStr)或 None""" + if name is None or self.GlobalFuncs is None: + return None + entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__() + for i in range(self.GlobalFuncCount): + entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalFuncs) + i * entry_size + entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + return entry + return None + + + def _init_global_defaults_table(self) -> int: + """初始化全局默认参数表""" + if self.GlobalDefaults is not None: + return 1 + size: t.CSizeT = GLOBAL_DEFAULTS_MAX * HandlesExprCall.FuncDefaultsEntry.__sizeof__() + self.GlobalDefaults = CompilerFactory.get_perm_pool().alloc(size) + if self.GlobalDefaults is None: + return 0 + string.memset(self.GlobalDefaults, 0, size) + self.GlobalDefaultsCount = 0 + return 1 + + + def _register_global_defaults(self, name: str, + defaults: t.CVoid | t.CPtr, + default_count: int, + param_count: int) -> int: + """注册函数默认参数到全局表,返回 0 成功 + + 注册时提取每个默认值 Constant 的常量快照到 stdlib(ConstKinds/ConstInts/ConstStrs), + 跨模块调用时优先用快照重建常量 IR,避免读取被 reset 回收的 pool 内 AST。 + """ + if name is None or defaults is None: + return 1 + if self._init_global_defaults_table() == 0: + return 1 + # 已存在则跳过 + if self.find_func_defaults(name) is not None: + return 0 + if self.GlobalDefaultsCount >= GLOBAL_DEFAULTS_MAX: + return 1 + entry_size: t.CSizeT = HandlesExprCall.FuncDefaultsEntry.__sizeof__() + entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalDefaults) + self.GlobalDefaultsCount * entry_size + entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr = (HandlesExprCall.FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + # Name 深拷贝到 stdlib(全局表跨文件永久存活) + nm_len: t.CSizeT = string.strlen(name) + nm_copy: str = CompilerFactory.get_perm_pool().alloc(nm_len + 1) + if nm_copy is None: + return 1 + string.strcpy(nm_copy, name) + entry.Name = nm_copy + entry.Defaults = defaults + entry.DefaultCount = default_count + entry.ParamCount = param_count + # 提取常量快照到 stdlib + if default_count > 0: + kinds: t.CInt | t.CPtr = CompilerFactory.get_perm_pool().alloc(default_count * 4) + ints: t.CInt64T | t.CPtr = CompilerFactory.get_perm_pool().alloc(default_count * 8) + strs: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(default_count * 8) + if kinds is not None and ints is not None and strs is not None: + string.memset(kinds, 0, default_count * 4) + string.memset(ints, 0, default_count * 8) + string.memset(strs, 0, default_count * 8) + dl: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(defaults), t.CPtr)) + di: int + for di in range(default_count): + dnode: ast.AST | t.CPtr = dl.get(di) + if dnode is not None and dnode.kind() == ast.ASTKind.Constant: + dcn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(dnode) + kinds[di] = dcn.const_kind + ints[di] = dcn.int_val + if dcn.const_kind == ast.CONST_STR and dcn.str_val is not None: + slen: t.CSizeT = string.strlen(dcn.str_val) + scopy: str = CompilerFactory.get_perm_pool().alloc(slen + 1) + if scopy is not None: + string.strcpy(scopy, dcn.str_val) + strs[di] = t.CSizeT(scopy) + elif dnode is not None and dnode.kind() == ast.ASTKind.Name: + # CDefine Name 引用默认值(如 share: ULONG = SHARE_READ): + # 注册时求值 CDefine 存快照——否则跨模块重建时快照为空 + # → "跨模块默认参数无法重建"(FileIoTest File.__init__ 根因)。 + # 仅支持已注册的整型 CDefine;未注册保持 kinds=0(重建时 + # 仍 fail-fast,绝不静默回退)。 + dnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(dnode) + if dnm.id is not None: + cdef_v: int = HandlesType.lookup_cdefine_constant(dnm.id) + if HandlesType.is_cdefine_found() != 0: + kinds[di] = ast.CONST_INT + ints[di] = cdef_v + entry.ConstKinds = kinds + entry.ConstInts = ints + entry.ConstStrs = strs + self.GlobalDefaultsCount += 1 + return 0 + + + def find_func_defaults(self, name: str) -> HandlesExprCall.FuncDefaultsEntry | t.CPtr: + """按函数名查找默认参数信息,返回 FuncDefaultsEntry 或 None""" + if name is None or self.GlobalDefaults is None: + return None + entry_size: t.CSizeT = HandlesExprCall.FuncDefaultsEntry.__sizeof__() + i: int = 0 + while i < self.GlobalDefaultsCount: + entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalDefaults) + i * entry_size + entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr = (HandlesExprCall.FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + return entry + i += 1 + return None + + + def _build_const_from_snapshot(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + gd_entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr, + di: int, + trans: HT.Translator | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr) -> llvmlite.Value | t.CPtr: + """从快照重建第 di 个默认值常量 IR""" + if gd_entry is None or gd_entry.ConstKinds is None or gd_entry.ConstInts is None: + return None + if di < 0 or di >= gd_entry.DefaultCount: + return None + kind: t.CInt = gd_entry.ConstKinds[di] + ival: t.CInt64T = gd_entry.ConstInts[di] + if kind == ast.CONST_INT: + if ival > 2147483647 or ival < -2147483648: + return llvmlite.const_int64(pool, ival) + return llvmlite.const_int32(pool, ival) + elif kind == ast.CONST_BOOL: + if ival != 0: + return llvmlite.const_int32(pool, 1) + return llvmlite.const_int32(pool, 0) + elif kind == ast.CONST_NONE: + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + return llvmlite.ConstNull(pool, i8_ptr_ty, "null") + elif kind == ast.CONST_STR: + if gd_entry.ConstStrs is not None and gd_entry.ConstStrs[di] != 0: + sv: str = (str | t.CPtr)(t.CVoid(gd_entry.ConstStrs[di], t.CPtr)) + return HandlesExpr.create_global_string(builder, pool, mod, sv, trans) + # 无法重建的(如 CONST_FLOAT/复杂表达式)返回 None,调用方回退到 AST + return None + + + def find_func_entry_in_table(self, funcs: HandlesExprCall.FuncEntry | t.CPtr, + func_count: int, + name: str) -> HandlesExprCall.FuncEntry | t.CPtr: + """在函数表中按名称查找,返回完整 FuncEntry 或 None""" + if name is None or funcs is None: + return None + entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__() + i: int = 0 + while i < func_count: + entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size + entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + return entry + i += 1 + return None + + + def NewExprCallHandle(self, pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr) -> HandlesExprCall.ExprCallHandle | t.CPtr: + h: HandlesExprCall.ExprCallHandle | t.CPtr = pool.alloc(HandlesExprCall.ExprCallHandle.__sizeof__()) + if h is None: + return None + string.memset(h, 0, HandlesExprCall.ExprCallHandle.__sizeof__()) + h.Trans = trans + return h + diff --git a/App/lib/core/Gen/CallGenMixin.vp b/App/lib/core/Gen/CallGenMixin.vp index 3d92066..854d19b 100644 --- a/App/lib/core/Gen/CallGenMixin.vp +++ b/App/lib/core/Gen/CallGenMixin.vp @@ -26,30 +26,24 @@ import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign import lib.core.CompilerFactory as CompilerFactory +import lib.core.Gen.CallGenBase as CallGenBase + + # ============================================================ -# CallGenMixin - 调用分派 Mixin(对象化 P4,wiki/14-oo-refactor.md) +# CallGenMixin - 调用分派 Mixin(拆分后顶层,阶段 A:底层已拆至 +# CallGenBase/CallGenCBuiltin/CallGenLeafKit) # -# 从 HandlesExprCall.vp(7043 行,本仓库最大文件)迁移: -# 模块级纯函数(translate_call/translate_c_*/_translate_method_call/ -# _do_virtual_call/va_arg 系列/函数表/默认参数表等)→ 类方法 -# 全局状态(_g_cexport_*/_g_llvmir_reg_seq/_g_temp_dir/ -# _g_closure_*/_g_funcptr_*/_global_funcs/_global_defaults)→ 本类字段 -# -# 迁移原则(与 P2/P3 一致,行为零变化): -# 1. 方法保留原函数签名(含 pool/builder/mod 首参),仅函数体内的 -# 本模块函数调用改为 self.xxx(...) -# 2. 外部模块调用(HandlesType.xxx/HandlesExpr.xxx/StubMerger.xxx 等) -# 保留模块前缀 -# 3. AsmOperand/FuncEntry/FuncDefaultsEntry 类保留在 HandlesExprCall.vp -# 4. HandlesExprCall.vp 原函数保留为"委托":本地模块级单例 _g_gen -# (BuildPipeline/main 注入)cast 成 Generator 类型 +# 500~1500 行/文件架构重构阶段 A:底层自包含组(模块查找/返回类型解析/ +# c.*/asm/llvmir/EH/isinstance/闭包/print/函数表)已拆出,本文件保留 +# 调用分派中枢(translate_call 等)。继承链 CallGenMixin → LeafKit → +# CBuiltin → Base,@t.NoVTable 静态绑定沿 MRO 解析 self 调用。 # # @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 # ============================================================ # ============================================================ -# 常量(与 HandlesExprCall 保持一致) +# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug) # ============================================================ GLOBAL_FUNC_MAX: t.CDefine = 8192 GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 @@ -68,409 +62,14 @@ MAX_FUNC_PTR_SIGS: t.CDefine = 64 # isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32) ISINSTANCE_CLASS_MAX: t.CDefine = 64 + # ============================================================ -# CallGenMixin - 调用分派/类型转换/c.*/stdarg/函数表 +# CallGenMixin - 调用分派中枢(顶层,继承 LeafKit) # ============================================================ @t.NoVTable -class CallGenMixin: - """调用分派 Mixin(状态从 HandlesExprCall 全局变量迁入)""" +class CallGenMixin(CallGenBase.CallGenBase): + """调用分派 Mixin(拆分后顶层,直接继承 CallGenBase——TPV self 调用仅支持 1 级父类)""" - # --- c.cexport 注册表(原 _g_cexport_sha1_arr/_g_cexport_func_arr/_g_cexport_count) --- - CexportSha1Arr: bytes - CexportFuncArr: bytes - CexportCount: int - - # --- LLVMIR 寄存器序号(原 _g_llvmir_reg_seq) --- - LLVMIRRegSeq: int - - # --- temp 目录(原 _g_temp_dir/_g_temp_dir_len) --- - TempDir: str - TempDirLen: t.CSizeT - - # --- 闭包名表(原 _g_closure_names/_g_closure_count) --- - ClosureNames: str - ClosureCount: int - - # --- 函数指针签名表(原 _g_funcptr_names/_g_funcptr_rets/_g_funcptr_count) --- - FuncptrNames: str - FuncptrRets: t.CUInt64T | t.CPtr - FuncptrCount: int - - # --- 全局函数注册表(原 _global_funcs/_global_func_count) --- - GlobalFuncs: HandlesExprCall.FuncEntry | t.CPtr - GlobalFuncCount: int - - # --- 全局默认参数表(原 _global_defaults/_global_defaults_count) --- - GlobalDefaults: HandlesExprCall.FuncDefaultsEntry | t.CPtr - GlobalDefaultsCount: int - - def InitCallGen(self) -> int: - """初始化调用 Mixin 字段(子类构造时内联调用,规避 NoVTable 继承符号不转发)""" - if self is None: - return 1 - self.CexportSha1Arr = None - self.CexportFuncArr = None - self.CexportCount = 0 - self.LLVMIRRegSeq = 0 - self.TempDir = None - self.TempDirLen = 0 - self.ClosureNames = None - self.ClosureCount = 0 - self.FuncptrNames = None - self.FuncptrRets = None - self.FuncptrCount = 0 - self.GlobalFuncs = None - self.GlobalFuncCount = 0 - self.GlobalDefaults = None - self.GlobalDefaultsCount = 0 - return 0 - - # ============================================================ - # P4 簇 1+2 迁移方法(函数体来自 HandlesExprCall.vp: - # 模块 SHA1 查询/CExport 注册表/c.* 系列/内联汇编/LLVMIR) - # 本模块函数调用改 self.,外部模块调用保留模块前缀 - # ============================================================ - - def _lookup_module_sha1(self, mod_name: str) -> str: - """查找模块名对应的 SHA1,找不到返回 None - - 委托给 StubMerger.LookupSha1ByModName(精确匹配 + 包名回退)。 - """ - return StubMerger.LookupSha1ByModName(mod_name) - - def _lookup_module_sha1_suffix(self, mod_suffix: str) -> str: - """后缀匹配查找模块 SHA1,如 mod_suffix="__types" 匹配 "llvmlite.__types" - - 用于 from .X import Y 的相对导入:impf.module 是 ".X"(带前导点), - 去掉前导点后为 "X",SHA1 映射表中键是 "pkg.X",需要后缀匹配。 - 委托给 StubMerger.LookupSha1ByModNameSuffix(精确 + 后缀 + 反向后缀)。 - """ - return StubMerger.LookupSha1ByModNameSuffix(mod_suffix) - - def _module_package_from_sha1(self, pool: memhub.MemBuddy | t.CPtr, - mod_sha1: str) -> str: - """从 SHA1 存储器的 rel_path 计算模块所属包名(目录部分,'/' → '.')""" - if pool is None or mod_sha1 is None: - return None - rel_arr_ptr: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr() - sha1_arr_ptr: bytes | t.CPtr = StubMerger.GetSha1StoreArrPtr() - count: int = StubMerger.GetSha1StoreCount() - if rel_arr_ptr is None or sha1_arr_ptr is None or count <= 0: - return None - for i in range(count): - sidx: t.CSizeT = t.CSizeT(i) * 17 - if string.strcmp(sha1_arr_ptr + sidx, mod_sha1) != 0: - continue - ridx: t.CSizeT = t.CSizeT(i) * StubMerger.MAX_REL_PATH_LEN - rel: str = rel_arr_ptr + ridx - last_slash: str = string.strrchr(rel, 47) # 47 = ord('/') - if last_slash is None: - return None - pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(last_slash) - t.CUInt64T(rel)) - if pkg_len == 0: - return None - pkg_buf: str = pool.alloc(pkg_len + 1) - if pkg_buf is None: - return None - for pi in range(pkg_len): - if rel[pi] == '/': - pkg_buf[pi] = '.' - else: - pkg_buf[pi] = rel[pi] - pkg_buf[pkg_len] = '\0' - return pkg_buf - return None - - def _lookup_reexport_from_vpi(self, pool: memhub.MemBuddy | t.CPtr, - mod_sha1: str, func_name: str) -> str: - """re-export 表未命中时,从模块 .vpi 按需解析 from-import 定位定义模块 - - includes 模块(如 llvmlite/__init__)的 stub/text 已存在时不会被按需 - 全量翻译(Phase2 3.5 仅在 stub/text 缺失时翻译),而 re-export 表只在 - declare_only=0 的全量翻译中注册(HandleImportFromNames),因此表可能为空。 - 本函数解析该模块 .vpi 的 "from .X import ... func_name ..." 语句, - 返回定义模块名(如 llvmlite/__init__ 的 .__builder → "llvmlite.__builder")。 - """ - if pool is None or mod_sha1 is None or func_name is None: - return None - temp_dir: str = HandlesType.get_temp_dir() - if temp_dir is None: - return None - td_len: t.CSizeT = string.strlen(temp_dir) - vpi_path: str = StubMerger._sliced_path(temp_dir, td_len, mod_sha1, "vpi") - if vpi_path is None: - return None - READ_SZ: t.CSizeT = 1048576 - buf: bytes = stdlib.malloc(READ_SZ) - if buf is None: - stdlib.free(vpi_path) - return None - vf: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R) - stdlib.free(vpi_path) - if vf.closed: - stdlib.free(buf) - return None - nrd: LONG = vf.read_all(buf, READ_SZ) - vf.close() - if nrd <= 0: - stdlib.free(buf) - return None - if nrd < READ_SZ: - buf[nrd] = 0 - else: - buf[READ_SZ - 1] = 0 - name_len: t.CSizeT = string.strlen(func_name) - total: t.CSizeT = string.strlen(buf) - pos: t.CSizeT = 0 - while pos < total: - ls: t.CSizeT = pos - while pos < total and buf[pos] != '\n': - pos += 1 - ll: t.CSizeT = pos - ls - if pos < total: - pos += 1 - # 行必须以 "from " 开头 - if ll < 6: - continue - if buf[ls] != 'f' or buf[ls + 1] != 'r' or buf[ls + 2] != 'o' or buf[ls + 3] != 'm' or buf[ls + 4] != ' ': - continue - # 找 " import " 分隔符 - imp_pos: t.CSizeT = ls + 5 - while imp_pos + 7 <= ls + ll: - if buf[imp_pos] == ' ' and buf[imp_pos + 1] == 'i' and buf[imp_pos + 2] == 'm' and \ - buf[imp_pos + 3] == 'p' and buf[imp_pos + 4] == 'o' and buf[imp_pos + 5] == 'r' and \ - buf[imp_pos + 6] == 't' and buf[imp_pos + 7] == ' ': - break - imp_pos += 1 - if imp_pos + 7 > ls + ll: - continue - mod_start: t.CSizeT = ls + 5 - mod_end: t.CSizeT = imp_pos - # 名称列表从 "import " 之后(逗号分隔,含 "A as B" 取原名 A) - nm_start: t.CSizeT = imp_pos + 8 - scan: t.CSizeT = nm_start - while scan < ls + ll: - while scan < ls + ll and (buf[scan] == ' ' or buf[scan] == ','): - scan += 1 - if scan >= ls + ll: - break - n_end: t.CSizeT = scan - while n_end < ls + ll and buf[n_end] != ',' and buf[n_end] != ' ': - n_end += 1 - cand_start: t.CSizeT = scan - cand_len: t.CSizeT = n_end - scan - as_pos: t.CSizeT = scan - while as_pos + 4 <= n_end: - if buf[as_pos] == ' ' and buf[as_pos + 1] == 'a' and buf[as_pos + 2] == 's' and buf[as_pos + 3] == ' ': - cand_start = as_pos + 4 - cand_len = n_end - cand_start - break - as_pos += 1 - if cand_len == name_len: - m_ok: int = 1 - for ki in range(name_len): - if buf[cand_start + ki] != func_name[ki]: - m_ok = 0 - break - if m_ok == 1: - # 命中:解析模块名(前导点 → 相对导入,补包前缀) - has_dot: int = 0 - if buf[mod_start] == '.': - has_dot = 1 - mod_buf: str = pool.alloc(mod_end - mod_start + 1) - if mod_buf is None: - stdlib.free(buf) - return None - mi: t.CSizeT = 0 - while mod_start + mi < mod_end: - mod_buf[mi] = buf[mod_start + mi] - mi += 1 - mod_buf[mi] = '\0' - while mod_buf[0] == '.': - mod_buf = mod_buf + 1 - if string.strlen(mod_buf) == 0: - stdlib.free(buf) - return None - if has_dot != 0: - pkg: str = self._module_package_from_sha1(pool, mod_sha1) - if pkg is None: - stdlib.free(buf) - return None - rl: t.CSizeT = string.strlen(pkg) + string.strlen(mod_buf) + 2 - res: str = pool.alloc(rl) - if res is None: - stdlib.free(buf) - return None - viperlib.snprintf(res, rl, "%s.%s", pkg, mod_buf) - stdlib.free(buf) - return res - stdlib.free(buf) - return mod_buf - scan = n_end - stdlib.free(buf) - return None - - def register_cexport_func(self, sha1: str, func_name: str) -> int: - """注册 CExport 函数到全局表(sha1+func_name 二元组)""" - if sha1 is None or func_name is None: - return 0 - if self.CexportSha1Arr is None: - self.CexportSha1Arr = CompilerFactory.get_perm_pool().alloc(_CEXPORT_MAX * 17) - self.CexportFuncArr = CompilerFactory.get_perm_pool().alloc(_CEXPORT_MAX * 64) - if self.CexportSha1Arr is None or self.CexportFuncArr is None: - return 0 - string.memset(self.CexportSha1Arr, 0, _CEXPORT_MAX * 17) - string.memset(self.CexportFuncArr, 0, _CEXPORT_MAX * 64) - if self.CexportCount < _CEXPORT_MAX: - idx: t.CSizeT = t.CSizeT(self.CexportCount) * 17 - # 槽位定长 17/64 字节,strcpy 无界会越界写相邻槽(stdlib 堆区) - string.strncpy(self.CexportSha1Arr + idx, sha1, 16) - self.CexportSha1Arr[idx + 16] = '\0' - idx2: t.CSizeT = t.CSizeT(self.CexportCount) * 64 - string.strncpy(self.CexportFuncArr + idx2, func_name, 63) - self.CexportFuncArr[idx2 + 63] = '\0' - self.CexportCount += 1 - return 1 - return 0 - - def is_cexport_func(self, sha1: str, func_name: str) -> int: - """检查 (sha1, func_name) 是否是 CExport 函数""" - if sha1 is None or func_name is None: - return 0 - if self.CexportSha1Arr is None: - return 0 - for i in range(self.CexportCount): - idx: t.CSizeT = t.CSizeT(i) * 17 - if string.strcmp(self.CexportSha1Arr + idx, sha1) == 0: - idx2: t.CSizeT = t.CSizeT(i) * 64 - if string.strcmp(self.CexportFuncArr + idx2, func_name) == 0: - return 1 - return 0 - - def _is_state_func_from_vpi(self, pool: memhub.MemBuddy | t.CPtr, - sha1: str, func_name: str) -> int: - """vpi 返回注解含 t.State → 外部 C 函数(定义端用裸名,跨模块调用无 sha1 头) - - t.State(同 t.CExtern/t.CExport)是外部函数标记:定义端生成裸名 - @PyList_Size(链接外部库 libpython),跨模块调用若生成 @{sha1}.PyList_Size - → ld.lld undefined symbol(CPythonTest PyList_Size 根因)。CExport 走 - is_cexport_func 注册表,State 函数未注册 → 按需解析 vpi 返回注解判断。 - """ - if pool is None or sha1 is None or func_name is None: - return 0 - import lib.StubGen.VpiReader as VpiReader - if self.TempDir is not None and self.TempDirLen > 0: - VpiReader._ensure_vpi_ret_annot_loaded(sha1, self.TempDir) - state_annot: str = VpiReader._lookup_vpi_ret_annot(sha1, None, func_name) - if state_annot is None: - return 0 - # 返回注解含 "State"(如 "t.CSizeT | t.State")→ 外部 C 函数 - if string.strstr(state_annot, "State") is not None: - return 1 - return 0 - - def _lookup_mod_sha1(self, pool: memhub.MemBuddy | t.CPtr, - from_imports: str, class_name: str, - allow_star_fallback: int = 1) -> str: - """从 from_imports 查找类所属模块的 SHA1,返回 None=未找到 - - allow_star_fallback: 传 0 禁用 star import 回退(用于明确模块名/函数名查找) - """ - mod_name_raw: str = HandlesImports.lookup_from_import( - from_imports, class_name, allow_star_fallback) - if mod_name_raw is None: - return None - return self._lookup_sha1_from_modname_raw(pool, mod_name_raw) - - def _lookup_sha1_from_modname_raw(self, pool: memhub.MemBuddy | t.CPtr, - mod_name_raw: str) -> str: - """从原始模块名查找 SHA1,返回 None=未找到""" - # 手动找到模块名结束位置(空格、null、或 ':' 别名分隔符),复制到新缓冲区 - mod_len: t.CSizeT = 0 - while mod_name_raw[mod_len] != ' ' and mod_name_raw[mod_len] != '\0' and mod_name_raw[mod_len] != ':': - mod_len += 1 - mod_name_buf: str = pool.alloc(mod_len + 1) - if mod_name_buf is None: - return None - for mi in range(mod_len): - mod_name_buf[mi] = mod_name_raw[mi] - mod_name_buf[mod_len] = '\0' - # 去掉相对导入的前导点 - base_mod: str = mod_name_buf - while base_mod[0] == '.': - base_mod = base_mod + 1 - sha1: str = self._lookup_module_sha1(base_mod) - if sha1 is None: - sha1 = self._lookup_module_sha1_suffix(base_mod) - return sha1 - - def find_func_in_module(self, mod: llvmlite.LLVMModule | t.CPtr, - name: str) -> llvmlite.Function | t.CPtr: - """在模块的函数链表中按名称查找函数 - - 查找策略: - 1. 精确匹配(如 "strlen" 匹配 @strlen,有 t.CExport 的函数) - 2. 后缀匹配(如 "atoi" 匹配 @"83210a72e829a086.atoi",无 t.CExport 的函数) - - 使用 llvmlite.function_get_name/next 访问器绕过 stub 类型限制 - (stub 类型字段不足且字段类型可能错误,直接字段访问会被静默跳过)。 - """ - if mod is None or name is None: - return None - name_len: t.CSizeT = string.strlen(name) - cur: llvmlite.Function | t.CPtr = mod.FuncHead - # 第一遍:精确匹配 - while cur is not None: - cur_name: str = llvmlite.function_get_name(cur) - if cur_name is not None: - if string.strcmp(cur_name, name) == 0: - return cur - cur = llvmlite.function_get_next(cur) - # 第二遍:后缀匹配(.name) - # 不跳过 declare:方法 stub 也是 declare,需要通过后缀匹配找到 - # 调用处(translate_call 等)负责判断 IsDeclared 并决定使用裸名还是 sha1 前缀名 - # - # 修复:本模块 define 优先于跨模块 stub declare。 - # 根因:跨模块同名函数(如 lexer.vp 的 _advance 与 parser.vp 的 _advance) - # 的 stub declare 在 stub 注入时排在 FuncHead 前面,裸名调用 _advance 后缀 - # 匹配按链表顺序先命中跨模块 declare → 参数按 Lexer* coerce → Parser* 被 - # bitcast 成 Lexer* → lexer 版 _advance 按 Lexer 布局操作 Parser 指针, - # cur 永不推进 → parse 无限循环。本模块同名 define 必须优先。 - cur = mod.FuncHead - while cur is not None: - cur_name2: str = llvmlite.function_get_name(cur) - if cur_name2 is not None: - cur_len: t.CSizeT = string.strlen(cur_name2) - if cur_len > name_len + 1: - suffix_start: t.CSizeT = cur_len - name_len - if cur_name2[suffix_start - 1] == '.': - match: int = 1 - for i in range(name_len): - if cur_name2[suffix_start + i] != name[i]: - match = 0 - break - if match == 1: - if cur.IsDeclared == 0: - return cur - cur = llvmlite.function_get_next(cur) - # 本模块无同名 define:回退到 stub declare(跨模块方法/函数调用) - cur = mod.FuncHead - while cur is not None: - cur_name3: str = llvmlite.function_get_name(cur) - if cur_name3 is not None: - cur_len3: t.CSizeT = string.strlen(cur_name3) - if cur_len3 > name_len + 1: - suffix_start3: t.CSizeT = cur_len3 - name_len - if cur_name3[suffix_start3 - 1] == '.': - match3: int = 1 - for i in range(name_len): - if cur_name3[suffix_start3 + i] != name[i]: - match3 = 0 - break - if match3 == 1: - return cur - cur = llvmlite.function_get_next(cur) - return None def _ensure_c_lib_declare(self, pool: memhub.MemBuddy | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, @@ -561,6 +160,7 @@ class CallGenMixin: llvmlite.add_param(pool, fn, i64_ty, "n") return fn + def _infer_external_func_ret_ty(self, pool: memhub.MemBuddy | t.CPtr, func_name: str) -> llvmlite.LLVMType | t.CPtr: """根据函数名推断外部 includes 函数的返回类型 @@ -751,6 +351,7 @@ class CallGenMixin: "HandlesExprCall") return llvmlite.Int32(pool) + def _get_external_func_param_ty(self, pool: memhub.MemBuddy | t.CPtr, func_name: str, param_idx: int) -> llvmlite.LLVMType | t.CPtr: @@ -787,6 +388,7 @@ class CallGenMixin: return None + def _is_sha1_mangled_call(self, call_name: str) -> int: """判断 call_name 是否为跨模块 Viper 函数("{16位hex}.func" 形式) @@ -809,6 +411,7 @@ class CallGenMixin: return 0 return 1 + def _emit_llvm_memcpy_intrinsic(self, pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, @@ -896,1284 +499,6 @@ class CallGenMixin: # 返回 dst(匹配 C memcpy 语义: 返回 dest 指针) return dst_coerced - def translate_c_deref(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.Deref(ptr) → load 按 ptr 的 pointee 类型""" - if cl is None: - return None - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None or len(cargs) < 1: - return None - - ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(0), None, 0, trans) - if ptr_val is None: - return None - - # 按 pointee 类型读取;非指针参数默认按 i8(保持向后兼容) - if HandlesExpr.is_ptr_type(ptr_val.Ty) != 0: - pointee: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee - if pointee is not None: - # i8*(void*)时按赋值目标类型推断读取宽度(对齐 TPC - # HandlesSpecialCall._infer_deref_target_type): - # v: int = c.Deref(p) → bitcast i32* 后 load 4 字节。 - # 背景:DictTest d3[key5]=500 读出 -12——固定按 i8 读 1 字节 + - # sext 截断(0xF4 → 0xFFFFFFF4);Test 1 的小值(10)恰好正确 - # 掩盖了缺陷。 - match pointee: - case llvmlite.LLVMType.Int(pointee_width): - # 仅当 c.Deref 是赋值语句的直接 RHS(如 v: int = c.Deref(p)) - # 时才用注解推断读取宽度(对齐 TPC _infer_deref_target_type - # 的直接 RHS 检查);嵌套在 while 条件/比较/binop/类型转换 - # 调用中(如 while c.Deref(p) != 0、total += t.CInt(c.Deref(p))) - # 不推断,否则 i8* 会被残留 CurAssignAnnot 误判为 i32* - # 读 4 字节 → StringIterTest ASCII sum/manual strcmp 失败。 - if pointee_width == 8 and trans is not None \ - and trans.CurAssignAnnot is not None \ - and trans.CurAssignNode is not None \ - and t.CUInt64T(cl) == t.CUInt64T(trans.CurAssignNode): - dref_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - trans.Pool, trans.CurAssignAnnot, - trans._imported_modules, trans._from_imports, trans) - if dref_ty is not None: - dref_bits: int = HandlesExpr.get_llvm_type_bits(dref_ty) - dref_fbits: int = HandlesExpr.get_llvm_float_bits(dref_ty) - # 仅整数/浮点目标(struct 值目标不推断,保持 i8 读) - dref_ptr: llvmlite.Value | t.CPtr = None - if (dref_bits != 0 or dref_fbits != 0) and dref_bits != 8: - dref_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, dref_ty) - dref_ptr = llvmlite.build_bitcast( - builder, ptr_val, dref_ptr_ty) - if dref_ptr is not None: - return llvmlite.build_load(builder, dref_ty, dref_ptr) - case _: - pass - return llvmlite.build_load(builder, pointee, ptr_val) - # 非指针参数即类型推断退化:fail-fast,绝不按 i8 兜底读取(会读到垃圾宽度) - HandlesType.fatal_error(cl, "c.Deref 参数不是指针类型(类型推断退化)", "TypeError") - return None - - def translate_c_derefas(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.DerefAs(ptr, val) → store val to ptr(bitcast 后 store)""" - if cl is None: - return None - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None or len(cargs) < 2: - return None - - ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(0), None, 0, trans) - val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(1), None, 0, trans) - if ptr_val is None or val is None: - return None - - # 两端均为指向同一结构体类型的指针时执行结构体拷贝(*ptr = *val), - # 而非存储指针值。这对 REnum 变体构造(c.DerefAs(ptr, LLVMType.Int(32)))至关重要: - # LLVMType.Int(32) 构造返回 alloca 指针(Ptr(LLVMType)),若直接 store 指针值, - # 只写入 8 字节指针(tag 字段仍是 0x0),导致运行时读 tag 错乱。 - # 对应 TPC HandlesExprCall.py:3696-3701 的 struct 拷贝逻辑。 - if HandlesExpr.is_ptr_type(ptr_val.Ty) != 0 and HandlesExpr.is_ptr_type(val.Ty) != 0: - ptr_pointee: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee - val_pointee: llvmlite.LLVMType | t.CPtr = val.Ty.Pointee - if ptr_pointee is not None and val_pointee is not None: - # ptr_pointee 是已注册结构体类型(用 find_struct_by_type 判断) - if HandlesStruct.find_struct_by_type(ptr_pointee) is not None: - if ptr_pointee is val_pointee: - # 同一结构体类型:load 值再 store(结构体拷贝) - loaded: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, val_pointee, val) - if loaded is not None: - # bitcast ptr 到结构体指针再 store - struct_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, ptr_pointee) - casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, ptr_val, struct_ptr_ty) - if casted_ptr is not None: - llvmlite.build_store(builder, loaded, casted_ptr) - return val - - # bitcast ptr 到 val.Ty* 再 store - val_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, val.Ty) - casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ptr_val, val_ptr_ty) - if casted_ptr is None: - return None - llvmlite.build_store(builder, val, casted_ptr) - return val - - def translate_c_set(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.Set(a, b) → a = b(赋值语义,a 为左值)""" - if cl is None: - return None - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None or len(cargs) < 2: - return None - a_node: ast.AST | t.CPtr = cargs.get(0) - b_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(1), None, 0, trans) - if b_val is None: - return None - - # 形态 1: c.Set(c.Deref(ptr), b) → *ptr = b - if a_node is not None and a_node.kind() == ast.ASTKind.Call: - d_call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(a_node) - if d_call.func is not None and d_call.func.kind() == ast.ASTKind.Attribute: - d_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(d_call.func) - if d_at.attr is not None and string.strcmp(d_at.attr, "Deref") == 0: - d_args: list[ast.AST | t.CPtr] | t.CPtr = d_call.args - if d_args is not None and len(d_args) >= 1: - ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, d_args.get(0), None, 0, trans) - if ptr_val is not None: - val_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, b_val.Ty) - casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, ptr_val, val_ptr_ty) - if casted_ptr is not None: - llvmlite.build_store(builder, b_val, casted_ptr) - return b_val - # 其他 Call 形态不可作左值 - return b_val - - # 形态 2: Name 变量赋值 - if a_node is not None and a_node.kind() == ast.ASTKind.Name and trans is not None: - nm_set: ast.Name | t.CPtr = (ast.Name | t.CPtr)(a_node) - if nm_set.id is not None: - if HT.is_global_name(trans, nm_set.id) != 0: - mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( - trans.SymTab, nm_set.id) - if mod_alloca is not None: - tg_ty: llvmlite.LLVMType | t.CPtr = None - if mod_alloca.Ty is not None: - tg_ty = mod_alloca.Ty.Pointee - sv: llvmlite.Value | t.CPtr = b_val - if tg_ty is not None: - sv = HandlesExpr.coerce_to_type(builder, b_val, tg_ty, a_node) - llvmlite.build_store(builder, sv, mod_alloca) - return b_val - if HT.is_nonlocal_name(trans, nm_set.id) != 0: - nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr( - trans, nm_set.id) - if nl_ptr is not None: - nl_ty: llvmlite.LLVMType | t.CPtr = None - if nl_ptr.Ty is not None: - nl_ty = nl_ptr.Ty.Pointee - sv2: llvmlite.Value | t.CPtr = b_val - if nl_ty is not None: - sv2 = HandlesExpr.coerce_to_type(builder, b_val, nl_ty, a_node) - llvmlite.build_store(builder, sv2, nl_ptr) - return b_val - alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym( - trans.SymTab, pool, builder, nm_set.id, b_val.Ty) - if alloca is not None: - ac_ty: llvmlite.LLVMType | t.CPtr = None - if alloca.Ty is not None: - ac_ty = alloca.Ty.Pointee - sv3: llvmlite.Value | t.CPtr = b_val - if ac_ty is not None: - sv3 = HandlesExpr.coerce_to_type(builder, b_val, ac_ty, a_node) - llvmlite.build_store(builder, sv3, alloca) - return b_val - return b_val - - # 形态 3: Attribute 字段赋值 - if a_node is not None and a_node.kind() == ast.ASTKind.Attribute: - field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( - builder, pool, mod, a_node, trans) - if field_ptr is not None: - fd_ty: llvmlite.LLVMType | t.CPtr = None - if field_ptr.Ty is not None: - fd_ty = field_ptr.Ty.Pointee - sv4: llvmlite.Value | t.CPtr = b_val - if fd_ty is not None: - sv4 = HandlesExpr.coerce_to_type(builder, b_val, fd_ty, a_node) - llvmlite.build_store(builder, sv4, field_ptr) - return b_val - - return b_val - - def translate_c_addr(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.Addr(var) → 返回变量的 alloca 指针(不 load)""" - if cl is None: - return None - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None or len(cargs) < 1: - return None - - arg0: ast.AST | t.CPtr = cargs.get(0) - if arg0 is None: - return None - - # Name 形式: c.Addr(var) → 返回变量的 alloca 指针(不 load) - if arg0.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0) - if nm.id is None: - return None - if trans is not None: - # self/cls 对象引用:c.Addr(self) 返回对象指针本身(Ptr(Struct)), - # 而非指针变量的地址(Ptr(Ptr(Struct)))。方法与 Attribute 分支 - # (c.Addr(self.field) 先 load self)语义一致,供 - # return t.CVoid(c.Addr(self), CPtr) 返回 this 使用。 - if string.strcmp(nm.id, "self") == 0 or string.strcmp(nm.id, "cls") == 0: - self_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm.id) - if self_entry is not None and self_entry.Alloca is not None and self_entry.Alloca.Ty is not None: - match self_entry.Alloca.Ty: - case llvmlite.LLVMType.Ptr(inner1): - match inner1: - case llvmlite.LLVMType.Ptr(inner2): - obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, inner2) - return llvmlite.build_load(builder, obj_ty, self_entry.Alloca) - case _: - pass - case _: - pass - return_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if return_var is not None and return_var.Ty is not None: - # 对象指针变量(如 lit_tree = zhuff.zhuff_tree(),alloca 是 - # Ptr(Ptr(Struct)),存对象指针):c.Addr(对象变量) 应返回对象 - # 指针本身(load 一次),对齐 self/cls 分支与 c.Addr(self.field) - # (GEP 后对象地址)。此前直接返回 &变量(Ptr(Ptr(Struct)))→ - # 调用端 bitcast 成 Ptr(Struct) 后 ht 指向指针变量存储 → 字段 - # 读到指针值/垃圾 → build_decode_tree 越界崩溃 - # (zinflate inflate_block_fixed 的 c.Addr(lit_tree) 根因)。 - match return_var.Ty: - case llvmlite.LLVMType.Ptr(addr_inner1): - match addr_inner1: - case llvmlite.LLVMType.Ptr(addr_inner2): - match addr_inner2: - case llvmlite.LLVMType.Struct(_, _, _): - addr_obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, addr_inner2) - return llvmlite.build_load(builder, addr_obj_ty, return_var) - case _: - pass - case _: - pass - case _: - pass - return return_var - - # Attribute 形式: c.Addr(self.field) → 取字段地址(GEP 到字段,不 load) - # 用于 atom.__atomic_test_and_set(c.Addr(self.lock_val), ...) 等锁操作 - if arg0.kind() == ast.ASTKind.Attribute: - if trans is None: - return None - at_addr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg0) - if at_addr is None or at_addr.attr is None or at_addr.value is None: - return None - # 解析 self(Name)→ 查找 alloca - if at_addr.value.kind() != ast.ASTKind.Name: - return None - self_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_addr.value) - if self_nm.id is None: - return None - self_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, self_nm.id) - if self_alloca is None or self_alloca.Ty is None: - return None - # 从 self 类型提取结构体类型(Ptr(Struct) 或 Ptr(Ptr(Struct))) - struct_ty: llvmlite.LLVMType | t.CPtr = None - self_is_ptr_ptr: int = 0 - match self_alloca.Ty: - case llvmlite.LLVMType.Ptr(inner1): - match inner1: - case llvmlite.LLVMType.Ptr(inner2): - struct_ty = inner2 - self_is_ptr_ptr = 1 - case _: - struct_ty = inner1 - case _: - return None - # 查找字段 - fe_addr: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - struct_ty, at_addr.attr) - if fe_addr is None: - return None - # self_alloca 是 Ptr(Ptr(Struct)) 时先 load 成 Ptr(Struct) 对象指针 - obj_ptr: llvmlite.Value | t.CPtr = self_alloca - if self_is_ptr_ptr == 1: - self_obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) - obj_ptr = llvmlite.build_load(builder, self_obj_ty, self_alloca) - if obj_ptr is None: - return None - # GEP 到字段地址 - return llvmlite.build_gep_struct( - builder, struct_ty, fe_addr.Ty, obj_ptr, fe_addr.Index) - - # Subscript 形式: c.Addr(arr[i]) → 数组元素地址(GEP 数组,不 load) - # 用于 self.root_directory = c.Addr(directories[directory_count]) 等。 - # 此前只支持 Name/Attribute,Subscript 落到函数末尾返回 None → - # 赋值右侧为 None(devfs.vp:159 根因)。 - if arg0.kind() == ast.ASTKind.Subscript: - if trans is None: - return None - sub_addr: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(arg0) - if sub_addr is None or sub_addr.value is None or sub_addr.slice is None: - return None - arr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sub_addr.value, None, 0, trans) - if arr_val is None or arr_val.Ty is None: - return None - idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sub_addr.slice, None, 0, trans) - if idx_val is None: - return None - # 数组基址 pointee 是 Array(elem_ty, N) → GEP 得元素指针 - arr_pointee_ca: llvmlite.LLVMType | t.CPtr = None - if HandlesExpr.is_ptr_type(arr_val.Ty) != 0: - arr_pointee_ca = arr_val.Ty.Pointee - if arr_pointee_ca is not None: - match arr_pointee_ca: - case llvmlite.LLVMType.Array(arr_et_ca, _): - return llvmlite.build_gep_array( - builder, arr_pointee_ca, arr_et_ca, arr_val, idx_val) - case _: - pass - return None - - def translate_c_load(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.Load(a, b) → *a = *b(加载 b 的值,存储到 a)""" - if cl is None: - return None - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None or len(cargs) < 2: - return None - - dst_ptr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(0), None, 0, trans) - src_ptr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(1), None, 0, trans) - if dst_ptr is None or src_ptr is None: - return None - - # 确定 pointee 类型(优先用 src 的 pointee,回退到 dst 的 pointee) - pointee: llvmlite.LLVMType | t.CPtr = None - if src_ptr.Ty is not None: - pointee = src_ptr.Ty.Pointee - if pointee is None and dst_ptr.Ty is not None: - pointee = dst_ptr.Ty.Pointee - if pointee is None: - return None - - # bitcast src 到 pointee* 并 load - target_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, pointee) - src_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, src_ptr, target_ptr_ty) - if src_cast is None: - return None - loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, pointee, src_cast) - if loaded is None: - return None - - # bitcast dst 到 pointee* 并 store - dst_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, dst_ptr, target_ptr_ty) - if dst_cast is None: - return None - llvmlite.build_store(builder, loaded, dst_cast) - return loaded - - def _asm_append_cstr(self, dst: str, dst_size: t.CSizeT, - src: str): - """将 C 字符串 src 追加到 dst 末尾""" - if dst is None or src is None: - return - dlen: t.CSizeT = string.strlen(dst) - slen: t.CSizeT = string.strlen(src) - remain: t.CSizeT = dst_size - dlen - if remain <= 0: - return - i: t.CSizeT = 0 - while i < slen and i + 1 < remain: - dst[dlen + i] = src[i] - i += 1 - dst[dlen + i] = '\0' - - def _asm_escape_for_ir(self, pool: memhub.MemBuddy | t.CPtr, - src: str) -> str: - """转义汇编文本用于 LLVM IR 字符串字面量""" - if src is None: - return None - slen: t.CSizeT = string.strlen(src) - buf: str = pool.alloc(slen * 4 + 8) - if buf is None: - return None - pos: t.CSizeT = 0 - for ch in src: - if ch == '\n': - buf[pos] = '\\' - pos += 1 - buf[pos] = '0' - pos += 1 - buf[pos] = 'A' - pos += 1 - elif ch == '"': - buf[pos] = '\\' - pos += 1 - buf[pos] = '2' - pos += 1 - buf[pos] = '2' - pos += 1 - elif ch == '\\': - buf[pos] = '\\' - pos += 1 - buf[pos] = '5' - pos += 1 - buf[pos] = 'C' - pos += 1 - else: - buf[pos] = ch - pos += 1 - buf[pos] = '\0' - return buf - - def _resolve_register(self, attr_name: str) -> str: - """将 t.ASM_DESCR.XXX 的属性名映射到约束字符串值""" - if attr_name is None: - return "" - - # Clobber 破坏描述符 - if string.strcmp(attr_name, "CLOBBER_MEMORY") == 0: return "memory" - if string.strcmp(attr_name, "CLOBBER_CC") == 0: return "cc" - if string.strcmp(attr_name, "CLOBBER_RAX") == 0: return "rax" - if string.strcmp(attr_name, "CLOBBER_RBX") == 0: return "rbx" - if string.strcmp(attr_name, "CLOBBER_RCX") == 0: return "rcx" - if string.strcmp(attr_name, "CLOBBER_RDX") == 0: return "rdx" - if string.strcmp(attr_name, "CLOBBER_RSI") == 0: return "rsi" - if string.strcmp(attr_name, "CLOBBER_RDI") == 0: return "rdi" - if string.strcmp(attr_name, "CLOBBER_RBP") == 0: return "rbp" - if string.strcmp(attr_name, "CLOBBER_RSP") == 0: return "rsp" - if string.strcmp(attr_name, "CLOBBER_R8") == 0: return "r8" - if string.strcmp(attr_name, "CLOBBER_R9") == 0: return "r9" - if string.strcmp(attr_name, "CLOBBER_R10") == 0: return "r10" - if string.strcmp(attr_name, "CLOBBER_R11") == 0: return "r11" - if string.strcmp(attr_name, "CLOBBER_R12") == 0: return "r12" - if string.strcmp(attr_name, "CLOBBER_R13") == 0: return "r13" - if string.strcmp(attr_name, "CLOBBER_R14") == 0: return "r14" - if string.strcmp(attr_name, "CLOBBER_R15") == 0: return "r15" - if string.strcmp(attr_name, "CLOBBER_EAX") == 0: return "eax" - if string.strcmp(attr_name, "CLOBBER_EBX") == 0: return "ebx" - if string.strcmp(attr_name, "CLOBBER_ECX") == 0: return "ecx" - if string.strcmp(attr_name, "CLOBBER_EDX") == 0: return "edx" - if string.strcmp(attr_name, "CLOBBER_ESI") == 0: return "esi" - if string.strcmp(attr_name, "CLOBBER_EDI") == 0: return "edi" - if string.strcmp(attr_name, "CLOBBER_DX") == 0: return "dx" - if string.strcmp(attr_name, "CLOBBER_AX") == 0: return "ax" - if string.strcmp(attr_name, "CLOBBER_CX") == 0: return "cx" - if string.strcmp(attr_name, "CLOBBER_SI") == 0: return "si" - if string.strcmp(attr_name, "CLOBBER_DI") == 0: return "di" - - # Output 输出约束 - if string.strcmp(attr_name, "OUTPUT_REG") == 0: return "=r" - if string.strcmp(attr_name, "OUTPUT_MEM") == 0: return "=m" - if string.strcmp(attr_name, "OUTPUT_EAX") == 0: return "=a" - if string.strcmp(attr_name, "OUTPUT_EBX") == 0: return "=b" - if string.strcmp(attr_name, "OUTPUT_ECX") == 0: return "=c" - if string.strcmp(attr_name, "OUTPUT_EDX") == 0: return "=d" - if string.strcmp(attr_name, "OUTPUT_ESI") == 0: return "=S" - if string.strcmp(attr_name, "OUTPUT_EDI") == 0: return "=D" - if string.strcmp(attr_name, "OUTPUT_RAX") == 0: return "=a" - if string.strcmp(attr_name, "OUTPUT_RBX") == 0: return "=b" - if string.strcmp(attr_name, "OUTPUT_RCX") == 0: return "=c" - if string.strcmp(attr_name, "OUTPUT_RDX") == 0: return "=d" - if string.strcmp(attr_name, "OUTPUT_RSI") == 0: return "=S" - if string.strcmp(attr_name, "OUTPUT_RDI") == 0: return "=D" - - # Input/Register 输入约束 - if string.strcmp(attr_name, "REG_ANY") == 0: return "r" - if string.strcmp(attr_name, "REG_EAX") == 0: return "a" - if string.strcmp(attr_name, "REG_EBX") == 0: return "b" - if string.strcmp(attr_name, "REG_ECX") == 0: return "c" - if string.strcmp(attr_name, "REG_EDX") == 0: return "d" - if string.strcmp(attr_name, "REG_ESI") == 0: return "S" - if string.strcmp(attr_name, "REG_EDI") == 0: return "D" - if string.strcmp(attr_name, "REG_RAX") == 0: return "a" - if string.strcmp(attr_name, "REG_RBX") == 0: return "b" - if string.strcmp(attr_name, "REG_RCX") == 0: return "c" - if string.strcmp(attr_name, "REG_RDX") == 0: return "d" - if string.strcmp(attr_name, "REG_RSI") == 0: return "S" - if string.strcmp(attr_name, "REG_RDI") == 0: return "D" - - if string.strcmp(attr_name, "INPUT_REG") == 0: return "r" - if string.strcmp(attr_name, "INPUT_MEM") == 0: return "m" - if string.strcmp(attr_name, "INPUT_EAX") == 0: return "a" - if string.strcmp(attr_name, "INPUT_EBX") == 0: return "b" - if string.strcmp(attr_name, "INPUT_ECX") == 0: return "c" - if string.strcmp(attr_name, "INPUT_EDX") == 0: return "d" - if string.strcmp(attr_name, "INPUT_ESI") == 0: return "S" - if string.strcmp(attr_name, "INPUT_EDI") == 0: return "D" - if string.strcmp(attr_name, "INPUT_RAX") == 0: return "a" - if string.strcmp(attr_name, "INPUT_RBX") == 0: return "b" - if string.strcmp(attr_name, "INPUT_RCX") == 0: return "c" - if string.strcmp(attr_name, "INPUT_RDX") == 0: return "d" - if string.strcmp(attr_name, "INPUT_RSI") == 0: return "S" - if string.strcmp(attr_name, "INPUT_RDI") == 0: return "D" - - return "" - - def _resolve_asm_descr(self, pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr) -> str: - """递归解析约束表达式,返回约束字符串""" - if node is None: - return "" - - k: int = node.kind() - - # BinOp with BitOr: 拼接左右 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if bop.op == ast.OpKind.BitOr: - left_str: str = self._resolve_asm_descr(pool, bop.left) - right_str: str = self._resolve_asm_descr(pool, bop.right) - llen: t.CSizeT = string.strlen(left_str) - rlen: t.CSizeT = string.strlen(right_str) - buf: str = pool.alloc(llen + rlen + 1) - if buf is None: - return "" - string.strcpy(buf, left_str) - for i in range(rlen): - buf[llen + i] = right_str[i] - buf[llen + rlen] = '\0' - return buf - return "" - - # Attribute: t.ASM_DESCR.XXX 或 t.XXX - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - # t.ASM_DESCR.XXX - if at.value is not None and at.value.kind() == ast.ASTKind.Attribute: - inner: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value) - if inner.value is not None and inner.value.kind() == ast.ASTKind.Name: - mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner.value) - if mod_nm.id is not None and string.strcmp(mod_nm.id, "t") == 0: - if inner.attr is not None and string.strcmp(inner.attr, "ASM_DESCR") == 0: - return self._resolve_register(at.attr) - # t.XXX 简化形式 - if at.value is not None and at.value.kind() == ast.ASTKind.Name: - mod_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if mod_nm2.id is not None and string.strcmp(mod_nm2.id, "t") == 0: - return self._resolve_register(at.attr) - return "" - - # Constant: 字符串常量 - if k == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - if cn.const_kind == ast.CONST_STR: - return cn.str_val - return "" - - return "" - - def _asm_get_operand(self, base: HandlesExprCall.AsmOperand | t.CPtr, - idx: int) -> HandlesExprCall.AsmOperand | t.CPtr: - """获取操作数数组中第 idx 个元素的指针""" - entry_size: t.CSizeT = HandlesExprCall.AsmOperand.__sizeof__() - entry_addr: t.CUInt64T = t.CUInt64T(base) + idx * entry_size - return (HandlesExprCall.AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - - def _asm_is_c_call(self, node: ast.Call | t.CPtr) -> str: - """检查 Call 节点是否是 c.XXX 调用,返回属性名或 None""" - if node is None or node.func is None: - return None - if node.func.kind() != ast.ASTKind.Attribute: - return None - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node.func) - if at.value is None or at.value.kind() != ast.ASTKind.Name: - return None - mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if mod_nm.id is None or string.strcmp(mod_nm.id, "c") != 0: - return None - return at.attr - - def _asm_add_operand(self, operands: HandlesExprCall.AsmOperand | t.CPtr, - count: int, - val: llvmlite.Value | t.CPtr, - constraint: str, - is_output: int) -> int: - """添加操作数到数组,返回新计数(失败返回原计数) - - 去重:f-string 模板内嵌的 AsmOut/AsmInp 与 out=/inp= 声明指向 - 同一变量时会重复收集(如 vrandom.vp 的 c.Asm(f"...{AsmOut(v)}", - out=[AsmOut(v)])),同一 (Value, IsOutput) 只保留第一个, - 避免约束数多于 asm 返回元素数(llc: output constraints mismatch)。 - """ - if count >= ASM_MAX_OPERANDS: - return count - if val is not None: - for ei in range(count): - eop: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, ei) - if eop is not None and eop.Value == val and eop.IsOutput == is_output: - return count - op: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, count) - op.Value = val - op.Constraint = constraint - op.IsOutput = is_output - return count + 1 - - def translate_c_asm(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译 c.Asm 内联汇编,返回结果 Value(无输出时返回 None)""" - if cl is None: - return None - - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None or len(cargs) < 1: - return None - - # 分配操作数数组 - operand_size: t.CSizeT = HandlesExprCall.AsmOperand.__sizeof__() - operands: HandlesExprCall.AsmOperand | t.CPtr = pool.alloc(operand_size * ASM_MAX_OPERANDS) - if operands is None: - return None - string.memset(operands, 0, operand_size * ASM_MAX_OPERANDS) - - # 分配 clobber 名数组 - clobbers: str | t.CPtr = pool.alloc(8 * ASM_MAX_OPERANDS) - if clobbers is None: - return None - string.memset(clobbers, 0, 8 * ASM_MAX_OPERANDS) - - # 分配 asm 文本缓冲区 - asm_text: str = pool.alloc(ASM_TEXT_BUF_SIZE) - if asm_text is None: - return None - asm_text[0] = '\0' - - operand_count: int = 0 - clobber_count: int = 0 - fv_count: int = 0 - - # 分配 fv 索引数组(记录每个 FormattedValue 对应的操作数原始索引) - fv_orig_indices: int | t.CPtr = pool.alloc(4 * ASM_MAX_OPERANDS) - if fv_orig_indices is None: - return None - string.memset(fv_orig_indices, 0, 4 * ASM_MAX_OPERANDS) - - # ============================================================ - # 1. 解析汇编模板(JoinedStr 或 Constant)— 第一遍:收集操作数 - # 不生成 asm 文本(占位符 $N 需在重排后才能确定编号) - # ============================================================ - tmpl_node: ast.AST | t.CPtr = cargs.get(0) - if tmpl_node is not None: - tk: int = tmpl_node.kind() - - if tk == ast.ASTKind.JoinedStr: - js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node) - jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values - if jvalues is not None: - jvlen: t.CSizeT = len(jvalues) - for vi in range(jvlen): - part: ast.AST | t.CPtr = jvalues.get(vi) - if part is None: - continue - pk: int = part.kind() - - if pk == ast.ASTKind.FormattedValue: - fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part) - fexpr: ast.AST | t.CPtr = fv.value - if fexpr is None or fexpr.kind() != ast.ASTKind.Call: - continue - fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr) - attr_nm: str = self._asm_is_c_call(fcall) - if attr_nm is None: - continue - - is_out: int = 0 - if string.strcmp(attr_nm, "AsmOut") == 0: - is_out = 1 - elif string.strcmp(attr_nm, "AsmInp") == 0: - is_out = 0 - else: - continue - - fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args - if fargs is None or len(fargs) < 1: - continue - - val_node: ast.AST | t.CPtr = fargs.get(0) - cons_str: str = "" - if len(fargs) >= 2: - cons_str = self._resolve_asm_descr(pool, fargs.get(1)) - - if is_out != 0: - # 输出:获取变量 alloca - if val_node is None or val_node.kind() != ast.ASTKind.Name: - continue - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node) - if nm.id is None: - continue - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is None: - continue - operand_count = self._asm_add_operand( - operands, operand_count, alloca, cons_str, 1) - else: - # 输入:翻译值 - ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, val_node, None, 0, trans) - if ival is None: - continue - operand_count = self._asm_add_operand( - operands, operand_count, ival, cons_str, 0) - - # 记录 fv 的原始操作数索引 - if fv_count < ASM_MAX_OPERANDS: - fv_orig_indices[fv_count] = operand_count - 1 - fv_count += 1 - - # ============================================================ - # 2. 解析关键字参数 out=/inp=/op=/clobber= - # ============================================================ - keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords - if keywords is not None: - kwlen: t.CSizeT = len(keywords) - for ki in range(kwlen): - kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) - if kw is None or kw.arg is None or kw.value is None: - continue - kwk: int = kw.value.kind() - - if string.strcmp(kw.arg, "out") == 0: - # 输出操作数列表 - if kwk != ast.ASTKind.List: - continue - out_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) - out_elts: list[ast.AST | t.CPtr] | t.CPtr = out_lst.elts - if out_elts is None: - continue - oelen: t.CSizeT = len(out_elts) - for oi in range(oelen): - oelt: ast.AST | t.CPtr = out_elts.get(oi) - if oelt is None or oelt.kind() != ast.ASTKind.Call: - continue - ocall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(oelt) - oattr: str = self._asm_is_c_call(ocall) - if oattr is None or string.strcmp(oattr, "AsmOut") != 0: - continue - oargs: list[ast.AST | t.CPtr] | t.CPtr = ocall.args - if oargs is None or len(oargs) < 1: - continue - oval_node: ast.AST | t.CPtr = oargs.get(0) - ocons: str = "" - if len(oargs) >= 2: - ocons = self._resolve_asm_descr(pool, oargs.get(1)) - if oval_node is None or oval_node.kind() != ast.ASTKind.Name: - continue - onm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(oval_node) - if onm.id is None: - continue - oalloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, onm.id) - if oalloca is None: - continue - operand_count = self._asm_add_operand( - operands, operand_count, oalloca, ocons, 1) - - elif string.strcmp(kw.arg, "inp") == 0 or string.strcmp(kw.arg, "inputs") == 0: - # 输入操作数列表 - if kwk != ast.ASTKind.List: - continue - in_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) - in_elts: list[ast.AST | t.CPtr] | t.CPtr = in_lst.elts - if in_elts is None: - continue - ielen: t.CSizeT = len(in_elts) - for ii in range(ielen): - ielt: ast.AST | t.CPtr = in_elts.get(ii) - if ielt is None or ielt.kind() != ast.ASTKind.Call: - continue - icall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(ielt) - iattr: str = self._asm_is_c_call(icall) - if iattr is None or string.strcmp(iattr, "AsmInp") != 0: - continue - iargs: list[ast.AST | t.CPtr] | t.CPtr = icall.args - if iargs is None or len(iargs) < 1: - continue - ival_node: ast.AST | t.CPtr = iargs.get(0) - icons: str = "" - if len(iargs) >= 2: - icons = self._resolve_asm_descr(pool, iargs.get(1)) - ival2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, ival_node, None, 0, trans) - if ival2 is None: - continue - operand_count = self._asm_add_operand( - operands, operand_count, ival2, icons, 0) - - elif string.strcmp(kw.arg, "op") == 0 or string.strcmp(kw.arg, "clobber") == 0: - # 破坏列表 - if kwk != ast.ASTKind.List: - continue - cl_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) - cl_elts: list[ast.AST | t.CPtr] | t.CPtr = cl_lst.elts - if cl_elts is None: - continue - clen: t.CSizeT = len(cl_elts) - for ci in range(clen): - celt: ast.AST | t.CPtr = cl_elts.get(ci) - if celt is None: - continue - cstr: str = self._resolve_asm_descr(pool, celt) - if cstr is None or cstr[0] == '\0': - continue - if clobber_count < ASM_MAX_OPERANDS: - cl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8 - cl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(cl_addr, t.CPtr)) - cl_ptr[0] = cstr - clobber_count += 1 - - # ============================================================ - # 3. 解析第二个位置参数作为破坏列表 - # ============================================================ - if len(cargs) >= 2: - pos_node: ast.AST | t.CPtr = cargs.get(1) - if pos_node is not None and pos_node.kind() == ast.ASTKind.List: - pos_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(pos_node) - pos_elts: list[ast.AST | t.CPtr] | t.CPtr = pos_lst.elts - if pos_elts is not None: - plen: t.CSizeT = len(pos_elts) - for pi in range(plen): - pelt: ast.AST | t.CPtr = pos_elts.get(pi) - if pelt is None: - continue - pstr: str = self._resolve_asm_descr(pool, pelt) - if pstr is None or pstr[0] == '\0': - continue - if clobber_count < ASM_MAX_OPERANDS: - pcl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8 - pcl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(pcl_addr, t.CPtr)) - pcl_ptr[0] = pstr - clobber_count += 1 - - # ============================================================ - # 4. 统计输出/输入数量,确定返回类型 - # ============================================================ - output_count: int = 0 - input_count: int = 0 - first_output_idx: int = -1 - for oi2 in range(operand_count): - op2: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi2) - if op2.IsOutput != 0: - if first_output_idx < 0: - first_output_idx = oi2 - output_count += 1 - else: - input_count += 1 - - # 确定返回类型 - # 多输出(如 vrandom rdrand*_step 的 val+ok 两个 AsmOut)返回 - # 匿名 struct {ty1, ty2, ...},元素数 = 输出操作数(LLVM asm - # 要求输出约束数 = 返回 struct 元素数)。 - ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) - if output_count > 0 and first_output_idx >= 0: - if output_count > 1: - out_pn_head: llvmlite.ParamNode | t.CPtr = None - out_pn_last: llvmlite.ParamNode | t.CPtr = None - out_pn_n: int = 0 - for oi5 in range(operand_count): - op5: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi5) - if op5 is None or op5.IsOutput == 0: - continue - if op5.Value is not None and op5.Value.Ty is not None \ - and op5.Value.Ty.Pointee is not None: - pn5: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node( - pool, op5.Value.Ty.Pointee) - if pn5 is not None: - if out_pn_head is None: - out_pn_head = pn5 - else: - out_pn_last.Next = pn5 - out_pn_last = pn5 - out_pn_n += 1 - if out_pn_head is not None and out_pn_n > 0: - ret_ty = llvmlite.Struct(pool, out_pn_head, out_pn_n, None) - else: - HandlesType.fatal_error( - cl, "c.Asm 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError") - ret_ty = llvmlite.Int32(pool) - else: - out_op: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, first_output_idx) - if out_op.Value is not None and out_op.Value.Ty is not None: - # alloca 的类型是指针,Pointee 是目标类型 - if out_op.Value.Ty.Pointee is not None: - ret_ty = out_op.Value.Ty.Pointee - else: - HandlesType.fatal_error( - cl, "c.Asm 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError") - ret_ty = llvmlite.Int32(pool) - - # 判断 void — 直接基于 output_count 判断,避免 match 类型匹配问题 - is_void: int = 1 - if output_count > 0: - is_void = 0 - - # ============================================================ - # 4.5 重排操作数:输出在前,输入在后(LLVM IR 要求) - # - # new_order[new_idx] = orig_idx — 新位置对应原索引 - # orig_to_new[orig_idx] = new_idx — 原索引映射到新位置(用于占位符编号) - # ============================================================ - new_order: int | t.CPtr = pool.alloc(4 * (operand_count + 1)) - orig_to_new: int | t.CPtr = pool.alloc(4 * (operand_count + 1)) - if new_order is None or orig_to_new is None: - return None - - new_idx: int = 0 - # 先放输出 - for oi3 in range(operand_count): - op3: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi3) - if op3.IsOutput != 0: - new_order[new_idx] = oi3 - new_idx += 1 - # 再放输入 - for oi4 in range(operand_count): - op4: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi4) - if op4.IsOutput == 0: - new_order[new_idx] = oi4 - new_idx += 1 - # 建立映射 orig -> new - for ni2 in range(operand_count): - orig_to_new[new_order[ni2]] = ni2 - - # ============================================================ - # 4.6 生成汇编文本(第二遍遍历 f-string,用重排后的索引生成占位符) - # 项目约定使用 Intel 语法,通过 IR 的 inteldialect 关键字启用 - # ============================================================ - if tmpl_node is not None: - tk2: int = tmpl_node.kind() - if tk2 == ast.ASTKind.JoinedStr: - js2: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node) - jvalues2: list[ast.AST | t.CPtr] | t.CPtr = js2.values - if jvalues2 is not None: - jvlen2: t.CSizeT = len(jvalues2) - fv_fi: int = 0 - for vi2 in range(jvlen2): - part2: ast.AST | t.CPtr = jvalues2.get(vi2) - if part2 is None: - continue - pk2: int = part2.kind() - if pk2 == ast.ASTKind.Constant: - cn3: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part2) - if cn3.const_kind == ast.CONST_STR and cn3.str_val is not None: - self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn3.str_val) - elif pk2 == ast.ASTKind.FormattedValue: - if fv_fi < fv_count: - orig_idx2: int = fv_orig_indices[fv_fi] - new_idx2: int = orig_to_new[orig_idx2] - ph_buf2: str = pool.alloc(16) - if ph_buf2 is not None: - viperlib.snprintf(ph_buf2, 16, "$%d", new_idx2) - self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, ph_buf2) - fv_fi += 1 - elif tk2 == ast.ASTKind.Constant: - cn4: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(tmpl_node) - if cn4.const_kind == ast.CONST_STR and cn4.str_val is not None: - self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn4.str_val) - - # ============================================================ - # 5. 构建约束字符串(按重排后的顺序:输出在前,输入在后) - # ============================================================ - const_buf: str = pool.alloc(ASM_CONST_BUF_SIZE) - if const_buf is None: - return None - const_buf[0] = '\0' - - first_const: int = 1 - for ci2 in range(operand_count): - orig_i: int = new_order[ci2] - cop: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, orig_i) - cons_val: str = cop.Constraint - if cons_val is None: - cons_val = "r" - - if first_const == 0: - self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",") - first_const = 0 - - if cop.IsOutput != 0: - # 输出约束:确保以 = 开头 - if cons_val[0] != '=': - self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "=") - self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val) - else: - self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val) - - # 追加 clobber 约束 ~{name} - for cidx in range(clobber_count): - cl_addr2: t.CUInt64T = t.CUInt64T(clobbers) + cidx * 8 - cname: str = (str | t.CPtr)(t.CVoid(cl_addr2, t.CPtr))[0] - if cname is None or cname[0] == '\0': - continue - if first_const == 0: - self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",") - first_const = 0 - self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "~{") - self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cname) - self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "}") - - # ============================================================ - # 6. 构建参数列表文本(仅输入操作数) - # ============================================================ - args_buf: str = pool.alloc(ASM_ARGS_BUF_SIZE) - if args_buf is None: - return None - args_buf[0] = '\0' - - first_arg: int = 1 - for ai3 in range(operand_count): - orig_i2: int = new_order[ai3] - aop: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, orig_i2) - if aop.IsOutput != 0: - continue - aval: llvmlite.Value | t.CPtr = aop.Value - if aval is None or aval.Ty is None or aval.Name is None: - continue - - if first_arg == 0: - self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ", ") - first_arg = 0 - - # 类型文本 - ty_buf: str = pool.alloc(64) - if ty_buf is not None: - ty_buf[0] = '\0' - llvmlite.TypePrint(ty_buf, 64, aval.Ty, pool) - self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ty_buf) - self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, " ") - self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, aval.Name) - - # ============================================================ - # 7. 转义汇编文本 - # ============================================================ - escaped_asm: str = self._asm_escape_for_ir(pool, asm_text) - if escaped_asm is None: - return None - - # ============================================================ - # 8. 生成 IR 行并发射 - # ============================================================ - line: str = pool.alloc(ASM_LINE_BUF_SIZE) - if line is None: - return None - line[0] = '\0' - - ssa_name: str = None - if is_void == 0: - ssa_name = pool.alloc(16) - if ssa_name is not None: - viperlib.snprintf(ssa_name, 16, "%%%d", builder.Counter) - builder.Counter += 1 - - # 获取返回类型文本 - ret_ty_buf: str = pool.alloc(64) - if ret_ty_buf is not None: - ret_ty_buf[0] = '\0' - llvmlite.TypePrint(ret_ty_buf, 64, ret_ty, pool) - - if is_void == 1: - viperlib.snprintf(line, ASM_LINE_BUF_SIZE, - "call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)", - ret_ty_buf, escaped_asm, const_buf, args_buf) - else: - viperlib.snprintf(line, ASM_LINE_BUF_SIZE, - "%s = call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)", - ssa_name, ret_ty_buf, escaped_asm, const_buf, args_buf) - - # 发射 IR 到当前块 - llvmlite.block_append_text(pool, builder.CurBlock, line) - - # ============================================================ - # 9. 处理输出:存储结果到输出变量 - # ============================================================ - if is_void == 0 and first_output_idx >= 0: - result_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, ret_ty, ssa_name) - out_emit_idx: int = 0 - for oi_out in range(operand_count): - orig_o: int = new_order[oi_out] - oo: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, orig_o) - if oo is None or oo.IsOutput == 0: - continue - if output_count > 1: - # 多输出:extractvalue 取第 out_emit_idx 个元素后 store - if oo.Value is not None and oo.Value.Ty is not None \ - and oo.Value.Ty.Pointee is not None: - ev_name: str = pool.alloc(32) - ev_line: str = pool.alloc(ASM_LINE_BUF_SIZE) - if ev_name is not None and ev_line is not None: - # ssa_name 形如 "%N"(纯数字 ID),构造唯一名 - # "%asm.N.e{i}"(字母开头,避免 %N.e{i} 被解析为 - # 数字 ID + 非法后缀导致 "expected '=' after id") - viperlib.snprintf(ev_name, 32, "%%asm.%s.e%d", ssa_name + 1, out_emit_idx) - viperlib.snprintf(ev_line, ASM_LINE_BUF_SIZE, - "%s = extractvalue %s %s, %d", - ev_name, ret_ty_buf, ssa_name, out_emit_idx) - llvmlite.block_append_text(pool, builder.CurBlock, ev_line) - ev_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, oo.Value.Ty.Pointee, ev_name) - llvmlite.build_store(builder, ev_val, oo.Value) - else: - if oo.Value is not None: - llvmlite.build_store(builder, result_val, oo.Value) - out_emit_idx += 1 - return result_val - - return None - - def translate_c_llvmir(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.LLVMIR 内联 LLVM IR:无返回值,直接嵌入原始 IR 文本 - - 不做指令解析,模板文本(c.LInp/c.LOut 替换后)用 block_append_text - 嵌入当前基本块。c.LOut 变量由唯一 SSA 寄存器 %llvmirN 接收结果, - 嵌入后自动追加 store 写回变量 alloca。返回 None(无返回值)。 - """ - if cl is None or builder is None or pool is None or trans is None: - return None - - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None or len(cargs) < 1: - HandlesType.fatal_error(cl, "c.LLVMIR 缺少模板参数", "TypeError") - - # LOut 写回记录(alloca 指针 + 寄存器名),最多 LLVMIR_MAX_OPS 个 - out_alloca: t.CSizeT | t.CPtr = pool.alloc(8 * LLVMIR_MAX_OPS) - out_regname: t.CSizeT | t.CPtr = pool.alloc(8 * LLVMIR_MAX_OPS) - if out_alloca is None or out_regname is None: - return None - string.memset(out_alloca, 0, 8 * LLVMIR_MAX_OPS) - string.memset(out_regname, 0, 8 * LLVMIR_MAX_OPS) - out_count: int = 0 - - # 模板文本缓冲区 - text: str = pool.alloc(LLVMIR_TEMPLATE_BUF) - if text is None: - return None - text[0] = '\0' - - # ============================================================ - # 1. 解析 IR 模板(JoinedStr 或 Constant)— 替换 LInp/LOut/表达式为值文本 - # ============================================================ - first_arg: ast.AST | t.CPtr = cargs.get(0) - if first_arg is None: - return None - - tk: int = first_arg.kind() - - if tk == ast.ASTKind.JoinedStr: - js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(first_arg) - jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values - if jvalues is not None: - jvlen: t.CSizeT = len(jvalues) - for vi in range(jvlen): - part: ast.AST | t.CPtr = jvalues.get(vi) - if part is None: - continue - pk: int = part.kind() - - if pk == ast.ASTKind.Constant: - # 字符串字面量片段 - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part) - if cn.str_val is not None: - self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, cn.str_val) - - elif pk == ast.ASTKind.FormattedValue: - fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part) - fexpr: ast.AST | t.CPtr = fv.value - if fexpr is None: - continue - # 检测 c.LInp / c.LOut - if fexpr.kind() == ast.ASTKind.Call: - fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr) - attr_nm: str = self._asm_is_c_call(fcall) - if attr_nm is not None: - fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args - if fargs is None or len(fargs) < 1: - continue - val_node: ast.AST | t.CPtr = fargs.get(0) - - if string.strcmp(attr_nm, "LInp") == 0: - # 输入操作数:翻译值,替换为 LLVM 值引用文本(%x 或常量文本) - inp_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, val_node, None, 0, trans) - if inp_val is not None and inp_val.Name is not None: - self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, inp_val.Name) - - elif string.strcmp(attr_nm, "LOut") == 0: - # 输出操作数:为变量分配唯一 SSA 寄存器 %llvmirN, - # 记录写回(模板嵌入后 store 到变量 alloca) - if val_node is not None and val_node.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node) - if nm.id is not None: - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, nm.id) - if alloca is None or out_count >= LLVMIR_MAX_OPS: - HandlesType.fatal_error( - fcall, - f"c.LOut 变量 '{nm.id}' 未定义或输出数超过 {LLVMIR_MAX_OPS}", - "TypeError") - self.LLVMIRRegSeq += 1 - reg_buf: str = pool.alloc(32) - if reg_buf is not None: - viperlib.snprintf(reg_buf, 32, "%%llvmir_%d", self.LLVMIRRegSeq) - self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, reg_buf) - out_alloca[out_count] = t.CSizeT(alloca) - out_regname[out_count] = t.CSizeT(reg_buf) - out_count += 1 - continue - # 非 c.LInp/c.LOut 的 f-string 表达式:翻译值并嵌入值文本 - ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, fexpr, None, 0, trans) - if ival is not None and ival.Name is not None: - self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, ival.Name) - - elif tk == ast.ASTKind.Constant: - cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(first_arg) - if cn2.str_val is not None: - # 裸 strcpy 无界:模板常量串 ≥ LLVMIR_TEMPLATE_BUF 会越界写 pool 块, - # 改用与 JoinedStr 分支一致的有界追加 - self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, cn2.str_val) - - # ============================================================ - # 2. 直接嵌入模板文本(不做指令解析)+ LOut 写回 - # ============================================================ - llvmlite.block_append_text(pool, builder.CurBlock, text) - - # LOut 写回: store %llvmirN, * %var - oi: int - for oi in range(out_count): - oa: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(t.CVoid(out_alloca[oi], t.CPtr)) - rn: str = (str)(t.CVoid(out_regname[oi], t.CPtr)) - if oa is None or oa.Ty is None or oa.Ty.Pointee is None or rn is None: - continue - reg_val: llvmlite.Value | t.CPtr = llvmlite.new_value(pool) - if reg_val is None: - continue - reg_val.Ty = oa.Ty.Pointee - reg_val.Name = rn - reg_val.IsConst = 0 - llvmlite.build_store(builder, reg_val, oa) - - return None # ============================================================ # _apply_struct_defaults — 应用结构体字段的默认值 @@ -2243,6 +568,19 @@ class CallGenMixin: default_val = HandlesExpr.coerce_to_type(builder, default_val, fe.Ty, fe.DefaultVal) llvmlite.build_store(builder, default_val, field_ptr) + # ============================================================ + # _translate_struct_ctor — 结构体构造函数 Point(10, 20) + # + # 生成: + # %tmp = alloca {i32, i32} + # store {i32, i32} zeroinitializer, {i32, i32}* %tmp + # %f0 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 0 + # store i32 10, i32* %f0 + # %f1 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 1 + # store i32 20, i32* %f1 + # %result = load {i32, i32}, {i32, i32}* %tmp + # ============================================================ + # ============================================================ # _translate_struct_ctor — 结构体构造函数 Point(10, 20) # @@ -2488,6 +826,25 @@ class CallGenMixin: # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load return tmp + # ============================================================ + # _translate_renum_construct — REnum 变体构造函数 + # + # 语法: ClassName.VariantName(args...) + # 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体,__tag=0,_p1=1 + # + # 生成 IR: + # %tmp = alloca {i32, i32, ...} ; REnum 类型 + # store zeroinitializer, %tmp ; 清零 + # %tag_ptr = gep %tmp, 0, 0 ; __tag 字段 + # store i32 , %tag_ptr ; 写入 tag + # %p1_ptr = gep %tmp, 0, 1 ; _p1 字段 + # store , %p1_ptr ; 写入 payload[0] + # ... (更多 payload 字段) + # return %tmp ; 返回指针 + # + # 对应 TPC 的 _HandleREnumConstructLlvm + # ============================================================ + # ============================================================ # _translate_renum_construct — REnum 变体构造函数 # @@ -2600,6 +957,25 @@ class CallGenMixin: # 返回指针(与 _translate_struct_ctor 一致,赋值时由 coerce_to_type 决定是否 load) return tmp + # ============================================================ + # _do_virtual_call — 通过虚表间接调用虚方法 + # + # IR 模式: + # %1 = getelementptr StructTy, StructTy* %self, i32 0, i32 0 ; i8** + # %2 = load i8*, i8** %1 ; i8* (vtable ptr) + # %3 = bitcast i8* %2 to {i8*, ...}* ; vtable typed ptr + # %4 = getelementptr {i8*, ...}, {i8*, ...}* %3, i32 0, i32 N ; i8** + # %5 = load i8*, i8** %4 ; i8* (func ptr) + # %6 = bitcast i8* %5 to RetTy(Params)* ; func typed ptr + # call RetTy %6(Params %self, ...) + # + # 参数: + # args_head — 已构建好的参数链表头(self_ptr 为首节点) + # args_count — 参数总数(含 self) + # found_func — 方法对应的 Function 对象(用于推断函数签名) + # ret_ty — 返回类型 + # ============================================================ + # ============================================================ # _do_virtual_call — 通过虚表间接调用虚方法 # @@ -2771,6 +1147,13 @@ class CallGenMixin: # 12. 间接调用 return llvmlite.build_call_indirect(builder, func_ptr, args_head, args_count, ret_ty) + # ============================================================ + # _call_method_on_ptr — 在结构体指针上调用方法 + # + # 辅助函数:构造 ClassName.method_name 调用,self 指针为首个参数 + # 如果该方法在虚表中,则走虚方法分发路径(间接调用) + # ============================================================ + # ============================================================ # _call_method_on_ptr — 在结构体指针上调用方法 # @@ -3123,494 +1506,6 @@ class CallGenMixin: # 当 found_func 为 None(stub 未注入或跨模块调用)时, # 在当前模块中创建函数声明,避免 llc 报 undefined value。 # ============================================================ - def _ensure_method_declare(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - call_name: str, - ret_ty: llvmlite.LLVMType | t.CPtr, - param_head: llvmlite.ParamNode | t.CPtr, - param_count: int): - """为跨模块方法调用创建 declare 声明 - - 若模块中已存在同名 declare 且参数数量较少(例如 File.__init__ 的 - stub 仅 3 个参数,而实际调用传入 4 个),则向现有 declare 追加缺失 - 参数,避免 llc 报 `argument invalid for parameter type` 之类的错误。 - 已存在的 define 不修改(其参数由定义决定)。 - """ - if pool is None or mod is None or call_name is None: - return - # 检查模块中是否已有同名函数(declare 或 define) - existing: llvmlite.Function | t.CPtr = mod.FuncHead - while existing is not None: - if existing.Name is not None: - if string.strcmp(existing.Name, call_name) == 0: - # 已存在:仅当是 declare 且参数数量不足时追加缺失参数 - if existing.IsDeclared == 1: - # 变长函数(*args,IsVarArg=1)不追加参数:多余实参由 - # 变参机制(...)承接,追加有类型参数会导致调用侧把变参 - # 强转为追加的类型(如 i8 → i64),%d/%x 等格式读错。 - if existing.IsVarArg == 1: - return - # 遍历现有参数链表计数(避免依赖 GSList.Count 字段的类型推断) - cur_count: int = 0 - cur_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(existing) - while cur_p is not None: - cur_count += 1 - cur_p = cur_p.Next - # 只追加缺失的参数(cur_count < param_count 时) - if cur_count < param_count: - # 定位到 param_head 的第 cur_count 个节点开始追加 - pnode2: llvmlite.ParamNode | t.CPtr = param_head - pi2: int = 0 - # 跳过已有的 cur_count 个参数 - while pnode2 is not None and pi2 < cur_count: - pnode2 = pnode2.Next - pi2 += 1 - # 追加剩余参数 - while pnode2 is not None and pi2 < param_count: - if pnode2.Ty is not None: - param2: llvmlite.Param | t.CPtr = llvmlite.new_param(pool, pnode2.Ty, None) - if param2 is not None: - llvmlite.function_add_param(existing, param2) - pnode2 = pnode2.Next - pi2 += 1 - return - existing = existing.Next - # 创建函数声明 - func: llvmlite.Function | t.CPtr = llvmlite.new_function(pool, call_name, ret_ty) - if func is None: - return - func.IsDeclared = 1 - # 添加参数(declare 中参数名无意义,设为 None 只输出类型) - pnode: llvmlite.ParamNode | t.CPtr = param_head - pi: int = 0 - while pnode is not None and pi < param_count: - if pnode.Ty is not None: - param: llvmlite.Param | t.CPtr = llvmlite.new_param(pool, pnode.Ty, None) - if param is not None: - llvmlite.function_add_param(func, param) - pnode = pnode.Next - pi += 1 - llvmlite.module_add_function(mod, func) - - # ============================================================ - # _lookup_method_ret_ty_via_vpi - 从 vpi stub 返回注解缓存精确获取方法返回类型 - # - # 方法定义处(.vpi stub)的返回注解(如 json.JsonValue._pool_alloc → - # "str")在 stub 注入时由 VpiReader 缓存(_cache_vpi_return_annots_text)。 - # 此函数按 模块SHA1 + 类名 + 方法名 查缓存并纯字符串解析为 LLVMType。 - # 无需硬编码白名单——返回类型始终来自方法定义处。 - # ============================================================ - def _lookup_method_ret_ty_via_vpi(self, pool: memhub.MemBuddy | t.CPtr, - cls_sha1: str, - cls_name: str, - method_name: str) -> llvmlite.LLVMType | t.CPtr: - """从 vpi stub 返回注解缓存获取方法返回类型,未命中返回 None""" - if pool is None or cls_sha1 is None or method_name is None: - return None - # 函数内懒 import:VpiReader imports HandlesExprCall,顶层 import 会成环 - import lib.StubGen.VpiReader as VpiReader - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - # 按需加载:缓存未命中时直接读 {temp_dir}/{sha1[0:2]}/{sha1}.vpi - # 覆盖"模块自身翻译时 stub 尚未注入"(同模块方法调用,定义在后)的场景 - if self.TempDir is not None and self.TempDirLen > 0: - VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, self.TempDir) - annot: str = VpiReader._lookup_vpi_ret_annot(cls_sha1, cls_name, method_name) - if annot is None: - return None - return VpiReader._resolve_vpi_ret_annot_str(pool, annot, i32_ty, i8_ptr_ty) - - # ============================================================ - # _special_method_ret_ty - 编译器内置特殊方法的固定返回类型 - # - # __before_init__ / __init__:编译器生成/约定返回 void - # __new__:返回 Ptr(StructTy)(存储空间指针) - # - # 这些方法不存在于源码(vpi stub 无条目),跨模块调用时 - # found_func/text.ll/vpi 缓存必然未命中,但返回类型是编译器 - # 确定性语义(与 HandlesClassDef._translate_method 3543-3548 一致), - # 在此直接固定,不触发 fail-fast 误报。非特殊方法返回 None。 - # ============================================================ - def _special_method_ret_ty(self, pool: memhub.MemBuddy | t.CPtr, - class_name: str, - method_name: str) -> llvmlite.LLVMType | t.CPtr: - """编译器内置特殊方法的固定返回类型;非特殊返回 None""" - if pool is None or method_name is None: - return None - if string.strcmp(method_name, "__before_init__") == 0 or \ - string.strcmp(method_name, "__init__") == 0: - return llvmlite.Void(pool) - if string.strcmp(method_name, "__new__") == 0: - if class_name is not None: - sp_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name) - if sp_struct_ty is not None: - return llvmlite.Ptr(pool, sp_struct_ty) - return None - return None - - # ============================================================ - # _fail_method_ret_ty - 方法返回类型无法精确获取时 fail-fast - # - # 返回类型来源(按序):当前模块函数 → text.ll define → vpi stub 返回注解缓存。 - # 全部未命中时立即 ERROR + 错误堆栈终止,绝不按名推断白名单/静默默认 i32。 - # - # node: 调用点 AST 节点(可选,用于 ERROR 堆栈定位) - # ============================================================ - def _fail_method_ret_ty(self, method_name: str, - node: ast.AST | t.CPtr = None) -> llvmlite.LLVMType | t.CPtr: - """方法返回类型无法精确获取时 fail-fast(ERROR + 错误堆栈) - - 返回类型来源(按序):当前模块函数 → text.ll define → vpi stub 返回注解缓存。 - 全部未命中说明方法定义缺失或 stub 损坏,立即终止暴露,绝不静默默认 i32。 - """ - VLogger.error( - f"方法返回类型无法精确获取(函数/text.ll/vpi stub 均未命中): {method_name}", - "HandlesExprCall") - HandlesType.fatal_error( - node, - f"方法返回类型无法精确获取,默认 i32 会截断指针/i64: {method_name}", - "TypeError") - return None - - # ============================================================ - # SetTempDir - 设置 temp 目录路径 - # - # 在 Phase2.py 的 Phase A 翻译前调用,使 CallGenMixin - # 能够读取依赖模块的 text.ll 文件。 - # ============================================================ - def SetTempDir(self, temp_dir: str): - """设置 temp 目录路径(供跨模块方法返回类型查找使用)""" - self.TempDir = temp_dir - if temp_dir is not None: - self.TempDirLen = string.strlen(temp_dir) - else: - self.TempDirLen = 0 - - # ============================================================ - # _ParseLLVMRetTyStr - 将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType - # - # 从 define 行中提取的返回类型字符串(define 与 @ 之间的内容), - # 转换为 llvmlite.LLVMType 对象。 - # - # 支持的类型: - # void → Void - # i8/i16/i32/i64 → Int8/Int16/Int32/Int64 - # double → Double, float → Float - # 任何含 * 的类型 → Ptr(Int8)(通用指针,保留 64 位地址) - # - # Args: - # pool: 内存池 - # buf: 包含类型字符串的缓冲区 - # start: 类型字符串起始位置 - # end: 类型字符串结束位置(不含) - # - # Returns: - # LLVM 类型对象,或 None(无法解析) - # ============================================================ - def _ParseLLVMRetTyStr(self, pool: memhub.MemBuddy | t.CPtr, - buf: bytes, - start: t.CSizeT, - end: t.CSizeT) -> llvmlite.LLVMType | t.CPtr: - """将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType""" - if pool is None or buf is None or start >= end: - return None - - # 去除前导空白 - s: t.CSizeT = start - while s < end: - c: int = buf[s] - if c != ' ' and c != '\t': - break - s += 1 - # 去除尾部空白 - e: t.CSizeT = end - while e > s: - c2: int = buf[e - 1] - if c2 != ' ' and c2 != '\t': - break - e -= 1 - - ty_len: t.CSizeT = e - s - if ty_len == 0: - return None - - # struct 字面量 {T1, T2, ...}(tuple 打包返回类型,如 b2a_hqx -> - # tuple[str, t.CUnsignedShort] 编译为 {i8*, i16})。必须在 * 检查 - # 之前——否则 "{i8*, i16}" 内含 * 会被误判为 i8*(b2a_hqx 调用侧 - # 返回类型退化 i8* → HandlesAssign tuple 解包静默跳过 → free 未初始化 - # 指针崩溃,HashLibTest hqx 段)。 - if s < e and buf[s] == '{': - th_st: llvmlite.ParamNode | t.CPtr = None - tt_st: llvmlite.ParamNode | t.CPtr = None - tc_st: int = 0 - ps_st: t.CSizeT = s + 1 - while ps_st < e and buf[ps_st] != '}': - while ps_st < e and (buf[ps_st] == ' ' or buf[ps_st] == ','): - ps_st += 1 - if ps_st >= e or buf[ps_st] == '}': - break - es_st: t.CSizeT = ps_st - while ps_st < e and buf[ps_st] != ',' and buf[ps_st] != '}': - ps_st += 1 - ee_st: t.CSizeT = ps_st - if ee_st > es_st: - et_st: llvmlite.LLVMType | t.CPtr = self._ParseLLVMRetTyStr( - pool, buf, es_st, ee_st) - if et_st is None: - return None - en_st: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node( - pool, et_st) - if en_st is None: - return None - if th_st is None: - th_st = en_st - else: - llvmlite.paramnode_set_next(tt_st, en_st) - tt_st = en_st - tc_st += 1 - if th_st is None or tc_st == 0: - return None - st_ty_st: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, th_st, tc_st, None) - # 指针到 struct({i32, i8}*):返回 Ptr(Struct);纯 tuple 打包 - # ({i8*, i16})无尾部 *,返回 Struct 本身。 - if ps_st < e and buf[ps_st] == '*': - return llvmlite.Ptr(pool, st_ty_st) - return st_ty_st - - # 检查是否含 * (指针类型) → 返回 i8* (通用指针) - # 包括 i8*, i32*, %"name"*, { i32, i8 }* 等 - ci: t.CSizeT = s - while ci < e: - if buf[ci] == '*': - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - ci += 1 - - # void - if ty_len == 4 and string.strncmp(buf + s, "void", 4) == 0: - return llvmlite.Void(pool) - - # double - if ty_len == 6 and string.strncmp(buf + s, "double", 6) == 0: - return llvmlite.Double(pool) - - # float - if ty_len == 5 and string.strncmp(buf + s, "float", 5) == 0: - return llvmlite.Float(pool) - - # iN (i8, i16, i32, i64) - if ty_len >= 2 and buf[s] == 'i': - bits: int = 0 - di: t.CSizeT = s + 1 - valid: int = 1 - while di < e: - d: int = buf[di] - if d >= '0' and d <= '9': - bits = bits * 10 + (d - '0') - else: - valid = 0 - break - di += 1 - if valid != 0 and bits > 0: - if bits == 8: - return llvmlite.Int8(pool) - if bits == 16: - return llvmlite.Int16(pool) - if bits == 32: - return llvmlite.Int32(pool) - if bits == 64: - return llvmlite.Int64(pool) - - # 无法解析 - return None - - # ============================================================ - # _LookupMethodRetTyFromTextLL - 从依赖模块的 text.ll 查找方法返回类型 - # - # 读取 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll (level=1),搜索 - # define 行中包含 "{sha1}.{class_name}.{method_name}" 的函数, - # 提取返回类型并转换为 llvmlite.LLVMType。 - # - # 解决问题: 旧实现 _infer_method_ret_ty(已移除)默认返回 i32,导致指针返回值 - # 被 inttoptr 截断为 32 位(coerce_to_type line 238-239)。 - # 本函数从 text.ll 获取实际返回类型,避免截断。 - # - # Args: - # pool: 内存池 - # class_sha1: 类所属模块的 SHA1 - # class_name: 类名 - # method_name: 方法名 - # - # Returns: - # LLVM 类型对象,或 None(未找到/text.ll 不存在) - # ============================================================ - def _LookupMethodRetTyFromTextLL(self, pool: memhub.MemBuddy | t.CPtr, - class_sha1: str, - class_name: str, - method_name: str, - use_bare: int = 0) -> llvmlite.LLVMType | t.CPtr: - """从依赖模块的 text.ll 中查找方法返回类型 - - use_bare: 1=按模块级函数查找(搜索 "{sha1}.{method_name}" define, - 用于 new_lexer/tokenize 等模块函数;class_name 忽略)。 - """ - if pool is None or class_sha1 is None or method_name is None: - return None - if self.TempDir is None or self.TempDirLen == 0: - return None - - sha1_len: t.CSizeT = string.strlen(class_sha1) - if sha1_len < 2: - return None - - # 构造 text.ll 路径 (level=1): {temp_dir}/{sha1[0:2]}/{sha1}.text.ll - # 使用 subdir 缓冲区避免 %c 格式化问题(与 StubMerger._sliced_path 一致) - path_len: t.CSizeT = self.TempDirLen + sha1_len + 14 - path_buf: bytes = stdlib.malloc(path_len) - if path_buf is None: - return None - subdir_buf: bytes = stdlib.malloc(3) - if subdir_buf is None: - stdlib.free(path_buf) - return None - subdir_buf[0] = class_sha1[0] - subdir_buf[1] = class_sha1[1] - subdir_buf[2] = '\0' - viperlib.snprintf(path_buf, path_len, "%s/%s/%s.text.ll", - self.TempDir, subdir_buf, class_sha1) - stdlib.free(subdir_buf) - - # 读取 text.ll(按文件实际大小分配:固定 _TEXT_LL_READ_BUF_SIZE(256KB) - # 会截断大模块的 text.ll,末尾方法定义查不到 → 误报"方法返回类型无法 - # 精确获取"(追加80b 根因,同追加74 _read_source_line 截断)。64MB 上限 - # 防御异常超大文件整体读取。) - tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R) - if tf.closed: - stdlib.free(path_buf) - return None - tfsize: LONGLONG = tf.size() - if tfsize <= 0 or tfsize > 67108864: - tf.close() - stdlib.free(path_buf) - return None - read_size: t.CSizeT = t.CSizeT(tfsize) - read_buf: bytes = stdlib.malloc(read_size + 1) - if read_buf is None: - tf.close() - stdlib.free(path_buf) - return None - text_len: t.CInt64T = tf.read_all(read_buf, ULONG(read_size + 1)) - tf.close() - stdlib.free(path_buf) - - if text_len <= 0: - stdlib.free(read_buf) - return None - read_buf[text_len] = '\0' - - # 构造搜索模式: "{sha1}.{class_name}.{method_name}" 或 bare 模式 "{sha1}.{method_name}" - cls_len: t.CSizeT = 0 - if class_name is not None: - cls_len = string.strlen(class_name) - meth_len: t.CSizeT = string.strlen(method_name) - search_len: t.CSizeT = sha1_len + meth_len + 2 - if use_bare == 0: - search_len = sha1_len + cls_len + meth_len + 4 - search_buf: bytes = stdlib.malloc(search_len) - if search_buf is None: - stdlib.free(read_buf) - return None - if use_bare != 0: - viperlib.snprintf(search_buf, search_len, "%s.%s", - class_sha1, method_name) - else: - viperlib.snprintf(search_buf, search_len, "%s.%s.%s", - class_sha1, class_name, method_name) - search_str_len: t.CSizeT = string.strlen(search_buf) - - # 在 text.ll 中搜索 define 行包含 search_buf - buf_len: t.CSizeT = string.strlen(read_buf) - pos: t.CSizeT = 0 - result_ty: llvmlite.LLVMType | t.CPtr = None - - while pos < buf_len and result_ty is None: - ls: t.CSizeT = pos - le: t.CSizeT = pos - while le < buf_len: - if read_buf[le] == '\n': - break - le += 1 - ll: t.CSizeT = le - ls - - # 检查是否是 define 行 - if ll >= 7 and string.strncmp(read_buf + ls, "define ", 7) == 0: - # 找 @ 符号 - at_pos: t.CSizeT = ls + 7 - while at_pos < ls + ll: - if read_buf[at_pos] == '@': - break - at_pos += 1 - if at_pos < ls + ll: - # 跳过可选引号 - name_start: t.CSizeT = at_pos + 1 - if name_start < ls + ll and read_buf[name_start] == '"': - name_start += 1 - # 检查是否匹配 search_buf - if name_start + search_str_len <= ls + ll: - if string.strncmp(read_buf + name_start, search_buf, search_str_len) == 0: - # 函数名边界检查:search 后必须是 '"'(带引号名)、'('(参数表)或行尾, - # 否则 "sha1.func" 会误匹配 "sha1.func_helper" 等前缀同名函数 - name_end: t.CSizeT = name_start + search_str_len - end_ch: int = 0 - if name_end < ls + ll: - end_ch = read_buf[name_end] - if end_ch == 34 or end_ch == 40 or end_ch == 0: - # 匹配!提取返回类型: [ls+7, at_pos) - result_ty = self._ParseLLVMRetTyStr(pool, read_buf, ls + 7, at_pos) - - pos = le + 1 - - stdlib.free(search_buf) - stdlib.free(read_buf) - return result_ty - - # ============================================================ - # _dep_text_ll_exists - 探测依赖模块 text.ll 是否已生成 - # - # 用于区分跨模块返回类型精确解析失败的两种场景: - # 1. text.ll 存在但函数未命中 → 真错误(依赖已编译,函数缺失) - # 2. text.ll 不存在 → 依赖模块尚未翻译(Phase A 按文件顺序翻译, - # main.vp 先于其 import 的 mbuddytest.vp),标记重试待下遍 - # ============================================================ - def _dep_text_ll_exists(self, pool: memhub.MemBuddy | t.CPtr, - sha1: str) -> int: - """探测 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll 是否存在,1=存在""" - if self.TempDir is None or self.TempDirLen == 0 or sha1 is None: - return 0 - sha1_len: t.CSizeT = string.strlen(sha1) - if sha1_len < 2: - return 0 - path_len: t.CSizeT = self.TempDirLen + sha1_len + 14 - path_buf: bytes = stdlib.malloc(path_len) - subdir_buf: bytes = stdlib.malloc(3) - if path_buf is None or subdir_buf is None: - if path_buf is not None: - stdlib.free(path_buf) - if subdir_buf is not None: - stdlib.free(subdir_buf) - return 0 - subdir_buf[0] = sha1[0] - subdir_buf[1] = sha1[1] - subdir_buf[2] = '\0' - viperlib.snprintf(path_buf, path_len, "%s/%s/%s.text.ll", - self.TempDir, subdir_buf, sha1) - stdlib.free(subdir_buf) - tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R) - exists: int = 0 - if not tf.closed: - tf.close() - exists = 1 - stdlib.free(path_buf) - return exists # ============================================================ # 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助 @@ -3734,6 +1629,14 @@ class CallGenMixin: self._ensure_method_declare(pool, mod, call_name, call_ret_ty, call_head, call_count) return llvmlite.build_call(builder, call_name, call_head, call_count, call_ret_ty, 0) + # ============================================================ + # _resolve_obj_class_name — 解析对象表达式的类名(短名) + # + # 优先从变量注解(AnnotClassName)解析(如 "memhub.MemBuddy" → "MemBuddy"), + # 失败时从 LLVM 类型解析(Ptr(Struct) → 类名)。 + # 供属性访问/赋值/删除识别 property 时使用。 + # ============================================================ + # ============================================================ # _resolve_obj_class_name — 解析对象表达式的类名(短名) # @@ -3760,6 +1663,13 @@ class CallGenMixin: return annot_val return None + # ============================================================ + # _try_property_getter_attr — 尝试将 obj.attr 翻译为 property getter 调用 + # + # 检查 obj 的类是否有 @property/@x.getter 的 attr 方法; + # 若有则生成 call Class.attr(obj) 并返回调用结果 Value;否则返回 None。 + # ============================================================ + # ============================================================ # _try_property_getter_attr — 尝试将 obj.attr 翻译为 property getter 调用 # @@ -3792,6 +1702,13 @@ class CallGenMixin: return self._translate_property_call( pool, builder, mod, class_name, at_node.attr, obj_ptr, 1, trans) + # ============================================================ + # _try_property_setter — 尝试将 obj.attr = v 翻译为 property setter 调用 + # + # 检查 obj 的类是否有 @x.setter 的 attr 方法; + # 若有则生成 call Class.attr$set(obj, v),返回 1;否则返回 0。 + # ============================================================ + # ============================================================ # _try_property_setter — 尝试将 obj.attr = v 翻译为 property setter 调用 # @@ -3833,6 +1750,13 @@ class CallGenMixin: setter_name_buf, obj_val, 2, trans) return 1 + # ============================================================ + # _try_property_deleter — 尝试将 del obj.attr 翻译为 property deleter 调用 + # + # 检查 obj 的类是否有 @x.deleter 的 attr 方法; + # 若有则生成 call Class.attr$del(obj),返回 1;否则返回 0。 + # ============================================================ + # ============================================================ # _try_property_deleter — 尝试将 del obj.attr 翻译为 property deleter 调用 # @@ -3870,6 +1794,13 @@ class CallGenMixin: del_name_buf, obj_val, 1, trans) return 1 + # ============================================================ + # _translate_static_class_call — 翻译 ClassName.method(args) 静态/类方法调用 + # + # @staticmethod: 直接 call Class.method(args...),无 self + # @classmethod: 在参数前插入栈上分配的类实例指针(与 TPC 一致) + # ============================================================ + # ============================================================ # _translate_static_class_call — 翻译 ClassName.method(args) 静态/类方法调用 # @@ -3945,6 +1876,19 @@ class CallGenMixin: return self._translate_property_call(pool, builder, mod, class_name, method_name, head, total_count, trans) + # ============================================================ + # _is_list_builtin_method - 判断是否是 list 泛型内置容器方法 + # + # list[T] 是内置泛型容器(_list.vp),其方法(append/get/set/pop/clear/ + # __iter__/__len__/__getitem__/__setitem__)由 translate_call 的 list + # 内置分支内联 GEP 处理,不注册为方法函数。若 obj.method() 检测把 + # list 特化 struct(如 list[AST | CPtr])误当普通结构体走 + # _translate_method_call,会查不到 append 返回类型 → fail-fast + # (NewAstTest body.append 根因)。此判断用于跳过 method_call 路径。 + # + # 返回: 1=list 内置方法(应落到 list 内置分支),0=普通方法 + # ============================================================ + # ============================================================ # _is_list_builtin_method - 判断是否是 list 泛型内置容器方法 # @@ -3977,6 +1921,17 @@ class CallGenMixin: if string.strcmp(method_name, "__setitem__") == 0: return 1 return 0 + # ============================================================ + # _translate_fakeduck_call - FakeDuck: str 变量方法调用 → 扩展类 _Type/_str + # + # 对齐 TPC HandlesExprCall.py L2841-2880: + # ClassName 常规解析失败且对象是 char*(i8*)时,遍历扩展类查找 + # {CN}.{method} 函数。对象是 Name 变量且有影子({var}__meta__,fd2 + # 创建)时 self=影子;否则(字符串字面量/匿名 str)在入口创建临时 + # 影子,写 __data__=obj 值、__mbuddy__=NULL 后作 self,避免 + # bitcast i8* → _str* 读取垃圾指针导致 ACCESS_VIOLATION。 + # ============================================================ + # ============================================================ # _translate_fakeduck_call - FakeDuck: str 变量方法调用 → 扩展类 _Type/_str # @@ -4140,6 +2095,17 @@ class CallGenMixin: fd_total: int = 1 + fd_can return llvmlite.build_call(builder, fd_fname, fd_head, fd_total, fd_ret_ty, 0) + # ============================================================ + # _inject_requires_fields - FakeDuck: with 上下文注入 requires 字段 + # + # 对齐 TPC HandlesExprCall.py L4021-4079: + # 对类 __requires__ 元数据(fd1 注册)中的每个字段,运行时调用 + # _find_provider(field) 查找 with 上下文提供的指针;非 NULL 时 + # bitcast 到字段类型写入 meta_ptr 对应槽位(条件注入,避免覆盖 + # 用户已手动设置的值)。_find_provider 未注册(未 import + # _withcontent)时跳过注入,不影响非 with 场景。 + # ============================================================ + # ============================================================ # _inject_requires_fields - FakeDuck: with 上下文注入 requires 字段 # @@ -4251,6 +2217,16 @@ class CallGenMixin: injected += 1 return injected + # ============================================================ + # _emit_provider_push / _emit_provider_pop - FakeDuck: with 上下文 + # provider push/pop(__provides__ 元数据,fd1 注册) + # + # 对齐 TPC HandlesWith.py L138-174: + # with 进入时对每个提供字段生成 _push_provider(field_str, ctx_i8); + # 退出时生成等量 _pop_provider()。运行时 _withcontent 模块负责 + # 维护 TLS provider 栈,供 _inject_requires_fields 查找。 + # ============================================================ + # ============================================================ # _emit_provider_push / _emit_provider_pop - FakeDuck: with 上下文 # provider push/pop(__provides__ 元数据,fd1 注册) @@ -4314,6 +2290,7 @@ class CallGenMixin: llvmlite.build_call(builder, fd_pfn, fd_fstr, 2, ret_i32_p, 0) return fd_pc + def _emit_provider_pop(self, trans: HT.Translator | t.CPtr, pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, @@ -4345,6 +2322,19 @@ class CallGenMixin: llvmlite.build_call(builder, fd_pon, None, 0, ret_i32_q, 0) return fd_pc + # ============================================================ + # _write_vtable_slot / _write_vtable_attr — vtable 方法槽位直接写入 + # + # serial0_file.open = serial0_open(devfs 驱动注册模式):把模块级函数 + # 指针写入对象 vtable 的方法槽位。vtable 方法不是数据字段(FieldEntry), + # get_attribute_ptr 查不到 → 此前 fatal_error "属性写入失败"。 + # 对齐 TPC HandlesAssign.py L905-949 的写时复制: + # 对象 vtable 仍指向类默认 vtable 时,先复制一份(internal 全局 + + # llvm.memcpy)并让对象指向副本,再 GEP method_index 槽位 store + # 函数指针(i8*)。多次写入互不覆盖(第二次起 vtable 已非默认, + # 跳过复制直接写槽位)。 + # ============================================================ + # ============================================================ # _write_vtable_slot / _write_vtable_attr — vtable 方法槽位直接写入 # @@ -4409,7 +2399,7 @@ class CallGenMixin: if vtable_ptr is None: return 0 # 类默认 vtable 地址(比较用) - class_vt: llvmlite.Value | t.CPtr = self._make_vtable_ref_i8( + class_vt: llvmlite.Value | t.CPtr = HandlesExprCall._make_vtable_ref_i8( pool, builder, mod, class_name, trans) if class_vt is None: return 0 @@ -4479,6 +2469,7 @@ class CallGenMixin: llvmlite.build_store(builder, fptr_i8, vt_slotp) return 1 + def _write_vtable_attr(self, builder: llvmlite.IRBuilder | t.CPtr, pool: memhub.MemBuddy | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, @@ -4544,6 +2535,14 @@ class CallGenMixin: return self._write_vtable_slot( pool, builder, mod, obj_ptr_v, class_nm_v, vm_idx_v, rhs_val, trans) + # ============================================================ + # _translate_method_call - 翻译方法调用 obj.method(args) + # + # 生成: call @SHA1.ClassName.method_name(Ptr(StructTy) %obj, args...) + # + # obj_ptr 是对象变量的 alloca(Ptr(StructTy)),作为 self 参数传入 + # ============================================================ + # ============================================================ # _translate_method_call - 翻译方法调用 obj.method(args) # @@ -5136,10 +3135,22 @@ class CallGenMixin: is_variadic_3441: int = HandlesExprCall._check_and_promote_variadic_call( pool, builder, mod, call_name, head, total_count, cargs, 1, trans) # try-except:方法含 raise(EH 输出参数)时追加输出实参 + 调用后检测 - return self._emit_eh_guarded_call( + return HandlesExprCall._emit_eh_guarded_call( builder, pool, mod, trans, found_func, call_name, head, total_count, call_ret_ty, is_variadic_3441) + # ============================================================ + # _translate_super_call — super().method(args) → 静态调用父类方法 + # + # Python super 语义(2026-08-10 实现): + # - 当前类来自 self.CurClassName(_translate_method 翻译方法体时设置) + # - 父类查找:沿 get_mro_chain(CurClassName) 跳过自身,找第一个定义 method 的祖先 + # - self 指针:符号表 self 变量 alloca load(对象头,复用 c.Addr(self) 模式) + # - this_adjust:父类字段区在子类中字节偏移 delta>0 时 GEP i8* + delta + # (复用 _field_byte_offset 字节偏移法,与 _translate_method_call 一致) + # - 静态调用父类实现:不虚分派(super() 不触发子类 override) + # ============================================================ + # ============================================================ # _translate_super_call — super().method(args) → 静态调用父类方法 # @@ -5366,6 +3377,14 @@ class CallGenMixin: pool, builder, mod, call_name, head, arg_count_sp, cargs_sp, 1, trans) return llvmlite.build_call(builder, call_name, head, arg_count_sp, ret_ty_sp, is_variadic_sp) + # ============================================================ + # _field_byte_offset — 计算字段在结构体布局中的字节偏移 + # + # 按 LLVM 布局遍历 struct elements 带对齐累加(与 ClassGenMixin._get_type_size + # 的 padding 规则一致)。field_index 是 FieldEntry.Index(OOP 类 __vtable__ 占 0)。 + # 供多继承 this 调整(字节偏移法)计算 delta。 + # ============================================================ + # ============================================================ # _field_byte_offset — 计算字段在结构体布局中的字节偏移 # @@ -5408,6 +3427,13 @@ class CallGenMixin: case _: return 0 + # ============================================================ + # _kwarg_name_matches — 检查关键字参数名是否匹配函数参数名 + # + # 函数参数名在 LLVM IR 中带 % 前缀(如 "%a"),关键字参数名无前缀(如 "a") + # 跳过 % 前缀后逐字符比较 + # ============================================================ + # ============================================================ # _kwarg_name_matches — 检查关键字参数名是否匹配函数参数名 # @@ -5430,6 +3456,16 @@ class CallGenMixin: return 0 return 1 + # ============================================================ + # _translate_struct_ctor_kw — 结构体构造函数(关键字参数) + # + # 支持两种语法: + # Point(x=10, y=20) — 全关键字 + # Point(10, y=20) — 混合(位置 + 关键字) + # + # 位置参数按字段索引赋值,关键字参数按字段名查找赋值 + # ============================================================ + # ============================================================ # _translate_struct_ctor_kw — 结构体构造函数(关键字参数) # @@ -5657,6 +3693,19 @@ class CallGenMixin: # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load return tmp + # ============================================================ + # _translate_call_with_kwargs — 带关键字参数的函数调用 + # + # 支持两种语法: + # add(b=4, a=3) — 全关键字乱序 + # greet("Hello", name="World") — 位置 + 关键字混合 + # + # 策略: 遍历 found_func.Params 链表,对每个参数: + # 1. 若位置参数仍有剩余(param_idx < can),取位置参数 + # 2. 否则按参数名匹配关键字参数 + # 3. 按参数顺序构建调用参数链表 + # ============================================================ + # ============================================================ # _translate_call_with_kwargs — 带关键字参数的函数调用 # @@ -5762,6 +3811,20 @@ class CallGenMixin: return self._emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst1, mc_src1, mc_num1) return llvmlite.build_call(builder, call_name, head, actual_count, call_ret_ty, 0) + # ============================================================ + # _translate_t_type_cast - 翻译 t.XXX(value) 类型转换 + # + # 当 func 是 t.XXX 形式且 XXX 是已知类型名(map_t_type 能映射)时, + # 将 value 转换为目标类型: + # - 指针 → 整数: ptrtoint (如 t.CUInt64T(ptr) → i64) + # - 整数 → 指针: inttoptr (如 t.CPtr(int_val) → i8*) + # - 整数 → 整数: trunc/zext (如 t.CInt8T(i32_val) → i8) + # - 指针 → 指针: bitcast (如 t.CPtr(ptr_val) → i8*) + # - 整数 → 浮点: sitofp (如 t.CDouble(i32_val) → double) + # - 浮点 → 整数: fptosi (如 t.CInt(double_val) → i32) + # - 浮点 → 浮点: fpext/fptrunc (如 t.CFloat(double_val) → float) + # ============================================================ + # ============================================================ # _translate_t_type_cast - 翻译 t.XXX(value) 类型转换 # @@ -5852,6 +3915,13 @@ class CallGenMixin: # _get_type_name_from_annotation 已移至 HandlesType.py(支持 BinOp/Attribute) # HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用 + + # ============================================================ + # 泛型实例化辅助:从 Subscript slice 提取类型实参名 + # ============================================================ + # _get_type_name_from_annotation 已移至 HandlesType.py(支持 BinOp/Attribute) + # HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用 + def _extract_type_args_from_slice(self, pool: memhub.MemBuddy | t.CPtr, slice_node: ast.AST | t.CPtr) -> list[str] | t.CPtr: """从 Subscript.slice 提取类型实参名列表 @@ -5883,6 +3953,22 @@ class CallGenMixin: result.append(tn) return result + # ============================================================ + # 泛型类构造调用辅助: list[str](pool, 8) → __new__ + __before_init__ + __init__ + # + # 复用 translate_list_literal 的构造逻辑: + # 1. alloca tmp(特化类临时空间,作为 __new__ 的 self) + # 2. 翻译 cl.args 为参数指针数组 + # 3. call __new__(tmp, *args) → storage_ptr + # 4. call __before_init__(storage_ptr) + # 5. call __init__(storage_ptr, *args) + # 6. return storage_ptr + # + # 必须独立于 translate_call 的普通函数路径:spec_name 是类名不是函数名, + # 走裸名路径会被 _lookup_mod_sha1 的 star import 回退误导,用错误的 SHA1 + # 且缺少 __new__ 方法名后缀,导致链接报 undefined reference。 + # ============================================================ + # ============================================================ # 泛型类构造调用辅助: list[str](pool, 8) → __new__ + __before_init__ + __init__ # @@ -5959,6 +4045,7 @@ class CallGenMixin: # 逻辑将其排除,只保留 float/str 等区分性提示)。 return "int" + def _translate_generic_ctor_call(self, pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, @@ -6047,6 +4134,10 @@ class CallGenMixin: return storage_ptr + # ============================================================ + # 翻译函数调用 Call(func, args) — 模块级版本 + # ============================================================ + # ============================================================ # 翻译函数调用 Call(func, args) — 模块级版本 # ============================================================ @@ -6156,21 +4247,21 @@ class CallGenMixin: mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_node.value) if mod_nm.id is not None and string.strcmp(mod_nm.id, "c") == 0: if string.strcmp(func_name, "Deref") == 0: - return self.translate_c_deref(pool, builder, mod, cl, trans) + return HandlesExprCall.translate_c_deref(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "DerefAs") == 0: - return self.translate_c_derefas(pool, builder, mod, cl, trans) + return HandlesExprCall.translate_c_derefas(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "Addr") == 0: - return self.translate_c_addr(pool, builder, mod, cl, trans) + return HandlesExprCall.translate_c_addr(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "Set") == 0: # c.Set(a, b) = a = b(赋值语义,非指针解引用)。 # 若当普通函数调用会生成 @Set 引用导致链接失败(undefined reference to `Set')。 - return self.translate_c_set(pool, builder, mod, cl, trans) + return HandlesExprCall.translate_c_set(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "Load") == 0: - return self.translate_c_load(pool, builder, mod, cl, trans) + return HandlesExprCall.translate_c_load(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "Asm") == 0: - return self.translate_c_asm(pool, builder, mod, cl, trans) + return HandlesExprCall.translate_c_asm(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "LLVMIR") == 0: - return self.translate_c_llvmir(pool, builder, mod, cl, trans) + return HandlesExprCall.translate_c_llvmir(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "LInp") == 0 or string.strcmp(func_name, "LOut") == 0: # c.LInp/c.LOut 独立调用时返回 0(仅在 c.LLVMIR 的 f-string 内有意义) return llvmlite.ConstInt(pool, llvmlite.Int32(pool), 0, "0") @@ -6794,7 +4885,7 @@ class CallGenMixin: if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: if func_name is not None and string.strcmp(func_name, "isinstance") == 0: if can >= 2: - is_res: llvmlite.Value | t.CPtr = self._translate_isinstance( + is_res: llvmlite.Value | t.CPtr = HandlesExprCall._translate_isinstance( pool, builder, mod, cargs.get(0), cargs.get(1), trans) if is_res is not None: return is_res @@ -8318,7 +6409,7 @@ class CallGenMixin: is_variadic_call: int = HandlesExprCall._check_and_promote_variadic_call( pool, builder, mod, call_name, head, can, cargs, 0, trans) # try-except:被调函数带 EH 输出参数时,追加输出实参 + 调用后检测异常 - return self._emit_eh_guarded_call( + return HandlesExprCall._emit_eh_guarded_call( builder, pool, mod, trans, found_func, call_name, head, can, call_ret_ty, is_variadic_call) @@ -8328,861 +6419,6 @@ class CallGenMixin: # EH 参数(%__eh_msg_out__/__eh_code_out__)由 translate_function_def/ # _translate_method 在含 raise 的函数签名末尾注入(main 除外)。 # ============================================================ - def _func_has_eh_params(self, func: llvmlite.Function | t.CPtr) -> int: - """返回 1=函数带 EH 输出参数 / 0=不带""" - if func is None: - return 0 - cur_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) - while cur_p is not None: - pn: str = llvmlite.param_get_name(cur_p) - if pn is not None and string.strcmp(pn, "%__eh_msg_out__") == 0: - return 1 - cur_p = llvmlite.param_get_next(cur_p) - return 0 - - # ============================================================ - # _emit_eh_guarded_call - 调用侧 try-except EH 检测(对齐 TPC - # HandlesExprCall._append_eh_msg_out_arg + _check_eh_return) - # - # 被调函数带 EH 输出参数时: - # 1. 确定 msg/code 输出指针: - # - 当前在 try(trans._eh_dispatch_bb 非空):复用 try 的 - # eh_message/exception_code alloca——被调函数直接写入,检查 - # 路径读同一 alloca 即得异常,无需搬运 - # - 当前函数有 EH 输出参数:复用本函数 out 参数(异常直接写进 - # 本函数输出,检查命中后仅返回,由调用方接管传播) - # - 两者皆无:局部 null alloca(异常被吞) - # 2. 调用前清零输出指针(复用 alloca 必须复位,防上次残留误判) - # 3. 追加 msg/code 两个实参(count+2) - # 4. 调用后检查 msg != null:命中 → err 块(try 内分支 DispatchBB; - # 否则仅返回默认值);未命中 → ok 块继续 - # ============================================================ - def _emit_eh_guarded_call(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - trans: HT.Translator | t.CPtr, - func: llvmlite.Function | t.CPtr, - call_name: str, - head: llvmlite.Value | t.CPtr, - count: int, - ret_ty: llvmlite.LLVMType | t.CPtr, - is_variadic: int) -> llvmlite.Value | t.CPtr: - """带 try-except EH 检测的函数调用,返回 call 结果(检查后位于 ok 块)""" - if trans is None or self._func_has_eh_params(func) == 0: - return llvmlite.build_call(builder, call_name, head, count, ret_ty, is_variadic) - # ---- 1. 确定输出指针 ---- - i8_ty_g: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty_g: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_g) - i32_ty_g: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if i8_ty_g is None or i8_ptr_ty_g is None or i32_ty_g is None: - return llvmlite.build_call(builder, call_name, head, count, ret_ty, is_variadic) - msg_ptr: llvmlite.Value | t.CPtr = None - code_ptr: llvmlite.Value | t.CPtr = None - if trans._eh_msg_ptr is not None and trans._eh_code_ptr is not None: - msg_ptr = trans._eh_msg_ptr - code_ptr = trans._eh_code_ptr - elif trans._cur_func_has_eh != 0 and trans._eh_msg_out_param is not None \ - and trans._eh_code_out_param is not None: - msg_ptr = trans._eh_msg_out_param - code_ptr = trans._eh_code_out_param - if msg_ptr is None: - msg_ptr = llvmlite.build_alloca(builder, i8_ptr_ty_g) - code_ptr = llvmlite.build_alloca(builder, i32_ty_g) - # ---- 2. 调用前清零 ---- - null_msg_g: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty_g, "null") - zero_code_g: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - if null_msg_g is not None: - llvmlite.build_store(builder, null_msg_g, msg_ptr) - if zero_code_g is not None: - llvmlite.build_store(builder, zero_code_g, code_ptr) - # ---- 3. 追加实参(链表末尾 + count+2)---- - msg_ptr.Next = code_ptr - code_ptr.Next = None - if head is None: - head = msg_ptr - else: - tail_g: llvmlite.Value | t.CPtr = head - while tail_g.Next is not None: - tail_g = tail_g.Next - tail_g.Next = msg_ptr - count = count + 2 - # ---- 4. 调用 + 检查 ---- - result: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, call_name, head, count, ret_ty, is_variadic) - cur_func_g: llvmlite.Function | t.CPtr = trans._cur_func - if cur_func_g is None or null_msg_g is None: - return result - msg_val_g: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i8_ptr_ty_g, msg_ptr) - if msg_val_g is None: - return result - is_err_g: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, msg_val_g, null_msg_g) - if is_err_g is None: - return result - lc_g: int = trans._label_counter - trans._label_counter = lc_g + 1 - bb_buf_g: str = pool.alloc(64) - if bb_buf_g is None: - return result - viperlib.snprintf(bb_buf_g, 64, "eh.err.%d", lc_g) - err_bb_g: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, cur_func_g, bb_buf_g) - viperlib.snprintf(bb_buf_g, 64, "eh.ok.%d", lc_g) - ok_bb_g: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, cur_func_g, bb_buf_g) - if err_bb_g is None or ok_bb_g is None: - return result - llvmlite.build_cond_br(builder, is_err_g, err_bb_g, ok_bb_g) - # err 块 - llvmlite.position_at_end(builder, err_bb_g) - if trans._eh_dispatch_bb is not None: - # try 内:异常已写入 try 的 alloca(code_ptr 即 try 的 alloca), - # 分支 DispatchBB 交给 except 链 - llvmlite.build_br(builder, trans._eh_dispatch_bb) - else: - # 非 try:异常已写入本函数 out 参数(复用)或局部 alloca(吞掉), - # 仅返回默认值,由调用方检测本函数 out 参数 - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - ret_ty_g2: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty( - cur_func_g) - if ret_ty_g2 is not None: - match ret_ty_g2: - case llvmlite.LLVMType.Void(): - llvmlite.build_ret_void(builder) - case llvmlite.LLVMType.Ptr(_pg): - nv_g: llvmlite.Value | t.CPtr = llvmlite.ConstNull( - pool, ret_ty_g2, "null") - if nv_g is not None: - llvmlite.build_ret(builder, nv_g) - case llvmlite.LLVMType.Float(_fg): - zf_g: llvmlite.Value | t.CPtr = llvmlite.ConstFloat( - pool, ret_ty_g2, 0.0) - if zf_g is not None: - llvmlite.build_ret(builder, zf_g) - case _: - zv_g: llvmlite.Value | t.CPtr = llvmlite.ConstZero( - pool, ret_ty_g2) - if zv_g is not None: - llvmlite.build_ret(builder, zv_g) - # ok 块:继续 - llvmlite.position_at_end(builder, ok_bb_g) - return result - - # ============================================================ - # isinstance - 运行时 vtable 子类集合比较(2026-08-10) - # - # CVTable 对象头部 vtable 指针唯一标识对象实际类。isinstance(obj, Cls) - # 语义 = Cls 是实际类的祖先(实际类 == Cls 或继承自 Cls)。运行时只能 - # 拿到实际类 vtable 地址,无法向上推导祖先链,因此在编译期沿 - # StructEntry.ParentNames 反向 BFS 枚举 Cls 的全部已知子类(含自身), - # 运行时比较 obj->vtable ∈ {Cls 子类 vtable 地址集合}。 - # NoVTable / 未知类回退编译时静态判断(obj 静态类型 MRO 判断)。 - # ============================================================ - - def _translate_isinstance(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - obj_node: ast.AST | t.CPtr, - cls_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """isinstance(obj, Cls):运行时 vtable 子类集合比较,返回 i1""" - if obj_node is None or cls_node is None: - # 参数缺失即调用错误:fail-fast,绝不返回 True 掩盖 - HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") - obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, obj_node, None, 0, trans) - if obj_val is None or obj_val.Ty is None: - # obj 类型推断失败:fail-fast,绝不返回 True 掩盖 - HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") - # 对象指针规整:二级指针(变量 alloca / 联合 Class|t.CPtr)先 load - obj_ptr: llvmlite.Value | t.CPtr = obj_val - match obj_val.Ty: - case llvmlite.LLVMType.Ptr(inner_ty): - match inner_ty: - case llvmlite.LLVMType.Ptr(_): - loaded: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, inner_ty, obj_val) - if loaded is not None: - obj_ptr = loaded - case _: - pass - obj_is_ptr: int = HandlesExpr.is_ptr_type(obj_ptr.Ty) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) - # 对象 vtable 指针惰性读取(首个 CVTable 类比较时执行一次) - vtable_ptr: llvmlite.Value | t.CPtr = None - vtable_ready: int = 0 - res: llvmlite.Value | t.CPtr = None - cls_names: t.CSizeT | t.CPtr = self._extract_isinstance_class_names(pool, cls_node) - if cls_names is None: - # 类名提取失败:fail-fast,绝不返回 True 掩盖 - HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") - ci: int = 0 - while cls_names[ci] != 0: - cn: str = (str | t.CPtr)(t.CVoid(cls_names[ci], t.CPtr)) - if cn is not None: - if HandlesStruct.is_novtable_by_name(cn) != 0 \ - or HandlesStruct.has_vtable_by_name(cn) == 0: - # NoVTable / 未知类 → 编译时静态判断(obj 静态类型 MRO) - st: int = self._isinstance_compile_time(pool, obj_ptr, cn) - c1: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 1, 1 if st > 0 else 0) - if res is None: - res = c1 - else: - res = llvmlite.build_or(builder, res, c1) - elif obj_is_ptr != 0: - # CVTable → 运行时 vtable 比较(读对象头部 vtable 指针) - if vtable_ready == 0: - vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, obj_ptr, i8_ptr_ptr_ty) - if vtable_slot is not None: - vtable_ptr = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot) - vtable_ready = 1 - if vtable_ptr is not None: - subs: t.CSizeT | t.CPtr = self._collect_subclass_vtable_classes(pool, cn) - if subs is not None: - k: int = 0 - while subs[k] != 0: - scn: str = (str | t.CPtr)(t.CVoid(subs[k], t.CPtr)) - if scn is not None: - sub_i8: llvmlite.Value | t.CPtr = self._make_vtable_ref_i8( - pool, builder, mod, scn, trans) - if sub_i8 is not None: - cmp: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_EQ, vtable_ptr, sub_i8) - if cmp is not None: - if res is None: - res = cmp - else: - res = llvmlite.build_or(builder, res, cmp) - k += 1 - ci += 1 - if res is None: - # 未产生任何比较结果(obj 非指针且类全部为 CVTable):推断失败,fail-fast - HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError") - return res - - def _extract_isinstance_class_names(self, pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr) -> t.CSizeT | t.CPtr: - """从 isinstance 第二参数提取类名数组(Name→id / Attribute→attr / Tuple→遍历)""" - arr: t.CSizeT | t.CPtr = pool.alloc(8 * 16) - if arr is None: - return None - # 全数组清零:pool 分配内存非零时,未初始化槽位会被 while cls_names[ci]!=0 - # 误当类名指针解引用 → 段错误 - string.memset(arr, 0, 8 * 16) - arr[0] = 0 - if node is None: - return arr - count: int = 0 - k: int = node.kind() - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is not None: - arr[0] = t.CSizeT(nm.id) - elif k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at.attr is not None: - arr[0] = t.CSizeT(at.attr) - elif k == ast.ASTKind.Tuple: - tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node) - elts: list[ast.AST | t.CPtr] | t.CPtr = tp.elts - if elts is not None: - n: t.CSizeT = len(elts) - for i in range(n): - if count >= 15: - break - elt: ast.AST | t.CPtr = elts.get(i) - if elt is None: - continue - ek: int = elt.kind() - if ek == ast.ASTKind.Name: - enm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(elt) - if enm.id is not None: - arr[count] = t.CSizeT(enm.id) - count += 1 - elif ek == ast.ASTKind.Attribute: - eat: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(elt) - if eat.attr is not None: - arr[count] = t.CSizeT(eat.attr) - count += 1 - arr[count] = 0 - return arr - - def _collect_subclass_vtable_classes(self, pool: memhub.MemBuddy | t.CPtr, - class_name: str) -> t.CSizeT | t.CPtr: - """反向 BFS 收集目标类及全部子类(含自身,仅 HasVTable==1),返回 0 结尾数组""" - if class_name is None: - return None - names: t.CSizeT | t.CPtr = pool.alloc(8 * (ISINSTANCE_CLASS_MAX + 1)) - queue: t.CSizeT | t.CPtr = pool.alloc(8 * ISINSTANCE_CLASS_MAX) - visited: t.CSizeT | t.CPtr = pool.alloc(8 * ISINSTANCE_CLASS_MAX) - if names is None or queue is None or visited is None: - return None - string.memset(names, 0, 8 * (ISINSTANCE_CLASS_MAX + 1)) - string.memset(queue, 0, 8 * ISINSTANCE_CLASS_MAX) - string.memset(visited, 0, 8 * ISINSTANCE_CLASS_MAX) - qcount: int = 0 - outcount: int = 0 - vcount: int = 0 - queue[0] = t.CSizeT(class_name) - qcount = 1 - while qcount > 0: - qcount -= 1 - cur_addr: t.CSizeT = queue[qcount] - cur: str = (str | t.CPtr)(t.CVoid(cur_addr, t.CPtr)) - if cur is None: - continue - dup: int = 0 - for vi in range(vcount): - va: t.CSizeT = visited[vi] - if va != 0: - vn: str = (str | t.CPtr)(t.CVoid(va, t.CPtr)) - if vn is not None and string.strcmp(vn, cur) == 0: - dup = 1 - break - if dup != 0: - continue - if vcount < ISINSTANCE_CLASS_MAX: - visited[vcount] = t.CSizeT(cur) - vcount += 1 - centry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(cur) - if centry is not None and centry.HasVTable != 0: - if outcount < ISINSTANCE_CLASS_MAX: - names[outcount] = t.CSizeT(cur) - outcount += 1 - # 子类入队:遍历全部已注册 struct,ParentNames 含 cur 者 - scnt: int = HandlesStruct.get_struct_count() - for i in range(scnt): - e2: HandlesStruct.StructEntry | t.CPtr = HandlesStruct._get_struct_entry(i) - if e2 is None or e2.Name is None: - continue - if e2.ParentCount > 0 and e2.ParentNames is not None: - parr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(e2.ParentNames, t.CPtr)) - for j in range(e2.ParentCount): - pa: t.CSizeT = parr[j] - if pa != 0: - pn: str = (str | t.CPtr)(t.CVoid(pa, t.CPtr)) - if pn is not None and string.strcmp(pn, cur) == 0: - if qcount < ISINSTANCE_CLASS_MAX: - queue[qcount] = t.CSizeT(e2.Name) - qcount += 1 - break - names[outcount] = 0 - return names - - def _make_vtable_ref_i8(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """构造类 vtable 地址引用(i8*):本模块已定义直接引用,跨模块声明 external""" - if class_name is None: - return None - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - buf: str = pool.alloc(256) - if buf is None: - return None - viperlib.snprintf(buf, 256, "%s.vtable", class_name) - vn: str = (str | t.CPtr)(buf) - sha1: str = HandlesStruct.get_struct_sha1(class_name) - if sha1 is None: - if trans is None: - return None - sha1 = trans.ModuleSha1 - if sha1 is None: - return None - mangled: str = HandlesFunctions._mangle_name_with_sha1(sha1, vn) - ref_name: str = pool.alloc(256) - if ref_name is None: - return None - # vtable 名含 sha1 点号前缀,一律 @"..." 引号形式 - viperlib.snprintf(ref_name, 256, "@\"%s\"", mangled) - gv: llvmlite.GlobalVariable | t.CPtr = HandlesExpr.find_global_in_module(mod, mangled) - ref_ty: llvmlite.LLVMType | t.CPtr = None - if gv is not None: - # 本模块已定义 vtable(constant {i8* x N})→ 引用类型 Ptr(struct) - ref_ty = llvmlite.Ptr(pool, gv.Ty) - else: - # 跨模块:声明 @mangled = external global i8*,引用类型 i8** - gv2: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable( - pool, mangled, i8_ptr_ty) - if gv2 is None: - return None - llvmlite.module_add_global(mod, gv2) - ref_ty = llvmlite.Ptr(pool, i8_ptr_ty) - ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, ref_ty, ref_name) - if ref is None: - return None - return llvmlite.build_bitcast(builder, ref, i8_ptr_ty) - - def _isinstance_compile_time(self, pool: memhub.MemBuddy | t.CPtr, - obj_ptr: llvmlite.Value | t.CPtr, - class_name: str) -> int: - """编译时静态判断:obj 静态类型 == class_name 或 class_name 在其 MRO 中""" - if obj_ptr is None or obj_ptr.Ty is None or class_name is None: - return 0 - match obj_ptr.Ty: - case llvmlite.LLVMType.Ptr(obj_struct_ty): - sname: str = HandlesStruct.get_class_name_by_type(pool, obj_struct_ty) - if sname is not None: - if string.strcmp(sname, class_name) == 0: - return 1 - mro: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, sname) - if mro is not None: - k: int = 0 - while mro[k] != 0: - mn: str = (str | t.CPtr)(t.CVoid(mro[k], t.CPtr)) - if mn is not None and string.strcmp(mn, class_name) == 0: - return 1 - k += 1 - case _: - pass - return 0 - - # ============================================================ - # P4 簇 5+6 迁移方法(函数体来自 HandlesExprCall.vp: - # 闭包调用/函数指针/printf/print/stdarg 糖/变长参数提升/函数表/全局注册表) - # 本模块函数调用改 self.,外部模块调用保留模块前缀,全局变量改 self 字段 - # ============================================================ - - def translate_closure_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - closure_alloca: llvmlite.Value | t.CPtr, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """通过闭包指针间接调用(支持带参 lambda:i32(i8*, args...))""" - if builder is None or closure_alloca is None: - return None - - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - - # 1. 加载闭包指针 (i8*) - closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, closure_alloca) - if closure_ptr is None: - return None - - # 2. 加载 fn_ptr (offset 0): bitcast to i8**, load i8* - fn_ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty)) - if fn_ptr_addr is None: - return None - fn_raw: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, fn_ptr_addr) - if fn_raw is None: - return None - - # 3. 加载 env_ptr (offset 8): GEP i8, closure, 8; load i8* - eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8) - env_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, closure_ptr, eight_val) - if env_addr is None: - return None - env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_addr) - if env_ptr is None: - return None - - # 4. 构建参数:env 头 + 实参尾(带参 lambda 时翻译实参) - total_args: int = 1 - arg_head: llvmlite.Value | t.CPtr = env_ptr - arg_tail: llvmlite.Value | t.CPtr = env_ptr - param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) - pn_tail: llvmlite.ParamNode | t.CPtr = param_node - if can > 0 and cargs is not None and trans is not None: - for ai in range(can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is None: - continue - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is None or arg_val.Ty is None: - continue - arg_val.Next = None - if arg_tail is not None: - arg_tail.Next = arg_val - arg_tail = arg_val - pn_new: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, arg_val.Ty) - if pn_new is not None: - pn_tail.Next = pn_new - pn_tail = pn_new - total_args += 1 - if total_args == 1: - env_ptr.Next = None - - # 5. bitcast fn_raw 到函数指针类型 i32(i8*, [args...])* - func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, param_node, total_args) - func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty) - fn_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, fn_raw, func_ptr_ty) - if fn_typed is None: - return None - - # 6. 间接调用: call i32 %fn_typed(env, args...) - return llvmlite.build_call_indirect(builder, fn_typed, arg_head, total_args, i32_ty) - - def _is_func_ptr_alloca(self, alloca: llvmlite.Value | t.CPtr) -> int: - """判断 alloca 是否为函数指针变量(类型 Ptr(Ptr(i8))),1=是 / 0=否""" - if alloca is None or alloca.Ty is None: - return 0 - if HandlesExpr.is_ptr_type(alloca.Ty) == 0: - return 0 - pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if pointee is None or HandlesExpr.is_ptr_type(pointee) == 0: - return 0 - inner: llvmlite.LLVMType | t.CPtr = pointee.Pointee - if inner is None or HandlesExpr.is_ptr_type(inner) != 0: - return 0 - return 1 - - def _ensure_closure_names(self) -> int: - """确保闭包名表已分配,0 失败""" - if self.ClosureNames is not None: - return 1 - self.ClosureNames = CompilerFactory.get_perm_pool().alloc(64 * MAX_CLOSURE_NAMES) - if self.ClosureNames is None: - return 0 - string.memset(self.ClosureNames, 0, 64 * MAX_CLOSURE_NAMES) - return 1 - - def register_closure_name(self, name: str) -> int: - """注册嵌套函数(闭包变量)名,0 成功""" - if name is None: - return 1 - if self._ensure_closure_names() == 0: - return 1 - if self.ClosureCount >= MAX_CLOSURE_NAMES: - return 1 - idx: t.CSizeT = t.CSizeT(self.ClosureCount) * 64 - string.strncpy(self.ClosureNames + idx, name, 63) - self.ClosureCount += 1 - return 0 - - def is_closure_name(self, name: str) -> int: - """检查 name 是否已注册为闭包变量名,1=是 / 0=否""" - if name is None or self.ClosureNames is None: - return 0 - i: t.CSizeT - for i in range(self.ClosureCount): - if string.strcmp(self.ClosureNames + i * 64, name) == 0: - return 1 - return 0 - - def _ensure_funcptr_sigs(self) -> int: - """确保函数指针签名表已分配(stdlib.malloc,懒初始化)""" - if self.FuncptrNames is not None: - return 1 - self.FuncptrNames = CompilerFactory.get_perm_pool().alloc(64 * MAX_FUNC_PTR_SIGS) - self.FuncptrRets = CompilerFactory.get_perm_pool().alloc(8 * MAX_FUNC_PTR_SIGS) - if self.FuncptrNames is None or self.FuncptrRets is None: - return 0 - string.memset(self.FuncptrNames, 0, 64 * MAX_FUNC_PTR_SIGS) - return 1 - - def register_func_ptr_sig(self, name: str, - ret_ty: llvmlite.LLVMType | t.CPtr) -> int: - """注册函数指针变量的返回类型签名,0 成功""" - if name is None or ret_ty is None: - return 1 - if self._ensure_funcptr_sigs() == 0: - return 1 - if self.FuncptrCount >= MAX_FUNC_PTR_SIGS: - return 1 - idx: t.CSizeT = t.CSizeT(self.FuncptrCount) * 64 - # 槽位定长 64 字节,与 register_closure_name 一致用 strncpy 钳制防越界 - string.strncpy(self.FuncptrNames + idx, name, 63) - # ret_ty 是调用方 pool 分配的裸 LLVMType,1a 每文件 reset 后悬空; - # 深拷贝到 perm_pool(lookup_func_ptr_ret 跨文件读取) - ret_copy_fp: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( - CompilerFactory.get_perm_pool(), ret_ty) - if ret_copy_fp is not None: - self.FuncptrRets[self.FuncptrCount] = t.CUInt64T(ret_copy_fp) - else: - self.FuncptrRets[self.FuncptrCount] = t.CUInt64T(ret_ty) - self.FuncptrCount += 1 - return 0 - - def lookup_func_ptr_ret(self, name: str) -> llvmlite.LLVMType | t.CPtr: - """查函数指针变量的返回类型,None=未注册(调用时默认 i32)""" - if name is None or self.FuncptrNames is None: - return None - for i in range(self.FuncptrCount): - idx: t.CSizeT = t.CSizeT(i) * 64 - if string.strcmp(self.FuncptrNames + idx, name) == 0: - return (llvmlite.LLVMType | t.CPtr)( - t.CVoid(self.FuncptrRets[i], t.CPtr)) - return None - - def _translate_func_ptr_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - fp_alloca: llvmlite.Value | t.CPtr, - func_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """函数指针变量间接调用,返回结果 Value""" - if builder is None or fp_alloca is None: - return None - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - - # 1. load 函数地址 (i8*) - fn_i8: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, fp_alloca) - if fn_i8 is None: - return None - - # 2. 翻译实参并链接为 Value 链表 - head: llvmlite.Value | t.CPtr = None - tail: llvmlite.Value | t.CPtr = None - arg_count: int = 0 - ai: t.CSizeT - for ai in range(can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is not None: - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is not None: - arg_val.Next = None - if head is None: - head = arg_val - else: - tail.Next = arg_val - tail = arg_val - arg_count += 1 - - # 3. 按实参类型 + 注册的返回类型构造签名(未注册即 t.Callable 注解缺失,fail-fast) - ret_ty: llvmlite.LLVMType | t.CPtr = self.lookup_func_ptr_ret(func_name) - if ret_ty is None: - HandlesType.fatal_error( - None, - f"函数指针变量 '{func_name}' 的返回类型未注册(t.Callable 注解缺失)", - "TypeError") - ret_ty = i32_ty - fp_first: llvmlite.ParamNode | t.CPtr = None - fp_prev: llvmlite.ParamNode | t.CPtr = None - cur_v: llvmlite.Value | t.CPtr = head - for pi in range(arg_count): - if cur_v is None: - break - cur_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(cur_v) - pn2: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, cur_ty) - if pn2 is not None: - if fp_first is None: - fp_first = pn2 - if fp_prev is not None: - llvmlite.paramnode_set_next(fp_prev, pn2) - fp_prev = pn2 - cur_v = llvmlite.value_get_next(cur_v) - - func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, ret_ty, fp_first, arg_count) - if func_ty is None: - return None - func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty) - - # 4. bitcast i8* → 函数指针类型,间接调用 - fn_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, fn_i8, func_ptr_ty) - if fn_typed is None: - return None - return llvmlite.build_call_indirect(builder, fn_typed, head, arg_count, ret_ty) - - def translate_printf_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None): - """翻译 printf 调用(特殊处理格式字符串)""" - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None: - return - can: t.CSizeT = len(cargs) - if can == 0: - return - - arg0: ast.AST | t.CPtr = cargs.get(0) - if arg0 is None: - return - - fmt_str: str = None - arg0_kind: int = arg0.kind() - if arg0_kind == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg0) - if cn.const_kind == ast.CONST_STR: - fmt_str = cn.str_val - - if fmt_str is None: - return - - fmt_ptr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string( - builder, pool, mod, fmt_str, trans) - if fmt_ptr is None: - return - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - - # 翻译额外参数并链接 - prev: llvmlite.Value | t.CPtr = fmt_ptr - for ai in range(1, can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is not None: - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is not None: - # C ABI integer promotion: i8/i16 → i32(printf 变参函数要求) - arg_bits: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty) - if arg_bits != 0 and arg_bits < 32: - arg_val = HandlesExpr.coerce_to_type(builder, arg_val, i32_ty, arg) - # C ABI float promotion: float → double(printf 变参函数要求) - arg_fbits: int = HandlesExpr.get_llvm_float_bits(arg_val.Ty) - if arg_fbits != 0 and arg_fbits < 64: - double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) - arg_val = HandlesExpr.coerce_to_type(builder, arg_val, double_ty, arg) - arg_val.Next = None - prev.Next = arg_val - prev = arg_val - prev.Next = None - - # is_variadic=1: 生成带显式函数类型签名的 call(如 call i32 (i8*, ...) @printf), - # 让 llc 识别为 variadic 调用,生成正确的 Win64 ABI 代码(浮点参数同时传 XMM 和整数寄存器) - llvmlite.build_call(builder, "printf", fmt_ptr, can, i32_ty, 1) - - def translate_print_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None): - """翻译 print 调用(类型感知格式化 + 默认换行)""" - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None: - return - - FMT_BUF_SIZE: t.CSizeT = 256 - fmt_buf: bytes = stdlib.malloc(FMT_BUF_SIZE) - if fmt_buf is None: - return - fmt_buf[0] = '\0' - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - dbl_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) - - can: t.CSizeT = len(cargs) - arg_head: llvmlite.Value | t.CPtr = None - arg_tail: llvmlite.Value | t.CPtr = None - arg_count: int = 1 # 格式串本身是第 1 个 printf 参数 - - for ai in range(can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is None: - continue - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is None or arg_val.Ty is None: - # fail-fast:print 参数翻译失败必须终止编译,绝不在格式串写 - # 误导为数据问题而非编译器 bug。 - fb_pp: str = VLogger.fmt_buf() - if fb_pp is not None: - viperlib.snprintf(fb_pp, 1024, "print 参数翻译失败(表达式返回 None): [arg=%d]", ai) - VLogger.error(fb_pp, "PRINT") - HandlesType.fatal_error(arg, "print 参数翻译失败(表达式返回 None)", "TypeError") - return - - # 数组名(如 print(l),l: t.CArray[t.CChar, N]): - # translate_value 会 load 出数组值([N x T]),print 无法格式化; - # 按数组退化语义取数组 alloca 地址——字符数组 → %s(打印字符串内容), - # 其他元素类型 → 0x%llx(打印数组地址)。 - array_ptr: llvmlite.Value | t.CPtr = None - array_elem_bits: int = 0 - if arg.kind() == ast.ASTKind.Name and trans is not None: - anm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg) - if anm.id is not None: - arr_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, anm.id) - if arr_alloca is not None and arr_alloca.Ty is not None \ - and HandlesExpr.is_ptr_type(arr_alloca.Ty) != 0: - arr_pointee: llvmlite.LLVMType | t.CPtr = arr_alloca.Ty.Pointee - if arr_pointee is not None: - match arr_pointee: - case llvmlite.LLVMType.Array(arr_et, arr_n): - array_ptr = arr_alloca - array_elem_bits = HandlesExpr.get_llvm_type_bits(arr_et) - case _: - pass - - token: str = None - chain_arg: int = 1 # 1=该 token 消耗一个参数,0=纯文本 - arg_bits: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty) - arg_fbits: int = HandlesExpr.get_llvm_float_bits(arg_val.Ty) - - if array_ptr is not None: - # 数组退化:字符数组 → %s(bitcast [N x i8]* 到 i8*);其他 → 0x%llx - if array_elem_bits == 8: - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - token = "%s" - arg_val = llvmlite.build_bitcast(builder, array_ptr, i8_ptr_ty) - else: - token = "0x%llx" - arg_val = llvmlite.build_ptrtoint(builder, array_ptr, i64_ty) - elif HandlesExpr.is_ptr_type(arg_val.Ty) != 0: - # i8*(str/bytes)→ %s;其他指针 → 0x%llx - pointee: llvmlite.LLVMType | t.CPtr = arg_val.Ty.Pointee - if pointee is not None and HandlesExpr.get_llvm_type_bits(pointee) == 8: - token = "%s" - else: - token = "0x%llx" - arg_val = llvmlite.build_ptrtoint(builder, arg_val, i64_ty) - elif arg_bits != 0: - if arg_bits == 1: - token = "%d" - arg_val = llvmlite.build_zext(builder, arg_val, i32_ty) - elif arg_bits == 8: - token = "%d" - arg_val = llvmlite.build_sext(builder, arg_val, i32_ty) - elif arg_bits == 16: - token = "%d" - arg_val = llvmlite.build_sext(builder, arg_val, i32_ty) - elif arg_bits == 32: - token = "%d" - else: - token = "%lld" - elif arg_fbits != 0: - token = "%f" - if arg_fbits < 64: - arg_val = llvmlite.build_fpext(builder, arg_val, dbl_ty) - else: - # 结构体值/数组/函数等 → "(unknown)",不传参 - token = "(unknown)" - chain_arg = 0 - - # 追加格式 token - if string.strlen(fmt_buf) < FMT_BUF_SIZE - 16: - viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 16, "%s", token) - # 链接参数 - if chain_arg != 0: - arg_val.Next = None - if arg_tail is None: - arg_head = arg_val - else: - arg_tail.Next = arg_val - arg_tail = arg_val - arg_count += 1 - - # 追加默认换行(Python print 默认 end="\n") - if string.strlen(fmt_buf) < FMT_BUF_SIZE - 2: - viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 2, "\n") - - fmt_ptr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string( - builder, pool, mod, fmt_buf, trans) - stdlib.free(fmt_buf) - if fmt_ptr is None: - return - fmt_ptr.Next = arg_head - # is_variadic=1: 带显式函数类型签名(C ABI 变参调用) - llvmlite.build_call(builder, "printf", fmt_ptr, arg_count, i32_ty, 1) def _va_arg_get_alloca_ptr(self, pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, @@ -9209,6 +6445,7 @@ class CallGenMixin: # 回退:translate_value(可能返回 load 后的值,仅适用于已是指针的情况) return HandlesExpr.translate_value(builder, pool, mod, arg_node, funcs_ptr, func_count, trans) + def _resolve_va_arg_type(self, pool: memhub.MemBuddy | t.CPtr, type_node: ast.AST | t.CPtr, trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr: @@ -9233,6 +6470,7 @@ class CallGenMixin: HandlesType.fatal_error(type_node, "va_arg 类型解析失败", "TypeError") return llvmlite.Int32(pool) + def _translate_va_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, @@ -9274,6 +6512,7 @@ class CallGenMixin: # 生成 va_arg 指令 return llvmlite.build_va_arg(builder, ap_ptr, read_ty) + def _translate_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, @@ -9306,6 +6545,7 @@ class CallGenMixin: # 生成 va_arg 指令(使用 trans._va_list_ptr 作为 va_list 地址) return llvmlite.build_va_arg(builder, trans._va_list_ptr, read_ty) + def _translate_va_start_sugar(self, pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, @@ -9339,6 +6579,7 @@ class CallGenMixin: llvmlite.build_call(builder, "llvm.va_start", ap_i8, 1, void_ty_vs, 0) return llvmlite.const_int32(pool, 0) + def _translate_va_end_sugar(self, pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, @@ -9372,6 +6613,7 @@ class CallGenMixin: llvmlite.build_call(builder, "llvm.va_end", ap_i8, 1, void_ty_ve, 0) return llvmlite.const_int32(pool, 0) + def _get_func_fixed_param_count(self, func: llvmlite.Function | t.CPtr) -> int: """获取函数的固定参数数量(遍历 Params 链表)""" if func is None: @@ -9383,6 +6625,7 @@ class CallGenMixin: param = llvmlite.param_get_next(param) return count + def _check_and_promote_variadic_call(self, pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, @@ -9478,346 +6721,3 @@ class CallGenMixin: return 1 - def init_func_table(self, pool: memhub.MemBuddy | t.CPtr, - max_count: int) -> HandlesExprCall.FuncEntry | t.CPtr: - """分配并清零函数表数组""" - size: t.CSizeT = max_count * HandlesExprCall.FuncEntry.__sizeof__() - funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = pool.alloc(size) - if funcs_ptr is not None: - string.memset(funcs_ptr, 0, size) - return funcs_ptr - - def find_func_in_table(self, funcs: HandlesExprCall.FuncEntry | t.CPtr, - func_count: int, - name: str) -> llvmlite.Function | t.CPtr: - """在函数表中按名称查找,返回 Function 指针或 None""" - if name is None or funcs is None: - return None - entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__() - for i in range(func_count): - entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size - entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - if entry.Name is not None: - if string.strcmp(entry.Name, name) == 0: - return entry.Func - return None - - def add_func_to_table(self, funcs: HandlesExprCall.FuncEntry | t.CPtr, - func_count: int, - name: str, - func: llvmlite.Function | t.CPtr, - max_count: int, - defaults: t.CVoid | t.CPtr = None, - default_count: int = 0, - param_count: int = 0, - pool: memhub.MemBuddy | t.CPtr = None) -> int: - """添加函数到函数表,返回 0 成功 - - Args: - defaults: ast.Arguments.defaults 列表节点指针,None=无默认值 - default_count: 默认值数量(len(defaults)) - param_count: 形参数量(不含 self,len(args.args)) - pool: 内存池(用于生成 TypeStr;None 时 TypeStr 为空,vtable 回退读 Func 对象) - """ - if name is None or func is None or funcs is None: - return 1 - if func_count >= max_count: - return 1 - entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__() - entry_addr: t.CUInt64T = t.CUInt64T(funcs) + func_count * entry_size - entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - entry.Name = name - entry.Func = func - entry.Defaults = defaults - entry.DefaultCount = default_count - entry.ParamCount = param_count - # 同时注册到全局函数表(供跨模块 vtable 初始化查找) - self._register_global_func(name, func, pool) - # 同时注册到全局默认参数表(供跨模块调用时填充默认值) - if default_count > 0: - self._register_global_defaults(name, defaults, default_count, param_count) - return 0 - - def _init_global_func_table(self) -> int: - """初始化全局函数表(用 stdlib.malloc 分配,生命周期=整个程序)""" - if self.GlobalFuncs is not None: - return 1 - size: t.CSizeT = GLOBAL_FUNC_MAX * HandlesExprCall.FuncEntry.__sizeof__() - self.GlobalFuncs = CompilerFactory.get_perm_pool().alloc(size) - if self.GlobalFuncs is None: - return 0 - string.memset(self.GlobalFuncs, 0, size) - self.GlobalFuncCount = 0 - return 1 - - def _build_func_type_str(self, pool: memhub.MemBuddy | t.CPtr, - func: llvmlite.Function | t.CPtr) -> str: - """生成函数类型文本(stdlib 分配)""" - if func is None: - return None - # 类型文本可能较长(SHA1 限定命名结构体 + 多参数),用 1024 缓冲 - ty_buf: str = pool.alloc(1024) - if ty_buf is None: - return None - ty_buf[0] = '\0' - - # 返回类型 - ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func) - ret_part: str = pool.alloc(512) - if ret_part is not None and ret_ty is not None: - ret_part[0] = '\0' - llvmlite.TypePrint(ret_part, 512, ret_ty, pool) - self._asm_append_cstr(ty_buf, 1024, ret_part) - self._asm_append_cstr(ty_buf, 1024, " (") - - # 参数类型(全部经 _asm_append_cstr 有界追加,防止 strcat 无界写穿 1024 缓冲) - cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) - first: int = 1 - param_part: str = pool.alloc(512) - while cur is not None: - if first == 0: - self._asm_append_cstr(ty_buf, 1024, ", ") - if param_part is not None: - param_part[0] = '\0' - param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur) - if param_ty is not None: - llvmlite.TypePrint(param_part, 512, param_ty, pool) - self._asm_append_cstr(ty_buf, 1024, param_part) - cur = llvmlite.param_get_next(cur) - first = 0 - self._asm_append_cstr(ty_buf, 1024, ")") - - # 深拷贝到 stdlib 区(TypeStr 跨文件永久存活) - ts_len: t.CSizeT = string.strlen(ty_buf) - ts_copy: str = CompilerFactory.get_perm_pool().alloc(ts_len + 1) - if ts_copy is None: - return None - string.strcpy(ts_copy, ty_buf) - return ts_copy - - def _register_global_func(self, name: str, func: llvmlite.Function | t.CPtr, - pool: memhub.MemBuddy | t.CPtr = None) -> int: - """注册函数到全局表(已存在则跳过),返回 0 成功 - - 直接操作全局表,不调用 add_func_to_table,避免递归。 - pool 用于生成 TypeStr(None 时 TypeStr 为空)。 - """ - if name is None or func is None: - return 1 - if self._init_global_func_table() == 0: - return 1 - # 已存在则跳过(避免重复) - if self.find_func_in_table(self.GlobalFuncs, self.GlobalFuncCount, name) is not None: - return 0 - if self.GlobalFuncCount >= GLOBAL_FUNC_MAX: - return 1 - # 直接写入全局表(不调用 add_func_to_table,避免递归) - entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__() - entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalFuncs) + self.GlobalFuncCount * entry_size - entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - # Name 深拷贝到 stdlib 区:全局表跨文件永久存活,pool 内名字会被 1b 每文件 - # reset_to(mark1) 回收导致悬空(vtable 生成 find_func_global 后 strcmp 崩溃) - name_len: t.CSizeT = string.strlen(name) - name_copy: str = CompilerFactory.get_perm_pool().alloc(name_len + 1) - if name_copy is None: - return 1 - string.strcpy(name_copy, name) - entry.Name = name_copy - entry.Func = func - # TypeStr 不在此生成:函数参数在 add_func_to_table 之后才添加, - # 需由调用方在参数添加完成后调用 update_global_func_typestr 补全。 - self.GlobalFuncCount += 1 - return 0 - - def update_global_func_typestr(self, pool: memhub.MemBuddy | t.CPtr, - name: str, - func: llvmlite.Function | t.CPtr) -> int: - """更新全局函数表的 TypeStr(在函数参数全部添加完成后调用) - - 调用时机:add_func_to_table 注册后、llvmlite.add_param 全部执行完。 - 生成 ret_ty (param1_ty, ...) 类型文本(stdlib 深拷贝), - 供 vtable 生成在 func 被 1b reset 后使用。 - """ - if name is None or func is None: - return 1 - entry: HandlesExprCall.FuncEntry | t.CPtr = self.find_func_entry_global(name) - if entry is None: - return 1 - entry.TypeStr = self._build_func_type_str(pool, func) - return 0 - - def find_func_global(self, name: str) -> llvmlite.Function | t.CPtr: - """在全局函数表中按名称查找,返回 Function 指针或 None""" - if name is None or self.GlobalFuncs is None: - return None - return self.find_func_in_table(self.GlobalFuncs, self.GlobalFuncCount, name) - - def find_func_entry_global(self, name: str) -> HandlesExprCall.FuncEntry | t.CPtr: - """在全局函数表中按名称查找,返回完整 FuncEntry(含 TypeStr)或 None""" - if name is None or self.GlobalFuncs is None: - return None - entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__() - for i in range(self.GlobalFuncCount): - entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalFuncs) + i * entry_size - entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - if entry.Name is not None: - if string.strcmp(entry.Name, name) == 0: - return entry - return None - - def _init_global_defaults_table(self) -> int: - """初始化全局默认参数表""" - if self.GlobalDefaults is not None: - return 1 - size: t.CSizeT = GLOBAL_DEFAULTS_MAX * HandlesExprCall.FuncDefaultsEntry.__sizeof__() - self.GlobalDefaults = CompilerFactory.get_perm_pool().alloc(size) - if self.GlobalDefaults is None: - return 0 - string.memset(self.GlobalDefaults, 0, size) - self.GlobalDefaultsCount = 0 - return 1 - - def _register_global_defaults(self, name: str, - defaults: t.CVoid | t.CPtr, - default_count: int, - param_count: int) -> int: - """注册函数默认参数到全局表,返回 0 成功 - - 注册时提取每个默认值 Constant 的常量快照到 stdlib(ConstKinds/ConstInts/ConstStrs), - 跨模块调用时优先用快照重建常量 IR,避免读取被 reset 回收的 pool 内 AST。 - """ - if name is None or defaults is None: - return 1 - if self._init_global_defaults_table() == 0: - return 1 - # 已存在则跳过 - if self.find_func_defaults(name) is not None: - return 0 - if self.GlobalDefaultsCount >= GLOBAL_DEFAULTS_MAX: - return 1 - entry_size: t.CSizeT = HandlesExprCall.FuncDefaultsEntry.__sizeof__() - entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalDefaults) + self.GlobalDefaultsCount * entry_size - entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr = (HandlesExprCall.FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - # Name 深拷贝到 stdlib(全局表跨文件永久存活) - nm_len: t.CSizeT = string.strlen(name) - nm_copy: str = CompilerFactory.get_perm_pool().alloc(nm_len + 1) - if nm_copy is None: - return 1 - string.strcpy(nm_copy, name) - entry.Name = nm_copy - entry.Defaults = defaults - entry.DefaultCount = default_count - entry.ParamCount = param_count - # 提取常量快照到 stdlib - if default_count > 0: - kinds: t.CInt | t.CPtr = CompilerFactory.get_perm_pool().alloc(default_count * 4) - ints: t.CInt64T | t.CPtr = CompilerFactory.get_perm_pool().alloc(default_count * 8) - strs: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(default_count * 8) - if kinds is not None and ints is not None and strs is not None: - string.memset(kinds, 0, default_count * 4) - string.memset(ints, 0, default_count * 8) - string.memset(strs, 0, default_count * 8) - dl: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(defaults), t.CPtr)) - di: int - for di in range(default_count): - dnode: ast.AST | t.CPtr = dl.get(di) - if dnode is not None and dnode.kind() == ast.ASTKind.Constant: - dcn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(dnode) - kinds[di] = dcn.const_kind - ints[di] = dcn.int_val - if dcn.const_kind == ast.CONST_STR and dcn.str_val is not None: - slen: t.CSizeT = string.strlen(dcn.str_val) - scopy: str = CompilerFactory.get_perm_pool().alloc(slen + 1) - if scopy is not None: - string.strcpy(scopy, dcn.str_val) - strs[di] = t.CSizeT(scopy) - elif dnode is not None and dnode.kind() == ast.ASTKind.Name: - # CDefine Name 引用默认值(如 share: ULONG = SHARE_READ): - # 注册时求值 CDefine 存快照——否则跨模块重建时快照为空 - # → "跨模块默认参数无法重建"(FileIoTest File.__init__ 根因)。 - # 仅支持已注册的整型 CDefine;未注册保持 kinds=0(重建时 - # 仍 fail-fast,绝不静默回退)。 - dnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(dnode) - if dnm.id is not None: - cdef_v: int = HandlesType.lookup_cdefine_constant(dnm.id) - if HandlesType.is_cdefine_found() != 0: - kinds[di] = ast.CONST_INT - ints[di] = cdef_v - entry.ConstKinds = kinds - entry.ConstInts = ints - entry.ConstStrs = strs - self.GlobalDefaultsCount += 1 - return 0 - - def find_func_defaults(self, name: str) -> HandlesExprCall.FuncDefaultsEntry | t.CPtr: - """按函数名查找默认参数信息,返回 FuncDefaultsEntry 或 None""" - if name is None or self.GlobalDefaults is None: - return None - entry_size: t.CSizeT = HandlesExprCall.FuncDefaultsEntry.__sizeof__() - i: int = 0 - while i < self.GlobalDefaultsCount: - entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalDefaults) + i * entry_size - entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr = (HandlesExprCall.FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - if entry.Name is not None: - if string.strcmp(entry.Name, name) == 0: - return entry - i += 1 - return None - - def _build_const_from_snapshot(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - gd_entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr, - di: int, - trans: HT.Translator | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr) -> llvmlite.Value | t.CPtr: - """从快照重建第 di 个默认值常量 IR""" - if gd_entry is None or gd_entry.ConstKinds is None or gd_entry.ConstInts is None: - return None - if di < 0 or di >= gd_entry.DefaultCount: - return None - kind: t.CInt = gd_entry.ConstKinds[di] - ival: t.CInt64T = gd_entry.ConstInts[di] - if kind == ast.CONST_INT: - if ival > 2147483647 or ival < -2147483648: - return llvmlite.const_int64(pool, ival) - return llvmlite.const_int32(pool, ival) - elif kind == ast.CONST_BOOL: - if ival != 0: - return llvmlite.const_int32(pool, 1) - return llvmlite.const_int32(pool, 0) - elif kind == ast.CONST_NONE: - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - return llvmlite.ConstNull(pool, i8_ptr_ty, "null") - elif kind == ast.CONST_STR: - if gd_entry.ConstStrs is not None and gd_entry.ConstStrs[di] != 0: - sv: str = (str | t.CPtr)(t.CVoid(gd_entry.ConstStrs[di], t.CPtr)) - return HandlesExpr.create_global_string(builder, pool, mod, sv, trans) - # 无法重建的(如 CONST_FLOAT/复杂表达式)返回 None,调用方回退到 AST - return None - - def find_func_entry_in_table(self, funcs: HandlesExprCall.FuncEntry | t.CPtr, - func_count: int, - name: str) -> HandlesExprCall.FuncEntry | t.CPtr: - """在函数表中按名称查找,返回完整 FuncEntry 或 None""" - if name is None or funcs is None: - return None - entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__() - i: int = 0 - while i < func_count: - entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size - entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - if entry.Name is not None: - if string.strcmp(entry.Name, name) == 0: - return entry - i += 1 - return None - - def NewExprCallHandle(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr) -> HandlesExprCall.ExprCallHandle | t.CPtr: - h: HandlesExprCall.ExprCallHandle | t.CPtr = pool.alloc(HandlesExprCall.ExprCallHandle.__sizeof__()) - if h is None: - return None - string.memset(h, 0, HandlesExprCall.ExprCallHandle.__sizeof__()) - h.Trans = trans - return h diff --git a/App/lib/core/Gen/Generator.vp b/App/lib/core/Gen/Generator.vp index 1c00bc4..f78a41e 100644 --- a/App/lib/core/Gen/Generator.vp +++ b/App/lib/core/Gen/Generator.vp @@ -7,6 +7,9 @@ import lib.core.Gen.TypeGenMixin as TypeGenMixin import lib.core.Gen.StructGenMixin as StructGenMixin import lib.core.Gen.ExprGenMixin as ExprGenMixin import lib.core.Gen.CallGenMixin as CallGenMixin +import lib.core.Gen.CallGenBase as CallGenBase +import lib.core.Gen.CallGenLeafKit as CallGenLeafKit +import lib.core.Gen.CallGenCBuiltin as CallGenCBuiltin import lib.core.Gen.FuncGenMixin as FuncGenMixin import lib.core.Gen.ClassGenMixin as ClassGenMixin import lib.core.Gen.ImportsGenMixin as ImportsGenMixin @@ -33,7 +36,9 @@ import lib.core.Handles.HandlesExprCall as HandlesExprCall @t.NoVTable class Generator(BaseGenMixin.BaseGenMixin, TypeGenMixin.TypeGenMixin, StructGenMixin.StructGenMixin, ExprGenMixin.ExprGenMixin, - CallGenMixin.CallGenMixin, FuncGenMixin.FuncGenMixin, + CallGenMixin.CallGenMixin, CallGenBase.CallGenBase, + CallGenLeafKit.CallGenLeafKit, CallGenCBuiltin.CallGenCBuiltin, + FuncGenMixin.FuncGenMixin, ClassGenMixin.ClassGenMixin, ImportsGenMixin.ImportsGenMixin, StmtGenMixin.StmtGenMixin, AssignGenMixin.AssignGenMixin, VarGenMixin.VarGenMixin, TranslatorGenMixin.TranslatorGenMixin): diff --git a/App/lib/core/Handles/HandlesExprCall.vp b/App/lib/core/Handles/HandlesExprCall.vp index 7994083..9d59467 100644 --- a/App/lib/core/Handles/HandlesExprCall.vp +++ b/App/lib/core/Handles/HandlesExprCall.vp @@ -1766,3 +1766,53 @@ def NewExprCallHandle(pool: memhub.MemBuddy | t.CPtr, if g is not None: return g.NewExprCallHandle(pool, trans) return None + + +# ============================================================ +# _make_vtable_ref_i8 / _emit_eh_guarded_call / _translate_isinstance +# (追加91:CallGenMixin 拆分后顶层经委托调用 CallGenLeafKit 方法—— +# TPV self 调用仅支持 1 级父类,跨 Mixin 统一走 _g_gen 委托) +# ============================================================ +def _make_vtable_ref_i8(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """构造类 vtable 地址引用(i8*)(委托到 gen._make_vtable_ref_i8)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._make_vtable_ref_i8(pool, builder, mod, class_name, trans) + return None + + +def _emit_eh_guarded_call(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + func: llvmlite.Function | t.CPtr, + call_name: str, + head: llvmlite.Value | t.CPtr, + count: int, + ret_ty: llvmlite.LLVMType | t.CPtr, + is_variadic: int) -> llvmlite.Value | t.CPtr: + """带 try-except EH 检测的函数调用(委托到 gen._emit_eh_guarded_call)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._emit_eh_guarded_call(builder, pool, mod, trans, func, call_name, head, count, ret_ty, is_variadic) + return None + + +def _translate_isinstance(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + obj_node: ast.AST | t.CPtr, + cls_node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译 isinstance()(委托到 gen._translate_isinstance)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._translate_isinstance(pool, builder, mod, obj_node, cls_node, trans) + return None