import t, c from stdint import * import ast import llvmlite import memhub import string 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.HandlesStruct as HandlesStruct import lib.core.Handles.HandlesImports as HandlesImports import lib.core.Handles.HandlesClassDef as HandlesClassDef import lib.core.StubMerger as StubMerger # ============================================================ # 模块 SHA1 查询(委托给 StubMerger 全局存储器) # # 翻译时用于跨模块函数调用名混淆: # string.strchr(...) → call @{sha1_of_string}.strchr(...) # # 数据来源是 StubMerger.PopulateSha1MapStore/AppendToSha1MapStore # 填充的全局存储器,不再维护独立的 SHA1 映射表副本。 # ============================================================ def _lookup_module_sha1(mod_name: str) -> str: """查找模块名对应的 SHA1,找不到返回 None 委托给 StubMerger.LookupSha1ByModName(精确匹配 + 包名回退)。 """ return StubMerger.LookupSha1ByModName(mod_name) def _lookup_module_sha1_suffix(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) # ============================================================ # 全局 CExport 函数表(module_sha1 + func_name) # # t.CExport 函数定义时不加 SHA1 前缀(如 @strlen), # 跨模块调用时需要查表确认目标函数是否是 CExport 函数。 # 若是,使用裸名调用(@strlen);否则使用 @{sha1}.func。 # 必须包含模块 SHA1 记录,避免同名跨模块函数冲突 # (一个模块有 CExport 的 strlen→@strlen,另一个没有→@{sha1}.strlen)。 # ============================================================ _g_cexport_sha1_arr: bytes = None _g_cexport_func_arr: bytes = None _g_cexport_count: int = 0 _CEXPORT_MAX: t.CDefine = 256 def register_cexport_func(sha1: str, func_name: str) -> int: """注册 CExport 函数到全局表(sha1+func_name 二元组)""" global _g_cexport_sha1_arr global _g_cexport_func_arr global _g_cexport_count if sha1 is None or func_name is None: return 0 if _g_cexport_sha1_arr is None: _g_cexport_sha1_arr = stdlib.malloc(_CEXPORT_MAX * 17) _g_cexport_func_arr = stdlib.malloc(_CEXPORT_MAX * 64) if _g_cexport_sha1_arr is None or _g_cexport_func_arr is None: return 0 string.memset(_g_cexport_sha1_arr, 0, _CEXPORT_MAX * 17) string.memset(_g_cexport_func_arr, 0, _CEXPORT_MAX * 64) if _g_cexport_count < _CEXPORT_MAX: idx: t.CSizeT = t.CSizeT(_g_cexport_count) * 17 string.strcpy(_g_cexport_sha1_arr + idx, sha1) idx2: t.CSizeT = t.CSizeT(_g_cexport_count) * 64 string.strcpy(_g_cexport_func_arr + idx2, func_name) _g_cexport_count += 1 return 1 return 0 def is_cexport_func(sha1: str, func_name: str) -> int: """检查 (sha1, func_name) 是否是 CExport 函数""" if sha1 is None or func_name is None: return 0 if _g_cexport_sha1_arr is None: return 0 for i in range(_g_cexport_count): idx: t.CSizeT = t.CSizeT(i) * 17 if string.strcmp(_g_cexport_sha1_arr + idx, sha1) == 0: idx2: t.CSizeT = t.CSizeT(i) * 64 if string.strcmp(_g_cexport_func_arr + idx2, func_name) == 0: return 1 return 0 # ============================================================ # _lookup_mod_sha1 - 从 from_imports 查找类所属模块的 SHA1 # # lookup_from_import 返回指向 from_imports 内部的指针,不是 null 终止 # (如 "namespace_defs Gadget:namespace_defs ...")。此函数手动截断 # 模块名,复制到新缓冲区,再查找 SHA1(精确+后缀匹配)。 # ============================================================ def _lookup_mod_sha1(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 _lookup_sha1_from_modname_raw(pool, mod_name_raw) # ============================================================ # _lookup_sha1_from_modname_raw - 原始模块名 → SHA1 # # 截断模块名(lookup_from_import 返回内部指针,空格/冒号/null 分隔), # 去掉相对导入前导点,再精确+后缀查找 SHA1。 # 供 _lookup_mod_sha1 与 HandlesExpr._lookup_cross_module_cdefine 复用。 # ============================================================ def _lookup_sha1_from_modname_raw(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 = _lookup_module_sha1(base_mod) if sha1 is None: sha1 = _lookup_module_sha1_suffix(base_mod) return sha1 # ============================================================ # HandlesExprCall - 函数调用表达式处理(Mixin 继承模式) # # 工具函数和 FuncEntry 保留为模块级,ExprCallHandle 提供 trans 接口 # ============================================================ # ============================================================ # 在模块函数链表中按名称查找函数 # ============================================================ def find_func_in_module(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: t.CChar | t.CPtr = 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 前缀名 cur = mod.FuncHead while cur is not None: cur_name2: t.CChar | t.CPtr = 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: return cur cur = llvmlite.function_get_next(cur) return None # ============================================================ # _ensure_c_lib_declare - 为已知的 C 库函数创建 declare 声明 # # 对应 TPC 的 _C_LIB_FUNCS 机制。当裸名调用 memset/memmove/memcmp/ # strcmp/strlen 等已知 C 库函数时,自动在当前模块创建 declare, # 避免报 "裸名调用未定义且未导入" 错误。 # memcpy 不在此处理(已有 _emit_llvm_memcpy_intrinsic 映射到 @llvm.memcpy)。 # # Args: # pool: 内存池 # mod: LLVM 模块 # name: 函数名 # # Returns: # Function 指针(已创建 declare),或 None 如果不是已知 C 库函数 # ============================================================ def _ensure_c_lib_declare(pool: memhub.MemBuddy | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, name: str) -> llvmlite.Function | t.CPtr: """为已知的 C 库函数创建 declare 声明""" if pool is None or mod is None or name is None: return None i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) ret_ty: llvmlite.LLVMType | t.CPtr = None params: int = 0 # 参数数量 if string.strcmp(name, "strlen") == 0 or string.strcmp(name, "strlength") == 0: ret_ty = i64_ty params = 1 elif string.strcmp(name, "memset") == 0: ret_ty = i8_ptr_ty params = 3 elif string.strcmp(name, "memcpy") == 0: ret_ty = i8_ptr_ty params = 3 elif string.strcmp(name, "memmove") == 0: ret_ty = i8_ptr_ty params = 3 elif string.strcmp(name, "memcmp") == 0: ret_ty = i32_ty params = 3 elif string.strcmp(name, "strcmp") == 0: ret_ty = i32_ty params = 2 elif string.strcmp(name, "strncmp") == 0: ret_ty = i32_ty params = 3 elif string.strcmp(name, "strcpy") == 0: ret_ty = i8_ptr_ty params = 2 elif string.strcmp(name, "strncpy") == 0: ret_ty = i8_ptr_ty params = 3 elif string.strcmp(name, "strcat") == 0: ret_ty = i8_ptr_ty params = 2 elif string.strcmp(name, "puts") == 0: ret_ty = i32_ty params = 1 elif string.strcmp(name, "atoi") == 0: ret_ty = i32_ty params = 1 elif string.strcmp(name, "atol") == 0: ret_ty = i64_ty params = 1 elif string.strcmp(name, "abs") == 0: ret_ty = i32_ty params = 1 elif string.strcmp(name, "labs") == 0: ret_ty = i64_ty params = 1 else: return None # 创建 declare fn: llvmlite.Function | t.CPtr = llvmlite.create_declare(pool, mod, name, ret_ty) if fn is None: return None # 添加参数 if params == 1: if string.strcmp(name, "abs") == 0: llvmlite.add_param(pool, fn, i32_ty, "n") elif string.strcmp(name, "labs") == 0: llvmlite.add_param(pool, fn, i64_ty, "n") else: llvmlite.add_param(pool, fn, i8_ptr_ty, "s") elif params == 2: llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") llvmlite.add_param(pool, fn, i8_ptr_ty, "src") elif params == 3: if string.strcmp(name, "memset") == 0: llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") llvmlite.add_param(pool, fn, i32_ty, "c") llvmlite.add_param(pool, fn, i64_ty, "n") else: llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") llvmlite.add_param(pool, fn, i8_ptr_ty, "src") llvmlite.add_param(pool, fn, i64_ty, "n") return fn # ============================================================ # _infer_external_func_ret_ty - 根据函数名推断外部函数返回类型 # # stubs 在翻译后才注入 IR,翻译时模块中无 stub 函数声明, # 因此对 includes 库函数(如 string.strchr 返回 i8*)需根据 # 函数名推断返回类型,避免指针被截断为 i32。 # # 覆盖 includes/string.py 所有导出函数: # i8*: strcpy, strncpy, strchr, strrchr, strstr, memset, memset32, memcpy, memmove # i64: strlen, atoll # double: atof # i8: samestr # i32(默认): strcmp, strncmp, memcmp, strspn, atoi, split # ============================================================ def _infer_external_func_ret_ty(pool: memhub.MemBuddy | t.CPtr, func_name: str) -> llvmlite.LLVMType | t.CPtr: """根据函数名推断外部 includes 函数的返回类型 支持三种函数名形式: 1. 裸名: "parse", "strlen" 2. 别名: "json_parse"(from X import parse as json_parse) 3. 带 SHA1 前缀: "240a9a4157959a9f.parse"(跨模块调用 mangled name) """ if pool is None or func_name is None: return llvmlite.Int32(pool) # 提取裸函数名:去掉 SHA1 前缀(如 "240a9a4157959a9f.parse" → "parse") # SHA1 前缀是 16 位十六进制 + '.',检查是否有 '.' 分隔 bare_name: str = func_name dot_pos: str = string.strrchr(func_name, 46) # 46 = ord('.') if dot_pos is not None: # '.' 后的部分是裸函数名 bare_name = dot_pos + 1 i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) # 返回 i8* 的函数(指针返回值,截断会导致错误) if string.strcmp(bare_name, "strchr") == 0 or string.strcmp(func_name, "strchr") == 0: return i8_ptr_ty if string.strcmp(bare_name, "strrchr") == 0 or string.strcmp(func_name, "strrchr") == 0: return i8_ptr_ty if string.strcmp(bare_name, "strstr") == 0 or string.strcmp(func_name, "strstr") == 0: return i8_ptr_ty if string.strcmp(bare_name, "strcpy") == 0 or string.strcmp(func_name, "strcpy") == 0: return i8_ptr_ty if string.strcmp(bare_name, "strncpy") == 0 or string.strcmp(func_name, "strncpy") == 0: return i8_ptr_ty if string.strcmp(bare_name, "memset") == 0 or string.strcmp(func_name, "memset") == 0: return i8_ptr_ty if string.strcmp(bare_name, "memset32") == 0 or string.strcmp(func_name, "memset32") == 0: return i8_ptr_ty if string.strcmp(bare_name, "memcpy") == 0 or string.strcmp(func_name, "memcpy") == 0: return i8_ptr_ty if string.strcmp(bare_name, "memmove") == 0 or string.strcmp(func_name, "memmove") == 0: return i8_ptr_ty # JSON 解析函数返回 JsonValue*(指针) # from json.__parser import parse as json_parse → 别名 json_parse 也需覆盖 if string.strcmp(bare_name, "parse") == 0 or string.strcmp(func_name, "parse") == 0 or string.strcmp(func_name, "json_parse") == 0: return i8_ptr_ty # MemBuddy 方法(当类型信息丢失时可能走外部函数路径) if string.strcmp(func_name, "alloc") == 0: return llvmlite.Ptr(pool, llvmlite.Int8(pool)) if string.strcmp(func_name, "calloc") == 0: return llvmlite.Ptr(pool, llvmlite.Int8(pool)) if string.strcmp(func_name, "realloc") == 0: return llvmlite.Ptr(pool, llvmlite.Int8(pool)) if string.strcmp(func_name, "alloc_buf") == 0: return llvmlite.Ptr(pool, llvmlite.Int8(pool)) # VLogger 模块函数(跨模块调用时 stub 未注入,返回指针被截断为 i32 导致崩溃) if string.strcmp(func_name, "get_logger") == 0: return llvmlite.Ptr(pool, llvmlite.Int8(pool)) if string.strcmp(func_name, "fmt_buf") == 0: return llvmlite.Ptr(pool, llvmlite.Int8(pool)) # Config 模块函数(跨模块调用时 stub 未注入,返回 i8* 被 inttoptr i32 截断导致路径损坏) if string.strcmp(func_name, "get_includes_binary_dir") == 0: return llvmlite.Ptr(pool, llvmlite.Int8(pool)) # HandlesType 模块函数(返回 ast.AST|t.CPtr 联合类型,跨模块推断为 i32 导致指针截断) if string.strcmp(bare_name, "_parse_type_string") == 0: return llvmlite.Ptr(pool, llvmlite.Int8(pool)) # 返回 i64 的函数 if string.strcmp(func_name, "strlen") == 0: return llvmlite.Int64(pool) if string.strcmp(func_name, "atoll") == 0: return llvmlite.Int64(pool) # 返回 double 的函数 if string.strcmp(func_name, "atof") == 0: return llvmlite.Double(pool) # 返回 i8 的函数 if string.strcmp(func_name, "samestr") == 0: return llvmlite.Int8(pool) # Win32 API 返回指针(VOIDPTR/HANDLE)的函数 # stubs 翻译时未注入,需推断返回 i8* 避免指针被截断为 i32 导致解引用崩溃 i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) if string.strcmp(func_name, "VirtualAlloc") == 0: return i8_ptr_ty if string.strcmp(func_name, "HeapAlloc") == 0: return i8_ptr_ty if string.strcmp(func_name, "HeapReAlloc") == 0: return i8_ptr_ty if string.strcmp(func_name, "HeapCreate") == 0: return i8_ptr_ty if string.strcmp(func_name, "GetProcessHeap") == 0: return i8_ptr_ty if string.strcmp(func_name, "GlobalAlloc") == 0: return i8_ptr_ty if string.strcmp(func_name, "GlobalFree") == 0: return i8_ptr_ty if string.strcmp(func_name, "GlobalLock") == 0: return i8_ptr_ty if string.strcmp(func_name, "LocalAlloc") == 0: return i8_ptr_ty if string.strcmp(func_name, "LocalFree") == 0: return i8_ptr_ty if string.strcmp(func_name, "GetProcAddress") == 0: return i8_ptr_ty if string.strcmp(func_name, "GetModuleHandleA") == 0: return i8_ptr_ty if string.strcmp(func_name, "GetModuleHandleW") == 0: return i8_ptr_ty if string.strcmp(func_name, "LoadLibraryA") == 0: return i8_ptr_ty if string.strcmp(func_name, "LoadLibraryW") == 0: return i8_ptr_ty # Win32 Handle 返回函数(HANDLE = void* = i8*) if string.strcmp(func_name, "GetStdHandle") == 0: return i8_ptr_ty if string.strcmp(func_name, "CreateFileA") == 0: return i8_ptr_ty if string.strcmp(func_name, "CreateFileW") == 0: return i8_ptr_ty if string.strcmp(func_name, "FindFirstFileA") == 0: return i8_ptr_ty if string.strcmp(func_name, "FindFirstFileW") == 0: return i8_ptr_ty # Win32 API 返回 i64 (SIZE_T) 的函数 if string.strcmp(func_name, "VirtualQuery") == 0: return llvmlite.Int64(pool) if string.strcmp(func_name, "HeapSize") == 0: return llvmlite.Int64(pool) if string.strcmp(func_name, "HeapCompact") == 0: return llvmlite.Int64(pool) if string.strcmp(func_name, "GlobalSize") == 0: return llvmlite.Int64(pool) # llvmlite build_* 函数返回类型推断 # stubs 翻译时未注入,需推断返回类型避免指针被截断为 i32 # 大多数 build_* 函数返回 Value*(指针),少数终止指令返回 void if string.strncmp(func_name, "build_", 6) == 0: # 返回 void 的 build_* 函数(终止指令和无返回值指令) if string.strcmp(func_name, "build_ret") == 0 or string.strcmp(func_name, "build_ret_void") == 0 or \ string.strcmp(func_name, "build_store") == 0 or string.strcmp(func_name, "build_br") == 0 or \ string.strcmp(func_name, "build_cond_br") == 0 or string.strcmp(func_name, "build_unreachable") == 0 or \ string.strcmp(func_name, "build_switch") == 0: return llvmlite.Void(pool) # 其他 build_* 函数返回 Value*(指针) return llvmlite.Ptr(pool, llvmlite.Int8(pool)) # llvmlite 类型工厂函数返回 LLVMType*(指针) # Int1/Int8/Int16/Int32/Int64/Ptr/Func/Array/Struct/Void/Half/Float/Double/FP128/Label # new_param_node/new_phi_incoming 返回 ParamNode*/PhiIncoming*(指针) # const_int32/const_int64/ConstFloat/ConstZero/ConstNull/ConstInt 返回 Value*(指针) # function_get_name/param_get_ty 等访问器返回指针 if string.strcmp(func_name, "Int1") == 0 or string.strcmp(func_name, "Int8") == 0 or string.strcmp(func_name, "Int16") == 0 or \ string.strcmp(func_name, "Int32") == 0 or string.strcmp(func_name, "Int64") == 0 or string.strcmp(func_name, "Ptr") == 0 or \ string.strcmp(func_name, "Func") == 0 or string.strcmp(func_name, "Array") == 0 or string.strcmp(func_name, "Struct") == 0 or \ string.strcmp(func_name, "Void") == 0 or string.strcmp(func_name, "Half") == 0 or string.strcmp(func_name, "Float") == 0 or \ string.strcmp(func_name, "Double") == 0 or string.strcmp(func_name, "FP128") == 0 or string.strcmp(func_name, "Label") == 0 or \ string.strcmp(func_name, "new_param_node") == 0 or string.strcmp(func_name, "new_phi_incoming") == 0 or \ string.strcmp(func_name, "const_int32") == 0 or string.strcmp(func_name, "const_int64") == 0 or \ string.strcmp(func_name, "ConstFloat") == 0 or string.strcmp(func_name, "ConstZero") == 0 or \ string.strcmp(func_name, "ConstNull") == 0 or string.strcmp(func_name, "ConstInt") == 0 or \ string.strcmp(func_name, "function_get_name") == 0 or string.strcmp(func_name, "param_get_ty") == 0 or \ string.strcmp(func_name, "value_get_ty") == 0 or string.strcmp(func_name, "value_get_next") == 0 or \ string.strcmp(func_name, "function_get_ret_ty") == 0 or string.strcmp(func_name, "function_get_params") == 0 or \ string.strcmp(func_name, "function_get_param_head") == 0 or string.strcmp(func_name, "param_get_next") == 0: return llvmlite.Ptr(pool, llvmlite.Int8(pool)) # 默认 i32(整数):与本模块函数定义的默认返回类型一致(HandlesFunctions.py line 324) # 已知返回指针的函数在上方显式列出(返回 i8*),已知返回 i64 的函数也显式列出 # 避免使用 i64 导致 stub 声明(declare i64)与实际定义(define i32)类型不匹配 # x86-64 ABI 中 i32 返回值在 rax 低 32 位,与 define i32 完全一致 # 与 _infer_method_ret_ty 的默认策略保持一致 # WARNING: 未登记的外部函数返回类型默认推断为 i32,若实际返回指针/i64 会被截断 VLogger.warning( f"外部函数返回类型未登记,默认推断为 i32(可能截断指针/i64): {func_name}", "HandlesExprCall") return llvmlite.Int32(pool) # ============================================================ # _get_external_func_param_ty - 获取外部函数第 idx 个参数的期望类型 # # stubs 翻译时未注入,需推断参数类型以提升字面量(如 i32→i64), # 避免 declare(i64) 与 call(i32) 类型不匹配。 # # 注意:stubs 翻译时 ULONG(t.CUnsignedLong) 在 LLVM IR 中被翻译为 i64 # (因为 LLVM 中 long 是 64 位),因此 Win32 API 中所有 ULONG/DWORD/SIZE_T # 参数在 declare 中都是 i64。call 时必须匹配,否则类型不匹配。 # # 策略:对 Win32 API 函数的所有非指针参数(字面量)都提升为 i64, # 以匹配 declare 中 ULONG 被翻译为 i64 的情况。 # # 指针参数(VOIDPTR/HANDLE)不在此处理,由调用点的 inttoptr 处理。 # ============================================================ def _get_external_func_param_ty(pool: memhub.MemBuddy | t.CPtr, func_name: str, param_idx: int) -> llvmlite.LLVMType | t.CPtr: """获取外部函数第 param_idx 个参数的期望类型,None 表示用字面量原类型 对 Win32 API 函数的所有非指针参数返回 i64,匹配 declare 中 ULONG/SIZE_T 被统一翻译为 i64 的情况。 """ if pool is None or func_name is None: return None i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) # Win32 API 函数列表:所有非指针参数在 declare 中都是 i64 # (因为 ULONG/DWORD/SIZE_T 在 LLVM stubs 翻译时都被映射为 i64) win32_apis: list[str] | t.CPtr = [ "VirtualAlloc", "VirtualFree", "VirtualProtect", "VirtualQuery", "VirtualLock", "VirtualUnlock", "HeapCreate", "HeapDestroy", "HeapAlloc", "HeapReAlloc", "HeapFree", "HeapSize", "HeapValidate", "HeapCompact", "GlobalAlloc", "GlobalFree", "GlobalLock", "GlobalUnlock", "GlobalSize", "LocalAlloc", "LocalFree", "GetLastError", "SetLastError", "Sleep", "SleepEx", "GetTickCount", "GetProcessHeap" ] # list 迭代不支持,用 range + get 替代 api_count: t.CSizeT = win32_apis.__len__() for ai in range(api_count): api_name: str = win32_apis.get(ai) if string.strcmp(api_name, func_name) == 0: return i64_ty return None # ============================================================ # _emit_llvm_memcpy_intrinsic — 将 memcpy 调用映射到 @llvm.memcpy 内联函数 # # 背景: string.memcpy 是 t.CExport 函数,跨模块调用生成 @memcpy 裸名调用。 # 但在 monomorphization 场景下,目标模块的 deps.txt 可能不含 string, # 导致 @memcpy 声明缺失,链接器报 undefined value。 # # 解决: 将 memcpy 调用映射到 LLVM 内联函数 @llvm.memcpy, # 该内联函数在当前模块内声明,无需跨模块依赖。 # # @llvm.memcpy 签名: void (i8* dst, i8* src, i64 len, i1 isvolatile) # C memcpy 签名: i8* (i8* dst, i8* src, i64 len) — 返回 dst # # Args: # args_head: 参数链表头(dst, src, num),通过 Value.Next 链接 # arg_count: 参数数量(应为 3) # # Returns: # dst 值(匹配 C memcpy 语义: 返回 dest 指针) # ============================================================ def _emit_llvm_memcpy_intrinsic(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, dst_val: llvmlite.Value | t.CPtr, src_val: llvmlite.Value | t.CPtr, num_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: """将 memcpy 调用映射到 @llvm.memcpy 内联函数 直接接收三个 Value 参数,避免通过 Next 链表遍历(共享 alloca 对象的 Next 字段可能被其他操作污染,导致链表断裂)。 """ if pool is None or builder is None or mod is None: return None if dst_val is None or src_val is None or num_val is None: return None # 在函数顶部声明 void_ty,避免后续遮蔽 void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) # 声明 @llvm.memcpy(如未声明) memcpy_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, "llvm.memcpy") if memcpy_func is None: memcpy_func = llvmlite.create_declare(pool, mod, "llvm.memcpy", void_ty) if memcpy_func is not None: i8_ptr_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) i64_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) i1_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "dst") llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "src") llvmlite.add_param(pool, memcpy_func, i64_ty_d, "len") llvmlite.add_param(pool, memcpy_func, i1_ty_d, "isvolatile") # 类型转换: dst, src → i8*; num → i64 # 注意: 使用 value_get_ty 访问器获取 Ty,避免本地 Value 类型字段索引偏移 i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) # dst → i8* dst_coerced: llvmlite.Value | t.CPtr = dst_val dst_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(dst_val) if HandlesExpr.is_ptr_type(dst_ty) != 0: dst_coerced = llvmlite.build_bitcast(builder, dst_val, i8_ptr_ty) else: dst_bits: int = HandlesExpr.get_llvm_type_bits(dst_ty) if dst_bits != 0: if dst_bits < 64: dst_coerced = llvmlite.build_zext(builder, dst_val, i64_ty) dst_coerced = llvmlite.build_inttoptr(builder, dst_coerced, i8_ptr_ty) # src → i8* src_coerced: llvmlite.Value | t.CPtr = src_val src_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(src_val) if HandlesExpr.is_ptr_type(src_ty) != 0: src_coerced = llvmlite.build_bitcast(builder, src_val, i8_ptr_ty) else: src_bits: int = HandlesExpr.get_llvm_type_bits(src_ty) if src_bits != 0: if src_bits < 64: src_coerced = llvmlite.build_zext(builder, src_val, i64_ty) src_coerced = llvmlite.build_inttoptr(builder, src_coerced, i8_ptr_ty) # num → i64 num_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, num_val, i64_ty) if dst_coerced is None or src_coerced is None or num_coerced is None: return None # 添加 i1 false 参数(isvolatile)— llvm.memcpy 需要 4 个参数 false_val: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "false") # 使用 includes 中的访问器函数构建参数链表,避免本地 Value 类型字段索引偏移 # (f26cd4c78b4d554c.Value 缺少 GSListNode 的 Next 字段,直接访问 .Next 会修改 .Ty) llvmlite.value_set_next(dst_coerced, src_coerced) llvmlite.value_set_next(src_coerced, num_coerced) if false_val is not None: llvmlite.value_set_next(num_coerced, false_val) llvmlite.value_set_next(false_val, None) else: llvmlite.value_set_next(num_coerced, None) # 使用 build_call 发射 call 指令(内部用 includes Value 类型访问字段,索引正确) # _ll_name_needs_quote 已对 llvm. 前缀豁免引号 result: llvmlite.Value | t.CPtr = llvmlite.build_call(builder, "llvm.memcpy", dst_coerced, 4, void_ty, 0) # 返回 dst(匹配 C memcpy 语义: 返回 dest 指针) return dst_coerced # ============================================================ # c.Deref(ptr) — 解引用指针,按指针 pointee 类型读取 # # 生成: %N = load , * %ptr # 返回 pointee 类型的值 # # 注意: 必须按 ptr 的 pointee 类型决定读取宽度。 # - i8* (str/bytes/字符遍历) → load i8 # - i64* (t.CUInt64T, 块头部) → load i64(memhub 的 free list 链表读 8 字节头部) # 之前固定 load i8 导致 memhub 读块头部只读到低 8 位, # free list 的 next 指针被截断成 0x88 等垃圾值,alloc 崩溃。 # ============================================================ def translate_c_deref(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 cargs.__len__() < 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: return llvmlite.build_load(builder, pointee, ptr_val) i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) return llvmlite.build_load(builder, i8_ty, ptr_val) # ============================================================ # c.DerefAs(ptr, val) — 解引用写入,*ptr = val # # 生成: %pc = bitcast i8* %ptr to * # store %val, * %pc # ============================================================ def translate_c_derefas(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 cargs.__len__() < 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 # ============================================================ # c.Addr(var) — 取变量地址,返回 alloca 指针(不 load) # # 用于获取栈变量的可写地址,配合 c.DerefAs 使用 # ============================================================ def translate_c_addr(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 cargs.__len__() < 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 return HandlesVar.lookup_var(trans.SymTab, nm.id) # 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) # ============================================================ # c.Load(a, b) — 指针间复制: *a = *b # # 加载 b 指向的值,存储到 a 指向的地址。 # 生成: %pc_src = bitcast i8* %src to * # %loaded = load , * %pc_src # %pc_dst = bitcast i8* %dst to * # store %loaded, * %pc_dst # ============================================================ def translate_c_load(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 cargs.__len__() < 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 # ============================================================ # c.Asm — 内联汇编支持 # # 生成: %N = call asm sideeffect "", ""() # 或: call void asm sideeffect "", ""() # # 操作数按出现顺序编号 $0, $1, ...(用户需按输出在前写 f-string) # ============================================================ 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 # ============================================================ # AsmOperand - 内联汇编操作数条目 # ============================================================ @t.NoVTable class AsmOperand: """内联汇编操作数条目""" Value: llvmlite.Value | t.CPtr # 输入值或输出 alloca Constraint: str # 约束字符串 (如 "r", "=r") IsOutput: int # 1=输出, 0=输入 # ============================================================ # _asm_append_cstr — 将 C 字符串 src 追加到 dst 末尾 # ============================================================ def _asm_append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): """将 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' # ============================================================ # _asm_escape_for_ir — 将汇编文本转义为 LLVM IR 字符串内容 # # \n → \0A, " → \22, \ → \5C # ============================================================ def _asm_escape_for_ir(pool: memhub.MemBuddy | t.CPtr, src: t.CChar | t.CPtr) -> t.CChar | t.CPtr: """转义汇编文本用于 LLVM IR 字符串字面量""" if src is None: return None slen: t.CSizeT = string.strlen(src) buf: t.CChar | t.CPtr = 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 # ============================================================ # _resolve_register — 将 ASM_DESCR 属性名映射到约束字符串 # ============================================================ def _resolve_register(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 "" # ============================================================ # _resolve_asm_descr — 递归解析约束表达式 # # 支持: # t.ASM_DESCR.XXX → _resolve_register(XXX) # expr | expr (BinOp BitOr) → 拼接 # "string" (Constant) → 直接返回 # ============================================================ def _resolve_asm_descr(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 = _resolve_asm_descr(pool, bop.left) right_str: str = _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 _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 _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 "" # ============================================================ # _asm_get_operand — 获取操作数数组中第 idx 个元素的指针 # ============================================================ def _asm_get_operand(base: AsmOperand | t.CPtr, idx: int) -> AsmOperand | t.CPtr: """获取操作数数组中第 idx 个元素的指针""" entry_size: t.CSizeT = AsmOperand.__sizeof__() entry_addr: t.CUInt64T = t.CUInt64T(base) + idx * entry_size return (AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) # ============================================================ # _asm_is_c_call — 检查 Call 节点是否是 c.XXX 调用 # # 返回 attr_name(如 "AsmInp"/"AsmOut"),不是则返回 None # ============================================================ def _asm_is_c_call(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 # ============================================================ # _asm_add_operand — 添加操作数到数组 # # 返回 1 成功, 0 失败(数组已满) # ============================================================ def _asm_add_operand(operands: AsmOperand | t.CPtr, count: int, val: llvmlite.Value | t.CPtr, constraint: str, is_output: int) -> int: """添加操作数到数组,返回新计数(失败返回原计数)""" if count >= ASM_MAX_OPERANDS: return count op: AsmOperand | t.CPtr = _asm_get_operand(operands, count) op.Value = val op.Constraint = constraint op.IsOutput = is_output return count + 1 # ============================================================ # translate_c_asm — 翻译 c.Asm 内联汇编 # # 语法: # c.Asm("nop", [t.ASM_DESCR.CLOBBER_MEMORY]) # c.Asm(f"mov rax, {c.AsmInp(val, t.ASM_DESCR.REG_ANY)}", op=[...]) # c.Asm(f"...", out=[c.AsmOut(var, t.ASM_DESCR.OUTPUT_REG)], op=[...]) # ============================================================ def translate_c_asm(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 cargs.__len__() < 1: return None # 分配操作数数组 operand_size: t.CSizeT = AsmOperand.__sizeof__() operands: 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: t.CChar | t.CPtr = 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 = jvalues.__len__() 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 = _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 fargs.__len__() < 1: continue val_node: ast.AST | t.CPtr = fargs.get(0) cons_str: str = "" if fargs.__len__() >= 2: cons_str = _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 = _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 = _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 = keywords.__len__() 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 = out_elts.__len__() 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 = _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 oargs.__len__() < 1: continue oval_node: ast.AST | t.CPtr = oargs.get(0) ocons: str = "" if oargs.__len__() >= 2: ocons = _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 = _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 = in_elts.__len__() 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 = _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 iargs.__len__() < 1: continue ival_node: ast.AST | t.CPtr = iargs.get(0) icons: str = "" if iargs.__len__() >= 2: icons = _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 = _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 = cl_elts.__len__() for ci in range(clen): celt: ast.AST | t.CPtr = cl_elts.get(ci) if celt is None: continue cstr: str = _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 cargs.__len__() >= 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 = pos_elts.__len__() for pi in range(plen): pelt: ast.AST | t.CPtr = pos_elts.get(pi) if pelt is None: continue pstr: str = _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: AsmOperand | t.CPtr = _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 # 确定返回类型 ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) if output_count > 0 and first_output_idx >= 0: out_op: AsmOperand | t.CPtr = _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: 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: AsmOperand | t.CPtr = _asm_get_operand(operands, oi3) if op3.IsOutput != 0: new_order[new_idx] = oi3 new_idx += 1 # 再放输入 for oi4 in range(operand_count): op4: AsmOperand | t.CPtr = _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 = jvalues2.__len__() 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: _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: t.CChar | t.CPtr = pool.alloc(16) if ph_buf2 is not None: viperlib.snprintf(ph_buf2, 16, "$%d", new_idx2) _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: _asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn4.str_val) # ============================================================ # 5. 构建约束字符串(按重排后的顺序:输出在前,输入在后) # ============================================================ const_buf: t.CChar | t.CPtr = 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: AsmOperand | t.CPtr = _asm_get_operand(operands, orig_i) cons_val: str = cop.Constraint if cons_val is None: cons_val = "r" if first_const == 0: _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",") first_const = 0 if cop.IsOutput != 0: # 输出约束:确保以 = 开头 if cons_val[0] != '=': _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "=") _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val) else: _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: _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",") first_const = 0 _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "~{") _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cname) _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "}") # ============================================================ # 6. 构建参数列表文本(仅输入操作数) # ============================================================ args_buf: t.CChar | t.CPtr = 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: AsmOperand | t.CPtr = _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: _asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ", ") first_arg = 0 # 类型文本 ty_buf: t.CChar | t.CPtr = pool.alloc(64) if ty_buf is not None: ty_buf[0] = '\0' llvmlite.TypePrint(ty_buf, 64, aval.Ty, pool) _asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ty_buf) _asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, " ") _asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, aval.Name) # ============================================================ # 7. 转义汇编文本 # ============================================================ escaped_asm: t.CChar | t.CPtr = _asm_escape_for_ir(pool, asm_text) if escaped_asm is None: return None # ============================================================ # 8. 生成 IR 行并发射 # ============================================================ line: t.CChar | t.CPtr = pool.alloc(ASM_LINE_BUF_SIZE) if line is None: return None line[0] = '\0' ssa_name: t.CChar | t.CPtr = 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: t.CChar | t.CPtr = 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_op2: AsmOperand | t.CPtr = _asm_get_operand(operands, first_output_idx) if out_op2.Value is not None: llvmlite.build_store(builder, result_val, out_op2.Value) return result_val return None # ============================================================ # c.LLVMIR — 内联 LLVM IR 支持 # # 语法: # c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) # c.LLVMIR(f"%{c.LOut(result)} = add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) # # c.LInp(expr) - 输入操作数,翻译后替换为对应的 LLVM 值 # c.LOut(expr) - 输出操作数,翻译后结果存储到该变量 # # 支持的指令: add/sub/mul/sdiv/udiv/srem/urem/and/or/xor/shl/lshr/ashr # fadd/fsub/fmul/fdiv # icmp eq/ne/sgt/sge/slt/sle/ugt/uge/ult/ule # fcmp oeq/one/olt/ogt/ole/oge # zext/sext/trunc/bitcast/ptrtoint/inttoptr # load/store # ============================================================ LLVMIR_MAX_OPS: t.CDefine = 16 LLVMIR_TEMPLATE_BUF: t.CDefine = 512 # ============================================================ # _llvmir_get_op — 获取第 i 个 AsmOperand 槽位 # ============================================================ def _llvmir_get_op(buf: AsmOperand | t.CPtr, i: int) -> AsmOperand | t.CPtr: """获取第 i 个操作数槽位""" entry_size: t.CSizeT = AsmOperand.__sizeof__() entry_addr: t.CUInt64T = t.CUInt64T(buf) + i * entry_size return (AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) # ============================================================ # _llvmir_find_op_marker — 在字符串中查找 %__OP 并返回编号 # # 返回 (位置, 编号),未找到返回 (None, 0) # ============================================================ def _llvmir_find_op_marker(s: t.CChar | t.CPtr) -> t.CPtr: """查找 %__OP 标记,返回标记开始位置或 None""" if s is None: return None return string.strstr(s, "%__OP") # ============================================================ # _llvmir_parse_op_num — 从 %__OPN__ 中解析编号 N # # 输入: 指向 "%__OP" 的指针 # 返回: 操作数编号 # ============================================================ def _llvmir_parse_op_num(marker: t.CChar | t.CPtr) -> int: """从 %__OPN__ 标记中解析编号 N""" if marker is None: return -1 # 跳过 "%__OP" (5 字符) num_start: t.CChar | t.CPtr = marker + 5 if num_start is None: return -1 # 解析数字直到 "__" num: int = 0 i: t.CSizeT = 0 ch: t.CChar = num_start[0] while '0' <= ch <= '9': num = num * 10 + (ch - '0') i += 1 ch = num_start[i] return num # ============================================================ # _llvmir_match_icmp_pred — 将预测字符串转为 ICMP 常量 # ============================================================ def _llvmir_match_icmp_pred(pred: str) -> int: """将 icmp 预测字符串转为常量""" if pred is None: return 0 if string.strcmp(pred, "eq") == 0: return 0 if string.strcmp(pred, "ne") == 0: return 1 if string.strcmp(pred, "sgt") == 0: return 2 if string.strcmp(pred, "sge") == 0: return 3 if string.strcmp(pred, "slt") == 0: return 4 if string.strcmp(pred, "sle") == 0: return 5 if string.strcmp(pred, "ugt") == 0: return 6 if string.strcmp(pred, "uge") == 0: return 7 if string.strcmp(pred, "ult") == 0: return 8 if string.strcmp(pred, "ule") == 0: return 9 return 0 # ============================================================ # _llvmir_match_fcmp_pred — 将预测字符串转为 FCMP 常量 # ============================================================ def _llvmir_match_fcmp_pred(pred: str) -> int: """将 fcmp 预测字符串转为常量""" if pred is None: return 0 if string.strcmp(pred, "oeq") == 0: return 0 if string.strcmp(pred, "ogt") == 0: return 1 if string.strcmp(pred, "oge") == 0: return 2 if string.strcmp(pred, "olt") == 0: return 3 if string.strcmp(pred, "ole") == 0: return 4 if string.strcmp(pred, "one") == 0: return 5 if string.strcmp(pred, "ord") == 0: return 6 if string.strcmp(pred, "uno") == 0: return 7 if string.strcmp(pred, "ueq") == 0: return 8 if string.strcmp(pred, "ugt") == 0: return 9 if string.strcmp(pred, "uge") == 0: return 10 if string.strcmp(pred, "ult") == 0: return 11 if string.strcmp(pred, "ule") == 0: return 12 if string.strcmp(pred, "une") == 0: return 13 return 0 # ============================================================ # _llvmir_extract_two_ops — 从模板中提取两个操作数编号 # # 通过输出参数返回 op1_num 和 op2_num # ============================================================ def _llvmir_extract_two_ops(template: t.CChar | t.CPtr, out_nums: int | t.CPtr) -> int: """从模板中提取前两个 %__OP 标记的编号 结果写入 out_nums[0] 和 out_nums[1] 返回 1 成功, 0 失败 """ out_nums[0] = -1 out_nums[1] = -1 m1: t.CChar | t.CPtr = _llvmir_find_op_marker(template) if m1 is None: return 0 out_nums[0] = _llvmir_parse_op_num(m1) # 跳过第一个标记 "%__OPN__" next_pos: t.CChar | t.CPtr = m1 + 5 # 跳过 "%__OP" i: t.CSizeT = 0 while next_pos[i] >= '0' and next_pos[i] <= '9': i += 1 next_pos = next_pos + i + 2 m2: t.CChar | t.CPtr = _llvmir_find_op_marker(next_pos) if m2 is None: return 1 out_nums[1] = _llvmir_parse_op_num(m2) return 1 # ============================================================ # _llvmir_resolve_op — 根据编号解析操作数值 # ============================================================ def _llvmir_resolve_op(op_num: int, all_kinds: int | t.CPtr, all_indices: int | t.CPtr, input_ops: AsmOperand | t.CPtr, output_targets: AsmOperand | t.CPtr) -> llvmlite.Value | t.CPtr: """根据操作数编号解析实际 Value""" if op_num < 0 or op_num >= LLVMIR_MAX_OPS: return None kind: int = all_kinds[op_num] idx: int = all_indices[op_num] if kind == 0: # 输入操作数 op: AsmOperand | t.CPtr = _llvmir_get_op(input_ops, idx) return op.Value else: # 输出操作数 op2: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, idx) return op2.Value # ============================================================ # _llvmir_store_outputs — 将结果存储到输出变量 # ============================================================ def _llvmir_store_outputs(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, result: llvmlite.Value | t.CPtr, output_targets: AsmOperand | t.CPtr, output_count: int) -> llvmlite.Value | t.CPtr: """将结果存储到所有输出变量""" if output_count == 0: return result for oi in range(output_count): op: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, oi) if op.Value is not None and result is not None: llvmlite.build_store(builder, result, op.Value) return result # ============================================================ # translate_c_llvmir — 翻译 c.LLVMIR 内联 LLVM IR # ============================================================ def translate_c_llvmir(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,返回结果 Value""" if cl is None: return None cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args if cargs is None or cargs.__len__() < 1: return None # 分配操作数数组 op_size: t.CSizeT = AsmOperand.__sizeof__() input_ops: AsmOperand | t.CPtr = pool.alloc(op_size * LLVMIR_MAX_OPS) output_targets: AsmOperand | t.CPtr = pool.alloc(op_size * LLVMIR_MAX_OPS) if input_ops is None or output_targets is None: return None string.memset(input_ops, 0, op_size * LLVMIR_MAX_OPS) string.memset(output_targets, 0, op_size * LLVMIR_MAX_OPS) # all_ops 映射: kinds[i]=0(inp)/1(out), indices[i]=在对应数组中的索引 all_kinds: int | t.CPtr = pool.alloc(4 * LLVMIR_MAX_OPS) all_indices: int | t.CPtr = pool.alloc(4 * LLVMIR_MAX_OPS) if all_kinds is None or all_indices is None: return None string.memset(all_kinds, 0, 4 * LLVMIR_MAX_OPS) string.memset(all_indices, 0, 4 * LLVMIR_MAX_OPS) input_count: int = 0 output_count: int = 0 op_seq: int = 0 # 分配模板缓冲区 template: t.CChar | t.CPtr = pool.alloc(LLVMIR_TEMPLATE_BUF) if template is None: return None template[0] = '\0' # 解析返回类型(默认 i32) ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) if cargs.__len__() >= 2: ret_type_node: ast.AST | t.CPtr = cargs.get(1) if ret_type_node is not None: resolved_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( pool, ret_type_node, trans._imported_modules, trans._from_imports, trans) if resolved_ty is not None: ret_ty = resolved_ty # ============================================================ # 1. 解析 IR 模板(JoinedStr 或 Constant)— 收集操作数 # ============================================================ 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 = jvalues.__len__() 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: _asm_append_cstr(template, 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 or fexpr.kind() != ast.ASTKind.Call: continue fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr) attr_nm: str = _asm_is_c_call(fcall) if attr_nm is None: # 非 c.LInp/c.LOut 调用,作为普通输入处理 ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, fexpr, None, 0, trans) if ival is not None and input_count < LLVMIR_MAX_OPS: op_in: AsmOperand | t.CPtr = _llvmir_get_op(input_ops, input_count) op_in.Value = ival all_kinds[op_seq] = 0 all_indices[op_seq] = input_count input_count += 1 op_seq += 1 # 追加占位符 viperlib.snprintf( template + string.strlen(template), LLVMIR_TEMPLATE_BUF - string.strlen(template), "%%__OP%d__", op_seq - 1) continue # 处理 c.LInp / c.LOut fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args if fargs is None or fargs.__len__() < 1: continue val_node: ast.AST | t.CPtr = fargs.get(0) if string.strcmp(attr_nm, "LInp") == 0: # 输入操作数:翻译值 inp_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, val_node, None, 0, trans) if inp_val is not None and input_count < LLVMIR_MAX_OPS: op_inp: AsmOperand | t.CPtr = _llvmir_get_op(input_ops, input_count) op_inp.Value = inp_val all_kinds[op_seq] = 0 all_indices[op_seq] = input_count input_count += 1 op_seq += 1 viperlib.snprintf( template + string.strlen(template), LLVMIR_TEMPLATE_BUF - string.strlen(template), "%%__OP%d__", op_seq - 1) elif string.strcmp(attr_nm, "LOut") == 0: # 输出操作数:获取变量 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 not None and output_count < LLVMIR_MAX_OPS: op_out: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, output_count) op_out.Value = alloca all_kinds[op_seq] = 1 all_indices[op_seq] = output_count output_count += 1 op_seq += 1 viperlib.snprintf( template + string.strlen(template), LLVMIR_TEMPLATE_BUF - string.strlen(template), "%%__OP%d__", op_seq - 1) elif tk == ast.ASTKind.Constant: cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(first_arg) if cn2.str_val is not None: string.strcpy(template, cn2.str_val) # ============================================================ # 2. 解析模板并生成 LLVM 指令 # ============================================================ # 检查是否为赋值形式: %__OPN__ = <指令> # 如果是,去掉赋值前缀,记录输出操作数编号 assign_out_num: int = -1 assign_marker: t.CChar | t.CPtr = _llvmir_find_op_marker(template) if assign_marker is not None and assign_marker == template: # 模板以 %__OP 开头 # 查找 "=" 号 eq_pos: t.CChar | t.CPtr = string.strchr(template, 61) # '=' = 61 if eq_pos is not None: # 确认 "%__OPN__ = " 格式 assign_out_num = _llvmir_parse_op_num(assign_marker) # 跳过 "%__OP__ = " 到实际指令开始 # 找到 "=" 后第一个非空格字符 instr_start: t.CChar | t.CPtr = eq_pos + 1 while instr_start[0] == ' ' or instr_start[0] == '\t': instr_start += 1 # 将剩余部分复制到新模板 tmpl2: t.CChar | t.CPtr = pool.alloc(LLVMIR_TEMPLATE_BUF) if tmpl2 is not None: string.strcpy(tmpl2, instr_start) template = tmpl2 # 去除前导空格 while template[0] == ' ' or template[0] == '\t': template += 1 # 提取指令关键字(第一个单词) instr_kw: t.CChar | t.CPtr = pool.alloc(32) if instr_kw is None: return None instr_kw[0] = '\0' ki: t.CSizeT = 0 while template[ki] != ' ' and template[ki] != '\t' and template[ki] != '\0' and ki < 31: instr_kw[ki] = template[ki] ki += 1 instr_kw[ki] = '\0' # ============================================================ # 二元运算: add/sub/mul/sdiv/udiv/srem/urem/and/or/xor/shl/lshr/ashr # ============================================================ binop_result: llvmlite.Value | t.CPtr = None # 提取两个操作数编号 op_nums: int | t.CPtr = pool.alloc(8) if op_nums is not None: string.memset(op_nums, 0, 8) _llvmir_extract_two_ops(template, op_nums) op1_num: int = -1 op2_num: int = -1 if op_nums is not None: op1_num = op_nums[0] op2_num = op_nums[1] lhs: llvmlite.Value | t.CPtr = _llvmir_resolve_op( op1_num, all_kinds, all_indices, input_ops, output_targets) rhs: llvmlite.Value | t.CPtr = _llvmir_resolve_op( op2_num, all_kinds, all_indices, input_ops, output_targets) if lhs is not None and rhs is not None: if string.strcmp(instr_kw, "add") == 0: binop_result = llvmlite.build_add(builder, lhs, rhs) elif string.strcmp(instr_kw, "sub") == 0: binop_result = llvmlite.build_sub(builder, lhs, rhs) elif string.strcmp(instr_kw, "mul") == 0: binop_result = llvmlite.build_mul(builder, lhs, rhs) elif string.strcmp(instr_kw, "sdiv") == 0: binop_result = llvmlite.build_sdiv(builder, lhs, rhs) elif string.strcmp(instr_kw, "udiv") == 0: binop_result = llvmlite.build_udiv(builder, lhs, rhs) elif string.strcmp(instr_kw, "srem") == 0: binop_result = llvmlite.build_srem(builder, lhs, rhs) elif string.strcmp(instr_kw, "urem") == 0: binop_result = llvmlite.build_urem(builder, lhs, rhs) elif string.strcmp(instr_kw, "and") == 0: binop_result = llvmlite.build_and(builder, lhs, rhs) elif string.strcmp(instr_kw, "or") == 0: binop_result = llvmlite.build_or(builder, lhs, rhs) elif string.strcmp(instr_kw, "xor") == 0: binop_result = llvmlite.build_xor(builder, lhs, rhs) elif string.strcmp(instr_kw, "shl") == 0: binop_result = llvmlite.build_shl(builder, lhs, rhs) elif string.strcmp(instr_kw, "lshr") == 0: binop_result = llvmlite.build_lshr(builder, lhs, rhs) elif string.strcmp(instr_kw, "ashr") == 0: binop_result = llvmlite.build_ashr(builder, lhs, rhs) elif string.strcmp(instr_kw, "fadd") == 0: binop_result = llvmlite.build_fadd(builder, lhs, rhs) elif string.strcmp(instr_kw, "fsub") == 0: binop_result = llvmlite.build_fsub(builder, lhs, rhs) elif string.strcmp(instr_kw, "fmul") == 0: binop_result = llvmlite.build_fmul(builder, lhs, rhs) elif string.strcmp(instr_kw, "fdiv") == 0: binop_result = llvmlite.build_fdiv(builder, lhs, rhs) # ============================================================ # icmp 比较: icmp %__OP0__, %__OP1__ # ============================================================ if binop_result is None and string.strcmp(instr_kw, "icmp") == 0: # 提取预测(第二个单词) pred_start: t.CChar | t.CPtr = template + ki + 1 while pred_start[0] == ' ' or pred_start[0] == '\t': pred_start += 1 pred_str: t.CChar | t.CPtr = pool.alloc(16) if pred_str is not None: pred_str[0] = '\0' pi: t.CSizeT = 0 while pred_start[pi] != ' ' and pred_start[pi] != '\t' and pred_start[pi] != '\0' and pi < 15: pred_str[pi] = pred_start[pi] pi += 1 pred_str[pi] = '\0' pred_val: int = _llvmir_match_icmp_pred(pred_str) if lhs is not None and rhs is not None: binop_result = llvmlite.build_icmp(builder, pred_val, lhs, rhs) # ============================================================ # fcmp 比较: fcmp %__OP0__, %__OP1__ # ============================================================ if binop_result is None and string.strcmp(instr_kw, "fcmp") == 0: pred_start2: t.CChar | t.CPtr = template + ki + 1 while pred_start2[0] == ' ' or pred_start2[0] == '\t': pred_start2 += 1 pred_str2: t.CChar | t.CPtr = pool.alloc(16) if pred_str2 is not None: pred_str2[0] = '\0' pi2: t.CSizeT = 0 while pred_start2[pi2] != ' ' and pred_start2[pi2] != '\t' and pred_start2[pi2] != '\0' and pi2 < 15: pred_str2[pi2] = pred_start2[pi2] pi2 += 1 pred_str2[pi2] = '\0' pred_val2: int = _llvmir_match_fcmp_pred(pred_str2) if lhs is not None and rhs is not None: binop_result = llvmlite.build_fcmp(builder, pred_val2, lhs, rhs) # ============================================================ # store 指令: store %__OP0__, %__OP1__ # ============================================================ if binop_result is None and string.strcmp(instr_kw, "store") == 0: if lhs is not None and rhs is not None: llvmlite.build_store(builder, lhs, rhs) return None # ============================================================ # load 指令: load , %__OP0__ # ============================================================ if binop_result is None and string.strcmp(instr_kw, "load") == 0: if lhs is not None: # 从指针加载,类型由 ret_ty 指定 binop_result = llvmlite.build_load(builder, ret_ty, lhs) # ============================================================ # 类型转换: zext/sext/trunc/bitcast/ptrtoint/inttoptr # ============================================================ if binop_result is None: if string.strcmp(instr_kw, "zext") == 0: if lhs is not None: binop_result = llvmlite.build_zext(builder, lhs, ret_ty) elif string.strcmp(instr_kw, "sext") == 0: if lhs is not None: binop_result = llvmlite.build_sext(builder, lhs, ret_ty) elif string.strcmp(instr_kw, "trunc") == 0: if lhs is not None: binop_result = llvmlite.build_trunc(builder, lhs, ret_ty) elif string.strcmp(instr_kw, "bitcast") == 0: if lhs is not None: binop_result = llvmlite.build_bitcast(builder, lhs, ret_ty) elif string.strcmp(instr_kw, "ptrtoint") == 0: if lhs is not None: binop_result = llvmlite.build_ptrtoint(builder, lhs, ret_ty) elif string.strcmp(instr_kw, "inttoptr") == 0: if lhs is not None: binop_result = llvmlite.build_inttoptr(builder, lhs, ret_ty) # ============================================================ # 3. 处理输出 # ============================================================ if binop_result is not None: # 如果有赋值形式(%__OPN__ = ...),存储到对应输出 if assign_out_num >= 0: target: llvmlite.Value | t.CPtr = _llvmir_resolve_op( assign_out_num, all_kinds, all_indices, input_ops, output_targets) if target is not None: llvmlite.build_store(builder, binop_result, target) # 存储到所有输出操作数 _llvmir_store_outputs(pool, builder, binop_result, output_targets, output_count) return binop_result # 未识别的指令,返回 0 fb_li: t.CChar | t.CPtr = VLogger.fmt_buf() if fb_li is not None: viperlib.snprintf(fb_li, 1024, "unsupported instruction: %s", instr_kw) VLogger.error(fb_li, "LLVMIR") return None # ============================================================ # _apply_struct_defaults — 应用结构体字段的默认值 # # 在 zeroinitializer 之后、显式参数之前调用 # 遍历所有字段,对有默认值的字段翻译并 store # 显式参数(位置/关键字)后续会覆盖默认值 # ============================================================ def _apply_struct_defaults(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, struct_ty: llvmlite.LLVMType | t.CPtr, class_name: str, tmp: llvmlite.Value | t.CPtr, trans: HT.Translator | t.CPtr): """应用结构体字段的默认值""" # 用类型指针定位 entry,规避跨模块同名 find_struct 找错 entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) if entry is None: # fast-fail: 结构体类型未注册,静默 return 会导致字段未初始化 VLogger.error( f"结构体类型未注册,无法应用默认值: {class_name}", "HandlesExprCall") return for fi in range(entry.FieldCount): fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( entry, fi) if fe is None: # fast-fail: 字段索引越界(entry.FieldCount 与实际不一致) VLogger.error( f"字段索引越界,无法获取字段 entry: {class_name}", "HandlesExprCall") continue if fe.DefaultVal is None: continue # 合理跳过:无默认值的字段 default_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, fe.DefaultVal, None, 0, trans) if default_val is None: # fast-fail: 默认值翻译失败(如引用了未定义符号) VLogger.error( f"字段默认值翻译失败: {class_name}", "HandlesExprCall") continue field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( builder, struct_ty, fe.Ty, tmp, fe.Index) if field_ptr is None: # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) VLogger.error( f"字段 GEP 失败,类型不匹配: {class_name}", "HandlesExprCall") continue 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 # ============================================================ def _translate_struct_ctor(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, struct_ty: llvmlite.LLVMType | t.CPtr, class_name: str, cargs: list[ast.AST | t.CPtr] | t.CPtr, can: t.CSizeT, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: """结构体构造函数:按字段顺序 store 参数值,返回结构体值 OOP 结构体:alloca → call __before_init__(ptr) → call __init__(ptr, args) 或 store 参数 → load 普通结构体:alloca → zero + defaults → store 参数 → load """ # 创建临时 alloca # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) if tmp is None: return llvmlite.ConstZero(pool, struct_ty) # 检查是否为 OOP 结构体(用类型指针定位 entry,规避跨模块同名 find_struct 找错) ctor_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) is_oop: int = 0 if ctor_entry is not None: is_oop = ctor_entry.IsOOP # 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods) # 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入) # 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠) if is_oop == 0 and class_name is not None: init_lookup_name: t.CChar | t.CPtr = pool.alloc(128) if init_lookup_name is not None: viperlib.snprintf(init_lookup_name, 128, "%s.__init__", class_name) # 方案1: 检查当前模块的函数声明 init_found_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, init_lookup_name) if init_found_func is not None: is_oop = 1 if ctor_entry is not None: ctor_entry.IsOOP = 1 ctor_entry.HasInit = 1 else: # 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入) init_defaults_entry: FuncDefaultsEntry | t.CPtr = find_func_defaults(init_lookup_name) if init_defaults_entry is not None: is_oop = 1 if ctor_entry is not None: ctor_entry.IsOOP = 1 ctor_entry.HasInit = 1 if is_oop != 0: # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 storage_ptr: llvmlite.Value | t.CPtr = tmp # 如果有 __new__,调用 __new__(tmp, args...) 获取实际存储指针 # __new__ 签名与 __init__ 一样(self + args),返回 Ptr(struct_ty) has_new_flag: int = 0 if ctor_entry is not None: has_new_flag = ctor_entry.HasNew # 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法) if has_new_flag != 0: new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) if new_arg_vals is not None: string.memset(new_arg_vals, 0, 8 * 32) new_arg_count: int = 0 for nai in range(can): new_arg_node: ast.AST | t.CPtr = cargs.get(nai) if new_arg_node is None: continue new_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, new_arg_node, None, 0, trans) if new_av is not None: if new_arg_count < 32: new_arg_vals[new_arg_count] = t.CSizeT(new_av) new_arg_count += 1 new_ptr: llvmlite.Value | t.CPtr = _call_method_on_ptr( pool, builder, mod, class_name, "__new__", tmp, new_arg_vals, new_arg_count, trans) if new_ptr is not None: storage_ptr = new_ptr # __new__ 只保证返回"实例存储指针",声明类型通常是 # `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。 # 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的 # obj.method(如 parser.add_argument)get_class_name_by_type # 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。 # bitcast 只改类型层视图,运行时零开销(指针位不变)。 if new_ptr.Ty is not None: nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty): nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty) if nw_bc is not None: storage_ptr = nw_bc # OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值 _call_method_on_ptr(pool, builder, mod, class_name, "__before_init__", storage_ptr, None, 0, trans) # 如果有 __init__,调用 __init__(ptr, args...) # 注意: 仅依据 ctor_entry.HasInit 判断,不强制推断 # (JsonValue 等类有 __new__ 但无 __init__,强制推断会导致 undefined reference) has_init_flag: int = 0 if ctor_entry is not None: has_init_flag = ctor_entry.HasInit if has_init_flag != 0: # 翻译构造函数参数 arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) if arg_vals is not None: string.memset(arg_vals, 0, 8 * 32) real_arg_count: int = 0 for ai in range(can): arg_node: ast.AST | t.CPtr = cargs.get(ai) if arg_node is None: continue av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, arg_node, None, 0, trans) if av is not None: if real_arg_count < 32: arg_vals[real_arg_count] = t.CSizeT(av) real_arg_count += 1 _call_method_on_ptr(pool, builder, mod, class_name, "__init__", storage_ptr, arg_vals, real_arg_count, trans) elif has_new_flag == 0: # 无 __init__ 且无 __new__:逐字段 store 参数值 # (有 __new__ 时参数已由 __new__ 消费,不应存入字段) 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: # fast-fail: 参数翻译失败 VLogger.error( f"构造函数参数翻译失败: {class_name}", "HandlesExprCall") continue fe: HandlesStruct.FieldEntry | t.CPtr = None if ctor_entry is not None: fe = HandlesStruct._get_field_entry(ctor_entry, ai) else: fe = HandlesStruct.get_field_by_index(class_name, ai) if fe is None: # fast-fail: 字段索引越界(用户传了多余参数) VLogger.error( f"构造函数参数过多,字段索引越界: {class_name}", "HandlesExprCall") continue field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( builder, struct_ty, fe.Ty, storage_ptr, fe.Index) if field_ptr is None: # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) VLogger.error( f"构造函数字段 GEP 失败: {class_name}", "HandlesExprCall") continue arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg) llvmlite.build_store(builder, arg_val, field_ptr) # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load return storage_ptr # 普通结构体:先 store zeroinitializer 清零(确保未赋值字段为零) zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) llvmlite.build_store(builder, zero, tmp) # 应用默认值(显式参数会覆盖默认值) _apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans) # 逐字段 store 参数值(覆盖默认值) 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: # fast-fail: 参数翻译失败 VLogger.error( f"构造函数参数翻译失败: {class_name}", "HandlesExprCall") continue # 获取字段信息(用 ctor_entry 规避跨模块同名 find_struct 找错) fe: HandlesStruct.FieldEntry | t.CPtr = None if ctor_entry is not None: fe = HandlesStruct._get_field_entry(ctor_entry, ai) else: fe = HandlesStruct.get_field_by_index(class_name, ai) if fe is None: # fast-fail: 字段索引越界(用户传了多余参数) VLogger.error( f"构造函数参数过多,字段索引越界: {class_name}", "HandlesExprCall") continue # GEP 到字段 ai field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( builder, struct_ty, fe.Ty, tmp, fe.Index) if field_ptr is None: # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) VLogger.error( f"构造函数字段 GEP 失败: {class_name}", "HandlesExprCall") continue # 类型转换并 store arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg) llvmlite.build_store(builder, arg_val, field_ptr) # 返回指针(而非结构体值),赋值时由 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 # ============================================================ def _translate_renum_construct(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, class_name: str, variant_name: str, tag_value: int, cargs: list[ast.AST | t.CPtr] | t.CPtr, can: t.CSizeT, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: """构造 REnum 变体实例,返回指向 alloca 的指针 class_name: REnum 类名(如 "LLVMType") variant_name: 变体名(如 "Int") tag_value: 变体的 tag 值(变体在类中的索引) cargs: 参数 AST 列表 can: 参数数量 """ if pool is None or builder is None or class_name is None: return None # 查找 REnum 结构体类型(用 find_struct_by_module 规避跨模块同名) renum_entry: HandlesStruct.StructEntry | t.CPtr = None if trans is not None: renum_entry = HandlesStruct.find_struct_by_module(class_name, trans.ModuleSha1) if renum_entry is None: renum_entry = HandlesStruct.find_struct(class_name) if renum_entry is None: fb_re: t.CChar | t.CPtr = VLogger.fmt_buf() if fb_re is not None: viperlib.snprintf(fb_re, 1024, "REnum construct: type %s not registered", class_name) VLogger.error(fb_re, "RENUM") return None renum_ty: llvmlite.LLVMType | t.CPtr = renum_entry.Ty if renum_ty is None: return None # alloca REnum 类型 # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) HandlesStruct.ensure_struct_def_in_module(pool, mod, renum_ty) tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, renum_ty) if tmp is None: return llvmlite.ConstZero(pool, renum_ty) # 清零(确保未赋值的 payload 位置为零) zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, renum_ty) llvmlite.build_store(builder, zero, tmp) # 写入 __tag 字段(索引 0) i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) tag_name_buf: t.CChar | t.CPtr = pool.alloc(32) if tag_name_buf is not None: viperlib.snprintf(tag_name_buf, 32, "%d", tag_value) tag_const: llvmlite.Value | t.CPtr = llvmlite.ConstInt( pool, i32_ty, tag_value, tag_name_buf if tag_name_buf is not None else "0") tag_field: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(renum_entry, 0) tag_field_ty: llvmlite.LLVMType | t.CPtr = i32_ty if tag_field is not None and tag_field.Ty is not None: tag_field_ty = tag_field.Ty tag_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( builder, renum_ty, tag_field_ty, tmp, 0) if tag_ptr is not None: llvmlite.build_store(builder, tag_const, tag_ptr) # 写入 payload 字段(索引 1, 2, ... 对应 _p1, _p2, ...) # 参数按位置顺序填充 payload,跳过 __tag(索引 0) 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: continue # payload 字段索引 = ai + 1(跳过 __tag) payload_idx: int = ai + 1 if payload_idx >= renum_entry.FieldCount: break pfe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( renum_entry, payload_idx) if pfe is None: continue payload_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( builder, renum_ty, pfe.Ty, tmp, payload_idx) if payload_ptr is None: continue # 类型转换并 store(payload 位置可能是 i32 或 i64,按字段类型 coerce) arg_val = HandlesExpr.coerce_to_type(builder, arg_val, pfe.Ty, arg) llvmlite.build_store(builder, arg_val, payload_ptr) # 返回指针(与 _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 — 返回类型 # ============================================================ def _do_virtual_call(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, class_name: str, method_name: str, self_ptr: llvmlite.Value | t.CPtr, args_head: llvmlite.Value | t.CPtr, args_count: int, found_func: llvmlite.Function | t.CPtr, ret_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: """通过虚表间接调用虚方法,返回 call 结果(void 方法返回 None)""" if pool is None or builder is None or class_name is None or method_name is None: return None if self_ptr is None or args_head is None: return None # 1. 获取结构体类型(用 find_struct_by_type 规避跨模块同名 find_struct 找错) vc_entry: HandlesStruct.StructEntry | t.CPtr = None struct_ty: llvmlite.LLVMType | t.CPtr = None if self_ptr.Ty is not None: vc_entry = HandlesStruct.get_struct_type_from_value(self_ptr) if vc_entry is not None: # vc_entry 是 struct_ty(LLVMType),需要找 StructEntry vc_entry = HandlesStruct.find_struct_by_type(vc_entry) if vc_entry is not None: struct_ty = vc_entry.Ty if struct_ty is None: struct_ty = HandlesStruct.get_struct_type(class_name) if struct_ty is None: return None # 2. 获取方法在虚表中的索引(用 entry 直接查找) method_index: int = -1 if vc_entry is not None and vc_entry.VTableMethods is not None: methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(vc_entry.VTableMethods, t.CPtr)) for mi in range(vc_entry.VTableMethodCount): mname_addr: t.CSizeT = methods_arr[mi] if mname_addr == 0: continue mname: str = (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr)) if mname is not None and string.strcmp(mname, method_name) == 0: method_index = mi break else: method_index = HandlesStruct.get_vtable_method_index(class_name, method_name) if method_index < 0: return None # 3. 基础类型 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) # 4. bitcast 到 i8** 访问 __vtable__ 字段(索引 0) # vtable 指针总是在对象第一个字段,无需 GEP,直接 bitcast 到 i8** 即可。 # 这样即使 struct_ty 是 opaque(跨模块未加载完整定义)也能正常工作。 vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( builder, self_ptr, i8_ptr_ptr_ty) if vtable_slot is None: return None # 5. load vtable 指针 (i8*) vtable_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot) if vtable_ptr is None: return None # 6. 构造 vtable 类型 {i8*, i8*, ...} method_count: int = 0 if vc_entry is not None: method_count = vc_entry.VTableMethodCount else: method_count = HandlesStruct.get_vtable_method_count(class_name) if method_count <= 0: return None vt_first: llvmlite.ParamNode | t.CPtr = None vt_prev: llvmlite.ParamNode | t.CPtr = None for vi in range(method_count): pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) if pn is None: continue if vt_first is None: vt_first = pn if vt_prev is not None: llvmlite.paramnode_set_next(vt_prev, pn) vt_prev = pn vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first, method_count, None) if vtable_ty is None: return None vtable_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vtable_ty) # 7. bitcast i8* 到 vtable 类型指针 vtable_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( builder, vtable_ptr, vtable_ptr_ty) if vtable_typed is None: return None # 8. GEP 到方法槽位 func_slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( builder, vtable_ty, i8_ptr_ty, vtable_typed, method_index) if func_slot is None: return None # 9. load 函数指针 (i8*) func_i8: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, func_slot) if func_i8 is None: return None # 10. 从 args_head 构造函数类型 RetTy(Param1, Param2, ...) # 直接遍历 Value 链表提取参数类型,避免跨模块访问 found_func(stub 字段偏移问题) fp_first: llvmlite.ParamNode | t.CPtr = None fp_prev: llvmlite.ParamNode | t.CPtr = None fp_count: int = 0 cur_val: llvmlite.Value | t.CPtr = args_head for vi in range(args_count): if cur_val is None: break cur_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(cur_val) fpn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, cur_ty) if fpn is not None: if fp_first is None: fp_first = fpn if fp_prev is not None: llvmlite.paramnode_set_next(fp_prev, fpn) fp_prev = fpn cur_val = llvmlite.value_get_next(cur_val) fp_count += 1 func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, ret_ty, fp_first, fp_count) if func_ty is None: return None func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty) # 11. bitcast i8* 到函数指针类型 func_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, func_i8, func_ptr_ty) if func_ptr is None: return None # 12. 间接调用 return llvmlite.build_call_indirect(builder, func_ptr, args_head, args_count, ret_ty) # ============================================================ # _call_method_on_ptr — 在结构体指针上调用方法 # # 辅助函数:构造 ClassName.method_name 调用,self 指针为首个参数 # 如果该方法在虚表中,则走虚方法分发路径(间接调用) # ============================================================ def _call_method_on_ptr(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, class_name: str, method_name: str, self_ptr: llvmlite.Value | t.CPtr, extra_args: t.CSizeT | t.CPtr, extra_count: int, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: """在结构体指针上调用方法,返回 call 结果(void 方法返回 None)""" if pool is None or builder is None or class_name is None or method_name is None: return None if self_ptr is None: return None # 提前获取结构体 entry(用 find_struct_by_type 规避跨模块同名 find_struct 找错) # 用于 SHA1 查找和虚表分派 cmop_entry: HandlesStruct.StructEntry | t.CPtr = None cmop_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(self_ptr) if cmop_struct_ty is not None: cmop_entry = HandlesStruct.find_struct_by_type(cmop_struct_ty) if cmop_entry is None: cmop_entry = HandlesStruct.find_struct(class_name) # fallback: 若 cmop_struct_ty 为 None 但 entry 存在,从 entry 获取类型 # 用于跨模块调用时 self_ptr 类型信息丢失的情况 if cmop_struct_ty is None and cmop_entry is not None: cmop_struct_ty = cmop_entry.Ty # 构造方法查找名: ClassName.method_name lookup_name: t.CChar | t.CPtr = pool.alloc(128) if lookup_name is None: return None viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name) # 查找函数(支持 SHA1 后缀匹配) found_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, lookup_name) # 确定调用名 call_name: str = lookup_name if found_func is not None: found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) if found_name is not None: call_name = found_name else: # found_func 为 None(stub 未注入):用类所属模块的 SHA1 构造调用名 # 优先从 entry 获取 SHA1(规避跨模块同名 find_struct 找错) cls_sha1: str = None if cmop_entry is not None: cls_sha1 = cmop_entry.ModuleSha1 else: cls_sha1 = HandlesStruct.get_struct_sha1(class_name) if cls_sha1 is None and trans is not None: # fallback: 从 from_imports 查找类所属模块的 SHA1(含截断处理) cls_sha1 = _lookup_mod_sha1(pool, trans._from_imports, class_name) if cls_sha1 is None: err_msg: t.CChar | t.CPtr = pool.alloc(256) if err_msg is not None: viperlib.snprintf(err_msg, 256, "类 '%s' 方法 '%s' 找不到模块 SHA1", class_name, method_name) HandlesType.fatal_error(None, err_msg) HandlesType.fatal_error(None, "找不到模块 SHA1") mangled_len2: t.CSizeT = string.strlen(cls_sha1) + string.strlen(lookup_name) + 2 mangled2: str = pool.alloc(mangled_len2) if mangled2 is not None: viperlib.snprintf(mangled2, mangled_len2, "%s.%s", cls_sha1, lookup_name) call_name = mangled2 # 确定返回类型(__before_init__ 和 __init__ 返回 void) void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) call_ret_ty: llvmlite.LLVMType | t.CPtr = void_ty if found_func is not None: frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) if frt is not None: call_ret_ty = frt elif string.strcmp(method_name, "__getitem__") == 0 or string.strcmp(method_name, "__new__") == 0: # fail-fast:__getitem__/__new__ 必返回指针,返回类型缺失意味着 # stub declare 损坏,静默推断会截断指针(32 位)崩溃,立即终止。 err_cm1: t.CChar | t.CPtr = pool.alloc(256) if err_cm1 is not None: viperlib.snprintf(err_cm1, 256, "方法 '%s' 返回类型无法确定(stub declare 返回类型缺失)", method_name) HandlesType.fatal_error(None, err_cm1) HandlesType.fatal_error(None, "方法返回类型无法确定") else: # found_func 为 None(跨模块调用 stub 未注入):无法从 declare 获取返回类型。 # __new__ 返回 Ptr(struct_ty)(构造函数返回自身指针,可推断)。 # __getitem__ 返回类型无法从 self 推断(可返回 i8* 如 HashTable.__getitem__ # -> t.CPtr,或 Ptr(JsonValue) 如 JsonValue.__getitem__)——推断 Ptr(cmop_struct_ty) # 会与 define 返回类型不匹配,调用侧按错误类型读取返回值导致指针截断崩溃。 # fail-fast:__getitem__ 无 stub declare 立即报错,暴露依赖模块 vpi 缺失或 # 拓扑顺序错误(依赖模块未先翻译生成 vpi/text.ll)。 if string.strcmp(method_name, "__new__") == 0: if cmop_struct_ty is not None: call_ret_ty = llvmlite.Ptr(pool, cmop_struct_ty) else: err_cm2: t.CChar | t.CPtr = pool.alloc(256) if err_cm2 is not None: viperlib.snprintf(err_cm2, 256, "方法 '%s' 的 self 结构体类型未知(字段类型退化,依赖模块未预注册?)", method_name) HandlesType.fatal_error(None, err_cm2) HandlesType.fatal_error(None, "self 结构体类型未知") elif string.strcmp(method_name, "__getitem__") == 0: err_cm3: t.CChar | t.CPtr = pool.alloc(256) if err_cm3 is not None: viperlib.snprintf(err_cm3, 256, "方法 '%s.__getitem__' 的 stub declare 未注入(依赖模块 vpi 缺失或拓扑顺序错误),无法确定返回类型", class_name) HandlesType.fatal_error(None, err_cm3) HandlesType.fatal_error(None, "__getitem__ stub declare 未注入") # 构建参数链表: self_ptr → extra_args... llvmlite.value_set_next(self_ptr, None) head: llvmlite.Value | t.CPtr = self_ptr tail: llvmlite.Value | t.CPtr = self_ptr if extra_args is not None and extra_count > 0: for ei in range(extra_count): arg_addr: t.CSizeT = extra_args[ei] if arg_addr == 0: continue av: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(t.CVoid(arg_addr, t.CPtr)) if av is not None: llvmlite.value_set_next(av, None) llvmlite.value_set_next(tail, av) tail = av total_count: int = 1 + extra_count # 默认参数填充:如果调用点参数少于函数定义参数,用默认值填充缺失参数 # 优先用函数定义的默认值,无默认值时用零值兜底 # 查找函数的 defaults 信息 mdf_defaults: t.CVoid | t.CPtr = None mdf_default_count: int = 0 mdf_param_count: int = 0 if trans is not None and trans._funcs is not None: mdf_entry: FuncEntry | t.CPtr = find_func_entry_in_table( trans._funcs, trans._func_count, lookup_name) if mdf_entry is not None: mdf_defaults = mdf_entry.Defaults mdf_default_count = mdf_entry.DefaultCount mdf_param_count = mdf_entry.ParamCount if mdf_defaults is None: mdf_gd: FuncDefaultsEntry | t.CPtr = find_func_defaults(lookup_name) if mdf_gd is not None: mdf_defaults = mdf_gd.Defaults mdf_default_count = mdf_gd.DefaultCount mdf_param_count = mdf_gd.ParamCount # 计算需要填充的参数(不含 self) # extra_count = 已提供的非 self 参数数量 # mdf_param_count = 函数定义的非 self 参数数量 if mdf_param_count > extra_count: mdf_offset: int = mdf_param_count - mdf_default_count mdf_pi: int = extra_count while mdf_pi < mdf_param_count: # 优先用默认值 if mdf_defaults is not None and mdf_default_count > 0 and mdf_pi >= mdf_offset: mdf_di: int = mdf_pi - mdf_offset if mdf_di < mdf_default_count: # 优先用 stdlib 常量快照重建(mdf_gd.Defaults 的 pool 内 AST 可能已被 reset 回收) mdf_val: llvmlite.Value | t.CPtr = None if mdf_gd is not None: mdf_val = _build_const_from_snapshot( pool, mod, mdf_gd, mdf_di, trans, builder) if mdf_val is None: mdf_defaults_list: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(mdf_defaults), t.CPtr)) mdf_node: ast.AST | t.CPtr = mdf_defaults_list.get(mdf_di) if mdf_node is not None: mdf_val = HandlesExpr.translate_value( builder, pool, mod, mdf_node, None, 0, trans) if mdf_val is not None: llvmlite.value_set_next(mdf_val, None) llvmlite.value_set_next(tail, mdf_val) tail = mdf_val total_count += 1 mdf_pi += 1 continue # 无默认值时用零值兜底(需要 found_func 获取参数类型) if found_func is not None: param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) skip_z: int = 0 while skip_z <= mdf_pi and param_node_z is not None: param_node_z = llvmlite.param_get_next(param_node_z) skip_z += 1 if param_node_z is not None: zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z) zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty) if zero_val is not None: llvmlite.value_set_next(zero_val, None) llvmlite.value_set_next(tail, zero_val) tail = zero_val total_count += 1 mdf_pi += 1 elif found_func is not None: # 无默认参数信息但有 found_func:用零值填充(保留原有逻辑) param_node: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) skip_idx: int = 0 while skip_idx < total_count and param_node is not None: param_node = llvmlite.param_get_next(param_node) skip_idx += 1 while param_node is not None: missing_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node) zero_val2: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, missing_ty) if zero_val2 is not None: llvmlite.value_set_next(zero_val2, None) llvmlite.value_set_next(tail, zero_val2) tail = zero_val2 total_count += 1 param_node = llvmlite.param_get_next(param_node) # 参数类型强制转换:按 found_func 的形参类型 coerce 每个实参(跳过 self/cls 参数 0) # 修复: 构造器调用 __init__(ptr, base, 4096) 时 size 形参是 i64 (t.CSizeT), # 但 4096 字面量按 i32 传递,未提升导致运行时 size 高 32 位垃圾, # 破坏伙伴分配器的池大小元数据(如 total=2048)引发 calloc 失败/OOM。 if found_func is not None and head is not None: pc_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) # 跳过 self 参数(索引 0) if pc_param is not None: pc_param = llvmlite.param_get_next(pc_param) pc_node: llvmlite.Value | t.CPtr = head.Next new_tail: llvmlite.Value | t.CPtr = head if head is not None: head.Next = None while pc_node is not None: pc_next_save: llvmlite.Value | t.CPtr = pc_node.Next coerced_pc: llvmlite.Value | t.CPtr = pc_node if pc_param is not None: pty_pc: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pc_param) if pty_pc is not None: c_pc: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( builder, pc_node, pty_pc, None) if c_pc is not None: coerced_pc = c_pc pc_param = llvmlite.param_get_next(pc_param) coerced_pc.Next = None new_tail.Next = coerced_pc new_tail = coerced_pc pc_node = pc_next_save # 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用 # 复用前面已获取的 cmop_entry(find_struct_by_type 规避跨模块同名找错) if found_func is not None: cmop_has_vt: int = 0 cmop_method_idx: int = -1 if cmop_entry is not None: cmop_has_vt = cmop_entry.HasVTable if cmop_has_vt == 1 and cmop_entry.VTableMethods is not None: cmop_methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(cmop_entry.VTableMethods, t.CPtr)) for cmop_mi in range(cmop_entry.VTableMethodCount): cmop_mname_addr: t.CSizeT = cmop_methods_arr[cmop_mi] if cmop_mname_addr == 0: continue cmop_mname: str = (str | t.CPtr)(t.CVoid(cmop_mname_addr, t.CPtr)) if cmop_mname is not None and string.strcmp(cmop_mname, method_name) == 0: cmop_method_idx = cmop_mi break if cmop_has_vt == 1 and cmop_method_idx >= 0: return _do_virtual_call(pool, builder, mod, class_name, method_name, self_ptr, head, total_count, found_func, call_ret_ty) # 跨模块调用(found_func 为 None):创建 declare 声明,避免 llc 报 undefined value if found_func is None: _ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count) return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0) # ============================================================ # _ensure_method_declare - 为跨模块方法调用创建 declare 声明 # # 当 found_func 为 None(stub 未注入或跨模块调用)时, # 在当前模块中创建函数声明,避免 llc 报 undefined value。 # ============================================================ def _ensure_method_declare(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) # ============================================================ # _infer_method_ret_ty - 根据方法名推断返回类型 # # stub 未注入时,find_func_in_module 返回 None, # 需要根据方法名推断返回类型避免指针被截断为 i32。 # ============================================================ def _infer_method_ret_ty(pool: memhub.MemBuddy | t.CPtr, method_name: str) -> llvmlite.LLVMType | t.CPtr: """根据方法名推断返回类型(stub 未注入时的回退方案)""" if pool is None or method_name is None: return llvmlite.Int32(pool) i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) # 返回 i8* 的方法(分配/返回指针) if string.strcmp(method_name, "alloc") == 0: return i8_ptr_ty if string.strcmp(method_name, "calloc") == 0: return i8_ptr_ty if string.strcmp(method_name, "realloc") == 0: return i8_ptr_ty if string.strcmp(method_name, "alloc_buf") == 0: return i8_ptr_ty if string.strcmp(method_name, "_fl_pop") == 0: return i8_ptr_ty if string.strcmp(method_name, "_buddy_of") == 0: return i8_ptr_ty if string.strcmp(method_name, "_split_to_order") == 0: return i8_ptr_ty if string.strcmp(method_name, "__enter__") == 0: return i8_ptr_ty # 工厂方法:返回对象指针(截断会导致后续方法调用崩溃) if string.strcmp(method_name, "parse_args") == 0: return i8_ptr_ty # 魔术方法:返回对象指针(如 JsonValue.__getitem__ 返回 JsonValue*) if string.strcmp(method_name, "__getitem__") == 0: return i8_ptr_ty # 返回 i8* 的方法(返回字符串/类型名/描述) if string.strcmp(method_name, "type_name") == 0: return i8_ptr_ty if string.strcmp(method_name, "get_name") == 0: return i8_ptr_ty if string.strcmp(method_name, "get_str") == 0: return i8_ptr_ty if string.strcmp(method_name, "get_path") == 0: return i8_ptr_ty if string.strcmp(method_name, "get_buf") == 0: return i8_ptr_ty if string.strcmp(method_name, "to_string") == 0: return i8_ptr_ty if string.strcmp(method_name, "as_string") == 0: return i8_ptr_ty if string.strcmp(method_name, "__repr__") == 0: return i8_ptr_ty if string.strcmp(method_name, "__str__") == 0: return i8_ptr_ty # 返回 i8* 的方法(返回对象指针,如 JsonValue.get_item → JsonValue*) if string.strcmp(method_name, "get_item") == 0: return i8_ptr_ty # 返回 void 的方法 if string.strcmp(method_name, "__before_init__") == 0: return llvmlite.Void(pool) if string.strcmp(method_name, "__init__") == 0: return llvmlite.Void(pool) if string.strcmp(method_name, "__exit__") == 0: return llvmlite.Void(pool) # 默认 i32(整数):与本模块函数定义的默认返回类型一致(HandlesFunctions.py line 324) # 已知返回指针的方法在上方显式列出(返回 i8*),已知返回 void 的方法也显式列出 # 避免使用 i64 导致 stub 声明(declare i64)与实际定义(define i32)类型不匹配 # x86-64 ABI 中 i32 返回值在 rax 低 32 位,与 define i32 完全一致 # 与 _infer_external_func_ret_ty 的默认策略保持一致 # WARNING: 未登记的方法返回类型默认推断为 i32,若实际返回指针/i64 会被截断 VLogger.warning( f"方法返回类型未登记,默认推断为 i32(可能截断指针/i64): {method_name}", "HandlesExprCall") return llvmlite.Int32(pool) # ============================================================ # 跨模块方法返回类型查找(从 text.ll) # # Phase A 翻译每个源文件后生成 text.ll,其中 define 行包含 # 方法的实际返回类型。当 Phase A 翻译后续文件调用跨模块方法时, # _infer_method_ret_ty 默认返回 i32,导致指针返回值被截断。 # _LookupMethodRetTyFromTextLL 读取依赖模块的 text.ll,从 define # 行提取实际返回类型,避免指针截断。 # ============================================================ _g_temp_dir: str = None _g_temp_dir_len: t.CSizeT = 0 # text.ll 读取缓冲区大小 _TEXT_LL_READ_BUF_SIZE: t.CDefine = 262144 # ============================================================ # SetTempDir - 设置 temp 目录路径 # # 在 Phase2.py 的 Phase A 翻译前调用,使 HandlesExprCall # 能够读取依赖模块的 text.ll 文件。 # ============================================================ def SetTempDir(temp_dir: str): """设置 temp 目录路径(供跨模块方法返回类型查找使用)""" global _g_temp_dir global _g_temp_dir_len _g_temp_dir = temp_dir if temp_dir is not None: _g_temp_dir_len = string.strlen(temp_dir) else: _g_temp_dir_len = 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(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 # 检查是否含 * (指针类型) → 返回 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(pool: memhub.MemBuddy | t.CPtr, class_sha1: str, class_name: str, method_name: str) -> llvmlite.LLVMType | t.CPtr: """从依赖模块的 text.ll 中查找方法返回类型""" if pool is None or class_sha1 is None or class_name is None or method_name is None: return None if _g_temp_dir is None or _g_temp_dir_len == 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 = _g_temp_dir_len + 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", _g_temp_dir, subdir_buf, class_sha1) stdlib.free(subdir_buf) # 读取 text.ll read_buf: bytes = stdlib.malloc(_TEXT_LL_READ_BUF_SIZE) if read_buf is None: stdlib.free(path_buf) return None tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R) if tf.closed: stdlib.free(path_buf) stdlib.free(read_buf) return None text_len: t.CInt64T = tf.read_all(read_buf, _TEXT_LL_READ_BUF_SIZE) tf.close() stdlib.free(path_buf) if text_len <= 0: stdlib.free(read_buf) return None if text_len < _TEXT_LL_READ_BUF_SIZE: read_buf[text_len] = '\0' else: read_buf[_TEXT_LL_READ_BUF_SIZE - 1] = '\0' # 构造搜索模式: "{sha1}.{class_name}.{method_name}" cls_len: t.CSizeT = string.strlen(class_name) meth_len: t.CSizeT = string.strlen(method_name) search_len: t.CSizeT = sha1_len + cls_len + meth_len + 3 search_buf: bytes = stdlib.malloc(search_len) if search_buf is None: stdlib.free(read_buf) return None 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: # 匹配!提取返回类型: [ls+7, at_pos) result_ty = _ParseLLVMRetTyStr(pool, read_buf, ls + 7, at_pos) pos = le + 1 stdlib.free(search_buf) stdlib.free(read_buf) return result_ty # ============================================================ # 属性方法(@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 一个参数) # ============================================================ def _translate_property_call(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, class_name: str, method_name: str, call_head: llvmlite.Value | t.CPtr, call_count: int, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: """翻译属性/静态方法调用,返回 call 结果 Value""" if pool is None or builder is None or class_name is None or method_name is None: return None # 构造查找名: ClassName.method_name lookup_name: t.CChar | t.CPtr = pool.alloc(128) if lookup_name is None: return None viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name) # 查找函数(精确/后缀匹配) found_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, lookup_name) # 确定调用名 call_name: str = lookup_name if found_func is not None: found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) if found_name is not None: call_name = found_name else: # 未找到:用类所属模块的 SHA1 构造调用名 cls_sha1_pc: str = HandlesStruct.get_struct_sha1(class_name) if cls_sha1_pc is not None: mlen_pc: t.CSizeT = string.strlen(cls_sha1_pc) + string.strlen(lookup_name) + 2 mangled_pc: str = pool.alloc(mlen_pc) if mangled_pc is not None: viperlib.snprintf(mangled_pc, mlen_pc, "%s.%s", cls_sha1_pc, lookup_name) call_name = mangled_pc # 确定返回类型 i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty if found_func is not None: frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) if frt is not None: call_ret_ty = frt else: cls_sha1_rt: str = HandlesStruct.get_struct_sha1(class_name) looked_up_ty: llvmlite.LLVMType | t.CPtr = _LookupMethodRetTyFromTextLL( pool, cls_sha1_rt, class_name, method_name) if looked_up_ty is not None: call_ret_ty = looked_up_ty else: call_ret_ty = _infer_method_ret_ty(pool, method_name) # 确保 declare 存在,然后调用 _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 时使用。 # ============================================================ def _resolve_obj_class_name(pool: memhub.MemBuddy | t.CPtr, trans: HT.Translator | t.CPtr, obj_node: ast.AST | t.CPtr) -> str: """解析对象表达式的类名(短名),失败返回 None""" if pool is None or trans is None or obj_node is None: return None if obj_node.kind() == ast.ASTKind.Name: obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(obj_node) if obj_nm.id is not None: var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( trans.SymTab, obj_nm.id) if var_entry is not None and var_entry.AnnotClassName is not None: annot_val: str = var_entry.AnnotClassName dot_ptr: t.CChar | t.CPtr = string.strrchr(annot_val, '.') if dot_ptr is not None: return dot_ptr + 1 return annot_val return None # ============================================================ # _try_property_getter_attr — 尝试将 obj.attr 翻译为 property getter 调用 # # 检查 obj 的类是否有 @property/@x.getter 的 attr 方法; # 若有则生成 call Class.attr(obj) 并返回调用结果 Value;否则返回 None。 # ============================================================ def _try_property_getter_attr(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, at_node: ast.Attribute | t.CPtr, obj_ptr: llvmlite.Value | t.CPtr, trans: HT.Translator | t.CPtr, fallback_class_name: str = None) -> llvmlite.Value | t.CPtr: """尝试 property getter 属性访问,返回调用结果 Value;非 getter 返回 None fallback_class_name: 对象表达式非 Name 时从 LLVM 类型解析出的类名兜底。 """ if at_node is None or at_node.attr is None or obj_ptr is None or trans is None: return None class_name: str = _resolve_obj_class_name(pool, trans, at_node.value) if class_name is None: class_name = fallback_class_name if class_name is None: return None meta: int = HandlesClassDef.lookup_method_meta(class_name, at_node.attr) if meta & HandlesClassDef.META_PROP_GETTER == 0: return None # 单参数调用: obj → getter llvmlite.value_set_next(obj_ptr, None) return _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。 # ============================================================ def _try_property_setter(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, target_attr: ast.Attribute | t.CPtr, rhs_val: llvmlite.Value | t.CPtr, trans: HT.Translator | t.CPtr) -> int: """尝试 property setter 赋值,返回 1=已处理(生成调用)""" if pool is None or builder is None or mod is None or trans is None: return 0 if target_attr is None or target_attr.attr is None or rhs_val is None: return 0 class_name: str = _resolve_obj_class_name(pool, trans, target_attr.value) if class_name is None: return 0 meta: int = HandlesClassDef.lookup_method_meta(class_name, target_attr.attr) if meta & HandlesClassDef.META_PROP_SETTER == 0: return 0 # 翻译对象值(self 参数) obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, target_attr.value, None, 0, trans) if obj_val is None: return 0 # 构建参数链表: obj → rhs llvmlite.value_set_next(obj_val, None) llvmlite.value_set_next(rhs_val, None) llvmlite.value_set_next(obj_val, rhs_val) # setter 函数名带 $set 后缀 setter_name_buf: t.CChar | t.CPtr = pool.alloc(128) if setter_name_buf is None: return 0 viperlib.snprintf(setter_name_buf, 128, "%s$set", target_attr.attr) _translate_property_call(pool, builder, mod, class_name, 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。 # ============================================================ def _try_property_deleter(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, target_attr: ast.Attribute | t.CPtr, trans: HT.Translator | t.CPtr) -> int: """尝试 property deleter 删除,返回 1=已处理(生成调用)""" if pool is None or builder is None or mod is None or trans is None: return 0 if target_attr is None or target_attr.attr is None: return 0 class_name: str = _resolve_obj_class_name(pool, trans, target_attr.value) if class_name is None: return 0 meta: int = HandlesClassDef.lookup_method_meta(class_name, target_attr.attr) if meta & HandlesClassDef.META_PROP_DELETER == 0: return 0 # 翻译对象值(self 参数) obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, target_attr.value, None, 0, trans) if obj_val is None: return 0 llvmlite.value_set_next(obj_val, None) # deleter 函数名带 $del 后缀 del_name_buf: t.CChar | t.CPtr = pool.alloc(128) if del_name_buf is None: return 0 viperlib.snprintf(del_name_buf, 128, "%s$del", target_attr.attr) _translate_property_call(pool, builder, mod, class_name, del_name_buf, obj_val, 1, trans) return 1 # ============================================================ # _translate_static_class_call — 翻译 ClassName.method(args) 静态/类方法调用 # # @staticmethod: 直接 call Class.method(args...),无 self # @classmethod: 在参数前插入栈上分配的类实例指针(与 TPC 一致) # ============================================================ def _translate_static_class_call(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, class_name: str, method_name: str, cl: ast.Call | t.CPtr, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: """翻译类名静态/类方法调用,返回 call 结果 Value;非静态/类方法返回 None""" if pool is None or builder is None or mod is None or trans is None: return None if class_name is None or method_name is None or cl is None: return None meta: int = HandlesClassDef.lookup_method_meta(class_name, method_name) is_static: int = 0 is_class: int = 0 if meta & HandlesClassDef.META_STATIC != 0: is_static = 1 if meta & HandlesClassDef.META_CLASS != 0: is_class = 1 if is_static == 0 and is_class == 0: return None # 构建参数链表 head: llvmlite.Value | t.CPtr = None total_count: int = 0 # @classmethod: 插入栈上分配的类实例指针作为 cls 参数 if is_class != 0: struct_ty_cc: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name) if struct_ty_cc is None: return None cls_ptr: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty_cc) if cls_ptr is None: return None llvmlite.value_set_next(cls_ptr, None) head = cls_ptr total_count = 1 # 翻译调用参数 cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args can: t.CSizeT = 0 if cargs is not None: can = cargs.__len__() tail: llvmlite.Value | t.CPtr = head for ai in range(can): arg_node: ast.AST | t.CPtr = cargs.get(ai) if arg_node is None: continue arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, arg_node, None, 0, trans) if arg_val is None: continue llvmlite.value_set_next(arg_val, None) if head is None: head = arg_val tail = arg_val else: llvmlite.value_set_next(tail, arg_val) tail = arg_val total_count += 1 if head is None: return None return _translate_property_call(pool, builder, mod, class_name, method_name, head, total_count, trans) # ============================================================ # _translate_method_call - 翻译方法调用 obj.method(args) # # 生成: call @SHA1.ClassName.method_name(Ptr(StructTy) %obj, args...) # # obj_ptr 是对象变量的 alloca(Ptr(StructTy)),作为 self 参数传入 # ============================================================ def _translate_method_call(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, class_name: str, method_name: str, obj_ptr: llvmlite.Value | t.CPtr, cl: ast.Call | t.CPtr, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: """翻译方法调用,返回 call 结果 Value""" if pool is None or builder is None or class_name is None or method_name is None: return None if obj_ptr is None or cl is None: return None # 提前获取结构体 entry(用 find_struct_by_type 规避跨模块同名 find_struct 找错) # 用于继承链遍历、SHA1 查找和虚表分派 mc_entry: HandlesStruct.StructEntry | t.CPtr = None mc_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(obj_ptr) if mc_struct_ty is not None: mc_entry = HandlesStruct.find_struct_by_type(mc_struct_ty) if mc_entry is None: mc_entry = HandlesStruct.find_struct(class_name) # 构造方法查找名: ClassName.method_name lookup_name: t.CChar | t.CPtr = pool.alloc(128) if lookup_name is None: return None viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name) # 查找函数(支持 SHA1 后缀匹配) found_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, lookup_name) # 沿继承链查找父类方法(子类未覆盖时回退到父类) if found_func is None: cur_parent: str = None if mc_entry is not None: cur_parent = mc_entry.ParentName else: cur_parent = HandlesStruct.get_parent_name(class_name) while cur_parent is not None: parent_lookup: t.CChar | t.CPtr = pool.alloc(128) if parent_lookup is not None: viperlib.snprintf(parent_lookup, 128, "%s.%s", cur_parent, method_name) parent_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, parent_lookup) if parent_func is not None: found_func = parent_func break # 后续父类按名查找(无 ParentSha1,只能按名回退) cur_parent = HandlesStruct.get_parent_name(cur_parent) # 确定调用名 call_name: str = lookup_name if found_func is not None: found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) if found_name is not None: call_name = found_name else: # found_func 为 None(stub 未注入):用类所属模块的 SHA1 构造调用名 # 沿继承链查找第一个有 SHA1 的类 cls_sha1_mc: str = None if mc_entry is not None: cls_sha1_mc = mc_entry.ModuleSha1 else: cls_sha1_mc = HandlesStruct.get_struct_sha1(class_name) if cls_sha1_mc is None: cur_p: str = None if mc_entry is not None: cur_p = mc_entry.ParentName else: cur_p = HandlesStruct.get_parent_name(class_name) while cur_p is not None and cls_sha1_mc is None: cls_sha1_mc = HandlesStruct.get_struct_sha1(cur_p) cur_p = HandlesStruct.get_parent_name(cur_p) if cls_sha1_mc is not None: mangled_len_mc: t.CSizeT = string.strlen(cls_sha1_mc) + string.strlen(lookup_name) + 2 mangled_mc: str = pool.alloc(mangled_len_mc) if mangled_mc is not None: viperlib.snprintf(mangled_mc, mangled_len_mc, "%s.%s", cls_sha1_mc, lookup_name) call_name = mangled_mc # 确定返回类型 i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty if found_func is not None: frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) if frt is not None: call_ret_ty = frt else: # found_func 为 None(stub 未注入):尝试从 text.ll 查找实际返回类型 # 避免指针返回值被 _infer_method_ret_ty 默认为 i32 导致 inttoptr 截断 looked_up_ty: llvmlite.LLVMType | t.CPtr = _LookupMethodRetTyFromTextLL( pool, cls_sha1_mc, class_name, method_name) if looked_up_ty is not None: call_ret_ty = looked_up_ty else: call_ret_ty = _infer_method_ret_ty(pool, method_name) # 翻译调用参数 cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args can: t.CSizeT = 0 if cargs is not None: can = cargs.__len__() kw_calls: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords kwc: t.CSizeT = 0 if kw_calls is not None: kwc = kw_calls.__len__() # 构建参数链表: obj_ptr → arg1 → arg2 → ... llvmlite.value_set_next(obj_ptr, None) head: llvmlite.Value | t.CPtr = obj_ptr tail: llvmlite.Value | t.CPtr = obj_ptr arg_count_eff: int = 0 if kwc > 0 and found_func is not None: # 关键字参数:遍历函数定义参数(跳过 self),位置参数优先,其余按名匹配 # 缺失参数用零值兜底,保持 call 参数数量与 define 一致 cur_param_k: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) if cur_param_k is not None: cur_param_k = llvmlite.param_get_next(cur_param_k) # 跳过 self pi_k: int = 0 while cur_param_k is not None: arg_node_k: ast.AST | t.CPtr = None if pi_k < can: arg_node_k = cargs.get(pi_k) else: pname_k: t.CChar | t.CPtr = llvmlite.param_get_name(cur_param_k) if pname_k is not None: ki_k: int for ki_k in range(kwc): kw_k: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(kw_calls.get(ki_k)) if kw_k is None or kw_k.arg is None or kw_k.value is None: continue if _kwarg_name_matches(kw_k.arg, pname_k) == 1: arg_node_k = kw_k.value break arg_val_k: llvmlite.Value | t.CPtr = None if arg_node_k is not None: arg_val_k = HandlesExpr.translate_value( builder, pool, mod, arg_node_k, None, 0, trans) if arg_val_k is None: # 缺失参数:零值兜底(保持参数数量匹配) pty_k: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k) if pty_k is not None: arg_val_k = llvmlite.ConstZero(pool, pty_k) if arg_val_k is not None: pty_k2: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k) if pty_k2 is not None: arg_val_k = HandlesExpr.coerce_to_type( builder, arg_val_k, pty_k2, arg_node_k) llvmlite.value_set_next(arg_val_k, None) llvmlite.value_set_next(tail, arg_val_k) tail = arg_val_k arg_count_eff += 1 pi_k += 1 cur_param_k = llvmlite.param_get_next(cur_param_k) else: # 位置参数(原逻辑) for ai in range(can): arg_node: ast.AST | t.CPtr = cargs.get(ai) if arg_node is None: continue arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, arg_node, None, 0, trans) if arg_val is None: continue # 按形参类型 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1) # 修复: CDefine/i32 常量传给 i64 形参(如 MemBuddy.__init__ 的 size: t.CSizeT) # 未提升导致 call(i32) 与 define(i64) 不匹配,运行时读到垃圾高 32 位崩溃 if found_func is not None: pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) pi: int = 0 while pp is not None and pi < ai + 1: if pi == ai + 1: break pp = llvmlite.param_get_next(pp) pi += 1 if pp is not None: pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp) if pty is not None: arg_val = HandlesExpr.coerce_to_type( builder, arg_val, pty, arg_node) llvmlite.value_set_next(arg_val, None) llvmlite.value_set_next(tail, arg_val) tail = arg_val arg_count_eff += 1 total_count: int = 1 + arg_count_eff # 默认参数填充:如果调用点参数少于函数定义参数,用默认值填充缺失参数 # 查找函数的 defaults 信息 mdf_defaults: t.CVoid | t.CPtr = None mdf_default_count: int = 0 mdf_param_count: int = 0 if trans is not None and trans._funcs is not None: mdf_entry: FuncEntry | t.CPtr = find_func_entry_in_table( trans._funcs, trans._func_count, lookup_name) if mdf_entry is not None: mdf_defaults = mdf_entry.Defaults mdf_default_count = mdf_entry.DefaultCount mdf_param_count = mdf_entry.ParamCount if mdf_defaults is None: mdf_gd: FuncDefaultsEntry | t.CPtr = find_func_defaults(lookup_name) if mdf_gd is not None: mdf_defaults = mdf_gd.Defaults mdf_default_count = mdf_gd.DefaultCount mdf_param_count = mdf_gd.ParamCount # 计算需要填充的参数(不含 self) # arg_count_eff = 已提供的非 self 参数数量(含关键字模式完整构建) # mdf_param_count = 函数定义的非 self 参数数量 if mdf_param_count > arg_count_eff: mdf_offset: int = mdf_param_count - mdf_default_count mdf_pi: int = arg_count_eff while mdf_pi < mdf_param_count: # 优先用默认值 if mdf_defaults is not None and mdf_default_count > 0 and mdf_pi >= mdf_offset: mdf_di: int = mdf_pi - mdf_offset if mdf_di < mdf_default_count: # 优先用 stdlib 常量快照重建(mdf_gd.Defaults 的 pool 内 AST 可能已被 reset 回收) mdf_val: llvmlite.Value | t.CPtr = None if mdf_gd is not None: mdf_val = _build_const_from_snapshot( pool, mod, mdf_gd, mdf_di, trans, builder) if mdf_val is None: mdf_defaults_list: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(mdf_defaults), t.CPtr)) mdf_node: ast.AST | t.CPtr = mdf_defaults_list.get(mdf_di) if mdf_node is not None: mdf_val = HandlesExpr.translate_value( builder, pool, mod, mdf_node, None, 0, trans) if mdf_val is not None: llvmlite.value_set_next(mdf_val, None) llvmlite.value_set_next(tail, mdf_val) tail = mdf_val total_count += 1 mdf_pi += 1 continue # 无默认值时用零值兜底(需要 found_func 获取参数类型) if found_func is not None: param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) skip_z: int = 0 while skip_z <= mdf_pi and param_node_z is not None: param_node_z = llvmlite.param_get_next(param_node_z) skip_z += 1 if param_node_z is not None: zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z) zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty) if zero_val is not None: llvmlite.value_set_next(zero_val, None) llvmlite.value_set_next(tail, zero_val) tail = zero_val total_count += 1 mdf_pi += 1 # 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用 # (不依赖 found_func — 继承的虚方法可能没有子类实现) # 复用前面已获取的 mc_entry(find_struct_by_type 规避跨模块同名找错) mc_has_vt: int = 0 mc_method_idx: int = -1 if mc_entry is not None: mc_has_vt = mc_entry.HasVTable if mc_has_vt == 1 and mc_entry.VTableMethods is not None: mc_methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(mc_entry.VTableMethods, t.CPtr)) for mc_mi in range(mc_entry.VTableMethodCount): mc_mname_addr: t.CSizeT = mc_methods_arr[mc_mi] if mc_mname_addr == 0: continue mc_mname: str = (str | t.CPtr)(t.CVoid(mc_mname_addr, t.CPtr)) if mc_mname is not None and string.strcmp(mc_mname, method_name) == 0: mc_method_idx = mc_mi break if mc_has_vt == 1 and mc_method_idx >= 0: return _do_virtual_call(pool, builder, mod, class_name, method_name, obj_ptr, head, total_count, found_func, call_ret_ty) # 跨模块调用:创建 declare 声明,避免 llc 报 undefined value _ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count) # 检查变长函数 + C ABI 提升 is_variadic_3441: int = _check_and_promote_variadic_call(pool, builder, mod, call_name, head, total_count) return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, is_variadic_3441) # ============================================================ # _kwarg_name_matches — 检查关键字参数名是否匹配函数参数名 # # 函数参数名在 LLVM IR 中带 % 前缀(如 "%a"),关键字参数名无前缀(如 "a") # 跳过 % 前缀后逐字符比较 # ============================================================ def _kwarg_name_matches(kw_arg: str, param_name: t.CChar | t.CPtr) -> int: """检查关键字参数名 kw_arg 是否匹配参数名 param_name(跳过 % 前缀)""" if kw_arg is None or param_name is None: return 0 start: t.CSizeT = 0 if param_name[0] == '%': start = 1 for i, ch in enumerate(kw_arg): c: t.CChar = param_name[start + i] if c == '\0' or c != ch: return 0 if param_name[start + i + 1] != '\0': return 0 return 1 # ============================================================ # _translate_struct_ctor_kw — 结构体构造函数(关键字参数) # # 支持两种语法: # Point(x=10, y=20) — 全关键字 # Point(10, y=20) — 混合(位置 + 关键字) # # 位置参数按字段索引赋值,关键字参数按字段名查找赋值 # ============================================================ def _translate_struct_ctor_kw(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, struct_ty: llvmlite.LLVMType | t.CPtr, class_name: str, cargs: list[ast.AST | t.CPtr] | t.CPtr, can: t.CSizeT, keywords: list[ast.AST | t.CPtr] | t.CPtr, kw_count: t.CSizeT, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: """结构体构造函数(关键字参数版本)""" # 创建临时 alloca # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) if tmp is None: return llvmlite.ConstZero(pool, struct_ty) # OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值 # 用 find_struct_by_type 规避跨模块同名 find_struct 找错 kw_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) is_oop: int = 0 if kw_entry is not None: is_oop = kw_entry.IsOOP # 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods) # 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入) # 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠) if is_oop == 0 and class_name is not None: kw_init_lookup: t.CChar | t.CPtr = pool.alloc(128) if kw_init_lookup is not None: viperlib.snprintf(kw_init_lookup, 128, "%s.__init__", class_name) # 方案1: 检查当前模块的函数声明 kw_init_found: llvmlite.Function | t.CPtr = find_func_in_module(mod, kw_init_lookup) if kw_init_found is not None: is_oop = 1 if kw_entry is not None: kw_entry.IsOOP = 1 kw_entry.HasInit = 1 else: # 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入) kw_init_defaults: FuncDefaultsEntry | t.CPtr = find_func_defaults(kw_init_lookup) if kw_init_defaults is not None: is_oop = 1 if kw_entry is not None: kw_entry.IsOOP = 1 kw_entry.HasInit = 1 if is_oop != 0: _call_method_on_ptr(pool, builder, mod, class_name, "__before_init__", tmp, None, 0, trans) else: # 普通结构体:store zeroinitializer + 应用默认值 zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) llvmlite.build_store(builder, zero, tmp) _apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans) # OOP 结构体且有 __init__:调用 __init__ 而非逐字段 store # 关键字构造调用此前总是逐字段 store,导致 __init__ 方法体不执行 # (如 self._args = mb.alloc(...) 不执行 → self._args 为 NULL → add_argument 崩溃) has_init_flag: int = 0 has_new_flag: int = 0 if kw_entry is not None: has_init_flag = kw_entry.HasInit has_new_flag = kw_entry.HasNew # 跨模块 OOP 类: HasInit 可能未设置(_translate_oop_methods 未被调用) # 但 IsOOP=1 说明类有方法,推断 HasInit=1(__init__ 在目标模块中存在) # 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法) if is_oop != 0 and has_init_flag == 0: has_init_flag = 1 if is_oop != 0 and has_init_flag != 0: # 有 __init__:构建参数数组并调用 __init__ storage_ptr: llvmlite.Value | t.CPtr = tmp # 如果有 __new__,调用 __new__ 获取实际存储指针 if has_new_flag != 0: new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) if new_arg_vals is not None: string.memset(new_arg_vals, 0, 8 * 32) new_arg_count: int = 0 for nai in range(can): new_arg_node: ast.AST | t.CPtr = cargs.get(nai) if new_arg_node is None: continue new_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, new_arg_node, None, 0, trans) if new_av is not None: if new_arg_count < 32: new_arg_vals[new_arg_count] = t.CSizeT(new_av) new_arg_count += 1 # 关键字参数也传递给 __new__ for nki in range(kw_count): nkw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(nki)) if nkw is None or nkw.value is None: continue nkw_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, nkw.value, None, 0, trans) if nkw_av is not None: if new_arg_count < 32: new_arg_vals[new_arg_count] = t.CSizeT(nkw_av) new_arg_count += 1 new_ptr: llvmlite.Value | t.CPtr = _call_method_on_ptr( pool, builder, mod, class_name, "__new__", tmp, new_arg_vals, new_arg_count, trans) if new_ptr is not None: storage_ptr = new_ptr # __new__ 只保证返回"实例存储指针",声明类型通常是 # `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。 # 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的 # obj.method(如 parser.add_argument)get_class_name_by_type # 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。 # bitcast 只改类型层视图,运行时零开销(指针位不变)。 if new_ptr.Ty is not None: nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty): nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty) if nw_bc is not None: storage_ptr = nw_bc # 构建 __init__ 参数数组:位置参数按顺序 + 关键字参数追加 init_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) if init_arg_vals is not None: string.memset(init_arg_vals, 0, 8 * 32) init_arg_count: int = 0 # 位置参数 for ai_init in range(can): arg_node_init: ast.AST | t.CPtr = cargs.get(ai_init) if arg_node_init is None: continue av_init: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, arg_node_init, None, 0, trans) if av_init is not None: if init_arg_count < 32: init_arg_vals[init_arg_count] = t.CSizeT(av_init) init_arg_count += 1 # 关键字参数(追加到末尾,按出现顺序) for ki_init in range(kw_count): kw_init: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki_init)) if kw_init is None or kw_init.value is None: continue kw_av_init: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, kw_init.value, None, 0, trans) if kw_av_init is not None: if init_arg_count < 32: init_arg_vals[init_arg_count] = t.CSizeT(kw_av_init) init_arg_count += 1 # 调用 __init__(storage_ptr, *args) _call_method_on_ptr(pool, builder, mod, class_name, "__init__", storage_ptr, init_arg_vals, init_arg_count, trans) # 返回指针 return storage_ptr # 无 __init__(或非 OOP):逐字段 store 参数值 # 先处理位置参数(按字段索引,覆盖默认值) 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: continue fe: HandlesStruct.FieldEntry | t.CPtr = None if kw_entry is not None: fe = HandlesStruct._get_field_entry(kw_entry, ai) else: fe = HandlesStruct.get_field_by_index(class_name, ai) if fe is None: continue field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( builder, struct_ty, fe.Ty, tmp, fe.Index) if field_ptr is None: continue arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg) llvmlite.build_store(builder, arg_val, field_ptr) # 处理关键字参数(按字段名查找) # SHA1 从 kw_entry 获取(规避跨模块同名 find_struct 找错) kw_sha1: str = None if kw_entry is not None: kw_sha1 = kw_entry.ModuleSha1 for ki in range(kw_count): 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 fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field_by_class( class_name, kw.arg, kw_sha1) if fe is None: continue kw_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, kw.value, None, 0, trans) if kw_val is None: continue field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( builder, struct_ty, fe.Ty, tmp, fe.Index) if field_ptr is None: continue kw_val = HandlesExpr.coerce_to_type(builder, kw_val, fe.Ty, kw.value) llvmlite.build_store(builder, kw_val, field_ptr) # 返回指针(而非结构体值),赋值时由 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. 按参数顺序构建调用参数链表 # ============================================================ def _translate_call_with_kwargs(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, func_name: str, found_func: llvmlite.Function | t.CPtr, cargs: list[ast.AST | t.CPtr] | t.CPtr, can: t.CSizeT, keywords: list[ast.AST | t.CPtr] | t.CPtr, kw_count: t.CSizeT, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: """带关键字参数的函数调用,按参数顺序构建调用链表 使用 llvmlite 访问器函数绕过 stub 类型限制: found_func.Params/RetTy/Name 和 cur_param.Name/Ty/Next 在 stub 类型中字段不足,直接访问会被 TransPyC 静默跳过。 """ head: llvmlite.Value | t.CPtr = None tail: llvmlite.Value | t.CPtr = None actual_count: t.CSizeT = 0 # memcpy 专用: 收集前三个 Value 的独立引用(避免共享 alloca 对象的 Next 被污染) mc_dst1: llvmlite.Value | t.CPtr = None mc_src1: llvmlite.Value | t.CPtr = None mc_num1: llvmlite.Value | t.CPtr = None # 遍历函数参数链表(使用访问器获取 Head) param_idx: t.CSizeT = 0 cur_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) while cur_param is not None: arg_val: llvmlite.Value | t.CPtr = None if param_idx < can: # 优先使用位置参数 arg: ast.AST | t.CPtr = cargs.get(param_idx) if arg is not None: arg_val = HandlesExpr.translate_value( builder, pool, mod, arg, None, 0, trans) else: # 查找匹配的关键字参数 param_name: t.CChar | t.CPtr = llvmlite.param_get_name(cur_param) if param_name is not None: for ki in range(kw_count): 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 if _kwarg_name_matches(kw.arg, param_name) == 1: arg_val = HandlesExpr.translate_value( builder, pool, mod, kw.value, None, 0, trans) break if arg_val is not None: # 类型转换(按参数类型,使用访问器) param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param) if param_ty is not None: arg_val = HandlesExpr.coerce_to_type(builder, arg_val, param_ty) arg_val.Next = None if head is None: head = arg_val else: tail.Next = arg_val tail = arg_val # memcpy 专用: 保存前三个参数的独立引用 if actual_count == 0: mc_dst1 = arg_val elif actual_count == 1: mc_src1 = arg_val elif actual_count == 2: mc_num1 = arg_val actual_count += 1 param_idx += 1 cur_param = llvmlite.param_get_next(cur_param) # 使用模块中的实际函数名(可能带 SHA1 前缀,使用访问器) # declare 和 define 统一用 found_func.Name: # - 普通函数的 declare/define 都带 SHA1 前缀(forward_declare_functions 和 stub 注入都用 mangled_name) # - t.CExtern/t.State/t.CExport 函数的 declare/define 都用裸名 # 旧逻辑(IsDeclared==1 时用 func_name 裸名)是错误的:stub 注入的 declare Name 已带 SHA1 前缀, # 用裸名会导致 call @_PathToModuleName 而 define 是 @"sha1._PathToModuleName",链接报 undefined reference call_name: str = func_name found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) if found_name is not None: call_name = found_name # 返回类型(使用访问器) call_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) if call_ret_ty is None: call_ret_ty = _infer_external_func_ret_ty(pool, func_name) # memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失) if string.strcmp(func_name, "memcpy") == 0 and actual_count >= 3: return _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) # ============================================================ def _translate_t_type_cast(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, val: llvmlite.Value | t.CPtr, target_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: """类型转换:根据参数类型和目标类型选择转换方式""" if val is None or target_ty is None: return None val_bits: int = HandlesExpr.get_llvm_type_bits(val.Ty) target_bits: int = HandlesExpr.get_llvm_type_bits(target_ty) val_fbits: int = HandlesExpr.get_llvm_float_bits(val.Ty) target_fbits: int = HandlesExpr.get_llvm_float_bits(target_ty) # 整数 → 整数: trunc/zext if val_bits != 0 and target_bits != 0: if val_bits == target_bits: return val elif val_bits < target_bits: return llvmlite.build_zext(builder, val, target_ty) else: return llvmlite.build_trunc(builder, val, target_ty) # 整数 → 浮点: sitofp if val_bits != 0 and target_fbits != 0: return llvmlite.build_si2fp(builder, val, target_ty) # 浮点 → 整数: fptosi if val_fbits != 0 and target_bits != 0: return llvmlite.build_fp2si(builder, val, target_ty) # 浮点 → 浮点: fpext/fptrunc if val_fbits != 0 and target_fbits != 0: if val_fbits == target_fbits: return val elif val_fbits < target_fbits: return llvmlite.build_fpext(builder, val, target_ty) else: return llvmlite.build_fptrunc(builder, val, target_ty) # 指针 → 整数: ptrtoint if val_bits == 0 and val_fbits == 0 and target_bits != 0: return llvmlite.build_ptrtoint(builder, val, target_ty) # 整数 → 指针: inttoptr(必须排除浮点 target,浮点 target_bits 也是 0) if val_bits != 0 and target_bits == 0 and target_fbits == 0: return llvmlite.build_inttoptr(builder, val, target_ty) # 指针 → 指针: bitcast return llvmlite.build_bitcast(builder, val, target_ty) # ============================================================ # 泛型实例化辅助:从 Subscript slice 提取类型实参名 # ============================================================ # _get_type_name_from_annotation 已移至 HandlesType.py(支持 BinOp/Attribute) # HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用 def _extract_type_args_from_slice(pool: memhub.MemBuddy | t.CPtr, slice_node: ast.AST | t.CPtr) -> list[str] | t.CPtr: """从 Subscript.slice 提取类型实参名列表 list[int] -> ["int"] dict[str, int] -> ["str", "int"] list[AST | t.CPtr] -> ["AST|t.CPtr"] """ if slice_node is None or pool is None: return None result: list[str] | t.CPtr = list[str](pool, 4) k: int = slice_node.kind() if k == ast.ASTKind.Tuple: tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(slice_node) elts: list[ast.AST | t.CPtr] | t.CPtr = tp.elts if elts is not None: n: t.CSizeT = elts.__len__() i: t.CSizeT for i in range(n): elt: ast.AST | t.CPtr = elts.get(i) tn: str = HandlesType._get_type_name_from_annotation(pool, elt) if tn is not None: result.append(tn) else: tn: str = HandlesType._get_type_name_from_annotation(pool, slice_node) if tn is not None: 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。 # ============================================================ def _translate_generic_ctor_call(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, spec_name: str, cl: ast.Call | t.CPtr, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: """泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__""" if pool is None or builder is None or mod is None or spec_name is None or cl is None: return None # 查找 struct entry 获取类型 struct_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) if struct_entry is None: HandlesType.fatal_error(cl, "泛型类构造调用: 特化类未注册") return None struct_ty: llvmlite.LLVMType | t.CPtr = struct_entry.Ty if struct_ty is None: return None # 确保结构体定义在当前模块中可用(供 alloca 分配空间) HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) # alloca tmp(self 指针) tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) if tmp is None: return None # 翻译 cl.args 为参数指针数组(extra_args[i] = Value 指针) cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args can: t.CSizeT = 0 if cargs is not None: can = cargs.__len__() extra_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) if extra_args is None: return None string.memset(extra_args, 0, 8 * 32) ai: t.CSizeT = 0 while ai < can: arg_node: ast.AST | t.CPtr = cargs.get(ai) if arg_node is not None: arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, arg_node, None, 0, trans) if arg_val is not None: extra_args[ai] = t.CSizeT(arg_val) ai += 1 # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 # __new__ 是可选的,仅当泛型类模板定义了 __new__ 方法时才调用 # (与 _translate_struct_ctor 保持一致,避免为无 __new__ 的类生成过度声明) storage_ptr: llvmlite.Value | t.CPtr = tmp has_new_flag: int = 0 if struct_entry is not None: has_new_flag = struct_entry.HasNew if has_new_flag != 0: new_ptr: llvmlite.Value | t.CPtr = _call_method_on_ptr( pool, builder, mod, spec_name, "__new__", tmp, extra_args, can, trans) if new_ptr is not None: storage_ptr = new_ptr # __new__ 只保证返回"实例存储指针",声明类型通常是 # `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。 # 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的 # obj.method(如 parser.add_argument)get_class_name_by_type # 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。 # bitcast 只改类型层视图,运行时零开销(指针位不变)。 if new_ptr.Ty is not None: nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty): nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty) if nw_bc is not None: storage_ptr = nw_bc # call __before_init__(storage_ptr)(TransPyV 自动生成,零值填充) _call_method_on_ptr( pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans) # call __init__(storage_ptr, *args) _call_method_on_ptr( pool, builder, mod, spec_name, "__init__", storage_ptr, extra_args, can, trans) return storage_ptr # ============================================================ # 翻译函数调用 Call(func, args) — 模块级版本 # ============================================================ def translate_call(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, node: ast.AST | t.CPtr, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: """翻译函数调用,返回 call 结果 Value""" cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) if cl is None: return None func_name: str = HandlesExpr.get_func_name(cl.func) if func_name is None: # 检查是否是 list[int](pool) 形式的泛型实例化调用 # Subscript 节点作为 Call func: 泛型类构造函数 if cl.func is not None and cl.func.kind() == ast.ASTKind.Subscript and trans is not None: sub_node: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(cl.func) if sub_node.value is not None and sub_node.value.kind() == ast.ASTKind.Name: gen_nm_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_node.value) gen_class_name: str = gen_nm_node.id # 检查是否是泛型类模板 template_cd: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(gen_class_name) if template_cd is not None: # 提取类型实参 gen_type_args: list[str] | t.CPtr = _extract_type_args_from_slice(pool, sub_node.slice) if gen_type_args is not None and gen_type_args.__len__() > 0: # 特化泛型类,返回特化类名 spec_name: str = HandlesClassDef._specialize_generic_class( trans, gen_class_name, gen_type_args) if spec_name is not None: # 泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__ # 不能直接用 spec_name 作为 func_name(会走裸名调用路径, # 被 star import 回退误导用错误的 SHA1,且缺少 __new__ 方法名后缀) return _translate_generic_ctor_call( pool, builder, mod, spec_name, cl, trans) else: # 泛型类模板未找到:可能未 import 定义模块 gt_err: str = pool.alloc(256) if gt_err is not None: viperlib.snprintf(gt_err, 256, "泛型类 '%s' 未找到模板,可能未 import 定义模块", gen_class_name) HandlesType.fatal_error(gen_nm_node, gt_err) HandlesType.fatal_error(gen_nm_node, "泛型类模板未找到") if func_name is None: # 检查是否是 (A | t.CPtr)(value) 形式的类型转换 # BinOp 节点作为 Call func: 联合类型注解用作类型转换 if cl.func is not None and cl.func.kind() == ast.ASTKind.BinOp and trans is not None: binop_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( pool, cl.func, trans._imported_modules, trans._from_imports, trans) if binop_ty is not None: binop_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args if binop_args is not None and binop_args.__len__() == 1: binop_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, binop_args.get(0), funcs_ptr, func_count, trans) if binop_arg_val is not None: return _translate_t_type_cast(pool, builder, binop_arg_val, binop_ty) return None # 检测 c.Deref / c.DerefAs / c.Addr 等特殊调用(内联 IR,不生成 call) if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: at_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) if at_node.value is not None and at_node.value.kind() == ast.ASTKind.Name: 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 translate_c_deref(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "DerefAs") == 0: return translate_c_derefas(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "Addr") == 0: return translate_c_addr(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "Load") == 0: return translate_c_load(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "Asm") == 0: return translate_c_asm(pool, builder, mod, cl, trans) elif string.strcmp(func_name, "LLVMIR") == 0: return 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") cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args can: t.CSizeT = 0 if cargs is not None: can = cargs.__len__() # ============================================================ # stdarg 糖函数处理: va_arg / arg / va_start / va_end # 这些函数在 stdarg.vp 中声明为 pass 体,由编译器在翻译期处理: # va_arg(ap, type) → %N = va_arg , (LLVM 指令) # va_arg(ap) → 同上,类型从赋值上下文推断(默认 i32) # arg(type) → 同上,使用当前函数的隐式 va_list (trans._va_list_ptr) # va_start(ap, _) → call void @llvm.va_start(i8* %ap) (LLVM intrinsic) # va_end(ap) → call void @llvm.va_end(i8* %ap) (LLVM intrinsic) # ============================================================ if func_name is not None and trans is not None: if string.strcmp(func_name, "va_arg") == 0: return _translate_va_arg_sugar(pool, builder, mod, cl, cargs, can, funcs_ptr, func_count, trans) elif string.strcmp(func_name, "arg") == 0: return _translate_arg_sugar(pool, builder, mod, cl, cargs, can, funcs_ptr, func_count, trans) elif string.strcmp(func_name, "va_start") == 0: return _translate_va_start_sugar(pool, builder, mod, cargs, can, funcs_ptr, func_count, trans) elif string.strcmp(func_name, "va_end") == 0: return _translate_va_end_sugar(pool, builder, mod, cargs, can, funcs_ptr, func_count, trans) # 内置强转函数: str(x)/bytes(x) → i8*, int(x) → i32 # 等价于 (t.CChar | t.CPtr)(x) / (t.CInt32T)(x) # 单参数:str(val) → bitcast val to i8* # int(val) → trunc/sext val to i32 if func_name is not None and can == 1: if string.strcmp(func_name, "str") == 0 or string.strcmp(func_name, "bytes") == 0: # str(x) / bytes(x) → i8* (bitcast) cast_arg: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) if cast_arg is not None: i8_ptr_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) return _translate_t_type_cast(pool, builder, cast_arg, i8_ptr_ty_builtin) return None elif string.strcmp(func_name, "int") == 0: # int(x) → i32 cast_arg_int: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) if cast_arg_int is not None: i32_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) return _translate_t_type_cast(pool, builder, cast_arg_int, i32_ty_builtin) return None elif string.strcmp(func_name, "bool") == 0: # bool(x) → i1(严格 != 0 归一化) # 整数: icmp ne x, 0 → i1 # 浮点: fcmp one x, 0.0 → i1 # 指针: icmp ne x, null → i1 cast_arg_bool: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) if cast_arg_bool is not None: arg_bits: int = HandlesExpr.get_llvm_type_bits(cast_arg_bool.Ty) arg_fbits: int = HandlesExpr.get_llvm_float_bits(cast_arg_bool.Ty) # 整数: icmp ne x, 0 if arg_bits != 0: zero_int: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, arg_bits, 0) if zero_int is not None: return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, zero_int) return None # 浮点: fcmp one x, 0.0 if arg_fbits != 0: zero_ty: llvmlite.LLVMType | t.CPtr = cast_arg_bool.Ty zero_flt: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, zero_ty, 0.0) if zero_flt is not None: return llvmlite.build_fcmp(builder, llvmlite.FCMP_ONE, cast_arg_bool, zero_flt) return None # 指针: icmp ne x, null ptr_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cast_arg_bool.Ty, "null") if ptr_null is not None: return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, ptr_null) return None return None # 检测 t.XXX 类型转换: t.CUInt64T(ptr), t.CPtr(val), t.CInt(val) 等 # 当 func 是 t.XXX 形式且 XXX 是已知类型名时,当作类型转换处理(而非函数调用) # 支持: # 单参数: t.CInt(val) → 目标类型 = map_t_type(func_name) # 双参数: t.CInt(val, t.CPtr) → 目标类型 = Ptr(map_t_type(func_name)) # t 是内部库,一旦确认为类型转换,绝不跌落到跨模块调用 FATAL 路径 if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: tc_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) if tc_at.value is not None and tc_at.value.kind() == ast.ASTKind.Name: tc_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_at.value) if tc_mod_nm.id is not None and string.strcmp(tc_mod_nm.id, "t") == 0: target_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, func_name) if target_ty is not None: tc_effective_can: t.CSizeT = can # 双参数形式: t.CInt(val, t.CPtr) → Ptr(target_ty) # 注意: void* 在 LLVM 中非法,CVoid* 应表示为 i8* if can == 2: tc_arg2_node: ast.AST | t.CPtr = cargs.get(1) if tc_arg2_node is not None and tc_arg2_node.kind() == ast.ASTKind.Attribute: tc_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tc_arg2_node) if tc_arg2_at.attr is not None and string.strcmp(tc_arg2_at.attr, "CPtr") == 0: if tc_arg2_at.value is not None and tc_arg2_at.value.kind() == ast.ASTKind.Name: tc_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_at.value) if tc_arg2_nm.id is not None and string.strcmp(tc_arg2_nm.id, "t") == 0: # CVoid* → i8*(LLVM 中 void* 表示为 i8*) match target_ty: case llvmlite.LLVMType.Void(): target_ty = llvmlite.Int8(pool) case _: pass target_ty = llvmlite.Ptr(pool, target_ty) tc_effective_can = 1 if tc_effective_can == 1: tc_arg_node: ast.AST | t.CPtr = cargs.get(0) if tc_arg_node is not None: tc_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, tc_arg_node, None, 0, trans) if tc_arg_val is not None: return _translate_t_type_cast(pool, builder, tc_arg_val, target_ty) # t.XXX 类型转换已确认但不满足参数条件:返回 None,不跌落到跨模块 FATAL return None # 裸名 typedef 调用: BYTEPTR(ptr1), HANDLE(val), CHARPTR(str) 等 # 用户通过 `from stdint import *` 导入 typedef 后,可直接用裸名做类型转换 # map_t_type 包含所有内置 typedef 名称(BYTEPTR/HANDLE/LPCSTR/size_t 等) if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: bare_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, func_name) if bare_ty is not None and can == 1: bare_arg_node: ast.AST | t.CPtr = cargs.get(0) if bare_arg_node is not None: bare_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, bare_arg_node, None, 0, trans) if bare_arg_val is not None: return _translate_t_type_cast(pool, builder, bare_arg_val, bare_ty) # 检测 ClassName.__sizeof__() — 返回结构体大小常量(i64) # __sizeof__ 是内置方法,不走跨模块调用路径 # 支持: Argument.__sizeof__() 和 w32.win32file.WIN32_FIND_DATAA.__sizeof__() if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: sz_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) if sz_at.attr is not None and string.strcmp(sz_at.attr, "__sizeof__") == 0: if sz_at.value is not None and can == 0: sz_cls_name: str = None sz_vk: int = sz_at.value.kind() if sz_vk == ast.ASTKind.Name: sz_cls_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sz_at.value) sz_cls_name = sz_cls_nm2.id elif sz_vk == ast.ASTKind.Attribute: sz_inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sz_at.value) sz_cls_name = sz_inner_at.attr if sz_cls_name is not None: # 泛型类型参数 T 替换: T.__sizeof__() → int.__sizeof__() sz_cls_name = HandlesType.resolve_generic_type_name(sz_cls_name) # 去除模块前缀: Viper 解析器将 t.CInt 解析为 Name(id="t.CInt") # 而非 Attribute(value=Name("t"), attr="CInt"),需要手动提取最后的类名分量 # "t.CInt" → "CInt", "w32.win32file.WIN32_FIND_DATAA" → "WIN32_FIND_DATAA" dot_pos: str = string.strrchr(sz_cls_name, '.') if dot_pos is not None: sz_cls_name = dot_pos + 1 # 联合类型(如 AST|t.CPtr)按指针大小处理(8 字节) # 联合类型在 TPV 中表示指针,可以指向多种类型 # 对应 TPC 中对 BinOp/BitOr 联合类型的特殊处理 if string.strstr(sz_cls_name, "|") is not None: return llvmlite.const_int64(pool, 8) # 内置类型 sizeof(int=4, str/bytes=8 指针, double=8 等) sz_builtin: int = -1 if string.strcmp(sz_cls_name, "int") == 0: sz_builtin = 4 elif string.strcmp(sz_cls_name, "str") == 0: sz_builtin = 8 elif string.strcmp(sz_cls_name, "bytes") == 0: sz_builtin = 8 elif string.strcmp(sz_cls_name, "CInt") == 0: sz_builtin = 4 elif string.strcmp(sz_cls_name, "CInt8T") == 0: sz_builtin = 1 elif string.strcmp(sz_cls_name, "CInt16T") == 0: sz_builtin = 2 elif string.strcmp(sz_cls_name, "CInt32T") == 0: sz_builtin = 4 elif string.strcmp(sz_cls_name, "CInt64T") == 0: sz_builtin = 8 elif string.strcmp(sz_cls_name, "CChar") == 0: sz_builtin = 1 elif string.strcmp(sz_cls_name, "CDouble") == 0: sz_builtin = 8 elif string.strcmp(sz_cls_name, "CFloat") == 0: sz_builtin = 4 elif string.strcmp(sz_cls_name, "CPtr") == 0: sz_builtin = 8 elif string.strcmp(sz_cls_name, "CSizeT") == 0: sz_builtin = 8 elif string.strcmp(sz_cls_name, "CBool") == 0: sz_builtin = 1 elif string.strcmp(sz_cls_name, "bool") == 0: sz_builtin = 1 if sz_builtin >= 0: # 注意: 必须用 const_int64 而非 ConstInt(...,"0") # ConstInt 的 name 参数是 IR 文本表示,ValuePrint 输出时使用 Name 而非 IntVal # 硬编码 "0" 会导致 IR 输出 i64 0 而非实际值 return llvmlite.const_int64(pool, sz_builtin) sz_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type( sz_cls_name) if sz_struct_ty is not None: sz_val: int = HandlesClassDef._get_type_size(sz_struct_ty) if sz_val > 0: return llvmlite.const_int64(pool, sz_val) # 类型已注册但大小为 0(opaque struct 或字段链表未填充):报错终止 fb_sz1: t.CChar | t.CPtr = VLogger.fmt_buf() if fb_sz1 is not None: viperlib.snprintf(fb_sz1, 1024, "类型 '%s' 已注册但大小为 0(字段链表未填充),立即终止编译", sz_cls_name) VLogger.critical(fb_sz1, "__sizeof__") # 类型未注册:报错终止,不静默返回 0(会导致 malloc(0)/alloc(0) 堆溢出) fb_sz2: t.CChar | t.CPtr = VLogger.fmt_buf() if fb_sz2 is not None: viperlib.snprintf(fb_sz2, 1024, "类型 '%s' 未在结构体表中注册,无法计算大小,立即终止编译", sz_cls_name) VLogger.critical(fb_sz2, "__sizeof__") # 检测 obj.__len__() — 返回 list 对象的 __count__ 字段(偏移 8,i64) # __len__ 是 list[T] 的内置方法,list 是泛型类不注册 struct # 注意: 必须用 translate_value 而非 translate_name_value,因为 len_at.value # 可能是 Attribute 节点(如 md_ags.args),translate_name_value 只处理 Name 节点, # 对 Attribute 会错误返回 i32 0,导致 GEP base 不是指针(base of getelementptr must be a pointer) if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: len_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) if len_at.attr is not None and string.strcmp(len_at.attr, "__len__") == 0: if len_at.value is not None and can == 0: obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, len_at.value, funcs_ptr, func_count, trans) if obj_val is not None and obj_val.Ty is not None: # 防御性类型检查: obj_val 必须是指针类型才能做 GEP # 如果 translate_value 返回 i32 (如 CDefine 常量被误解析、 # 模块属性前向引用回退为 i32),GEP base 会是 i32 而非指针, # 导致 llc 报错 "base of getelementptr must be a pointer" if HandlesExpr.is_ptr_type(obj_val.Ty) == 0: return llvmlite.const_int64(pool, 0) i64_ty_len: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) # 注意: 必须用 const_int64 而非 ConstInt(...,"0") # ConstInt 的 name 参数 "0" 会被当作 IR 文本值输出 i64 0 # 导致 GEP 索引为 0(访问 __data__)而非 1(访问 __count__) idx_one: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) count_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( builder, i64_ty_len, obj_val, idx_one) if count_ptr is not None: return llvmlite.build_load(builder, i64_ty_len, count_ptr) # 检测 len() 内置函数调用 — 转换为 strlen 调用 # len(s) 对 str 类型调用 strlen,返回 i64 if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: if func_name is not None and string.strcmp(func_name, "len") == 0: if can == 1: len_arg_node: ast.AST | t.CPtr = cargs.get(0) if len_arg_node is not None: len_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, len_arg_node, None, 0, trans) if len_val is not None: # 确保 strlen 在模块中有声明 strlen_fn: llvmlite.Function | t.CPtr = find_func_in_module(mod, "strlen") if strlen_fn is None: i64_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) i8_ptr_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) strlen_fn = llvmlite.create_declare(pool, mod, "strlen", i64_ty_ln) if strlen_fn is not None: llvmlite.add_param(pool, strlen_fn, i8_ptr_ty_ln, "s") # 参数类型转换为 i8* i8_ptr_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) len_arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(len_val) len_coerced: llvmlite.Value | t.CPtr = len_val if HandlesExpr.is_ptr_type(len_arg_ty) != 0: len_coerced = llvmlite.build_bitcast(builder, len_val, i8_ptr_ty_ln2) # 构建单参数链表并调用 strlen len_coerced.Next = None i64_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) return llvmlite.build_call(builder, "strlen", len_coerced, 1, i64_ty_ln2, 0) # 检测类名静态/类方法调用: ClassName.method(args) # 当 cl.func 是 Attribute、value 是已注册结构体类名(非普通变量)时, # 且方法带 @staticmethod/@classmethod 元数据,走静态调用路径 if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: st_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) if st_at is not None and st_at.value is not None and trans is not None: if st_at.value.kind() == ast.ASTKind.Name: st_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(st_at.value) if st_nm.id is not None: # 仅当该名称不是普通变量且是已注册结构体类名时尝试静态/类方法 st_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( trans.SymTab, st_nm.id) if st_var is None and HandlesStruct.get_struct_type(st_nm.id) is not None: st_res: llvmlite.Value | t.CPtr = _translate_static_class_call( pool, builder, mod, st_nm.id, func_name, cl, trans) if st_res is not None: return st_res # 检测方法调用: obj.method(args) # 当 cl.func 是 Attribute 且 obj 是已注册的结构体变量时,翻译为方法调用 if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) if method_at is not None and method_at.value is not None: if method_at.value.kind() == ast.ASTKind.Name and trans is not None: method_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(method_at.value) if method_obj_nm.id is not None: # 查找对象变量 obj_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( trans.SymTab, method_obj_nm.id) if obj_var is not None and obj_var.Ty is not None: # 检查是否为 Ptr(Struct(...))(结构体值变量) # 或 Ptr(Ptr(Struct(...)))(指针变量,需 load) match obj_var.Ty: case llvmlite.LLVMType.Ptr(obj_struct_ty): class_nm: str = HandlesStruct.get_class_name_by_type( pool, obj_struct_ty) if class_nm is not None: return _translate_method_call( pool, builder, mod, class_nm, func_name, obj_var, cl, trans) # 指针变量: alloca 类型是 Ptr(Ptr(Struct)) # load 获取实际指针 Ptr(Struct) 后再查找 match obj_struct_ty: case llvmlite.LLVMType.Ptr(inner_struct_ty): inner_nm: str = HandlesStruct.get_class_name_by_type( pool, inner_struct_ty) if inner_nm is not None: obj_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load( builder, obj_struct_ty, obj_var) if obj_ptr is not None: return _translate_method_call( pool, builder, mod, inner_nm, func_name, obj_ptr, cl, trans) # AnnotClassName 回退:联合类型简化为 Ptr(i8) 时, # 通过原始类型注解的类名查找结构体 var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( trans.SymTab, method_obj_nm.id) if var_entry is not None and var_entry.AnnotClassName is not None: annot_val: str = var_entry.AnnotClassName # 解析模块限定名 "memhub.MemBuddy" → mod_nm="memhub", cls_nm="MemBuddy" dot_ptr: t.CChar | t.CPtr = string.strrchr(annot_val, '.') cls_nm2: str = annot_val mod_nm2: str = None if dot_ptr is not None: cls_nm2 = dot_ptr + 1 total_len_av: t.CSizeT = string.strlen(annot_val) cls_len_av: t.CSizeT = string.strlen(cls_nm2) mod_len2: t.CSizeT = total_len_av - cls_len_av - 1 mod_nm2 = pool.alloc(mod_len2 + 1) if mod_nm2 is not None: string.strncpy(mod_nm2, annot_val, mod_len2) mod_nm2[mod_len2] = '\0' # 检查结构体是否已注册 if HandlesStruct.get_struct_type(cls_nm2) is not None: # 结构体已注册:load obj_ptr 走方法调用 i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( pool, llvmlite.Int8(pool)) obj_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load( builder, i8_ptr_ty2, obj_var) if obj_ptr2 is not None: return _translate_method_call( pool, builder, mod, cls_nm2, func_name, obj_ptr2, cl, trans) else: # 结构体未注册(跨模块依赖未翻译): # 用模块名查 SHA1 构造方法调用名 sha1_fc: str = None if mod_nm2 is not None: sha1_fc = _lookup_module_sha1(mod_nm2) if sha1_fc is not None: # 构造 "{sha1}.{cls_nm2}.{func_name}" 调用名 mlen3: t.CSizeT = string.strlen(sha1_fc) + string.strlen(cls_nm2) + string.strlen(func_name) + 3 mangled3: str = pool.alloc(mlen3) if mangled3 is not None: viperlib.snprintf(mangled3, mlen3, "%s.%s.%s", sha1_fc, cls_nm2, func_name) # load obj_ptr (self) i8_ptr_ty3: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( pool, llvmlite.Int8(pool)) obj_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_load( builder, i8_ptr_ty3, obj_var) if obj_ptr3 is not None: # 构建参数链表: obj_ptr3 (self) → 其他参数 llvmlite.value_set_next(obj_ptr3, None) head3: llvmlite.Value | t.CPtr = obj_ptr3 tail3: llvmlite.Value | t.CPtr = obj_ptr3 for ai3 in range(can): arg3: ast.AST | t.CPtr = cargs.get(ai3) if arg3 is not None: arg_val3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, arg3, None, 0, trans) if arg_val3 is not None: llvmlite.value_set_next(arg_val3, None) llvmlite.value_set_next(tail3, arg_val3) tail3 = arg_val3 total3: int = 1 + can ret_ty3: llvmlite.LLVMType | t.CPtr = _LookupMethodRetTyFromTextLL( pool, sha1_fc, cls_nm2, func_name) if ret_ty3 is None: ret_ty3 = _infer_method_ret_ty(pool, func_name) _ensure_method_declare(pool, mod, mangled3, ret_ty3, head3, total3) return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0) # ============================================================ # 检测 self.field.method() 调用 # # 当 method_at.value 是 Attribute(字段访问,如 self.__pool__)时, # 翻译字段值获取对象指针,然后走方法调用路径。 # # 路径1: 从字段值的 LLVM 类型获取类名(字段类型为 Ptr(Struct("MemManager"))) # 路径2: 从字段的 AnnotClassName 回退查找(字段类型被简化为 Ptr(i8) 时) # ============================================================ if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: attr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) if attr_method_at is not None and attr_method_at.value is not None: if attr_method_at.value.kind() == ast.ASTKind.Attribute and trans is not None: inner_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(attr_method_at.value) if inner_attr is not None and inner_attr.attr is not None: # 翻译 self.__pool__ 获取字段值(已 load 的对象指针) field_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, attr_method_at.value, funcs_ptr, func_count, trans) if field_obj is not None and field_obj.Ty is not None: field_cls_nm: str = None # 路径1: 从字段值的 LLVM 类型获取类名 match field_obj.Ty: case llvmlite.LLVMType.Ptr(field_struct_ty): field_cls_nm = HandlesStruct.get_class_name_by_type( pool, field_struct_ty) # 路径2: 从字段注解类名回退查找 if field_cls_nm is None: if inner_attr.value is not None and inner_attr.value.kind() == ast.ASTKind.Name: inner_name_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_attr.value) if inner_name_node is not None and inner_name_node.id is not None: inner_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( trans.SymTab, inner_name_node.id) if inner_var is not None and inner_var.Ty is not None: match inner_var.Ty: case llvmlite.LLVMType.Ptr(field_owner_struct_ty): field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( field_owner_struct_ty, inner_attr.attr) if field_info is not None: field_annot: str = HandlesStruct.get_field_annot_class_name(field_info) if field_annot is not None: dot_p: t.CChar | t.CPtr = string.strrchr(field_annot, 46) if dot_p is not None: field_cls_nm = dot_p + 1 else: field_cls_nm = field_annot if field_cls_nm is not None: return _translate_method_call( pool, builder, mod, field_cls_nm, func_name, field_obj, cl, trans) # ============================================================ # 检测 list 内置方法调用: lst.get(i), lst.set(i,v), lst.pop(), lst.clear(), lst.__iter__() # list[T] 是泛型类不注册 struct,方法调用处理器(上方)无法处理, # 需要在此特殊处理。 # list 结构布局 (6 字段 × 8 字节): # __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) # ============================================================ if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: lm_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) if lm_at is not None and lm_at.attr is not None and lm_at.value is not None: lm_name: str = lm_at.attr # 判断是否是 list 方法名 lm_is_list: int = 0 if string.strcmp(lm_name, "get") == 0: lm_is_list = 1 elif string.strcmp(lm_name, "__getitem__") == 0: lm_is_list = 1 elif string.strcmp(lm_name, "set") == 0: lm_is_list = 1 elif string.strcmp(lm_name, "__setitem__") == 0: lm_is_list = 1 elif string.strcmp(lm_name, "pop") == 0: lm_is_list = 1 elif string.strcmp(lm_name, "clear") == 0: lm_is_list = 1 elif string.strcmp(lm_name, "__iter__") == 0: lm_is_list = 1 elif string.strcmp(lm_name, "append") == 0: lm_is_list = 1 if lm_is_list == 1 and trans is not None: # 翻译 list 对象 lm_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, lm_at.value, funcs_ptr, func_count, trans) if lm_obj is not None: # 防御性类型检查: lm_obj 必须是指针类型才能做 GEP # translate_value 对某些 Attribute 节点(如 ast.Arguments 的属性) # 可能返回 i32 0 (非指针),直接 GEP 会导致 # "base of getelementptr must be a pointer" 错误 if lm_obj.Ty is None or HandlesExpr.is_ptr_type(lm_obj.Ty) == 0: lm_node_kind: int = lm_at.value.kind() fb_lm: t.CChar | t.CPtr = VLogger.fmt_buf() if fb_lm is not None: viperlib.snprintf(fb_lm, 1024, "list 方法 '%s' 的目标对象非指针 (node kind=%d)," "translate_value 类型推断失败", lm_name, lm_node_kind) VLogger.critical(fb_lm, "LIST-METHOD") return None i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) # get / __getitem__: 返回 index 处的元素 if string.strcmp(lm_name, "get") == 0 or string.strcmp(lm_name, "__getitem__") == 0: if can >= 1: # 加载 __data__ (偏移 0) g_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0) g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp) # 加载 __elem_size__ (偏移 32, index 4) g_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4) g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp) # 翻译 index g_idx_node: ast.AST | t.CPtr = cargs.get(0) g_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, g_idx_node, None, 0, trans) if g_data is not None and g_esize is not None and g_idx_val is not None: g_idx_i64: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( builder, g_idx_val, i64_ty, g_idx_node) g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize) g_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, g_data, g_offset) if g_addr is not None: return llvmlite.build_load(builder, i8_ptr_ty, g_addr) # set / __setitem__: 设置 index 处的元素 elif string.strcmp(lm_name, "set") == 0 or string.strcmp(lm_name, "__setitem__") == 0: if can >= 2: s_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0) s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp) s_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4) s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp) s_idx_node: ast.AST | t.CPtr = cargs.get(0) s_val_node: ast.AST | t.CPtr = cargs.get(1) s_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, s_idx_node, None, 0, trans) s_val_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, s_val_node, None, 0, trans) if s_data is not None and s_esize is not None and s_idx_val is not None and s_val_val is not None: s_idx_i64: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( builder, s_idx_val, i64_ty, s_idx_node) s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize) s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset) if s_addr is not None: s_val_ptr: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( builder, s_val_val, i8_ptr_ty, s_val_node) llvmlite.build_store(builder, s_val_ptr, s_addr) return None # pop: 返回最后一个元素,count-- elif string.strcmp(lm_name, "pop") == 0: p_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) p_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx1) p_count: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_cpp) p_nc: llvmlite.Value | t.CPtr = llvmlite.build_sub( builder, p_count, llvmlite.const_int64(pool, 1)) llvmlite.build_store(builder, p_nc, p_cpp) p_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) p_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx0) p_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, p_dpp) p_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) p_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx4) p_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_epp) if p_data is not None and p_esize is not None and p_nc is not None: p_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, p_nc, p_esize) p_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, p_data, p_offset) if p_addr is not None: return llvmlite.build_load(builder, i8_ptr_ty, p_addr) # clear: count = 0 elif string.strcmp(lm_name, "clear") == 0: c_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) c_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, c_idx1) llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), c_cpp) return None # __iter__: iter_index = 0, return self elif string.strcmp(lm_name, "__iter__") == 0: it_idx5: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 5) it_ipp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, it_idx5) llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), it_ipp) return lm_obj # append: 直接调用 list.append(self, item) # append 需要容量检查和内存重分配,逻辑复杂,直接调用 _list.py 中的实现 elif string.strcmp(lm_name, "append") == 0: if can >= 1: ap_sha1: str = _lookup_module_sha1("_list") if ap_sha1 is not None: ap_mlen: t.CSizeT = string.strlen(ap_sha1) + 13 ap_mangled: str = pool.alloc(ap_mlen) if ap_mangled is not None: viperlib.snprintf(ap_mangled, ap_mlen, "%s.list.append", ap_sha1) ap_item_node: ast.AST | t.CPtr = cargs.get(0) ap_item_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, ap_item_node, None, 0, trans) if ap_item_val is not None: llvmlite.value_set_next(lm_obj, None) llvmlite.value_set_next(ap_item_val, None) llvmlite.value_set_next(lm_obj, ap_item_val) ap_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) _ensure_method_declare(pool, mod, ap_mangled, ap_ret_ty, lm_obj, 2) return llvmlite.build_call(builder, ap_mangled, lm_obj, 2, ap_ret_ty, 0) # 获取关键字参数 keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords kw_count: t.CSizeT = 0 if keywords is not None: kw_count = keywords.__len__() # 检查是否是结构体构造函数: Point() / Point(10, 20) / Point(x=10, y=20) # 命名空间隔离:严格模式下检查结构体可见性 # - 裸名 Class(): 需要 from X import Class 或本地定义 # - 模块限定 Module.Class(): 需要 import Module # 用 find_struct_by_module 规避跨模块同名 find_struct 找错 struct_ty: llvmlite.LLVMType | t.CPtr = None gen_ctor_entry: HandlesStruct.StructEntry | t.CPtr = None vis: int = HandlesStruct.is_struct_visible(func_name) if vis != 0: if trans is not None: gen_ctor_entry = HandlesStruct.find_struct_by_module(func_name, trans.ModuleSha1) if gen_ctor_entry is None: gen_ctor_entry = HandlesStruct.find_struct(func_name) if gen_ctor_entry is not None: struct_ty = gen_ctor_entry.Ty elif trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: at_qc: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) if at_qc.value is not None and at_qc.value.kind() == ast.ASTKind.Name: mod_nm_qc: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_qc.value) imp_ok: int = HandlesImports.is_module_imported(trans._imported_modules, mod_nm_qc.id) if imp_ok != 0: if trans is not None: gen_ctor_entry = HandlesStruct.find_struct_by_module(func_name, trans.ModuleSha1) if gen_ctor_entry is None: gen_ctor_entry = HandlesStruct.find_struct(func_name) if gen_ctor_entry is not None: struct_ty = gen_ctor_entry.Ty # 别名导入的类构造: from X import Class as Alias → Alias(args) # 可见性列表按别名注册(HandleImportFromNames 用 local_name=asname),但结构体 # 按原名注册(如 Keyword as KwNode → 可见 "KwNode"、注册名 "Keyword")。 # 直接按别名 find_struct 查不到 → 误走普通函数路径生成 @sha1.Keyword 调用 # (该函数不存在)→ 链接期 undefined reference。此处解析别名→原名再查结构体。 if gen_ctor_entry is None and trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name: if trans._from_imports is not None: ctor_sha1: str = _lookup_mod_sha1(pool, trans._from_imports, func_name, 0) if ctor_sha1 is not None: ctor_orig: str = HandlesImports.lookup_from_import_original( trans._from_imports, func_name) if ctor_orig is not None: # 复制到独立 null 终止缓冲区(from_imports 内部缓冲未终止) co_len: t.CSizeT = 0 while ctor_orig[co_len] != ' ' and ctor_orig[co_len] != '\0': co_len += 1 co_buf: str = pool.alloc(co_len + 1) if co_buf is not None: for co_i in range(co_len): co_buf[co_i] = ctor_orig[co_i] co_buf[co_len] = '\0' # 原名结构体查找(可见性已由别名保证,原名无需再查) gen_ctor_entry = HandlesStruct.find_struct_by_module(co_buf, ctor_sha1) if gen_ctor_entry is None: gen_ctor_entry = HandlesStruct.find_struct(co_buf) if gen_ctor_entry is not None: struct_ty = gen_ctor_entry.Ty func_name = co_buf if struct_ty is not None: if can == 0 and kw_count == 0: # OOP 结构体:即使无参数也调用 __before_init__ # 用 gen_ctor_entry 规避跨模块同名 find_struct 找错 ctor_is_oop: int = 0 if gen_ctor_entry is not None: ctor_is_oop = gen_ctor_entry.IsOOP if ctor_is_oop != 0: return _translate_struct_ctor( pool, builder, mod, struct_ty, func_name, cargs, 0, trans) # 普通结构体:检查是否有默认值(用 entry 直接访问) gen_has_defaults: int = 0 if gen_ctor_entry is not None: for gdi in range(gen_ctor_entry.FieldCount): gdf: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( gen_ctor_entry, gdi) if gdf is not None and gdf.DefaultVal is not None: gen_has_defaults = 1 break else: gen_has_defaults = HandlesStruct.struct_has_defaults(func_name) if gen_has_defaults == 1: # 有默认值:走构造函数路径应用默认值 return _translate_struct_ctor( pool, builder, mod, struct_ty, func_name, cargs, 0, trans) # 无默认值:返回 zeroinitializer ret: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) return ret if kw_count > 0: # 有关键字参数:按字段名赋值 return _translate_struct_ctor_kw( pool, builder, mod, struct_ty, func_name, cargs, can, keywords, kw_count, trans) # 仅位置参数:按字段顺序构建 return _translate_struct_ctor( pool, builder, mod, struct_ty, func_name, cargs, can, trans) # REnum 变体构造检测: ClassName.VariantName(args...) # 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体 # 必须在跨模块调用查找之前,否则 ClassName 会被误判为模块名 # 对应 TPC HandlesExprCall.py:585-644 的三条检测路径之一 if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: rc_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) if rc_at.value is not None and rc_at.value.kind() == ast.ASTKind.Name: rc_cls_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rc_at.value) if rc_cls_node.id is not None: rc_cls_name: str = rc_cls_node.id # 检查 ClassName 是否是已注册的 REnum 类 if HandlesClassDef._is_renum_class_name(rc_cls_name) != 0: # 在该 REnum 类中查找变体名 func_name rc_tag: int = HandlesClassDef._lookup_renum_variant_in_class( rc_cls_name, func_name) if rc_tag >= 0: return _translate_renum_construct( pool, builder, mod, rc_cls_name, func_name, rc_tag, cargs, can, trans) # 查找函数:优先从函数表按裸名精确匹配(同模块函数), # 再从模块函数链表按后缀匹配(SHA1 前缀名)。 # 注意:模块限定/属性调用(如 stdlib.free)不能做后缀匹配—— # "free" 会误命中 viperio.Buf.free 等方法,导致普通 malloc 指针被 # 当作 Buf 对象释放(Buf.free 读 self 字段/写 self.data), # 传入句柄数组等指针时把句柄值当地址写入直接崩溃。 # 后缀匹配仅用于裸名调用(cl.func 是 Name,如 _thread_alloc_free)。 # stubs 在翻译后才注入,翻译时跨模块函数 found_func 通常为 None, # 此时根据函数名推断 includes 库函数的返回类型(如 strchr 返回 i8*) # 如果调用方未传 funcs_ptr/func_count(如 AnnAssign 路径),从 trans 获取 actual_funcs: HandlesExprCall.FuncEntry | t.CPtr = funcs_ptr actual_func_count: int = func_count if actual_funcs is None and trans is not None: actual_funcs = trans._funcs actual_func_count = trans._func_count found_func: llvmlite.Function | t.CPtr = None if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: # 裸名调用:允许精确 + 后缀匹配 found_func = find_func_in_module(mod, func_name) else: # 模块限定/属性调用:精确匹配优先,后缀匹配仅接受模块函数。 # 后缀匹配命中的"方法"(SHA1.Class.method,Class 是已注册类)必须拒绝—— # 短方法名(free/reset/close 等)会误命中其他模块的方法 # (如 stdlib.free 命中 viperio.Buf.free,普通指针被当 Buf 释放崩溃; # 且 atom.__atomic_test_and_set 若被误拒,返回类型从 i1 推断成 i32, # 调用按 i32 读 i1 返回值读到垃圾高位,spinlock 恒非 0 卡死)。 # 模块函数(SHA1.func)或子模块函数(SHA1.submod.func)的后缀匹配保留。 found_func = find_func_in_module(mod, func_name) if found_func is not None: ff_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) if ff_name is not None: ff_dots: int = 0 ffi2: t.CSizeT = 0 while ff_name[ffi2] != '\0': if ff_name[ffi2] == '.': ff_dots += 1 ffi2 += 1 if ff_dots >= 2: # 提取第 2 段(SHA1.Class.method → Class;SHA1.submod.func → submod) seg2: t.CChar | t.CPtr = pool.alloc(64) if seg2 is not None: seg2[0] = '\0' si: t.CSizeT = 0 while ff_name[si] != '\0' and si < 17: si += 1 seg_start: t.CSizeT = si seg_end: t.CSizeT = si while ff_name[seg_end] != '\0' and ff_name[seg_end] != '.': seg_end += 1 seg_len: t.CSizeT = seg_end - seg_start if seg_len > 0 and seg_len < 63: string.strncpy(seg2, ff_name + seg_start, seg_len) seg2[seg_len] = '\0' # 第 2 段是已注册结构体类 → 是方法,拒绝(走模块 SHA1 路径) if HandlesStruct.get_struct_type(seg2) is not None: found_func = None # C 库函数裸名调用支持:若模块中找不到且是已知 C 库函数,自动创建 declare # 对应 TPC 的 _C_LIB_FUNCS 机制,支持 memset/memmove/memcmp/strcmp 等裸名调用 if found_func is None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name: found_func = _ensure_c_lib_declare(pool, mod, func_name) # 使用访问器绕过 stub 类型限制 found_ret_ty: llvmlite.LLVMType | t.CPtr = None found_params: t.CPtr = None if found_func is not None: found_ret_ty = llvmlite.function_get_ret_ty(found_func) found_params = llvmlite.function_get_params(found_func) if found_ret_ty is not None: call_ret_ty: llvmlite.LLVMType | t.CPtr = found_ret_ty else: call_ret_ty = _infer_external_func_ret_ty(pool, func_name) # 如果模块中找不到函数,检查是否是变量(闭包调用) if found_func is None: closure_ptr: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, func_name) if closure_ptr is not None: return translate_closure_call(pool, builder, mod, closure_ptr, cargs, can) # 翻译参数并链接 # 有关键字参数且找到函数定义时,按参数名匹配 if kw_count > 0 and found_func is not None and found_params is not None: return _translate_call_with_kwargs( pool, builder, mod, func_name, found_func, cargs, can, keywords, kw_count, trans) head: llvmlite.Value | t.CPtr = None tail: llvmlite.Value | t.CPtr = None # memcpy 专用: 收集前三个 Value 的独立引用(避免共享 alloca 对象的 Next 被污染) mc_dst2: llvmlite.Value | t.CPtr = None mc_src2: llvmlite.Value | t.CPtr = None mc_num2: llvmlite.Value | t.CPtr = None 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: # 参数类型提升:当 found_func 为 None(stub 未注入)时, # 根据外部函数签名推断期望类型,提升字面量(如 i32→i64) # 避免 declare(i64) 与 call(i32) 类型不匹配 if found_func is None and arg_val.Ty is not None: ext_param_ty: llvmlite.LLVMType | t.CPtr = _get_external_func_param_ty( pool, func_name, ai) if ext_param_ty is not None: val_bits_ap: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty) tgt_bits_ap: int = HandlesExpr.get_llvm_type_bits(ext_param_ty) if val_bits_ap != 0 and tgt_bits_ap != 0 and val_bits_ap != tgt_bits_ap: if val_bits_ap == 1 and val_bits_ap < tgt_bits_ap: arg_val = llvmlite.build_zext(builder, arg_val, ext_param_ty) else: arg_val = HandlesExpr.coerce_to_type(builder, arg_val, ext_param_ty, arg) elif found_func is not None: # found_func 存在:按形参类型 coerce(如 stdlib.malloc(size: t.CSizeT)) # 修复: CDefine/i32 常量传给 i64 形参未提升,导致 call(i32) 与 define(i64) 不匹配 fp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) fpi: int = 0 while fp is not None and fpi < ai: fp = llvmlite.param_get_next(fp) fpi += 1 if fp is not None: fpty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(fp) if fpty is not None: arg_val = HandlesExpr.coerce_to_type( builder, arg_val, fpty, arg) arg_val.Next = None if head is None: head = arg_val else: tail.Next = arg_val tail = arg_val # memcpy 专用: 保存前三个参数的独立引用 if ai == 0: mc_dst2 = arg_val elif ai == 1: mc_src2 = arg_val elif ai == 2: mc_num2 = arg_val # 默认参数填充:当实参数量 < 形参数量时,用默认值填充缺失参数 # defaults 数组右对齐到 args:defaults[0] 对应 args[offset],offset = param_count - default_count if can > 0 or (can == 0 and cargs is not None): df_defaults: t.CVoid | t.CPtr = None df_default_count: int = 0 df_param_count: int = 0 # 先从当前模块函数表查找 FuncEntry if trans is not None and trans._funcs is not None: df_entry: FuncEntry | t.CPtr = find_func_entry_in_table( trans._funcs, trans._func_count, func_name) if df_entry is not None: df_defaults = df_entry.Defaults df_default_count = df_entry.DefaultCount df_param_count = df_entry.ParamCount # 如果当前模块没有,从全局默认参数表查找(跨模块) if df_defaults is None: gd_entry: FuncDefaultsEntry | t.CPtr = find_func_defaults(func_name) if gd_entry is not None: df_defaults = gd_entry.Defaults df_default_count = gd_entry.DefaultCount df_param_count = gd_entry.ParamCount # 填充缺失参数 if df_defaults is not None and df_default_count > 0 and can < df_param_count: df_offset: int = df_param_count - df_default_count df_di: int = 0 while df_di < df_default_count: df_param_idx: int = df_offset + df_di if df_param_idx >= can: # 优先用 stdlib 常量快照重建(gd_entry.Defaults 的 pool 内 AST 可能已被 reset 回收) df_arg_val: llvmlite.Value | t.CPtr = None if gd_entry is not None: df_arg_val = _build_const_from_snapshot( pool, mod, gd_entry, df_di, trans, builder) if df_arg_val is None: df_defaults_list: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(df_defaults), t.CPtr)) df_default_node: ast.AST | t.CPtr = df_defaults_list.get(df_di) if df_default_node is not None: df_arg_val = HandlesExpr.translate_value( builder, pool, mod, df_default_node, None, 0, trans) if df_arg_val is not None: df_arg_val.Next = None if head is None: head = df_arg_val else: tail.Next = df_arg_val tail = df_arg_val df_di += 1 # 使用模块中的实际函数名(可能带 SHA1 前缀,如 "83210a72e829a086.atoi") # t.CExtern/t.State/t.CExport 函数不加 SHA1 前缀,使用裸名 # declare 和 define 统一用 found_func.Name: # - 普通函数的 declare/define 都带 SHA1 前缀(forward_declare_functions 和 stub 注入都用 mangled_name) # - t.CExtern/t.State/t.CExport 函数的 declare/define 都用裸名 # 旧逻辑(IsDeclared==1 时用 func_name 裸名)是错误的:stub 注入的 declare Name 已带 SHA1 前缀, # 用裸名会导致 call @_PathToModuleName 而 define 是 @"sha1._PathToModuleName",链接报 undefined reference call_name: str = func_name # 原始函数名(别名导入时记录,如 from X import parse as json_parse → orig_func_name="parse") # 用于在别名处理后重新推断返回类型,避免 _infer_external_func_ret_ty 用别名匹配失败 orig_func_name: str = None if found_func is not None: found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) if found_name is not None: call_name = found_name else: # 跨模块函数调用:found_func 为 None 时,检查是否是模块限定调用 # 如 string.strchr(...) → @{sha1_of_string}.strchr if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: xmod_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) if xmod_at.value is not None and xmod_at.value.kind() == ast.ASTKind.Name: xmod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(xmod_at.value) if xmod_nm.id is not None: mod_sha1: str = _lookup_module_sha1(xmod_nm.id) if mod_sha1 is not None: # fast-fail: 模块限定调用要求模块已被当前文件 import。 # 全局 SHA1 存储包含所有被扫描的 includes,未导入的模块 # (如 this.this() 但 import this 被注释)也会命中存储, # 静默生成 @{sha1}.func 调用而非报错——违反"找不到 fast-fail"原则。 is_xmod_imported: int = 1 if trans is not None and trans._imported_modules is not None: is_xmod_imported = HandlesImports.is_module_imported( trans._imported_modules, xmod_nm.id) if is_xmod_imported == 0: err_ni: t.CChar | t.CPtr = pool.alloc(256) if err_ni is not None: viperlib.snprintf(err_ni, 256, "跨模块调用 '%s.%s':模块 '%s' 未导入(请先 import %s)", xmod_nm.id, func_name, xmod_nm.id, xmod_nm.id) HandlesType.fatal_error(xmod_nm, err_ni) HandlesType.fatal_error(xmod_nm, "跨模块调用:模块未导入") # 检查是否是 re-export 函数(如 ast._lexer_init 实际定义在 ast.lexer) reexport_src: str = HandlesImports.lookup_reexport(mod_sha1, func_name) if reexport_src is not None: reexport_sha1: str = _lookup_module_sha1(reexport_src) if reexport_sha1 is not None: mod_sha1 = reexport_sha1 # CExport 函数定义用裸名(@strlen),跨模块调用需用裸名而非 @{sha1}.func if is_cexport_func(mod_sha1, func_name) != 0: call_name = func_name else: mangled_len: t.CSizeT = string.strlen(mod_sha1) + string.strlen(func_name) + 2 mangled: str = pool.alloc(mangled_len) if mangled is not None: viperlib.snprintf(mangled, mangled_len, "%s.%s", mod_sha1, func_name) call_name = mangled else: # t 和 c 是内部库,豁免 SHA1 查找:使用裸名调用 if string.strcmp(xmod_nm.id, "t") == 0 or string.strcmp(xmod_nm.id, "c") == 0: call_name = func_name else: # Bug 修复: 先检查是否是已导入的模块名(如 BuildPipeline.run_pipeline) # 如果是已导入模块但 SHA1 未注册,说明该模块未被编译(如 Phase2 未扫描到), # 应该立即报错,而不是错误地走 from_imports 查找(会被 star import 回退误导) is_imported_mod: int = 0 if trans is not None and trans._imported_modules is not None: is_imported_mod = HandlesImports.is_module_imported( trans._imported_modules, xmod_nm.id) if is_imported_mod != 0: # 别名导入(import X as Y):Y 在 _imported_modules 中, # 但 _lookup_module_sha1("Y") 精确匹配失败(mod_arr 只存文件名)。 # 先尝试 from_imports 查找别名→完整模块名→后缀匹配 SHA1。 # allow_star_fallback=0 避免被 star import 回退误导。 alias_sha1: str = None if trans is not None and trans._from_imports is not None: alias_sha1 = _lookup_mod_sha1(pool, trans._from_imports, xmod_nm.id, 0) if alias_sha1 is not None: if is_cexport_func(alias_sha1, func_name) != 0: call_name = func_name else: AliasMangledLen: t.CSizeT = string.strlen(alias_sha1) + string.strlen(func_name) + 2 alias_mangled: str = pool.alloc(AliasMangledLen) if alias_mangled is not None: viperlib.snprintf(alias_mangled, AliasMangledLen, "%s.%s", alias_sha1, func_name) call_name = alias_mangled else: # 已导入模块但 SHA1 未注册:该模块未被编译,立即报错 err_msg_imp: t.CChar | t.CPtr = pool.alloc(256) if err_msg_imp is not None: viperlib.snprintf(err_msg_imp, 256, "模块 '%s' 已导入但 SHA1 未注册(该模块未被编译)", xmod_nm.id) HandlesType.fatal_error(xmod_nm, err_msg_imp) HandlesType.fatal_error(xmod_nm, "已导入模块 SHA1 未注册") else: # 检查是否是通过 from import 导入的名称(如 from .__types import LLVMType) # LLVMType.Ptr(ty) 中 LLVMType 是类名不是模块名, # 但 Ptr 是 __types 模块的模块级函数 # 禁用 star import 回退:xmod_nm.id 是明确名称,不应回退到 star import 模块 from_sha1: str = None if trans is not None and trans._from_imports is not None: from_sha1 = _lookup_mod_sha1(pool, trans._from_imports, xmod_nm.id, 0) if from_sha1 is not None: # CExport 函数定义用裸名,跨模块调用需用裸名 if is_cexport_func(from_sha1, func_name) != 0: call_name = func_name else: fmangled_len: t.CSizeT = string.strlen(from_sha1) + string.strlen(func_name) + 2 fmangled: str = pool.alloc(fmangled_len) if fmangled is not None: viperlib.snprintf(fmangled, fmangled_len, "%s.%s", from_sha1, func_name) call_name = fmangled else: err_msg2: t.CChar | t.CPtr = pool.alloc(256) if err_msg2 is not None: viperlib.snprintf(err_msg2, 256, "跨模块调用 '%s.%s' 找不到模块 SHA1", xmod_nm.id, func_name) HandlesType.fatal_error(xmod_nm, err_msg2) HandlesType.fatal_error(xmod_nm, "跨模块调用找不到模块 SHA1") else: # 裸名调用(非 Attribute):检查 from_imports # 治本修复:函数调用禁用 star import 回退(allow_star_fallback=0)。 # star import(from stdint import *)本意是导入类型/常量(如 BYTEPTR),而非函数; # 函数应显式 from import。漏导函数若走 star 回退会被错归到 star 模块,生成错误 SHA1 符号 # (如 block_insert_text_before_terminator 漏导后被错归 stdint,生成 # f5522571bcce7bcb.block_insert... 而非 874bac141c97bae9.block_insert...)。 # 禁用回退后,漏导函数编译期即报"未定义且未导入"(fast-fail),优于链接期 undefined reference。 if trans is not None and trans._from_imports is not None: bare_sha1: str = _lookup_mod_sha1(pool, trans._from_imports, func_name, 0) if bare_sha1 is not None: # 别名处理: from X import Y as Z → 调用 Z 时需用 Y 作为源模块函数名 # 例如 from json.__parser import parse as json_parse → 修饰为 SHA1.parse 而非 SHA1.json_parse bare_orig: str = HandlesImports.lookup_from_import_original( trans._from_imports, func_name) bare_func_name: str = func_name if bare_orig is not None: # bare_orig 指向 from_imports 内部缓冲区,未 null 终止 # 需复制到独立缓冲区(截断于空格或 null) bo_len: t.CSizeT = 0 while bare_orig[bo_len] != ' ' and bare_orig[bo_len] != '\0': bo_len += 1 bo_buf: str = pool.alloc(bo_len + 1) if bo_buf is not None: for bo_i in range(bo_len): bo_buf[bo_i] = bare_orig[bo_i] bo_buf[bo_len] = '\0' bare_func_name = bo_buf # 记录原始函数名,供后续重新推断返回类型 # 例如 from json.__parser import parse as json_parse # func_name="json_parse", bare_func_name="parse" # _infer_external_func_ret_ty 用 "parse" 能正确匹配,用 "json_parse" 则返回默认 i32 orig_func_name = bare_func_name if is_cexport_func(bare_sha1, bare_func_name) != 0: call_name = bare_func_name else: bare_mangled_len: t.CSizeT = string.strlen(bare_sha1) + string.strlen(bare_func_name) + 2 bare_mangled: str = pool.alloc(bare_mangled_len) if bare_mangled is not None: viperlib.snprintf(bare_mangled, bare_mangled_len, "%s.%s", bare_sha1, bare_func_name) call_name = bare_mangled else: err_msg3: t.CChar | t.CPtr = pool.alloc(256) if err_msg3 is not None: viperlib.snprintf(err_msg3, 256, "裸名调用 '%s' 未定义且未导入", func_name) HandlesType.fatal_error(node, err_msg3) HandlesType.fatal_error(node, "裸名调用未定义且未导入") else: err_msg4: t.CChar | t.CPtr = pool.alloc(256) if err_msg4 is not None: viperlib.snprintf(err_msg4, 256, "裸名调用 '%s' 未定义且未导入", func_name) HandlesType.fatal_error(node, err_msg4) HandlesType.fatal_error(node, "裸名调用未定义且未导入") # 直接调用 # memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失) if string.strcmp(func_name, "memcpy") == 0 and can >= 3: return _emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst2, mc_src2, mc_num2) # 别名导入重新推断返回类型: # from X import parse as json_parse → func_name="json_parse" 时 _infer_external_func_ret_ty 返回默认 i32 # 用 orig_func_name="parse" 重新推断,能正确匹配返回 i8*(JsonValue*) # 避免指针被截断为 i32 后 inttoptr 丢失高 32 位导致崩溃 if orig_func_name is not None and orig_func_name != func_name: re_inferred_ty: llvmlite.LLVMType | t.CPtr = _infer_external_func_ret_ty(pool, orig_func_name) if re_inferred_ty is not None: call_ret_ty = re_inferred_ty # 跨模块调用:创建 declare 声明,避免 llc 报 undefined value _ensure_method_declare(pool, mod, call_name, call_ret_ty, head, can) # 检查被调用函数是否为变长函数(*args),若是则对变长参数进行 C ABI 提升 is_variadic_call: int = _check_and_promote_variadic_call(pool, builder, mod, call_name, head, can) return llvmlite.build_call(builder, call_name, head, can, call_ret_ty, is_variadic_call) # ============================================================ # 翻译闭包调用 — 通过闭包指针间接调用 # # 闭包结构: {i8* fn_ptr, i8* env_ptr} (16 字节) # 调用过程: # 1. load closure_ptr 从变量 alloca # 2. load fn_ptr 从 offset 0 # 3. load env_ptr 从 offset 8 # 4. bitcast fn_ptr to i32 (i8*)* # 5. call i32 %fn_typed(i8* %env_ptr) # ============================================================ def translate_closure_call(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) -> llvmlite.Value | t.CPtr: """通过闭包指针间接调用""" 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. bitcast fn_raw to i32 (i8*)* param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, param_node, 1) 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 # 5. 间接调用: call i32 %fn_typed(i8* %env_ptr) env_ptr.Next = None return llvmlite.build_call_indirect(builder, fn_typed, env_ptr, 1, i32_ty) # ============================================================ # 翻译 printf 调用 — 模块级版本 # ============================================================ def translate_printf_call(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 = cargs.__len__() 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) # ============================================================ # 翻译 print 调用 — 类型感知格式化 + 默认换行 # # 与 printf 不同,print 不需要用户提供格式串:每个参数按 LLVM # 类型自动选择格式(%s/%d/%f/0x%llx),结尾追加 "\n"(对齐 Python # print 默认 end="\n",以及 TPC HandlesExprBuiltin._HandlePrintLlvm)。 # # 类型分派规则: # i8*(str/bytes) → %s # 其他指针(struct*/int*) → 0x%llx(ptrtoint 到 i64) # i1(bool) → %d(zext 到 i32) # i8/i16/i32 → %d(sext 到 i32,C ABI 整数提升) # i64 → %lld # float/double → %f(float fpext 到 double,C ABI 提升) # 无法识别的类型 → "(unknown)"(不传参) # ============================================================ def translate_print_call(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 = cargs.__len__() 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: # 参数翻译失败 → "(null)"(与 TPC 一致,不传参) if string.strlen(fmt_buf) < FMT_BUF_SIZE - 16: viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 16, "(null)") continue token: t.CChar | t.CPtr = 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 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) # ============================================================ # stdarg 糖函数实现: va_arg / arg / va_start / va_end # # 这些函数对应 stdarg.vp 中的 pass 体声明,由编译器在翻译期 # 转换为 LLVM 指令或 intrinsic 调用,不生成函数 call。 # # va_list 在 TPV 中表示为 i8*(与 stdarg.vp 中 va_list = t.CUnsignedChar | t.CPtr 一致)。 # va_list 对象存储在 alloca 中(i8**),va_arg/va_start/va_end 需要传入 alloca 指针。 # ============================================================ def _va_arg_get_alloca_ptr(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, arg_node: ast.AST | t.CPtr, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: """获取 va_list 变量的 alloca 指针(不 load) va_arg/va_start/va_end 需要的是 va_list 对象的地址(alloca 指针), 而非 va_list 的值。若 arg_node 是 Name,查符号表获取 alloca; 否则用 translate_value 翻译(调用者负责确保传入的是指针)。 """ if arg_node is None: return None # Name 节点:直接查符号表获取 alloca 指针(不 load) if arg_node.kind() == ast.ASTKind.Name: nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg_node) if nm.id is not None: alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) if alloca is not None: return alloca # 回退:translate_value(可能返回 load 后的值,仅适用于已是指针的情况) return HandlesExpr.translate_value(builder, pool, mod, arg_node, funcs_ptr, func_count, trans) def _resolve_va_arg_type(pool: memhub.MemBuddy | t.CPtr, type_node: ast.AST | t.CPtr, trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr: """解析 va_arg/arg 的类型参数为 LLVMType 支持的类型表达式: t.CInt / t.CInt32T → i32 t.CInt64T → i64 t.CDouble → double t.CPtr / t.CChar | t.CPtr → i8* str / bytes → i8* 无类型参数时默认 i32(vsnprintf 中 va_arg(ap) 常用于读取 i32) """ if type_node is None: return llvmlite.Int32(pool) # 使用 HandlesType.resolve_annotation_type 解析类型表达式 resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( pool, type_node, trans._imported_modules, trans._from_imports, trans) if resolved is not None: return resolved # 回退为 i32 return llvmlite.Int32(pool) def _translate_va_arg_sugar(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, cl: ast.Call | t.CPtr, cargs: list[ast.AST | t.CPtr] | t.CPtr, can: t.CSizeT, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: """va_arg(ap, type) / va_arg(ap) → %N = va_arg , 生成 LLVM va_arg 指令,从 va_list 读取下一个变长参数。 """ if can == 0 or cargs is None: return llvmlite.const_int32(pool, 0) # 第一个参数:va_list 指针(获取 alloca,不 load) ap_node: ast.AST | t.CPtr = cargs.get(0) ap_ptr: llvmlite.Value | t.CPtr = _va_arg_get_alloca_ptr( pool, builder, mod, ap_node, funcs_ptr, func_count, trans) if ap_ptr is None: return llvmlite.const_int32(pool, 0) # 第二个参数:目标类型(可选,默认 i32) arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) if can >= 2: type_node: ast.AST | t.CPtr = cargs.get(1) arg_ty = _resolve_va_arg_type(pool, type_node, trans) # 生成 va_arg 指令 return llvmlite.build_va_arg(builder, ap_ptr, arg_ty) def _translate_arg_sugar(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, cl: ast.Call | t.CPtr, cargs: list[ast.AST | t.CPtr] | t.CPtr, can: t.CSizeT, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: """arg(type) → %N = va_arg , 使用当前函数的隐式 va_list(trans._va_list_ptr), 简化 *args 函数体内的 va_arg 调用。 """ if trans._va_list_ptr is None: return llvmlite.const_int32(pool, 0) # 第一个参数:目标类型(可选,默认 i32) arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) if can >= 1 and cargs is not None: type_node: ast.AST | t.CPtr = cargs.get(0) arg_ty = _resolve_va_arg_type(pool, type_node, trans) # 生成 va_arg 指令(使用 trans._va_list_ptr 作为 va_list 指针) return llvmlite.build_va_arg(builder, trans._va_list_ptr, arg_ty) def _translate_va_start_sugar(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, cargs: list[ast.AST | t.CPtr] | t.CPtr, can: t.CSizeT, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: """va_start(ap, last_arg) → call void @llvm.va_start(i8* %ap) 初始化 va_list。第二个参数 last_arg 在 LLVM intrinsic 中不使用(C 宏兼容)。 """ if can == 0 or cargs is None: return llvmlite.const_int32(pool, 0) # 第一个参数:va_list 指针(获取 alloca,不 load) ap_node: ast.AST | t.CPtr = cargs.get(0) ap_ptr: llvmlite.Value | t.CPtr = _va_arg_get_alloca_ptr( pool, builder, mod, ap_node, funcs_ptr, func_count, trans) if ap_ptr is None: return llvmlite.const_int32(pool, 0) # bitcast 到 i8*(@llvm.va_start 接受 i8*) i8_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) i8_ptr_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_vs) ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_vs) if ap_i8 is None: return llvmlite.const_int32(pool, 0) void_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) 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(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, cargs: list[ast.AST | t.CPtr] | t.CPtr, can: t.CSizeT, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: """va_end(ap) → call void @llvm.va_end(i8* %ap) 清理 va_list。在大多数平台上是 no-op,但调用它是良好的 C ABI 习惯。 """ if can == 0 or cargs is None: return llvmlite.const_int32(pool, 0) # 第一个参数:va_list 指针(获取 alloca,不 load) ap_node: ast.AST | t.CPtr = cargs.get(0) ap_ptr: llvmlite.Value | t.CPtr = _va_arg_get_alloca_ptr( pool, builder, mod, ap_node, funcs_ptr, func_count, trans) if ap_ptr is None: return llvmlite.const_int32(pool, 0) # bitcast 到 i8*(@llvm.va_end 接受 i8*) i8_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) i8_ptr_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_ve) ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_ve) if ap_i8 is None: return llvmlite.const_int32(pool, 0) void_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) llvmlite.build_call(builder, "llvm.va_end", ap_i8, 1, void_ty_ve, 0) return llvmlite.const_int32(pool, 0) # ============================================================ # 变长函数调用支持: 检查 IsVarArg + C ABI 参数提升 # # C ABI 要求变长参数(...部分)进行默认提升: # 整数提升: i8/i16 → i32 (sext/zext) # 浮点提升: float → double (fpext) # 固定参数不需要提升(有明确类型签名)。 # ============================================================ def _get_func_fixed_param_count(func: llvmlite.Function | t.CPtr) -> int: """获取函数的固定参数数量(遍历 Params 链表)""" if func is None: return 0 count: int = 0 param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) while param is not None: count += 1 param = llvmlite.param_get_next(param) return count def _check_and_promote_variadic_call(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, call_name: str, head: llvmlite.Value | t.CPtr, can: t.CSizeT) -> int: """检查被调用函数是否为变长函数,若是则对变长参数进行 C ABI 提升 返回: is_variadic (1=变长调用, 0=普通调用) 副作用: 修改 head 链表中超过固定参数数量的节点(C ABI 提升) """ if mod is None or call_name is None or head is None: return 0 # 查找函数对象 func: llvmlite.Function | t.CPtr = find_func_in_module(mod, call_name) if func is None: return 0 if func.IsVarArg != 1: return 0 # 获取固定参数数量 fixed_count: int = _get_func_fixed_param_count(func) # 无变长参数(实参数量 <= 固定参数数量),仍需 is_variadic=1 if can <= fixed_count: return 1 # 遍历到第 fixed_count 个节点(固定参数的最后一个) cur: llvmlite.Value | t.CPtr = head prev: llvmlite.Value | t.CPtr = None idx: int = 0 while cur is not None and idx < fixed_count: prev = cur cur = cur.Next idx += 1 # cur 指向第 fixed_count+1 个节点(第一个变长参数) # 对变长参数进行 C ABI 提升 i32_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) double_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) while cur is not None: next_node: llvmlite.Value | t.CPtr = cur.Next promoted: llvmlite.Value | t.CPtr = cur # C ABI integer promotion: i8/i16 → i32 arg_bits: int = HandlesExpr.get_llvm_type_bits(cur.Ty) if arg_bits != 0 and arg_bits < 32: promoted = HandlesExpr.coerce_to_type(builder, cur, i32_ty_promote, None) if promoted is not None: promoted.Next = next_node if prev is not None: prev.Next = promoted # C ABI float promotion: float → double arg_fbits: int = HandlesExpr.get_llvm_float_bits(promoted.Ty) if arg_fbits != 0 and arg_fbits < 64: promoted = HandlesExpr.coerce_to_type(builder, promoted, double_ty_promote, None) if promoted is not None: promoted.Next = next_node if prev is not None: prev.Next = promoted prev = promoted cur = next_node return 1 # ============================================================ # FuncEntry 结构体(用于函数表) # ============================================================ @t.NoVTable class FuncEntry: """函数表条目""" Name: str Func: llvmlite.Function | t.CPtr Defaults: t.CVoid | t.CPtr # defaults 列表节点指针 (list[AST | CPtr]),None=无默认值 DefaultCount: int # 默认值数量 ParamCount: int # 形参数量(不含 self) # TypeStr: 函数类型文本(stdlib 深拷贝,跨文件安全) # 1b 每文件 reset_to(mark1) 回收 pool 内 Function 对象后, # vtable 生成 find_func_global 读类型改用此文本,避免悬空。 TypeStr: t.CChar | t.CPtr # ============================================================ # 初始化函数表 # ============================================================ def init_func_table(pool: memhub.MemBuddy | t.CPtr, max_count: int) -> FuncEntry | t.CPtr: """分配并清零函数表数组""" size: t.CSizeT = max_count * FuncEntry.__sizeof__() funcs_ptr: 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(funcs: 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 = FuncEntry.__sizeof__() for i in range(func_count): entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size entry: FuncEntry | t.CPtr = (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(funcs: 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 = FuncEntry.__sizeof__() entry_addr: t.CUInt64T = t.CUInt64T(funcs) + func_count * entry_size entry: FuncEntry | t.CPtr = (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 初始化查找) _register_global_func(name, func, pool) # 同时注册到全局默认参数表(供跨模块调用时填充默认值) if default_count > 0: _register_global_defaults(name, defaults, default_count, param_count) return 0 # ============================================================ # 全局函数注册表(跨模块函数查找) # # 所有模块翻译的函数都会注册到此表(通过 add_func_to_table 自动注册)。 # 主要用途: vtable 初始化时查找跨模块继承方法的 Function 对象, # 以获取函数类型信息构造 bitcast 字符串。 # ============================================================ GLOBAL_FUNC_MAX: t.CDefine = 8192 _global_funcs: FuncEntry | t.CPtr = None _global_func_count: int = 0 def _init_global_func_table() -> int: """初始化全局函数表(用 stdlib.malloc 分配,生命周期=整个程序)""" global _global_funcs global _global_func_count if _global_funcs is not None: return 1 size: t.CSizeT = GLOBAL_FUNC_MAX * FuncEntry.__sizeof__() _global_funcs = stdlib.malloc(size) if _global_funcs is None: return 0 string.memset(_global_funcs, 0, size) _global_func_count = 0 return 1 # _build_func_type_str — 从 Function 对象生成函数类型文本(stdlib 存储) # # 格式: ret_ty (param1_ty, param2_ty, ...),与 vtable bitcast 需要一致。 # 用 stdlib.malloc 分配返回,跨文件永久存活(1b reset 不回收)。 # 返回 None 表示失败。 def _build_func_type_str(pool: memhub.MemBuddy | t.CPtr, func: llvmlite.Function | t.CPtr) -> t.CChar | t.CPtr: """生成函数类型文本(stdlib 分配)""" if func is None: return None # 类型文本可能较长(SHA1 限定命名结构体 + 多参数),用 1024 缓冲 ty_buf: t.CChar | t.CPtr = 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: t.CChar | t.CPtr = 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) string.strcat(ty_buf, ret_part) string.strcat(ty_buf, " (") # 参数类型 cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) first: int = 1 param_part: t.CChar | t.CPtr = pool.alloc(512) while cur is not None: if first == 0: string.strcat(ty_buf, ", ") 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) string.strcat(ty_buf, param_part) cur = llvmlite.param_get_next(cur) first = 0 string.strcat(ty_buf, ")") # 深拷贝到 stdlib 区(TypeStr 跨文件永久存活) ts_len: t.CSizeT = string.strlen(ty_buf) ts_copy: t.CChar | t.CPtr = stdlib.malloc(ts_len + 1) if ts_copy is None: return None string.strcpy(ts_copy, ty_buf) return ts_copy def _register_global_func(name: str, func: llvmlite.Function | t.CPtr, pool: memhub.MemBuddy | t.CPtr = None) -> int: """注册函数到全局表(已存在则跳过),返回 0 成功 直接操作全局表,不调用 add_func_to_table,避免递归。 pool 用于生成 TypeStr(None 时 TypeStr 为空)。 """ global _global_func_count if name is None or func is None: return 1 if _init_global_func_table() == 0: return 1 # 已存在则跳过(避免重复) if find_func_in_table(_global_funcs, _global_func_count, name) is not None: return 0 if _global_func_count >= GLOBAL_FUNC_MAX: return 1 # 直接写入全局表(不调用 add_func_to_table,避免递归) entry_size: t.CSizeT = FuncEntry.__sizeof__() entry_addr: t.CUInt64T = t.CUInt64T(_global_funcs) + _global_func_count * entry_size entry: FuncEntry | t.CPtr = (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: t.CChar | t.CPtr = stdlib.malloc(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 补全。 _global_func_count += 1 return 0 def update_global_func_typestr(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: FuncEntry | t.CPtr = find_func_entry_global(name) if entry is None: return 1 entry.TypeStr = _build_func_type_str(pool, func) return 0 def find_func_global(name: str) -> llvmlite.Function | t.CPtr: """在全局函数表中按名称查找,返回 Function 指针或 None""" if name is None or _global_funcs is None: return None return find_func_in_table(_global_funcs, _global_func_count, name) def find_func_entry_global(name: str) -> FuncEntry | t.CPtr: """在全局函数表中按名称查找,返回完整 FuncEntry(含 TypeStr)或 None""" if name is None or _global_funcs is None: return None entry_size: t.CSizeT = FuncEntry.__sizeof__() for i in range(_global_func_count): entry_addr: t.CUInt64T = t.CUInt64T(_global_funcs) + i * entry_size entry: FuncEntry | t.CPtr = (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 # ============================================================ # 全局默认参数注册表(跨模块默认参数填充) # # 独立于 _global_funcs,因为 _register_global_func 可能在 # add_func_to_table 之前被调用(如 stub 注入),此时 defaults 还不可用。 # ============================================================ GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 @t.NoVTable class FuncDefaultsEntry: """默认参数表条目""" Name: str Defaults: t.CVoid | t.CPtr # defaults 列表节点指针 (list[AST | CPtr])(pool 内,可能被 reset) DefaultCount: int ParamCount: int # 形参数量(不含 self) # 常量快照(stdlib 分配,跨文件永久存活): # 注册时提取每个默认值 Constant 的值,跨模块调用时优先用快照重建常量 IR, # 避免读取已被 1b reset_to(mark1) 回收的 pool 内 AST。 ConstKinds: t.CInt | t.CPtr # const_kind 数组(DefaultCount 个 i32) ConstInts: t.CInt64T | t.CPtr # int_val 数组(DefaultCount 个 i64) ConstStrs: t.CSizeT | t.CPtr # str_val 指针数组(DefaultCount 个 i8*) _global_defaults: FuncDefaultsEntry | t.CPtr = None _global_defaults_count: int = 0 def _init_global_defaults_table() -> int: """初始化全局默认参数表""" global _global_defaults global _global_defaults_count if _global_defaults is not None: return 1 size: t.CSizeT = GLOBAL_DEFAULTS_MAX * FuncDefaultsEntry.__sizeof__() _global_defaults = stdlib.malloc(size) if _global_defaults is None: return 0 string.memset(_global_defaults, 0, size) _global_defaults_count = 0 return 1 def _register_global_defaults(name: str, defaults: t.CVoid | t.CPtr, default_count: int, param_count: int) -> int: """注册函数默认参数到全局表,返回 0 成功 注册时提取每个默认值 Constant 的常量快照到 stdlib(ConstKinds/ConstInts/ConstStrs), 跨模块调用时优先用快照重建常量 IR,避免读取被 reset 回收的 pool 内 AST。 """ global _global_defaults_count if name is None or defaults is None: return 1 if _init_global_defaults_table() == 0: return 1 # 已存在则跳过 if find_func_defaults(name) is not None: return 0 if _global_defaults_count >= GLOBAL_DEFAULTS_MAX: return 1 entry_size: t.CSizeT = FuncDefaultsEntry.__sizeof__() entry_addr: t.CUInt64T = t.CUInt64T(_global_defaults) + _global_defaults_count * entry_size entry: FuncDefaultsEntry | t.CPtr = (FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) # Name 深拷贝到 stdlib(全局表跨文件永久存活) nm_len: t.CSizeT = string.strlen(name) nm_copy: t.CChar | t.CPtr = stdlib.malloc(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 = stdlib.malloc(default_count * 4) ints: t.CInt64T | t.CPtr = stdlib.malloc(default_count * 8) strs: t.CSizeT | t.CPtr = stdlib.malloc(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: t.CChar | t.CPtr = stdlib.malloc(slen + 1) if scopy is not None: string.strcpy(scopy, dcn.str_val) strs[di] = t.CSizeT(scopy) entry.ConstKinds = kinds entry.ConstInts = ints entry.ConstStrs = strs _global_defaults_count += 1 return 0 def find_func_defaults(name: str) -> FuncDefaultsEntry | t.CPtr: """按函数名查找默认参数信息,返回 FuncDefaultsEntry 或 None""" if name is None or _global_defaults is None: return None entry_size: t.CSizeT = FuncDefaultsEntry.__sizeof__() i: int = 0 while i < _global_defaults_count: entry_addr: t.CUInt64T = t.CUInt64T(_global_defaults) + i * entry_size entry: FuncDefaultsEntry | t.CPtr = (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 # _build_const_from_snapshot — 从常量快照重建常量 IR 值 # # 用于跨模块默认参数填充:gd_entry.Defaults(pool 内 AST)可能已被 reset 回收, # 改用注册时提取的 stdlib 常量快照(ConstKinds/ConstInts/ConstStrs)重建常量 IR。 # 返回 llvmlite.Value*,失败返回 None。 def _build_const_from_snapshot(pool: memhub.MemBuddy | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, gd_entry: 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(funcs: FuncEntry | t.CPtr, func_count: int, name: str) -> FuncEntry | t.CPtr: """在函数表中按名称查找,返回完整 FuncEntry 或 None""" if name is None or funcs is None: return None entry_size: t.CSizeT = FuncEntry.__sizeof__() i: int = 0 while i < func_count: entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size entry: FuncEntry | t.CPtr = (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 # ============================================================ # ExprCallHandle - 函数调用处理器(Mixin 继承模式) # # HandleCall / HandlePrintfCall 提供 trans 接口 # ============================================================ @t.NoVTable class ExprCallHandle(HandlesBase.Mixin): """函数调用处理器:继承 Mixin 获得 Trans 回指针""" def __init__(self, trans: HT.Translator | t.CPtr): self.Trans = trans # ============================================================ # HandleCall - 翻译函数调用,返回 call 结果 Value # ============================================================ def HandleCall(self, node: ast.AST | t.CPtr) -> llvmlite.Value | t.CPtr: """翻译函数调用,从 self.Trans 获取共享状态""" return translate_call( self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module, node, self.Trans._funcs, self.Trans._func_count, self.Trans) # ============================================================ # HandlePrintfCall - 翻译 printf 调用 # ============================================================ def HandlePrintfCall(self, cl: ast.Call | t.CPtr): """翻译 printf 调用,从 self.Trans 获取共享状态""" translate_printf_call( self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module, cl, self.Trans) # ============================================================ # HandlePrintCall - 翻译 print 调用 # ============================================================ def HandlePrintCall(self, cl: ast.Call | t.CPtr): """翻译 print 调用(类型感知格式化 + 默认换行)""" translate_print_call( self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module, cl, self.Trans) # ============================================================ # NewExprCallHandle - 工厂函数 # ============================================================ def NewExprCallHandle(pool: memhub.MemBuddy | t.CPtr, trans: HT.Translator | t.CPtr) -> ExprCallHandle | t.CPtr: h: ExprCallHandle | t.CPtr = pool.alloc(ExprCallHandle.__sizeof__()) if h is None: return None string.memset(h, 0, ExprCallHandle.__sizeof__()) h.Trans = trans return h