import t, c from stdint import * import ast import llvmlite import memhub import string import stdio import stdlib import sys import viperlib 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 # ============================================================ # 全局模块 SHA1 映射(module_name → SHA1) # # 翻译时用于跨模块函数调用名混淆: # string.strchr(...) → call @{sha1_of_string}.strchr(...) # # 通过 set_module_sha1_map 设置,_lookup_module_sha1 查询 # ============================================================ _g_sha1_arr: bytes = None _g_mod_arr: bytes = None _g_sha1_count: int = 0 def set_module_sha1_map(sha1_arr: bytes, mod_arr: bytes, count: int) -> int: """设置全局模块 SHA1 映射""" global _g_sha1_arr global _g_mod_arr global _g_sha1_count _g_sha1_arr = sha1_arr _g_mod_arr = mod_arr _g_sha1_count = count return 0 def _lookup_module_sha1(mod_name: str) -> str: """查找模块名对应的 SHA1,找不到返回 None""" if mod_name is None: return None if _g_sha1_arr is None or _g_mod_arr is None: return None if _g_sha1_count <= 0: return None for i in range(_g_sha1_count): idx: t.CSizeT = t.CSizeT(i) * 64 if string.strcmp(_g_mod_arr + idx, mod_name) == 0: sidx: t.CSizeT = t.CSizeT(i) * 17 return _g_sha1_arr + sidx return None 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",需要后缀匹配。 """ if mod_suffix is None: return None if _g_sha1_arr is None or _g_mod_arr is None: return None if _g_sha1_count <= 0: return None suffix_len: t.CSizeT = string.strlen(mod_suffix) if suffix_len == 0: return None for i in range(_g_sha1_count): idx: t.CSizeT = t.CSizeT(i) * 64 mod_name: str = _g_mod_arr + idx mod_len: t.CSizeT = string.strlen(mod_name) if mod_len == 0: continue # 精确匹配 if mod_len == suffix_len: if string.strcmp(mod_name, mod_suffix) == 0: sidx: t.CSizeT = t.CSizeT(i) * 17 return _g_sha1_arr + sidx # 后缀匹配:mod_name 以 "." + mod_suffix 结尾 if mod_len > suffix_len: if mod_name[mod_len - suffix_len - 1] == '.': cmp_start: str = mod_name + mod_len - suffix_len if string.strcmp(cmp_start, mod_suffix) == 0: sidx2: t.CSizeT = t.CSizeT(i) * 17 return _g_sha1_arr + sidx2 # 反向后缀匹配:mod_suffix 以 "." + mod_name 结尾 # 用于 from_imports 存完整路径(如 lib.core.Handles.HandlesTranslator) # 而 mod_arr 只存文件名(如 HandlesTranslator)的情况: # import X as Y 的别名 Y 经 from_imports 查到完整路径, # 需反向匹配 mod_arr 中的文件名才能找到 SHA1 if suffix_len > mod_len: if mod_suffix[suffix_len - mod_len - 1] == '.': cmp_start_rev: str = mod_suffix + suffix_len - mod_len if string.strcmp(cmp_start_rev, mod_name) == 0: sidx_rev: t.CSizeT = t.CSizeT(i) * 17 return _g_sha1_arr + sidx_rev return None # ============================================================ # 全局 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 # 手动找到模块名结束位置(空格、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 函数的返回类型""" if pool is None or func_name is None: return llvmlite.Int32(pool) # 返回 i8* 的函数(指针返回值,截断会导致错误) if func_name == "strchr": return llvmlite.Ptr(pool, llvmlite.Int8(pool)) if func_name == "strrchr": return llvmlite.Ptr(pool, llvmlite.Int8(pool)) if func_name == "strstr": return llvmlite.Ptr(pool, llvmlite.Int8(pool)) if func_name == "strcpy": return llvmlite.Ptr(pool, llvmlite.Int8(pool)) if func_name == "strncpy": return llvmlite.Ptr(pool, llvmlite.Int8(pool)) if func_name == "memset": return llvmlite.Ptr(pool, llvmlite.Int8(pool)) if func_name == "memset32": return llvmlite.Ptr(pool, llvmlite.Int8(pool)) if func_name == "memcpy": return llvmlite.Ptr(pool, llvmlite.Int8(pool)) if func_name == "memmove": return llvmlite.Ptr(pool, llvmlite.Int8(pool)) # MemBuddy 方法(当类型信息丢失时可能走外部函数路径) if func_name == "alloc": return llvmlite.Ptr(pool, llvmlite.Int8(pool)) if func_name == "calloc": return llvmlite.Ptr(pool, llvmlite.Int8(pool)) if func_name == "realloc": return llvmlite.Ptr(pool, llvmlite.Int8(pool)) if func_name == "alloc_buf": return llvmlite.Ptr(pool, llvmlite.Int8(pool)) # 返回 i64 的函数 if func_name == "strlen": return llvmlite.Int64(pool) if func_name == "atoll": return llvmlite.Int64(pool) # 返回 double 的函数 if func_name == "atof": return llvmlite.Double(pool) # 返回 i8 的函数 if func_name == "samestr": 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 func_name == "VirtualAlloc": return i8_ptr_ty if func_name == "HeapAlloc": return i8_ptr_ty if func_name == "HeapReAlloc": return i8_ptr_ty if func_name == "HeapCreate": return i8_ptr_ty if func_name == "GetProcessHeap": return i8_ptr_ty if func_name == "GlobalAlloc": return i8_ptr_ty if func_name == "GlobalFree": return i8_ptr_ty if func_name == "GlobalLock": return i8_ptr_ty if func_name == "LocalAlloc": return i8_ptr_ty if func_name == "LocalFree": return i8_ptr_ty if func_name == "GetProcAddress": return i8_ptr_ty if func_name == "GetModuleHandleA": return i8_ptr_ty if func_name == "GetModuleHandleW": return i8_ptr_ty if func_name == "LoadLibraryA": return i8_ptr_ty if func_name == "LoadLibraryW": return i8_ptr_ty # Win32 API 返回 i64 (SIZE_T) 的函数 if func_name == "VirtualQuery": return llvmlite.Int64(pool) if func_name == "HeapSize": return llvmlite.Int64(pool) if func_name == "HeapCompact": return llvmlite.Int64(pool) if func_name == "GlobalSize": return llvmlite.Int64(pool) # llvmlite build_* 函数返回类型推断 # stubs 翻译时未注入,需推断返回类型避免指针被截断为 i32 # 大多数 build_* 函数返回 Value*(指针),少数终止指令返回 void if string.strncmp(func_name, "build_", 6) == 0: # 返回 void 的 build_* 函数(终止指令和无返回值指令) if func_name == "build_ret" or func_name == "build_ret_void" or \ func_name == "build_store" or func_name == "build_br" or \ func_name == "build_cond_br" or func_name == "build_unreachable" or \ func_name == "build_switch": 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 func_name == "Int1" or func_name == "Int8" or func_name == "Int16" or \ func_name == "Int32" or func_name == "Int64" or func_name == "Ptr" or \ func_name == "Func" or func_name == "Array" or func_name == "Struct" or \ func_name == "Void" or func_name == "Half" or func_name == "Float" or \ func_name == "Double" or func_name == "FP128" or func_name == "Label" or \ func_name == "new_param_node" or func_name == "new_phi_incoming" or \ func_name == "const_int32" or func_name == "const_int64" or \ func_name == "ConstFloat" or func_name == "ConstZero" or \ func_name == "ConstNull" or func_name == "ConstInt" or \ func_name == "function_get_name" or func_name == "param_get_ty" or \ func_name == "value_get_ty" or func_name == "value_get_next" or \ func_name == "function_get_ret_ty" or func_name == "function_get_params" or \ func_name == "function_get_param_head" or func_name == "param_get_next": return llvmlite.Ptr(pool, llvmlite.Int8(pool)) # 默认 i32 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 api_name == func_name: 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) — 解引用指针,load i8(字符遍历用例) # # 生成: %N = load i8, i8* %ptr # 返回 i8 值 # ============================================================ 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 i8 from ptr""" 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 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 # 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 or arg0.kind() != ast.ASTKind.Name: return None 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) # ============================================================ # 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 attr_name == "CLOBBER_MEMORY": return "memory" if attr_name == "CLOBBER_CC": return "cc" if attr_name == "CLOBBER_RAX": return "rax" if attr_name == "CLOBBER_RBX": return "rbx" if attr_name == "CLOBBER_RCX": return "rcx" if attr_name == "CLOBBER_RDX": return "rdx" if attr_name == "CLOBBER_RSI": return "rsi" if attr_name == "CLOBBER_RDI": return "rdi" if attr_name == "CLOBBER_RBP": return "rbp" if attr_name == "CLOBBER_RSP": return "rsp" if attr_name == "CLOBBER_R8": return "r8" if attr_name == "CLOBBER_R9": return "r9" if attr_name == "CLOBBER_R10": return "r10" if attr_name == "CLOBBER_R11": return "r11" if attr_name == "CLOBBER_R12": return "r12" if attr_name == "CLOBBER_R13": return "r13" if attr_name == "CLOBBER_R14": return "r14" if attr_name == "CLOBBER_R15": return "r15" if attr_name == "CLOBBER_EAX": return "eax" if attr_name == "CLOBBER_EBX": return "ebx" if attr_name == "CLOBBER_ECX": return "ecx" if attr_name == "CLOBBER_EDX": return "edx" if attr_name == "CLOBBER_ESI": return "esi" if attr_name == "CLOBBER_EDI": return "edi" if attr_name == "CLOBBER_DX": return "dx" if attr_name == "CLOBBER_AX": return "ax" if attr_name == "CLOBBER_CX": return "cx" if attr_name == "CLOBBER_SI": return "si" if attr_name == "CLOBBER_DI": return "di" # Output 输出约束 if attr_name == "OUTPUT_REG": return "=r" if attr_name == "OUTPUT_MEM": return "=m" if attr_name == "OUTPUT_EAX": return "=a" if attr_name == "OUTPUT_EBX": return "=b" if attr_name == "OUTPUT_ECX": return "=c" if attr_name == "OUTPUT_EDX": return "=d" if attr_name == "OUTPUT_ESI": return "=S" if attr_name == "OUTPUT_EDI": return "=D" if attr_name == "OUTPUT_RAX": return "=a" if attr_name == "OUTPUT_RBX": return "=b" if attr_name == "OUTPUT_RCX": return "=c" if attr_name == "OUTPUT_RDX": return "=d" if attr_name == "OUTPUT_RSI": return "=S" if attr_name == "OUTPUT_RDI": return "=D" # Input/Register 输入约束 if attr_name == "REG_ANY": return "r" if attr_name == "REG_EAX": return "a" if attr_name == "REG_EBX": return "b" if attr_name == "REG_ECX": return "c" if attr_name == "REG_EDX": return "d" if attr_name == "REG_ESI": return "S" if attr_name == "REG_EDI": return "D" if attr_name == "REG_RAX": return "a" if attr_name == "REG_RBX": return "b" if attr_name == "REG_RCX": return "c" if attr_name == "REG_RDX": return "d" if attr_name == "REG_RSI": return "S" if attr_name == "REG_RDI": return "D" if attr_name == "INPUT_REG": return "r" if attr_name == "INPUT_MEM": return "m" if attr_name == "INPUT_EAX": return "a" if attr_name == "INPUT_EBX": return "b" if attr_name == "INPUT_ECX": return "c" if attr_name == "INPUT_EDX": return "d" if attr_name == "INPUT_ESI": return "S" if attr_name == "INPUT_EDI": return "D" if attr_name == "INPUT_RAX": return "a" if attr_name == "INPUT_RBX": return "b" if attr_name == "INPUT_RCX": return "c" if attr_name == "INPUT_RDX": return "d" if attr_name == "INPUT_RSI": return "S" if attr_name == "INPUT_RDI": 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: return for fi in range(entry.FieldCount): fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( entry, fi) if fe is None or 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: 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 default_val = HandlesExpr.coerce_to_type(builder, default_val, fe.Ty) 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 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 # OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值 _call_method_on_ptr(pool, builder, mod, class_name, "__before_init__", storage_ptr, None, 0, trans) # 如果有 __init__,调用 __init__(ptr, args...) has_init_flag: int = 0 if ctor_entry is not None: has_init_flag = ctor_entry.HasInit # 跨模块 OOP 类: HasInit 可能未设置(_translate_oop_methods 未被调用) # 但 IsOOP=1 说明类有方法,推断 HasInit=1 if is_oop != 0 and has_init_flag == 0: has_init_flag = 1 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) else: # 无 __init__:逐字段 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 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: 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: continue arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty) 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: 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: 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: continue # 类型转换并 store arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty) 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_const: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i32_ty, tag_value, "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) 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 else: # found_func 为 None(跨模块调用 stub 未注入):根据方法名推断返回类型 # __new__ 返回 Ptr(struct_ty) # __getitem__ 返回 Ptr(struct_ty)(自定义结构体 subscript 读取) # 其他方法默认 void if string.strcmp(method_name, "__new__") == 0 and cmop_struct_ty is not None: call_ret_ty = llvmlite.Ptr(pool, cmop_struct_ty) elif string.strcmp(method_name, "__getitem__") == 0 and cmop_struct_ty is not None: # __getitem__ 返回对象指针 (如 JsonValue|t.CPtr, HashTable|t.CPtr) call_ret_ty = llvmlite.Ptr(pool, cmop_struct_ty) # 构建参数链表: 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: 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: llvmlite.Value | t.CPtr = 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) # 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用 # 复用前面已获取的 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 声明""" 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: 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 # 返回 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, "to_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 # 返回 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) # 默认 i64(整数):既可安全截断为 i32(trunc),也可转换为指针(inttoptr) # 避免使用指针类型(i8*)导致 coerce_to_type 生成 load(解引用)造成崩溃 # x86-64 ABI 中 i32 返回值在 rax 低 32 位,i64 读取后 trunc 取低 32 位是安全的 return llvmlite.Int64(pool) # ============================================================ # _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 未注入):根据方法名推断返回类型 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__() # 构建参数链表: 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 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) llvmlite.value_set_next(tail, arg_val) tail = arg_val total_count: int = 1 + can # 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用 # (不依赖 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) return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0) # ============================================================ # _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 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 # 构建 __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) 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) 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 func_name == "memcpy" 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*) # ============================================================ 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) # 整数 → 整数: 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) # 指针 → 整数: ptrtoint if val_bits == 0 and target_bits != 0: return llvmlite.build_ptrtoint(builder, val, target_ty) # 整数 → 指针: inttoptr if val_bits != 0 and target_bits == 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 # 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__() # 检测 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 # 检测 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 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__") sys.exit(1) # 类型未注册:报错终止,不静默返回 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__") sys.exit(1) # 检测 obj.__len__() — 返回 list 对象的 __count__ 字段(偏移 8,i64) # __len__ 是 list[T] 的内置方法,list 是泛型类不注册 struct 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_name_value( builder, pool, len_at.value, trans) if obj_val is not None: 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) # 检测方法调用: 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 = _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: 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.ConstInt(pool, i64_ty, 0, "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.ConstInt(pool, i64_ty, 4, "0") 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_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.ConstInt(pool, i64_ty, 0, "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.ConstInt(pool, i64_ty, 4, "0") 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_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) 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.ConstInt(pool, i64_ty, 1, "0") 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.ConstInt(pool, i64_ty, 1, "0")) llvmlite.build_store(builder, p_nc, p_cpp) p_idx0: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 0, "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.ConstInt(pool, i64_ty, 4, "0") 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.ConstInt(pool, i64_ty, 1, "0") c_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, c_idx1) llvmlite.build_store(builder, llvmlite.ConstInt(pool, i64_ty, 0, "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.ConstInt(pool, i64_ty, 5, "0") it_ipp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, it_idx5) llvmlite.build_store(builder, llvmlite.ConstInt(pool, i64_ty, 0, "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 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 前缀名)。 # 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 = find_func_in_module(mod, func_name) # 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_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: 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: llvmlite.Value | t.CPtr = 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 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: # 检查是否是 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 回退:from stdint import * 导入的名称(如 BYTEPTR)需要通过 star import 查找 if trans is not None and trans._from_imports is not None: bare_sha1: str = _lookup_mod_sha1(pool, trans._from_imports, func_name, 1) 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 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 func_name == "memcpy" and can >= 3: return _emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst2, mc_src2, mc_num2) # 跨模块调用:创建 declare 声明,避免 llc 报 undefined value _ensure_method_declare(pool, mod, call_name, call_ret_ty, head, can) return llvmlite.build_call(builder, call_name, head, can, call_ret_ty, 0) # ============================================================ # 翻译闭包调用 — 通过闭包指针间接调用 # # 闭包结构: {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) # 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_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) # ============================================================ # 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) # ============================================================ # 初始化函数表 # ============================================================ 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) -> int: """添加函数到函数表,返回 0 成功 Args: defaults: ast.Arguments.defaults 列表节点指针,None=无默认值 default_count: 默认值数量(len(defaults)) param_count: 形参数量(不含 self,len(args.args)) """ 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) # 同时注册到全局默认参数表(供跨模块调用时填充默认值) 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 def _register_global_func(name: str, func: llvmlite.Function | t.CPtr) -> int: """注册函数到全局表(已存在则跳过),返回 0 成功 直接操作全局表,不调用 add_func_to_table,避免递归。 """ 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)) entry.Name = name entry.Func = func _global_func_count += 1 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) # ============================================================ # 全局默认参数注册表(跨模块默认参数填充) # # 独立于 _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]) DefaultCount: int ParamCount: int # 形参数量(不含 self) _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 成功""" 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)) entry.Name = name entry.Defaults = defaults entry.DefaultCount = default_count entry.ParamCount = param_count _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 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) # ============================================================ # 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