diff --git a/App/lib/StubGen/Converter.vp b/App/lib/StubGen/Converter.vp index f173168..7d82eb4 100644 --- a/App/lib/StubGen/Converter.vp +++ b/App/lib/StubGen/Converter.vp @@ -614,7 +614,20 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr, pos = _PyiEmit(buf, buf_size, pos, ": ") pos = _PyiTypeStr(buf, buf_size, pos, aa.annotation) # 如果有值(如 CDefine 常量),输出 = value - if aa.value is not None and aa.value.kind() == ast.ASTKind.Constant: + # CTypedef 特殊处理:值是类型表达式(如 VOIDPTR / t.CVoid | t.CPtr), + # 不是整数,用 _PyiTypeStr 输出类型字符串 + is_ctypedef_ann: int = 0 + if aa.annotation is not None and aa.annotation.kind() == ast.ASTKind.Attribute: + ctd_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(aa.annotation) + if ctd_at.attr is not None and string.strcmp(ctd_at.attr, "CTypedef") == 0: + if ctd_at.value is not None and ctd_at.value.kind() == ast.ASTKind.Name: + ctd_mod: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ctd_at.value) + if ctd_mod.id is not None and string.strcmp(ctd_mod.id, "t") == 0: + is_ctypedef_ann = 1 + if is_ctypedef_ann != 0 and aa.value is not None: + pos = _PyiEmit(buf, buf_size, pos, " = ") + pos = _PyiTypeStr(buf, buf_size, pos, aa.value) + elif aa.value is not None and aa.value.kind() == ast.ASTKind.Constant: cv: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aa.value) if cv.const_kind == ast.CONST_INT: num_buf: bytes = mb.alloc(32) diff --git a/App/lib/StubGen/VpiReader.vp b/App/lib/StubGen/VpiReader.vp new file mode 100644 index 0000000..83f461a --- /dev/null +++ b/App/lib/StubGen/VpiReader.vp @@ -0,0 +1,479 @@ +import t, c +from stdint import * +import ast +import string +import stdlib +import stdio +import sys +import memhub +import llvmlite +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesFunctions as HandlesFunctions +import lib.core.Handles.HandlesTranslator as HT + + +# ============================================================ +# _ddebug_exit - DDEBUG 拦截退出辅助函数 +# +# 刷新 stderr 缓冲区并通过 VLogger 输出可见消息后退出。 +# 解决 sys.exit(1) 不刷新缓冲区导致 DDEBUG 消息丢失的问题。 +# ============================================================ +def _ddebug_exit() -> None: + stdio.fflush(stdio.stderr) + VLogger.error("DDEBUG intercept triggered - check stderr for details") + + +# ============================================================ +# VpiReader - .vpi AST 解析器 +# +# 从 .vpi 存根文件读取函数签名和 CTypedef 定义,注入 declare +# 到当前模块。用于跨模块函数调用时补充缺失的函数声明。 +# +# .vpi 文件由 StubGen.Converter._GeneratePyiFromAst 生成, +# 包含函数签名(无函数体)、类定义、变量声明、import 语句。 +# VpiReader 解析 .vpi 为 AST,提取 FunctionDef 和 CTypedef +# AnnAssign,在当前模块创建对应的 declare 声明。 +# ============================================================ + +# .vpi 读取缓冲区大小(256KB,与 PYI_BUF_SIZE 一致) +VPI_READ_BUF_SIZE: t.CSizeT = 262144 + +# SHA1 字符串长度(16 hex 字符) +SHA1_LEN: t.CSizeT = 16 + + +# ============================================================ +# _extract_sha1_from_path - 从 .vpi 文件路径提取 SHA1 +# +# .vpi 文件名格式为 {sha1}.vpi,sha1 是 16 位十六进制字符。 +# 从路径中找到最后一个路径分隔符(/ 或 \),取后续文件名的前 +# 16 个字符作为 SHA1。分配新缓冲区存储 SHA1(调用者负责 free)。 +# +# Args: +# vpi_path: .vpi 文件路径 +# +# Returns: +# SHA1 字符串(stdlib.malloc 分配,需 stdlib.free),None 失败 +# ============================================================ +def _extract_sha1_from_path(vpi_path: str) -> str: + """从 .vpi 文件路径提取 SHA1(文件名前16字符,malloc 分配)""" + if vpi_path is None: + return None + # 查找最后一个路径分隔符 / 或 \ + total_len: t.CSizeT = string.strlen(vpi_path) + if total_len < SHA1_LEN + 4: # 至少需要 "xxxx.vpi" 的长度 + return None + # 从后向前查找最后一个 / 或 \ + sep_pos: t.CSizeT = total_len + while sep_pos > 0: + sep_pos -= 1 + ch: t.CChar = vpi_path[sep_pos] + if ch == '/' or ch == '\\': + sep_pos += 1 + break + if sep_pos + SHA1_LEN > total_len: + return None + # 分配缓冲区并复制 SHA1(16 字符 + null 终止符) + sha1_buf: str = stdlib.malloc(SHA1_LEN + 1) + if sha1_buf is None: + return None + string.strncpy(sha1_buf, vpi_path + sep_pos, SHA1_LEN) + sha1_buf[SHA1_LEN] = '\0' + # DDEBUG: 检测从路径提取的 SHA1 是否带尾随点(>=17 字符),发现问题立即终止 + _ext_sl: t.CSizeT = string.strlen(sha1_buf) + if _ext_sl >= 17: + stdio.printf("[DDEBUG] _extract_sha1_from_path too long: len=%d sha1='%s' path='%s'\n", _ext_sl, sha1_buf, vpi_path) + _ddebug_exit() + return sha1_buf + + +# ============================================================ +# ParseVpiIntoModule - 解析 .vpi 文件,将函数声明注入到当前模块 +# +# 读取 .vpi 文件 → AST 解析 → 遍历顶层节点 → 创建 declare 声明。 +# 对每个 FunctionDef: +# 1. 提取函数名、参数、返回类型 +# 2. 检测 CExport/CExtern/State 标记(决定是否用裸名) +# 3. 用 find_func_in_module 去重(已存在则跳过) +# 4. 用 create_declare + add_param 创建 declare 声明 +# 5. 注册到函数表(用裸名,非 mangled_name) +# 对 AnnAssign with t.CTypedef:调用 register_ctypedef 注册 +# ClassDef/Import/ImportFrom:跳过 +# +# Args: +# pool: 内存池 +# mod: 当前 LLVM 模块 +# vpi_path: .vpi 文件路径 +# trans: 翻译器对象 +# +# Returns: +# 1=成功,0=失败 +# ============================================================ +def ParseVpiIntoModule(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + vpi_path: str, + trans: HT.Translator | t.CPtr) -> int: + """解析 .vpi 文件,将函数声明注入到当前模块""" + if pool is None or mod is None or vpi_path is None or trans is None: + return 0 + + # 获取当前翻译器的导入信息(供 resolve_annotation_type 使用) + imported_modules: str = trans._imported_modules + from_imports: str = trans._from_imports + + # 1. 读取 .vpi 文件 + f: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R) + if f.closed: + return 0 + vpi_buf: bytes = stdlib.malloc(VPI_READ_BUF_SIZE) + if vpi_buf is None: + f.close() + return 0 + bytes_read: LONG = f.read_all(vpi_buf, VPI_READ_BUF_SIZE) + f.close() + if bytes_read <= 0: + stdlib.free(vpi_buf) + return 0 + if bytes_read < VPI_READ_BUF_SIZE: + vpi_buf[bytes_read] = 0 + else: + vpi_buf[VPI_READ_BUF_SIZE - 1] = 0 + + # 2. 解析为 AST + lx: ast.Lexer | t.CPtr = ast.new_lexer(pool) + if lx is None: + stdlib.free(vpi_buf) + return 0 + ast._lexer_init(lx, vpi_buf, pool) + tokens: ast.Token | t.CPtr = ast.tokenize(lx) + tree: ast.AST | t.CPtr = ast.parse_tokens(pool, tokens) + stdlib.free(vpi_buf) + if tree is None: + return 0 + + # 提取源模块 SHA1(用于函数名混淆,在 AST 解析成功后提取避免提前返回时泄漏) + src_sha1: str = _extract_sha1_from_path(vpi_path) + + # 3. 遍历 AST 顶层节点 + ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children + if ch is None: + if src_sha1 is not None: + stdlib.free(src_sha1) + return 1 + n: t.CSizeT = ch.__len__() + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + # 函数表信息 + funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs + max_funcs: int = 256 + + i: t.CSizeT + for i in range(n): + child: ast.AST | t.CPtr = ch.get(i) + if child is None: + continue + kd: int = child.kind() + + # FunctionDef → 提取函数名、参数、返回类型 → 注入 declare + if kd == ast.ASTKind.FunctionDef: + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) + if fd is None or fd.name is None: + continue + _inject_function_declare(pool, mod, fd, trans, src_sha1, + imported_modules, from_imports, + i32_ty, i8_ptr_ty, + funcs_ptr, max_funcs) + continue + + # AnnAssign with t.CTypedef → 注册 CTypedef + if kd == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(child) + if aa is None: + continue + if HandlesType._is_ctypedef_annotation(aa.annotation) != 0: + _register_ctypedef_from_annassign(pool, aa) + continue + + # ClassDef → 递归注入类内方法(如 MemBuddy.__init__/alloc) + # 方法 declare 使用 {sha1}.{ClassName}.{method} 混淆名, + # 参数类型从 vpi 注解解析(避免调用时 _ensure_method_declare 用实参类型 + # 创建错误 declare,如 size: t.CSizeT 被写成 i32 而非 i64) + if kd == ast.ASTKind.ClassDef: + class_cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child) + if class_cd is None or class_cd.name is None: + continue + cls_name_v: str = class_cd.name + cls_children: list[ast.AST | t.CPtr] | t.CPtr = class_cd.children + if cls_children is not None: + cn2: t.CSizeT = cls_children.__len__() + for ci2 in range(cn2): + m_child: ast.AST | t.CPtr = cls_children.get(ci2) + if m_child is None: + continue + if m_child.kind() != ast.ASTKind.FunctionDef: + continue + m_fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(m_child) + if m_fd is None or m_fd.name is None: + continue + _inject_method_declare(pool, mod, m_fd, cls_name_v, trans, + src_sha1, imported_modules, from_imports, + i32_ty, i8_ptr_ty, funcs_ptr, max_funcs) + continue + + # Import/ImportFrom → 跳过 + # (import 不需要处理) + + # 释放 SHA1 缓冲区(_extract_sha1_from_path 用 stdlib.malloc 分配) + if src_sha1 is not None: + stdlib.free(src_sha1) + return 1 + + +# ============================================================ +# _inject_function_declare - 为单个 FunctionDef 创建 declare 声明 +# +# 检测 CExport/CExtern/State 标记,计算 mangled name, +# 用 find_func_in_module 去重,创建 declare 并添加参数, +# 注册到函数表。 +# ============================================================ +def _inject_function_declare(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + fd: ast.FunctionDef | t.CPtr, + trans: HT.Translator | t.CPtr, + src_sha1: str, + imported_modules: str, + from_imports: str, + i32_ty: llvmlite.LLVMType | t.CPtr, + i8_ptr_ty: llvmlite.LLVMType | t.CPtr, + funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr, + max_funcs: int) -> None: + """为 FunctionDef 创建 declare 声明并注入到模块""" + if fd.name is None: + return + + # 检测 CExtern/State/CExport 标记(从返回类型注解) + has_extern: int = 0 + has_state: int = 0 + has_export: int = 0 + if fd.returns is not None: + has_extern = HandlesType.has_decorator_marker(fd.returns, "CExtern") + has_state = HandlesType.has_decorator_marker(fd.returns, "State") + has_export = HandlesType.has_decorator_marker(fd.returns, "CExport") + + # 计算 mangled name + # CExport/CExtern/State/main 函数用裸名,其他函数用源模块 SHA1 前缀 + use_bare_name: int = 0 + if has_extern != 0 or has_state != 0 or has_export != 0 or string.strcmp(fd.name, "main") == 0: + mangled_name: str = fd.name + use_bare_name = 1 + else: + mangled_name = HandlesFunctions._mangle_name_with_sha1(src_sha1, fd.name) + + # DDEBUG: VpiReader 是注入模块级函数 declare 的路径(无拦截,最可疑双点源头) + # 检测 src_sha1 带尾随点 / fd.name 带前导点 / mangled_name 含双点,发现立即终止 + if mangled_name is not None and src_sha1 is not None and fd.name is not None: + _vpi_sl: t.CSizeT = string.strlen(src_sha1) + if _vpi_sl >= 17: + stdio.printf("[DDEBUG] VpiReader src_sha1 too long: len=%d sha1='%s' func='%s'\n", _vpi_sl, src_sha1, fd.name) + _ddebug_exit() + _vpi_fn_len: t.CSizeT = string.strlen(fd.name) + if _vpi_fn_len > 0 and fd.name[0] == '.': + stdio.printf("[DDEBUG] VpiReader fd.name starts with dot: name='%s' sha1='%s'\n", fd.name, src_sha1) + _ddebug_exit() + _vpi_mi: int = 0 + _vpi_ml: t.CSizeT = string.strlen(mangled_name) + while _vpi_mi < _vpi_ml - 1: + if mangled_name[_vpi_mi] == 46 and mangled_name[_vpi_mi + 1] == 46: + stdio.printf("[DDEBUG] VpiReader mangled double-dot: sha1='%s' func='%s' mangled='%s'\n", src_sha1, fd.name, mangled_name) + _ddebug_exit() + _vpi_mi += 1 + + # 去重:如果函数已存在则跳过 + existing: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name) + if existing is not None: + return + # 也检查裸名(非裸名模式时,CExport 函数可能已通过其他途径注册) + if use_bare_name == 0: + existing_bare: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, fd.name) + if existing_bare is not None: + return + + # 推断返回类型 + ret_ty: llvmlite.LLVMType | t.CPtr = None + if fd.returns is not None: + ret_ty = HandlesType.resolve_annotation_type( + pool, fd.returns, imported_modules, from_imports, trans) + # 如果返回类型是纯 t.State(无实际类型),用 Void + if ret_ty is None and fd.returns is not None: + if has_state != 0: + ret_ty = llvmlite.Void(pool) + # 默认返回 i32 + if ret_ty is None: + ret_ty = i32_ty + + # 创建 declare + func: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, mangled_name, ret_ty) + if func is None: + return + + # 提取参数并添加到 declare + param_count: int = 0 + if fd.args is not None: + args_node: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args) + if args_node.args is not None: + args_list: list[ast.AST | t.CPtr] | t.CPtr = args_node.args + param_count = args_list.__len__() + pi: t.CSizeT + for pi in range(param_count): + ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(args_list.get(pi)) + if ag is None: + continue + pname: str = ag.arg + if pname is None: + pname = "arg" + # 解析参数类型 + param_ty: llvmlite.LLVMType | t.CPtr = i8_ptr_ty + if ag.annotation is not None: + resolved_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, ag.annotation, imported_modules, from_imports, trans) + if resolved_ty is not None: + param_ty = resolved_ty + llvmlite.add_param(pool, func, param_ty, pname) + + # 注册到函数表(用裸名 fd.name,不是 mangled_name) + if funcs_ptr is not None: + cur_count: int = trans._func_count + if HandlesExprCall.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs, + None, 0, param_count) == 0: + trans._func_count = cur_count + 1 + + +# ============================================================ +# _inject_method_declare - 为 ClassDef 内的方法创建 declare +# +# 方法混淆名: {src_sha1}.{ClassName}.{method} +# 参数类型从 vpi 注解解析(self 无注解时默认为 i8*)。 +# 注入正确签名避免调用时 _ensure_method_declare 用实参类型 +# 创建错误 declare(如 size: t.CSizeT 被写成 i32 而非 i64)。 +# ============================================================ +def _inject_method_declare(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + m_fd: ast.FunctionDef | t.CPtr, + cls_name: str, + trans: HT.Translator | t.CPtr, + src_sha1: str, + imported_modules: str, + from_imports: str, + i32_ty: llvmlite.LLVMType | t.CPtr, + i8_ptr_ty: llvmlite.LLVMType | t.CPtr, + funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr, + max_funcs: int) -> None: + """为 ClassDef 内方法创建 declare 声明并注入到模块""" + if m_fd is None or m_fd.name is None or cls_name is None: + return + if src_sha1 is None: + return + + # 构造方法查找名: ClassName.method + lookup_name_len: t.CSizeT = string.strlen(cls_name) + 1 + string.strlen(m_fd.name) + 1 + lookup_name: str = pool.alloc(lookup_name_len) + if lookup_name is None: + return + viperlib.snprintf(lookup_name, lookup_name_len, "%s.%s", cls_name, m_fd.name) + + # mangled name: {src_sha1}.{ClassName}.{method} + mangled_len: t.CSizeT = string.strlen(src_sha1) + 1 + lookup_name_len + mangled_name: str = pool.alloc(mangled_len) + if mangled_name is None: + return + viperlib.snprintf(mangled_name, mangled_len, "%s.%s", src_sha1, lookup_name) + + # 去重:如果方法已存在则跳过 + existing: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name) + if existing is not None: + return + + # 推断返回类型 + ret_ty: llvmlite.LLVMType | t.CPtr = None + if m_fd.returns is not None: + ret_ty = HandlesType.resolve_annotation_type( + pool, m_fd.returns, imported_modules, from_imports, trans) + # __new__ 无返回注解时推断为类指针(__new__ 返回 self 指针,默认 i32 会截断指针) + if ret_ty is None and string.strcmp(m_fd.name, "__new__") == 0: + cls_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(cls_name) + if cls_ty is not None: + ret_ty = llvmlite.Ptr(pool, cls_ty) + if ret_ty is None: + ret_ty = i32_ty + + # 创建 declare + func: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, mangled_name, ret_ty) + if func is None: + return + + # 提取参数并添加到 declare + param_count: int = 0 + if m_fd.args is not None: + args_node: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(m_fd.args) + if args_node.args is not None: + args_list: list[ast.AST | t.CPtr] | t.CPtr = args_node.args + param_count = args_list.__len__() + pi: t.CSizeT + for pi in range(param_count): + ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(args_list.get(pi)) + if ag is None: + continue + pname: str = ag.arg + if pname is None: + pname = "arg" + # 解析参数类型 + param_ty: llvmlite.LLVMType | t.CPtr = i8_ptr_ty + if ag.annotation is not None: + resolved_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, ag.annotation, imported_modules, from_imports, trans) + if resolved_ty is not None: + param_ty = resolved_ty + llvmlite.add_param(pool, func, param_ty, pname) + + # 注册到函数表(用裸名 ClassName.method,与调用方 lookup_name 一致) + if funcs_ptr is not None: + cur_count: int = trans._func_count + if HandlesExprCall.add_func_to_table(funcs_ptr, cur_count, lookup_name, func, max_funcs, + None, 0, param_count) == 0: + trans._func_count = cur_count + 1 + + +# ============================================================ +# _register_ctypedef_from_annassign - 从 AnnAssign 节点注册 CTypedef +# +# 提取 NAME: t.CTypedef = Type 中的名称和类型表达式字符串, +# 调用 register_ctypedef 注册到动态 CTypedef 表。 +# ============================================================ +def _register_ctypedef_from_annassign(pool: memhub.MemBuddy | t.CPtr, + aa: ast.AnnAssign | t.CPtr) -> None: + """从 AnnAssign 节点提取并注册 CTypedef""" + if aa is None or pool is None: + return + # 提取目标名称(必须是 Name 节点) + if aa.target is None or aa.target.kind() != ast.ASTKind.Name: + return + tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) + if tgt.id is None: + return + # 提取类型表达式字符串(从 value AST 节点) + if aa.value is None: + return + type_str: str = HandlesType._get_type_name_from_annotation(pool, aa.value) + if type_str is None: + return + # 注册 CTypedef + HandlesType.register_ctypedef(pool, tgt.id, type_str) diff --git a/App/lib/core/BuildPipeline.vp b/App/lib/core/BuildPipeline.vp index e439cca..9e1ecae 100644 --- a/App/lib/core/BuildPipeline.vp +++ b/App/lib/core/BuildPipeline.vp @@ -15,6 +15,8 @@ import lib.core.Handles.HandlesTranslator as HandlesTranslator import lib.core.Handles.HandlesStruct as HandlesStruct import lib.core.Handles.HandlesType as HandlesType import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.StubMerger as StubMerger +import lib.StubGen.Converter as StubConverter import lib.Projectrans.Config as Config # ============================================================ @@ -32,11 +34,14 @@ _mbuddy: memhub.MemBuddy | t.CPtr # 源代码缓冲区大小(1MB) SRC_BUF_SIZE: t.CDefine = 1048576 # 2^20 = 1MB +# .vpi 存根缓冲区大小(256KB,与 Phase1 一致) +PYI_BUF_SIZE: t.CSizeT = 262144 + # ============================================================ # TranslateFileGetTrans - 翻译单个文件,返回 Translator 对象 # -# 读取文件 → AST 解析 → LLVM IR 翻译,返回 Translator 对象供 +# 读取文件 → AST 解析 → .vpi 生成 → LLVM IR 翻译,返回 Translator 对象供 # 调用者 dump_ir。命名空间隔离:includes 文件宽松模式(全部可见), # 用户文件严格模式(仅本地+import)。 # @@ -44,6 +49,9 @@ SRC_BUF_SIZE: t.CDefine = 1048576 # 2^20 = 1MB # mb: 内存池 # file_path: 源文件路径 # sha1_val: 文件内容的 SHA1 前16字符(用于函数名混淆) +# current_package: 当前文件所属包名(用于解析相对导入),None 表示顶级模块 +# declare_only: 0=全量翻译(默认),1=仅注册 struct/enum/union(不翻译方法体) +# temp_dir: temp 目录路径(非 None 时在翻译前生成 .vpi 存根文件) # # Returns: # Translator 对象(None 失败) @@ -51,11 +59,13 @@ SRC_BUF_SIZE: t.CDefine = 1048576 # 2^20 = 1MB def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str, sha1_val: str, current_package: str = None, - declare_only: int = 0) -> HandlesTranslator.Translator | t.CPtr: + declare_only: int = 0, + temp_dir: str = None) -> HandlesTranslator.Translator | t.CPtr: """翻译文件,返回 Translator 对象(调用者负责 dump_ir),None 失败 current_package: 当前文件所属包名(用于解析相对导入),None 表示顶级模块 declare_only: 0=全量翻译(默认),1=仅注册 struct/enum/union(不翻译方法体) + temp_dir: temp 目录路径(非 None 时在翻译前生成 .vpi 存根文件) """ if file_path is None: return None @@ -83,6 +93,24 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str, stdlib.free(src_buf) if tree is None: return None + # 生成 .vpi 存根文件(从 AST 直接生成,在 tr.translate 之前,与 Phase1 一致) + # .vpi 供其他模块跨模块查询函数签名和 CTypedef 定义 + if temp_dir is not None: + pyi_buf: bytes = stdlib.malloc(PYI_BUF_SIZE) + if pyi_buf is not None: + pyi_buf[0] = 0 + pyi_pos: t.CSizeT = StubConverter._GeneratePyiFromAst(mb, tree, None, pyi_buf, PYI_BUF_SIZE) + if pyi_pos > 0: + # 写入 {sha1}.vpi 到 temp_dir(切片路径) + td_len_vpi: t.CSizeT = string.strlen(temp_dir) + pyi_path: str = StubMerger._sliced_path(temp_dir, td_len_vpi, sha1_val, "vpi") + if pyi_path is not None: + pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.W) + if not pf.closed: + pf.write(pyi_buf, pyi_pos) + pf.close() + stdlib.free(pyi_path) + stdlib.free(pyi_buf) tr: HandlesTranslator.Translator | t.CPtr = mb.alloc(HandlesTranslator.Translator.__sizeof__()) tr.__before_init__() tr.__init__() @@ -95,6 +123,8 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str, HandlesType.clear_trace() # 模块切换:清空 CDefine 常量表,确保每个模块的 CDefine 常量正确隔离 HandlesType.clear_cdefine_constants() + # 模块切换:清空 CTypedef 表,确保每个模块的 CTypedef 正确隔离 + HandlesType.clear_ctypedefs() # 命名空间隔离:includes 文件宽松模式(全部可见),用户文件严格模式(仅本地+import) strict_mode: int = 1 if string.strstr(file_path, "includes") is not None: diff --git a/App/lib/core/Handles/HandlesAnnAssign.vp b/App/lib/core/Handles/HandlesAnnAssign.vp index 63b6142..3fcd8ea 100644 --- a/App/lib/core/Handles/HandlesAnnAssign.vp +++ b/App/lib/core/Handles/HandlesAnnAssign.vp @@ -244,7 +244,7 @@ def _init_global_array_from_list(builder: llvmlite.IRBuilder | t.CPtr, store_val: llvmlite.Value | t.CPtr = elem_val if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None: store_val = HandlesExpr.coerce_to_type( - builder, elem_val, elem_ptr.Ty.Pointee) + builder, elem_val, elem_ptr.Ty.Pointee, elem_node) llvmlite.build_store(builder, store_val, elem_ptr) i += 1 @@ -296,10 +296,12 @@ class AnnAssignHandle(HandlesBase.Mixin): if HT.is_nonlocal_name(self.Trans, nm.id) != 0: return 0 - # 模块级全局变量已由 handle_module_level_var 注册到模块作用域, - # 不需要创建局部 alloca(否则会导致局部变量遮蔽全局变量) - if HandlesVar.lookup_module_var(self.Trans.SymTab, nm.id) is not None: - return 0 + # 模块级全局变量已由 handle_module_level_var 注册到模块作用域。 + # Python 语义:仅模块级代码(Current == Root)时跳过局部 alloca; + # 函数内无 global 声明时应创建局部变量(不遮蔽全局)。 + if HandlesVar.is_module_scope(self.Trans.SymTab) != 0: + if HandlesVar.lookup_module_var(self.Trans.SymTab, nm.id) is not None: + return 0 # 检查是否已存在 existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( @@ -434,7 +436,7 @@ class AnnAssignHandle(HandlesBase.Mixin): if mod_alloca.Ty is not None: target_ty = mod_alloca.Ty.Pointee if target_ty is not None: - rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty) + rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node) llvmlite.build_store(builder, rhs_val, mod_alloca) return 0 @@ -460,14 +462,18 @@ class AnnAssignHandle(HandlesBase.Mixin): "HandlesAnnAssign") return 0 rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( - builder, rhs_val, nl_target_ty) + builder, rhs_val, nl_target_ty, node) llvmlite.build_store(builder, rhs_coerced, nl_ptr) return 0 # 模块级全局变量(由 handle_module_level_var 注册到模块作用域) - # 非函数内 global 声明,但变量已在模块作用域中(如模块级 t.CArray 初始化) - mod_glob: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( - self.Trans.SymTab, nm.id) + # Python 语义:仅模块级代码(Current == Root)时修改全局变量; + # 函数内无 global 声明时应创建局部变量(走后面的 get_or_create_sym 路径)。 + if HandlesVar.is_module_scope(self.Trans.SymTab) != 0: + mod_glob: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( + self.Trans.SymTab, nm.id) + else: + mod_glob = None if mod_glob is not None: if aa.value is not None: # 列表字面量 → 逐元素 GEP + store 初始化数组 @@ -483,7 +489,7 @@ class AnnAssignHandle(HandlesBase.Mixin): if mod_glob.Ty is not None: target_ty_mg = mod_glob.Ty.Pointee if target_ty_mg is not None: - rhs_val_mg = HandlesExpr.coerce_to_type(builder, rhs_val_mg, target_ty_mg) + rhs_val_mg = HandlesExpr.coerce_to_type(builder, rhs_val_mg, target_ty_mg, node) llvmlite.build_store(builder, rhs_val_mg, mod_glob) return 0 @@ -523,7 +529,7 @@ class AnnAssignHandle(HandlesBase.Mixin): if alloca.Ty is not None: target_ty = alloca.Ty.Pointee if target_ty is not None: - rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty) + rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node) llvmlite.build_store(builder, rhs_val, alloca) return 0 diff --git a/App/lib/core/Handles/HandlesAssign.vp b/App/lib/core/Handles/HandlesAssign.vp index 9649c48..61a1169 100644 --- a/App/lib/core/Handles/HandlesAssign.vp +++ b/App/lib/core/Handles/HandlesAssign.vp @@ -152,7 +152,7 @@ class AssignHandle(HandlesBase.Mixin): builder, pool, mod, sub_node.slice, None, 0, self.Trans) if list_idx_val is not None: HandlesExpr.list_setitem_inline( - builder, pool, list_obj, list_idx_val, rhs_val) + builder, pool, list_obj, list_idx_val, rhs_val, target) continue # 普通 Subscript 赋值 elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr( @@ -163,7 +163,7 @@ class AssignHandle(HandlesBase.Mixin): elem_ty: llvmlite.LLVMType | t.CPtr = elem_ptr.Ty.Pointee if elem_ty is not None: store_val = HandlesExpr.coerce_to_type( - builder, rhs_val, elem_ty) + builder, rhs_val, elem_ty, node) llvmlite.build_store(builder, store_val, elem_ptr) else: # get_subscript_ptr 返回 None: 尝试 __setitem__ 运算符重载 @@ -281,7 +281,7 @@ class AssignHandle(HandlesBase.Mixin): pt_gen: llvmlite.LLVMType | t.CPtr = elem_ptr_gen.Ty.Pointee if pt_gen is not None: store_val_gen = HandlesExpr.coerce_to_type( - builder, rhs_val, pt_gen) + builder, rhs_val, pt_gen, node) llvmlite.build_store(builder, store_val_gen, elem_ptr_gen) setitem_done = 1 if setitem_done == 0: @@ -301,7 +301,7 @@ class AssignHandle(HandlesBase.Mixin): field_ty: llvmlite.LLVMType | t.CPtr = field_ptr.Ty.Pointee if field_ty is not None: store_val = HandlesExpr.coerce_to_type( - builder, rhs_val, field_ty) + builder, rhs_val, field_ty, node) llvmlite.build_store(builder, store_val, field_ptr) else: # 构造详细错误信息 @@ -336,7 +336,7 @@ class AssignHandle(HandlesBase.Mixin): if mod_alloca.Ty is not None: target_ty = mod_alloca.Ty.Pointee if target_ty is not None: - rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty) + rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node) llvmlite.build_store(builder, rhs_val, mod_alloca) continue @@ -357,10 +357,24 @@ class AssignHandle(HandlesBase.Mixin): "HandlesAssign") continue rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( - builder, rhs_val, nl_target_ty) + builder, rhs_val, nl_target_ty, node) llvmlite.build_store(builder, rhs_coerced, nl_ptr) continue + # 拦截:函数内对模块级全局变量赋值但没 global 声明 + # 否则静默创建局部变量遮蔽全局,全局保持 null 导致运行时崩溃 + # (_mbuddy = mb 缺 global 声明即此类 bug:Int32 解引用 null 崩溃) + if HandlesVar.is_module_scope(self.Trans.SymTab) == 0: + mod_gv: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( + self.Trans.SymTab, nm.id) + if mod_gv is not None: + fb_g: t.CChar | t.CPtr = VLogger.fmt_buf() + msg_g: str = "global 声明缺失" + if fb_g is not None: + viperlib.snprintf(fb_g, 1024, "变量 '%s' 是模块级全局变量,函数内赋值需用 global 声明(否则创建局部变量遮蔽全局,导致全局保持 null 崩溃)", nm.id) + msg_g = fb_g + HandlesType.fatal_error(target, msg_g, "SyntaxError") + # 普通局部变量 alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym( self.Trans.SymTab, pool, builder, nm.id, rhs_val.Ty) @@ -371,7 +385,7 @@ class AssignHandle(HandlesBase.Mixin): alloca_ty: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee if alloca_ty is not None: store_val = HandlesExpr.coerce_to_type( - builder, rhs_val, alloca_ty) + builder, rhs_val, alloca_ty, node) llvmlite.build_store(builder, store_val, alloca) existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( self.Trans.SymTab, nm.id) diff --git a/App/lib/core/Handles/HandlesAugAssign.vp b/App/lib/core/Handles/HandlesAugAssign.vp index a8d471e..6228cb5 100644 --- a/App/lib/core/Handles/HandlesAugAssign.vp +++ b/App/lib/core/Handles/HandlesAugAssign.vp @@ -82,7 +82,7 @@ class AugAssignHandle(HandlesBase.Mixin): # 4. 应用二元运算 result: llvmlite.Value | t.CPtr = _apply_aug_op( - pool, builder, aug.op, cur_val, rhs_val) + pool, builder, aug.op, cur_val, rhs_val, node) if result is None: fb: t.CChar | t.CPtr = VLogger.fmt_buf() if fb is not None: @@ -91,7 +91,7 @@ class AugAssignHandle(HandlesBase.Mixin): return 0 # 5. 类型对齐并存储 - result = HandlesExpr.coerce_to_type(builder, result, target_ty) + result = HandlesExpr.coerce_to_type(builder, result, target_ty, node) if result is None: return 0 llvmlite.build_store(builder, result, field_ptr) @@ -130,7 +130,7 @@ class AugAssignHandle(HandlesBase.Mixin): # 4. 应用二元运算 result: llvmlite.Value | t.CPtr = _apply_aug_op( - pool, builder, aug.op, cur_val, rhs_val) + pool, builder, aug.op, cur_val, rhs_val, node) if result is None: fb: t.CChar | t.CPtr = VLogger.fmt_buf() if fb is not None: @@ -139,7 +139,7 @@ class AugAssignHandle(HandlesBase.Mixin): return 0 # 5. 类型对齐并存储 - result = HandlesExpr.coerce_to_type(builder, result, target_ty) + result = HandlesExpr.coerce_to_type(builder, result, target_ty, node) if result is None: return 0 llvmlite.build_store(builder, result, elem_ptr) @@ -208,7 +208,7 @@ class AugAssignHandle(HandlesBase.Mixin): # 4. 类型对齐 + 应用二元运算 # 注意: AugAssign 不走运算符重载(语义上需要 __iadd__ 而非 __add__) result: llvmlite.Value | t.CPtr = _apply_aug_op( - pool, builder, aug.op, cur_val, rhs_val) + pool, builder, aug.op, cur_val, rhs_val, node) if result is None: fb: t.CChar | t.CPtr = VLogger.fmt_buf() if fb is not None: @@ -217,7 +217,7 @@ class AugAssignHandle(HandlesBase.Mixin): return 0 # 5. 存储结果 - result = HandlesExpr.coerce_to_type(builder, result, target_ty) + result = HandlesExpr.coerce_to_type(builder, result, target_ty, node) if result is None: return 0 @@ -249,7 +249,8 @@ def _apply_aug_op(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, op: int, lhs: llvmlite.Value | t.CPtr, - rhs: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + rhs: llvmlite.Value | t.CPtr, + node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: """应用增强赋值的二元运算(浮点 + 指针算术 + 整数运算)""" lhs_bits: int = HandlesExpr.get_llvm_type_bits(lhs.Ty) rhs_bits: int = HandlesExpr.get_llvm_type_bits(rhs.Ty) @@ -267,8 +268,8 @@ def _apply_aug_op(pool: memhub.MemBuddy | t.CPtr, if target_fbits == 32: target_float_ty = llvmlite.Float(pool) # 将两个操作数转换为目标浮点类型(int→float via si2fp, float→float via fpext/fptrunc) - lhs = HandlesExpr.coerce_to_type(builder, lhs, target_float_ty) - rhs = HandlesExpr.coerce_to_type(builder, rhs, target_float_ty) + lhs = HandlesExpr.coerce_to_type(builder, lhs, target_float_ty, node) + rhs = HandlesExpr.coerce_to_type(builder, rhs, target_float_ty, node) if op == ast.OpKind.Add: return llvmlite.build_fadd(builder, lhs, rhs) if op == ast.OpKind.Sub: @@ -286,7 +287,7 @@ def _apply_aug_op(pool: memhub.MemBuddy | t.CPtr, if op == ast.OpKind.Add or op == ast.OpKind.Sub: i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) ptr_as_int: llvmlite.Value | t.CPtr = llvmlite.build_ptrtoint(builder, lhs, i64_ty) - int_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, rhs, i64_ty) + int_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, rhs, i64_ty, node) if ptr_as_int is None or int_val is None: return None if op == ast.OpKind.Add: @@ -300,9 +301,9 @@ def _apply_aug_op(pool: memhub.MemBuddy | t.CPtr, # 整数运算:类型提升 if lhs_bits > rhs_bits and rhs_bits > 0: - rhs = HandlesExpr.coerce_to_type(builder, rhs, lhs.Ty) + rhs = HandlesExpr.coerce_to_type(builder, rhs, lhs.Ty, node) elif rhs_bits > lhs_bits and lhs_bits > 0: - lhs = HandlesExpr.coerce_to_type(builder, lhs, rhs.Ty) + lhs = HandlesExpr.coerce_to_type(builder, lhs, rhs.Ty, node) if op == ast.OpKind.Add: return llvmlite.build_add(builder, lhs, rhs) diff --git a/App/lib/core/Handles/HandlesBody.vp b/App/lib/core/Handles/HandlesBody.vp index 714cadb..c51572b 100644 --- a/App/lib/core/Handles/HandlesBody.vp +++ b/App/lib/core/Handles/HandlesBody.vp @@ -11,6 +11,7 @@ import lib.core.Handles.HandlesExpr as HandlesExpr import lib.core.Handles.HandlesExprCall as HandlesExprCall import lib.core.Handles.HandlesFunctions as HandlesFunctions import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesVar as HandlesVar # ============================================================ @@ -67,6 +68,8 @@ def translate_stmt(trans: HT.Translator | t.CPtr, return translate_break(trans) elif k == ast.ASTKind.Continue: return translate_continue(trans) + elif k == ast.ASTKind.Match: + return trans.MatchH.Handle(node) return 0 @@ -101,7 +104,10 @@ def translate_global(trans: HT.Translator | t.CPtr, # ============================================================ def translate_nonlocal(trans: HT.Translator | t.CPtr, node: ast.AST | t.CPtr) -> int: - """翻译 nonlocal 语句:记录 nonlocal 变量名""" + """翻译 nonlocal 语句:记录 nonlocal 变量名及其类型 + + 类型信息通过查找父作用域的 alloca 获取(用于 env 指针数组方案的类型恢复)。 + """ nl: ast.Nonlocal | t.CPtr = (ast.Nonlocal | t.CPtr)(node) if nl is None: return 0 @@ -114,7 +120,22 @@ def translate_nonlocal(trans: HT.Translator | t.CPtr, if nm_node is not None and nm_node.kind() == ast.ASTKind.Name: nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node) if nm.id is not None: - HT.add_nonlocal_name(trans, nm.id) + # 查找父作用域中的变量 alloca,获取类型信息 + var_ty: llvmlite.LLVMType | t.CPtr = None + var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, nm.id) + if var_alloca is not None and var_alloca.Ty is not None: + var_ty = var_alloca.Ty.Pointee + # Void 类型视为无效(Pointee 访问异常时可能返回 Void), + # 设为 None 让 add_nonlocal_name 回退为 i32,避免生成 + # "bitcast ... to void*" / "load void, void*" 非法 IR + if var_ty is not None: + match var_ty: + case llvmlite.LLVMType.Void(): + var_ty = None + case _: + pass + HT.add_nonlocal_name(trans, nm.id, var_ty) return 0 @@ -166,6 +187,26 @@ def pre_scan_allocas(trans: HT.Translator | t.CPtr, return trans.AnnAssignH.PreScan(node) +# ============================================================ +# 预扫描:Global/Nonlocal 声明(Python 作用域语义) +# +# Python 中 global/nonlocal 声明对整个函数作用域生效,与声明 +# 位置无关。必须在翻译任何赋值之前注册 global/nonlocal 名称, +# 否则 global 声明前的赋值会错误创建局部变量遮蔽全局。 +# ============================================================ +def pre_scan_scope_decls(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """预扫描 Global/Nonlocal 声明,提前注册作用域名称""" + if node is None: + return 0 + k: int = node.kind() + if k == ast.ASTKind.Global: + return translate_global(trans, node) + if k == ast.ASTKind.Nonlocal: + return translate_nonlocal(trans, node) + return 0 + + # ============================================================ # 翻译 break 语句 # ============================================================ diff --git a/App/lib/core/Handles/HandlesClassDef.vp b/App/lib/core/Handles/HandlesClassDef.vp index f0482e4..22590f5 100644 --- a/App/lib/core/Handles/HandlesClassDef.vp +++ b/App/lib/core/Handles/HandlesClassDef.vp @@ -985,7 +985,11 @@ def _translate_union_def(trans: HT.Translator | t.CPtr, field_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( pool, aa.annotation, trans._imported_modules, trans._from_imports, trans) if field_ty is None: - # fast-fail: 字段类型解析失败,用 fatal_error 输出 Python 风格 traceback + # Phase A-pre(declare_only=1):依赖的类可能尚未注册, + # 静默 return 1 让多遍收敛机制生效(renum 返回 1=跳过该类) + if trans._declare_only == 1: + return 1 + # Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止 type_name: str = HandlesType.annotation_to_str(aa.annotation) HandlesType.fatal_error( aa, @@ -2070,6 +2074,31 @@ def _specialize_generic_class(trans: HT.Translator | t.CPtr, if spec_name is None: return None + # 治本修复:Phase B 补译泛型特化类方法体(统一入口,在 cache/existing 检查之前) + # Phase 1a(declare_only==1)特化时只注册结构体不译方法体(MethodsEmitted==0), + # Phase B(declare_only==0)重复进入时若方法体未译,补译方法体生成 define, + # 避免 GSList[Line].append 等符号只有 declare 无 define → 链接失败。 + # 首次 Phase B 特化(Phase 1a 未特化)find_struct 返回 None,不补译,走下方正常全量翻译。 + if trans._declare_only == 0: + pre_existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) + if pre_existing is not None and pre_existing.MethodsEmitted == 0: + tp_names_pre: list[str] | t.CPtr = template_cd.type_params + spec_cd_pre: ast.ClassDef | t.CPtr = _clone_classdef_for_spec( + pool, template_cd, spec_name, tp_names_pre, type_args) + if spec_cd_pre is not None: + trans.GenericTypeParamNames = tp_names_pre + trans.GenericTypeArgs = type_args + HandlesType.set_generic_context(tp_names_pre, type_args) + saved_ms_pre: str = trans.ModuleSha1 + template_sha1_pre: str = _find_generic_template_sha1(class_name) + if template_sha1_pre is not None: + trans.ModuleSha1 = template_sha1_pre + _translate_oop_methods(trans, spec_cd_pre, pre_existing.Ty, spec_name, 0) + trans.ModuleSha1 = saved_ms_pre + trans.GenericTypeParamNames = None + trans.GenericTypeArgs = None + HandlesType.clear_generic_context() + # 3. 检查缓存(spec_key 包含所有类型实参,避免多参数泛型缓存冲突) # 分配新缓冲区避免原地 strcat 溢出 sk_n: t.CSizeT = type_args.__len__() @@ -2393,13 +2422,16 @@ def translate_class_def(trans: HT.Translator | t.CPtr, # 泛型未特化:回退为 Ptr(i8),依赖 AnnotClassName 做后续类型恢复 field_ty = llvmlite.Ptr(pool, llvmlite.Int8(pool)) else: + # Phase A-pre(declare_only=1):依赖的类可能尚未注册, + # 静默 return 0 让多遍收敛机制生效(下一遍依赖类已注册即可成功) + if trans._declare_only == 1: + return 0 + # Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止 type_name2: str = HandlesType.annotation_to_str(aa.annotation) HandlesType.fatal_error( aa, f"'{type_name2}' is not defined", "NameError") - if trans._declare_only == 1: - return 0 return 0 # 存储到数组(指针转 CSizeT) @@ -3033,6 +3065,11 @@ def _translate_oop_methods(trans: HT.Translator | t.CPtr, # 生成 __before_init__ 函数(零值填充 + 默认值赋值 + vtable 指针设置) _generate_before_init(trans, struct_ty, class_name) + # 治本修复:标记方法体已翻译,供 _specialize_generic_class 已注册分支判断 + # Phase 1a mark_only==1 不设此标志,Phase B 补译时据此判断需补译方法体 + if oop_entry is not None: + oop_entry.MethodsEmitted = 1 + return 0 @@ -3439,7 +3476,7 @@ def _generate_before_init(trans: HT.Translator | t.CPtr, if field_ptr is None: continue # 类型转换并 store - default_val = HandlesExpr.coerce_to_type(func_builder, default_val, fe.Ty) + default_val = HandlesExpr.coerce_to_type(func_builder, default_val, fe.Ty, fe.DefaultVal) llvmlite.build_store(func_builder, default_val, field_ptr) # 3. ret void diff --git a/App/lib/core/Handles/HandlesEnum.vp b/App/lib/core/Handles/HandlesEnum.vp index bb4bb55..6b8a1c2 100644 --- a/App/lib/core/Handles/HandlesEnum.vp +++ b/App/lib/core/Handles/HandlesEnum.vp @@ -55,8 +55,7 @@ _enum_count: int = 0 # ============================================================ def init_enum_table(pool: memhub.MemBuddy | t.CPtr) -> int: """初始化枚举注册表,返回 1 成功""" - global _enum_table - global _enum_count + global _enum_table, _enum_count if _enum_table is not None: return 1 @@ -102,6 +101,7 @@ def _get_enum_member(enum_entry: EnumEntry | t.CPtr, i: int) -> EnumMember | t.C def register_enum(pool: memhub.MemBuddy | t.CPtr, name: str, base_ty: llvmlite.LLVMType | t.CPtr) -> EnumEntry | t.CPtr: + global _enum_count """注册枚举类型,返回 EnumEntry 指针""" if init_enum_table(pool) == 0: return None diff --git a/App/lib/core/Handles/HandlesExpr.vp b/App/lib/core/Handles/HandlesExpr.vp index 6eedd36..88e44ff 100644 --- a/App/lib/core/Handles/HandlesExpr.vp +++ b/App/lib/core/Handles/HandlesExpr.vp @@ -249,13 +249,16 @@ def _deref_if_ptr_ptr(builder: llvmlite.IRBuilder | t.CPtr, # ============================================================ def coerce_to_type(builder: llvmlite.IRBuilder | t.CPtr, val: llvmlite.Value | t.CPtr, - target_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + target_ty: llvmlite.LLVMType | t.CPtr, + node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: """将 val 强制转换为 target_ty 整数: sext(扩展)/ trunc(截断) 浮点: fpext(扩展)/ fptrunc(截断) int→float: sitofp float→int: fptosi + + node: AST 节点(用于错误定位),可为 None """ if val is None or target_ty is None: return val @@ -284,7 +287,7 @@ def coerce_to_type(builder: llvmlite.IRBuilder | t.CPtr, # float ↔ ptr: 禁止(无意义的转换,fast-fail 防止误走入 build_load 路径) if (val_fbits != 0 and is_ptr_type(target_ty) != 0) or \ (is_ptr_type(val.Ty) != 0 and target_fbits != 0): - VLogger.error("coerce_to_type: 不支持的类型转换 float↔ptr", "Coerce") + HandlesType.fatal_error(node, "unsupported type conversion: float <-> ptr", "CastError") return val if val_fbits != 0 and target_fbits != 0: if val_fbits == target_fbits: @@ -784,21 +787,21 @@ def translate_ifexp(builder: llvmlite.IRBuilder | t.CPtr, # coerce_to_type 内部会调用 ptrtoint(指针→整数)或 inttoptr(整数→指针) if body_is_ptr != orelse_is_ptr: llvmlite.position_at_end(builder, else_blk_for_phi) - orelse_val = coerce_to_type(builder, orelse_val, body_val.Ty) + orelse_val = coerce_to_type(builder, orelse_val, body_val.Ty, node) elif body_bits > orelse_bits and orelse_bits > 0: # 在 else 块中转换 orelse_val llvmlite.position_at_end(builder, else_blk_for_phi) - orelse_val = coerce_to_type(builder, orelse_val, body_val.Ty) + orelse_val = coerce_to_type(builder, orelse_val, body_val.Ty, node) elif orelse_bits > body_bits and body_bits > 0: # 回到 then 块转换 body_val llvmlite.position_at_end(builder, then_blk_for_phi) - body_val = coerce_to_type(builder, body_val, orelse_val.Ty) + body_val = coerce_to_type(builder, body_val, orelse_val.Ty, node) elif body_bits == orelse_bits and body_bits > 0: # bits 相同但类型不同(如 i64 vs Ptr):null 不能用于 i64 PHI # 此分支理论上不会触发(已被情况0覆盖),保留作为防御 if is_ptr_type(body_val.Ty) != is_ptr_type(orelse_val.Ty): llvmlite.position_at_end(builder, else_blk_for_phi) - orelse_val = coerce_to_type(builder, orelse_val, body_val.Ty) + orelse_val = coerce_to_type(builder, orelse_val, body_val.Ty, node) # 现在分别在 then/else 块中 br 到 merge(在类型转换之后) llvmlite.position_at_end(builder, then_blk_for_phi) @@ -940,6 +943,7 @@ def translate_compare(builder: llvmlite.IRBuilder | t.CPtr, # None 比较: None 被翻译为 i8* null(一级指针) # 如果 lhs 是指针,将 rhs (i8* null) bitcast 为 lhs 的指针类型 # 如果 lhs 是数值,将 rhs 转为数值 0(走正常整数比较) + # 如果 lhs 是结构体值类型,结构体永远不等于 None,返回常量 i1 lhs_ptr_level_none: int = get_ptr_level(lhs.Ty) rhs_ptr_level_none: int = get_ptr_level(rhs.Ty) if lhs_ptr_level_none != 0 and rhs_ptr_level_none != 0: @@ -950,6 +954,19 @@ def translate_compare(builder: llvmlite.IRBuilder | t.CPtr, # lhs 是指针, rhs 是数值 → 将 rhs 转为同层级 null 指针 rhs = llvmlite.ConstNull(pool, lhs.Ty, None) elif rhs_ptr_level_none != 0 and lhs_ptr_level_none == 0: + # 检查 lhs 是否是结构体值类型(非指针的 Struct) + lhs_is_struct_none: int = 0 + match lhs.Ty: + case llvmlite.LLVMType.Struct(_, _, _): + lhs_is_struct_none = 1 + case _: + lhs_is_struct_none = 0 + if lhs_is_struct_none != 0: + # 结构体值永远不等于 None:==/is 返回 false,!=/is not 返回 true + if op == ast.OpKind.Eq or op == ast.OpKind.Is: + return llvmlite.const_int(pool, 1, 0) + else: # Ne, IsNot + return llvmlite.const_int(pool, 1, 1) # lhs 是数值, rhs 是 i8* null → 将 rhs 转为数值 0(保持 lhs 不变) rhs = llvmlite.const_int32(pool, 0) @@ -1054,6 +1071,15 @@ def translate_unaryop(builder: llvmlite.IRBuilder | t.CPtr, # 指针类型:与 null 比较 null_op: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, operand.Ty, "null") return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, null_op) + # 结构体值类型:永远为真(非空),not 返回 false + operand_is_struct_not: int = 0 + match operand.Ty: + case llvmlite.LLVMType.Struct(_, _, _): + operand_is_struct_not = 1 + case _: + operand_is_struct_not = 0 + if operand_is_struct_not != 0: + return llvmlite.const_int(pool, 1, 0) operand_bits_not: int = get_llvm_type_bits(operand.Ty) zero = llvmlite.const_int32(pool, 0) if operand_bits_not == 64: @@ -1942,7 +1968,8 @@ def NewExprHandle(pool: memhub.MemBuddy | t.CPtr, def list_getitem_inline(builder: llvmlite.IRBuilder | t.CPtr, pool: memhub.MemBuddy | t.CPtr, lm_obj: llvmlite.Value | t.CPtr, - idx_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + idx_val: llvmlite.Value | t.CPtr, + node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: """内联生成 list __getitem__ 逻辑,返回元素地址 (i8*)""" if builder is None or pool is None or lm_obj is None or idx_val is None: return None @@ -1963,7 +1990,7 @@ def list_getitem_inline(builder: llvmlite.IRBuilder | t.CPtr, g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp) if g_data is None or g_esize is None: return None - g_idx_i64: llvmlite.Value | t.CPtr = coerce_to_type(builder, idx_val, i64_ty) + g_idx_i64: llvmlite.Value | t.CPtr = coerce_to_type(builder, idx_val, i64_ty, node) if g_idx_i64 is None: return None g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize) @@ -2021,7 +2048,8 @@ def list_setitem_inline(builder: llvmlite.IRBuilder | t.CPtr, pool: memhub.MemBuddy | t.CPtr, lm_obj: llvmlite.Value | t.CPtr, idx_val: llvmlite.Value | t.CPtr, - rhs_val: llvmlite.Value | t.CPtr) -> int: + rhs_val: llvmlite.Value | t.CPtr, + node: ast.AST | t.CPtr = None) -> int: """内联生成 list __setitem__ 逻辑,返回 0""" if builder is None or pool is None or lm_obj is None or idx_val is None or rhs_val is None: return 0 @@ -2042,7 +2070,7 @@ def list_setitem_inline(builder: llvmlite.IRBuilder | t.CPtr, s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp) if s_data is None or s_esize is None: return 0 - s_idx_i64: llvmlite.Value | t.CPtr = coerce_to_type(builder, idx_val, i64_ty) + s_idx_i64: llvmlite.Value | t.CPtr = coerce_to_type(builder, idx_val, i64_ty, node) if s_idx_i64 is None: return 0 s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize) @@ -2051,7 +2079,7 @@ def list_setitem_inline(builder: llvmlite.IRBuilder | t.CPtr, s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset) if s_addr is None: return 0 - s_val_ptr: llvmlite.Value | t.CPtr = coerce_to_type(builder, rhs_val, i8_ptr_ty) + s_val_ptr: llvmlite.Value | t.CPtr = coerce_to_type(builder, rhs_val, i8_ptr_ty, node) if s_val_ptr is None: return 0 llvmlite.build_store(builder, s_val_ptr, s_addr) @@ -2169,7 +2197,7 @@ def translate_subscript(builder: llvmlite.IRBuilder | t.CPtr, builder, pointee, alloca) if ptr_val_list is not None: elem_addr_list: llvmlite.Value | t.CPtr = list_getitem_inline( - builder, pool, ptr_val_list, idx_val) + builder, pool, ptr_val_list, idx_val, node) if elem_addr_list is not None: # 根据类型名提取元素类型,bitcast 后 load elem_ty_list: llvmlite.LLVMType | t.CPtr = _list_elem_type_from_name( diff --git a/App/lib/core/Handles/HandlesExprCall.vp b/App/lib/core/Handles/HandlesExprCall.vp index 1b4046f..f2fff3c 100644 --- a/App/lib/core/Handles/HandlesExprCall.vp +++ b/App/lib/core/Handles/HandlesExprCall.vp @@ -1,5367 +1,5827 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import stdlib -import sys -import viperlib -import w32.fileio as fileio -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.HandlesImports as HandlesImports -import lib.core.Handles.HandlesClassDef as HandlesClassDef -import lib.core.StubMerger as StubMerger - -# ============================================================ -# 模块 SHA1 查询(委托给 StubMerger 全局存储器) -# -# 翻译时用于跨模块函数调用名混淆: -# string.strchr(...) → call @{sha1_of_string}.strchr(...) -# -# 数据来源是 StubMerger.PopulateSha1MapStore/AppendToSha1MapStore -# 填充的全局存储器,不再维护独立的 SHA1 映射表副本。 -# ============================================================ - -def _lookup_module_sha1(mod_name: str) -> str: - """查找模块名对应的 SHA1,找不到返回 None - - 委托给 StubMerger.LookupSha1ByModName(精确匹配 + 包名回退)。 - """ - return StubMerger.LookupSha1ByModName(mod_name) - -def _lookup_module_sha1_suffix(mod_suffix: str) -> str: - """后缀匹配查找模块 SHA1,如 mod_suffix="__types" 匹配 "llvmlite.__types" - - 用于 from .X import Y 的相对导入:impf.module 是 ".X"(带前导点), - 去掉前导点后为 "X",SHA1 映射表中键是 "pkg.X",需要后缀匹配。 - 委托给 StubMerger.LookupSha1ByModNameSuffix(精确 + 后缀 + 反向后缀)。 - """ - return StubMerger.LookupSha1ByModNameSuffix(mod_suffix) - -# ============================================================ -# 全局 CExport 函数表(module_sha1 + func_name) -# -# t.CExport 函数定义时不加 SHA1 前缀(如 @strlen), -# 跨模块调用时需要查表确认目标函数是否是 CExport 函数。 -# 若是,使用裸名调用(@strlen);否则使用 @{sha1}.func。 -# 必须包含模块 SHA1 记录,避免同名跨模块函数冲突 -# (一个模块有 CExport 的 strlen→@strlen,另一个没有→@{sha1}.strlen)。 -# ============================================================ -_g_cexport_sha1_arr: bytes = None -_g_cexport_func_arr: bytes = None -_g_cexport_count: int = 0 -_CEXPORT_MAX: t.CDefine = 256 - -def register_cexport_func(sha1: str, func_name: str) -> int: - """注册 CExport 函数到全局表(sha1+func_name 二元组)""" - global _g_cexport_sha1_arr - global _g_cexport_func_arr - global _g_cexport_count - if sha1 is None or func_name is None: - return 0 - if _g_cexport_sha1_arr is None: - _g_cexport_sha1_arr = stdlib.malloc(_CEXPORT_MAX * 17) - _g_cexport_func_arr = stdlib.malloc(_CEXPORT_MAX * 64) - if _g_cexport_sha1_arr is None or _g_cexport_func_arr is None: - return 0 - string.memset(_g_cexport_sha1_arr, 0, _CEXPORT_MAX * 17) - string.memset(_g_cexport_func_arr, 0, _CEXPORT_MAX * 64) - if _g_cexport_count < _CEXPORT_MAX: - idx: t.CSizeT = t.CSizeT(_g_cexport_count) * 17 - string.strcpy(_g_cexport_sha1_arr + idx, sha1) - idx2: t.CSizeT = t.CSizeT(_g_cexport_count) * 64 - string.strcpy(_g_cexport_func_arr + idx2, func_name) - _g_cexport_count += 1 - return 1 - return 0 - -def is_cexport_func(sha1: str, func_name: str) -> int: - """检查 (sha1, func_name) 是否是 CExport 函数""" - if sha1 is None or func_name is None: - return 0 - if _g_cexport_sha1_arr is None: - return 0 - for i in range(_g_cexport_count): - idx: t.CSizeT = t.CSizeT(i) * 17 - if string.strcmp(_g_cexport_sha1_arr + idx, sha1) == 0: - idx2: t.CSizeT = t.CSizeT(i) * 64 - if string.strcmp(_g_cexport_func_arr + idx2, func_name) == 0: - return 1 - return 0 - -# ============================================================ -# _lookup_mod_sha1 - 从 from_imports 查找类所属模块的 SHA1 -# -# lookup_from_import 返回指向 from_imports 内部的指针,不是 null 终止 -# (如 "namespace_defs Gadget:namespace_defs ...")。此函数手动截断 -# 模块名,复制到新缓冲区,再查找 SHA1(精确+后缀匹配)。 -# ============================================================ -def _lookup_mod_sha1(pool: memhub.MemBuddy | t.CPtr, - from_imports: str, class_name: str, - allow_star_fallback: int = 1) -> str: - """从 from_imports 查找类所属模块的 SHA1,返回 None=未找到 - - allow_star_fallback: 传 0 禁用 star import 回退(用于明确模块名/函数名查找) - """ - mod_name_raw: str = HandlesImports.lookup_from_import( - from_imports, class_name, allow_star_fallback) - if mod_name_raw is None: - return None - # 手动找到模块名结束位置(空格、null、或 ':' 别名分隔符),复制到新缓冲区 - mod_len: t.CSizeT = 0 - while mod_name_raw[mod_len] != ' ' and mod_name_raw[mod_len] != '\0' and mod_name_raw[mod_len] != ':': - mod_len += 1 - mod_name_buf: str = pool.alloc(mod_len + 1) - if mod_name_buf is None: - return None - for mi in range(mod_len): - mod_name_buf[mi] = mod_name_raw[mi] - mod_name_buf[mod_len] = '\0' - # 去掉相对导入的前导点 - base_mod: str = mod_name_buf - while base_mod[0] == '.': - base_mod = base_mod + 1 - sha1: str = _lookup_module_sha1(base_mod) - if sha1 is None: - sha1 = _lookup_module_sha1_suffix(base_mod) - return sha1 - -# ============================================================ -# HandlesExprCall - 函数调用表达式处理(Mixin 继承模式) -# -# 工具函数和 FuncEntry 保留为模块级,ExprCallHandle 提供 trans 接口 -# ============================================================ - -# ============================================================ -# 在模块函数链表中按名称查找函数 -# ============================================================ -def find_func_in_module(mod: llvmlite.LLVMModule | t.CPtr, - name: str) -> llvmlite.Function | t.CPtr: - """在模块的函数链表中按名称查找函数 - - 查找策略: - 1. 精确匹配(如 "strlen" 匹配 @strlen,有 t.CExport 的函数) - 2. 后缀匹配(如 "atoi" 匹配 @"83210a72e829a086.atoi",无 t.CExport 的函数) - - 使用 llvmlite.function_get_name/next 访问器绕过 stub 类型限制 - (stub 类型字段不足且字段类型可能错误,直接字段访问会被静默跳过)。 - """ - if mod is None or name is None: - return None - name_len: t.CSizeT = string.strlen(name) - cur: llvmlite.Function | t.CPtr = mod.FuncHead - # 第一遍:精确匹配 - while cur is not None: - cur_name: t.CChar | t.CPtr = llvmlite.function_get_name(cur) - if cur_name is not None: - if string.strcmp(cur_name, name) == 0: - return cur - cur = llvmlite.function_get_next(cur) - # 第二遍:后缀匹配(.name) - # 不跳过 declare:方法 stub 也是 declare,需要通过后缀匹配找到 - # 调用处(translate_call 等)负责判断 IsDeclared 并决定使用裸名还是 sha1 前缀名 - cur = mod.FuncHead - while cur is not None: - cur_name2: t.CChar | t.CPtr = llvmlite.function_get_name(cur) - if cur_name2 is not None: - cur_len: t.CSizeT = string.strlen(cur_name2) - if cur_len > name_len + 1: - suffix_start: t.CSizeT = cur_len - name_len - if cur_name2[suffix_start - 1] == '.': - match: int = 1 - for i in range(name_len): - if cur_name2[suffix_start + i] != name[i]: - match = 0 - break - if match == 1: - return cur - cur = llvmlite.function_get_next(cur) - return None - -# ============================================================ -# _ensure_c_lib_declare - 为已知的 C 库函数创建 declare 声明 -# -# 对应 TPC 的 _C_LIB_FUNCS 机制。当裸名调用 memset/memmove/memcmp/ -# strcmp/strlen 等已知 C 库函数时,自动在当前模块创建 declare, -# 避免报 "裸名调用未定义且未导入" 错误。 -# memcpy 不在此处理(已有 _emit_llvm_memcpy_intrinsic 映射到 @llvm.memcpy)。 -# -# Args: -# pool: 内存池 -# mod: LLVM 模块 -# name: 函数名 -# -# Returns: -# Function 指针(已创建 declare),或 None 如果不是已知 C 库函数 -# ============================================================ -def _ensure_c_lib_declare(pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - name: str) -> llvmlite.Function | t.CPtr: - """为已知的 C 库函数创建 declare 声明""" - if pool is None or mod is None or name is None: - return None - - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - ret_ty: llvmlite.LLVMType | t.CPtr = None - params: int = 0 # 参数数量 - - if string.strcmp(name, "strlen") == 0 or string.strcmp(name, "strlength") == 0: - ret_ty = i64_ty - params = 1 - elif string.strcmp(name, "memset") == 0: - ret_ty = i8_ptr_ty - params = 3 - elif string.strcmp(name, "memcpy") == 0: - ret_ty = i8_ptr_ty - params = 3 - elif string.strcmp(name, "memmove") == 0: - ret_ty = i8_ptr_ty - params = 3 - elif string.strcmp(name, "memcmp") == 0: - ret_ty = i32_ty - params = 3 - elif string.strcmp(name, "strcmp") == 0: - ret_ty = i32_ty - params = 2 - elif string.strcmp(name, "strncmp") == 0: - ret_ty = i32_ty - params = 3 - elif string.strcmp(name, "strcpy") == 0: - ret_ty = i8_ptr_ty - params = 2 - elif string.strcmp(name, "strncpy") == 0: - ret_ty = i8_ptr_ty - params = 3 - elif string.strcmp(name, "strcat") == 0: - ret_ty = i8_ptr_ty - params = 2 - elif string.strcmp(name, "puts") == 0: - ret_ty = i32_ty - params = 1 - elif string.strcmp(name, "atoi") == 0: - ret_ty = i32_ty - params = 1 - elif string.strcmp(name, "atol") == 0: - ret_ty = i64_ty - params = 1 - elif string.strcmp(name, "abs") == 0: - ret_ty = i32_ty - params = 1 - elif string.strcmp(name, "labs") == 0: - ret_ty = i64_ty - params = 1 - else: - return None - - # 创建 declare - fn: llvmlite.Function | t.CPtr = llvmlite.create_declare(pool, mod, name, ret_ty) - if fn is None: - return None - # 添加参数 - if params == 1: - if string.strcmp(name, "abs") == 0: - llvmlite.add_param(pool, fn, i32_ty, "n") - elif string.strcmp(name, "labs") == 0: - llvmlite.add_param(pool, fn, i64_ty, "n") - else: - llvmlite.add_param(pool, fn, i8_ptr_ty, "s") - elif params == 2: - llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") - llvmlite.add_param(pool, fn, i8_ptr_ty, "src") - elif params == 3: - if string.strcmp(name, "memset") == 0: - llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") - llvmlite.add_param(pool, fn, i32_ty, "c") - llvmlite.add_param(pool, fn, i64_ty, "n") - else: - llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") - llvmlite.add_param(pool, fn, i8_ptr_ty, "src") - llvmlite.add_param(pool, fn, i64_ty, "n") - return fn - -# ============================================================ -# _infer_external_func_ret_ty - 根据函数名推断外部函数返回类型 -# -# stubs 在翻译后才注入 IR,翻译时模块中无 stub 函数声明, -# 因此对 includes 库函数(如 string.strchr 返回 i8*)需根据 -# 函数名推断返回类型,避免指针被截断为 i32。 -# -# 覆盖 includes/string.py 所有导出函数: -# i8*: strcpy, strncpy, strchr, strrchr, strstr, memset, memset32, memcpy, memmove -# i64: strlen, atoll -# double: atof -# i8: samestr -# i32(默认): strcmp, strncmp, memcmp, strspn, atoi, split -# ============================================================ -def _infer_external_func_ret_ty(pool: memhub.MemBuddy | t.CPtr, - func_name: str) -> llvmlite.LLVMType | t.CPtr: - """根据函数名推断外部 includes 函数的返回类型 - - 支持三种函数名形式: - 1. 裸名: "parse", "strlen" - 2. 别名: "json_parse"(from X import parse as json_parse) - 3. 带 SHA1 前缀: "240a9a4157959a9f.parse"(跨模块调用 mangled name) - """ - if pool is None or func_name is None: - return llvmlite.Int32(pool) - - # 提取裸函数名:去掉 SHA1 前缀(如 "240a9a4157959a9f.parse" → "parse") - # SHA1 前缀是 16 位十六进制 + '.',检查是否有 '.' 分隔 - bare_name: str = func_name - dot_pos: str = string.strrchr(func_name, 46) # 46 = ord('.') - if dot_pos is not None: - # '.' 后的部分是裸函数名 - bare_name = dot_pos + 1 - - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - - # 返回 i8* 的函数(指针返回值,截断会导致错误) - if string.strcmp(bare_name, "strchr") == 0 or string.strcmp(func_name, "strchr") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "strrchr") == 0 or string.strcmp(func_name, "strrchr") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "strstr") == 0 or string.strcmp(func_name, "strstr") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "strcpy") == 0 or string.strcmp(func_name, "strcpy") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "strncpy") == 0 or string.strcmp(func_name, "strncpy") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "memset") == 0 or string.strcmp(func_name, "memset") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "memset32") == 0 or string.strcmp(func_name, "memset32") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "memcpy") == 0 or string.strcmp(func_name, "memcpy") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "memmove") == 0 or string.strcmp(func_name, "memmove") == 0: - return i8_ptr_ty - # JSON 解析函数返回 JsonValue*(指针) - # from json.__parser import parse as json_parse → 别名 json_parse 也需覆盖 - if string.strcmp(bare_name, "parse") == 0 or string.strcmp(func_name, "parse") == 0 or string.strcmp(func_name, "json_parse") == 0: - return i8_ptr_ty - # MemBuddy 方法(当类型信息丢失时可能走外部函数路径) - if string.strcmp(func_name, "alloc") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - if string.strcmp(func_name, "calloc") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - if string.strcmp(func_name, "realloc") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - if string.strcmp(func_name, "alloc_buf") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - # VLogger 模块函数(跨模块调用时 stub 未注入,返回指针被截断为 i32 导致崩溃) - if string.strcmp(func_name, "get_logger") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - if string.strcmp(func_name, "fmt_buf") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - # Config 模块函数(跨模块调用时 stub 未注入,返回 i8* 被 inttoptr i32 截断导致路径损坏) - if string.strcmp(func_name, "get_includes_binary_dir") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - # HandlesType 模块函数(返回 ast.AST|t.CPtr 联合类型,跨模块推断为 i32 导致指针截断) - if string.strcmp(bare_name, "_parse_type_string") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - - # 返回 i64 的函数 - if string.strcmp(func_name, "strlen") == 0: - return llvmlite.Int64(pool) - if string.strcmp(func_name, "atoll") == 0: - return llvmlite.Int64(pool) - - # 返回 double 的函数 - if string.strcmp(func_name, "atof") == 0: - return llvmlite.Double(pool) - - # 返回 i8 的函数 - if string.strcmp(func_name, "samestr") == 0: - return llvmlite.Int8(pool) - - # Win32 API 返回指针(VOIDPTR/HANDLE)的函数 - # stubs 翻译时未注入,需推断返回 i8* 避免指针被截断为 i32 导致解引用崩溃 - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - if string.strcmp(func_name, "VirtualAlloc") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "HeapAlloc") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "HeapReAlloc") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "HeapCreate") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GetProcessHeap") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GlobalAlloc") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GlobalFree") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GlobalLock") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "LocalAlloc") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "LocalFree") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GetProcAddress") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GetModuleHandleA") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GetModuleHandleW") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "LoadLibraryA") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "LoadLibraryW") == 0: - return i8_ptr_ty - # Win32 Handle 返回函数(HANDLE = void* = i8*) - if string.strcmp(func_name, "GetStdHandle") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "CreateFileA") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "CreateFileW") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "FindFirstFileA") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "FindFirstFileW") == 0: - return i8_ptr_ty - - # Win32 API 返回 i64 (SIZE_T) 的函数 - if string.strcmp(func_name, "VirtualQuery") == 0: - return llvmlite.Int64(pool) - if string.strcmp(func_name, "HeapSize") == 0: - return llvmlite.Int64(pool) - if string.strcmp(func_name, "HeapCompact") == 0: - return llvmlite.Int64(pool) - if string.strcmp(func_name, "GlobalSize") == 0: - return llvmlite.Int64(pool) - - # llvmlite build_* 函数返回类型推断 - # stubs 翻译时未注入,需推断返回类型避免指针被截断为 i32 - # 大多数 build_* 函数返回 Value*(指针),少数终止指令返回 void - if string.strncmp(func_name, "build_", 6) == 0: - # 返回 void 的 build_* 函数(终止指令和无返回值指令) - if string.strcmp(func_name, "build_ret") == 0 or string.strcmp(func_name, "build_ret_void") == 0 or \ - string.strcmp(func_name, "build_store") == 0 or string.strcmp(func_name, "build_br") == 0 or \ - string.strcmp(func_name, "build_cond_br") == 0 or string.strcmp(func_name, "build_unreachable") == 0 or \ - string.strcmp(func_name, "build_switch") == 0: - return llvmlite.Void(pool) - # 其他 build_* 函数返回 Value*(指针) - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - - # llvmlite 类型工厂函数返回 LLVMType*(指针) - # Int1/Int8/Int16/Int32/Int64/Ptr/Func/Array/Struct/Void/Half/Float/Double/FP128/Label - # new_param_node/new_phi_incoming 返回 ParamNode*/PhiIncoming*(指针) - # const_int32/const_int64/ConstFloat/ConstZero/ConstNull/ConstInt 返回 Value*(指针) - # function_get_name/param_get_ty 等访问器返回指针 - if string.strcmp(func_name, "Int1") == 0 or string.strcmp(func_name, "Int8") == 0 or string.strcmp(func_name, "Int16") == 0 or \ - string.strcmp(func_name, "Int32") == 0 or string.strcmp(func_name, "Int64") == 0 or string.strcmp(func_name, "Ptr") == 0 or \ - string.strcmp(func_name, "Func") == 0 or string.strcmp(func_name, "Array") == 0 or string.strcmp(func_name, "Struct") == 0 or \ - string.strcmp(func_name, "Void") == 0 or string.strcmp(func_name, "Half") == 0 or string.strcmp(func_name, "Float") == 0 or \ - string.strcmp(func_name, "Double") == 0 or string.strcmp(func_name, "FP128") == 0 or string.strcmp(func_name, "Label") == 0 or \ - string.strcmp(func_name, "new_param_node") == 0 or string.strcmp(func_name, "new_phi_incoming") == 0 or \ - string.strcmp(func_name, "const_int32") == 0 or string.strcmp(func_name, "const_int64") == 0 or \ - string.strcmp(func_name, "ConstFloat") == 0 or string.strcmp(func_name, "ConstZero") == 0 or \ - string.strcmp(func_name, "ConstNull") == 0 or string.strcmp(func_name, "ConstInt") == 0 or \ - string.strcmp(func_name, "function_get_name") == 0 or string.strcmp(func_name, "param_get_ty") == 0 or \ - string.strcmp(func_name, "value_get_ty") == 0 or string.strcmp(func_name, "value_get_next") == 0 or \ - string.strcmp(func_name, "function_get_ret_ty") == 0 or string.strcmp(func_name, "function_get_params") == 0 or \ - string.strcmp(func_name, "function_get_param_head") == 0 or string.strcmp(func_name, "param_get_next") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - - # 默认 i32(整数):与本模块函数定义的默认返回类型一致(HandlesFunctions.py line 324) - # 已知返回指针的函数在上方显式列出(返回 i8*),已知返回 i64 的函数也显式列出 - # 避免使用 i64 导致 stub 声明(declare i64)与实际定义(define i32)类型不匹配 - # x86-64 ABI 中 i32 返回值在 rax 低 32 位,与 define i32 完全一致 - # 与 _infer_method_ret_ty 的默认策略保持一致 - # WARNING: 未登记的外部函数返回类型默认推断为 i32,若实际返回指针/i64 会被截断 - VLogger.warning( - f"外部函数返回类型未登记,默认推断为 i32(可能截断指针/i64): {func_name}", - "HandlesExprCall") - return llvmlite.Int32(pool) - -# ============================================================ -# _get_external_func_param_ty - 获取外部函数第 idx 个参数的期望类型 -# -# stubs 翻译时未注入,需推断参数类型以提升字面量(如 i32→i64), -# 避免 declare(i64) 与 call(i32) 类型不匹配。 -# -# 注意:stubs 翻译时 ULONG(t.CUnsignedLong) 在 LLVM IR 中被翻译为 i64 -# (因为 LLVM 中 long 是 64 位),因此 Win32 API 中所有 ULONG/DWORD/SIZE_T -# 参数在 declare 中都是 i64。call 时必须匹配,否则类型不匹配。 -# -# 策略:对 Win32 API 函数的所有非指针参数(字面量)都提升为 i64, -# 以匹配 declare 中 ULONG 被翻译为 i64 的情况。 -# -# 指针参数(VOIDPTR/HANDLE)不在此处理,由调用点的 inttoptr 处理。 -# ============================================================ -def _get_external_func_param_ty(pool: memhub.MemBuddy | t.CPtr, - func_name: str, - param_idx: int) -> llvmlite.LLVMType | t.CPtr: - """获取外部函数第 param_idx 个参数的期望类型,None 表示用字面量原类型 - - 对 Win32 API 函数的所有非指针参数返回 i64,匹配 declare 中 - ULONG/SIZE_T 被统一翻译为 i64 的情况。 - """ - if pool is None or func_name is None: - return None - - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - - # Win32 API 函数列表:所有非指针参数在 declare 中都是 i64 - # (因为 ULONG/DWORD/SIZE_T 在 LLVM stubs 翻译时都被映射为 i64) - win32_apis: list[str] | t.CPtr = [ - "VirtualAlloc", "VirtualFree", "VirtualProtect", "VirtualQuery", - "VirtualLock", "VirtualUnlock", - "HeapCreate", "HeapDestroy", "HeapAlloc", "HeapReAlloc", - "HeapFree", "HeapSize", "HeapValidate", "HeapCompact", - "GlobalAlloc", "GlobalFree", "GlobalLock", "GlobalUnlock", "GlobalSize", - "LocalAlloc", "LocalFree", - "GetLastError", "SetLastError", - "Sleep", "SleepEx", - "GetTickCount", "GetProcessHeap" - ] - - # list 迭代不支持,用 range + get 替代 - api_count: t.CSizeT = win32_apis.__len__() - for ai in range(api_count): - api_name: str = win32_apis.get(ai) - if string.strcmp(api_name, func_name) == 0: - return i64_ty - - return None - -# ============================================================ -# _emit_llvm_memcpy_intrinsic — 将 memcpy 调用映射到 @llvm.memcpy 内联函数 -# -# 背景: string.memcpy 是 t.CExport 函数,跨模块调用生成 @memcpy 裸名调用。 -# 但在 monomorphization 场景下,目标模块的 deps.txt 可能不含 string, -# 导致 @memcpy 声明缺失,链接器报 undefined value。 -# -# 解决: 将 memcpy 调用映射到 LLVM 内联函数 @llvm.memcpy, -# 该内联函数在当前模块内声明,无需跨模块依赖。 -# -# @llvm.memcpy 签名: void (i8* dst, i8* src, i64 len, i1 isvolatile) -# C memcpy 签名: i8* (i8* dst, i8* src, i64 len) — 返回 dst -# -# Args: -# args_head: 参数链表头(dst, src, num),通过 Value.Next 链接 -# arg_count: 参数数量(应为 3) -# -# Returns: -# dst 值(匹配 C memcpy 语义: 返回 dest 指针) -# ============================================================ -def _emit_llvm_memcpy_intrinsic(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - dst_val: llvmlite.Value | t.CPtr, - src_val: llvmlite.Value | t.CPtr, - num_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: - """将 memcpy 调用映射到 @llvm.memcpy 内联函数 - - 直接接收三个 Value 参数,避免通过 Next 链表遍历(共享 alloca 对象的 - Next 字段可能被其他操作污染,导致链表断裂)。 - """ - if pool is None or builder is None or mod is None: - return None - if dst_val is None or src_val is None or num_val is None: - return None - - # 在函数顶部声明 void_ty,避免后续遮蔽 - void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) - - # 声明 @llvm.memcpy(如未声明) - memcpy_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, "llvm.memcpy") - if memcpy_func is None: - memcpy_func = llvmlite.create_declare(pool, mod, "llvm.memcpy", void_ty) - if memcpy_func is not None: - i8_ptr_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - i64_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i1_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "dst") - llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "src") - llvmlite.add_param(pool, memcpy_func, i64_ty_d, "len") - llvmlite.add_param(pool, memcpy_func, i1_ty_d, "isvolatile") - - # 类型转换: dst, src → i8*; num → i64 - # 注意: 使用 value_get_ty 访问器获取 Ty,避免本地 Value 类型字段索引偏移 - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - - # dst → i8* - dst_coerced: llvmlite.Value | t.CPtr = dst_val - dst_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(dst_val) - if HandlesExpr.is_ptr_type(dst_ty) != 0: - dst_coerced = llvmlite.build_bitcast(builder, dst_val, i8_ptr_ty) - else: - dst_bits: int = HandlesExpr.get_llvm_type_bits(dst_ty) - if dst_bits != 0: - if dst_bits < 64: - dst_coerced = llvmlite.build_zext(builder, dst_val, i64_ty) - dst_coerced = llvmlite.build_inttoptr(builder, dst_coerced, i8_ptr_ty) - - # src → i8* - src_coerced: llvmlite.Value | t.CPtr = src_val - src_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(src_val) - if HandlesExpr.is_ptr_type(src_ty) != 0: - src_coerced = llvmlite.build_bitcast(builder, src_val, i8_ptr_ty) - else: - src_bits: int = HandlesExpr.get_llvm_type_bits(src_ty) - if src_bits != 0: - if src_bits < 64: - src_coerced = llvmlite.build_zext(builder, src_val, i64_ty) - src_coerced = llvmlite.build_inttoptr(builder, src_coerced, i8_ptr_ty) - - # num → i64 - num_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, num_val, i64_ty) - - if dst_coerced is None or src_coerced is None or num_coerced is None: - return None - - # 添加 i1 false 参数(isvolatile)— llvm.memcpy 需要 4 个参数 - false_val: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "false") - - # 使用 includes 中的访问器函数构建参数链表,避免本地 Value 类型字段索引偏移 - # (f26cd4c78b4d554c.Value 缺少 GSListNode 的 Next 字段,直接访问 .Next 会修改 .Ty) - llvmlite.value_set_next(dst_coerced, src_coerced) - llvmlite.value_set_next(src_coerced, num_coerced) - if false_val is not None: - llvmlite.value_set_next(num_coerced, false_val) - llvmlite.value_set_next(false_val, None) - else: - llvmlite.value_set_next(num_coerced, None) - - # 使用 build_call 发射 call 指令(内部用 includes Value 类型访问字段,索引正确) - # _ll_name_needs_quote 已对 llvm. 前缀豁免引号 - result: llvmlite.Value | t.CPtr = llvmlite.build_call(builder, "llvm.memcpy", dst_coerced, 4, void_ty, 0) - - # 返回 dst(匹配 C memcpy 语义: 返回 dest 指针) - return dst_coerced - -# ============================================================ -# c.Deref(ptr) — 解引用指针,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 string.strcmp(attr_name, "CLOBBER_MEMORY") == 0: return "memory" - if string.strcmp(attr_name, "CLOBBER_CC") == 0: return "cc" - if string.strcmp(attr_name, "CLOBBER_RAX") == 0: return "rax" - if string.strcmp(attr_name, "CLOBBER_RBX") == 0: return "rbx" - if string.strcmp(attr_name, "CLOBBER_RCX") == 0: return "rcx" - if string.strcmp(attr_name, "CLOBBER_RDX") == 0: return "rdx" - if string.strcmp(attr_name, "CLOBBER_RSI") == 0: return "rsi" - if string.strcmp(attr_name, "CLOBBER_RDI") == 0: return "rdi" - if string.strcmp(attr_name, "CLOBBER_RBP") == 0: return "rbp" - if string.strcmp(attr_name, "CLOBBER_RSP") == 0: return "rsp" - if string.strcmp(attr_name, "CLOBBER_R8") == 0: return "r8" - if string.strcmp(attr_name, "CLOBBER_R9") == 0: return "r9" - if string.strcmp(attr_name, "CLOBBER_R10") == 0: return "r10" - if string.strcmp(attr_name, "CLOBBER_R11") == 0: return "r11" - if string.strcmp(attr_name, "CLOBBER_R12") == 0: return "r12" - if string.strcmp(attr_name, "CLOBBER_R13") == 0: return "r13" - if string.strcmp(attr_name, "CLOBBER_R14") == 0: return "r14" - if string.strcmp(attr_name, "CLOBBER_R15") == 0: return "r15" - if string.strcmp(attr_name, "CLOBBER_EAX") == 0: return "eax" - if string.strcmp(attr_name, "CLOBBER_EBX") == 0: return "ebx" - if string.strcmp(attr_name, "CLOBBER_ECX") == 0: return "ecx" - if string.strcmp(attr_name, "CLOBBER_EDX") == 0: return "edx" - if string.strcmp(attr_name, "CLOBBER_ESI") == 0: return "esi" - if string.strcmp(attr_name, "CLOBBER_EDI") == 0: return "edi" - if string.strcmp(attr_name, "CLOBBER_DX") == 0: return "dx" - if string.strcmp(attr_name, "CLOBBER_AX") == 0: return "ax" - if string.strcmp(attr_name, "CLOBBER_CX") == 0: return "cx" - if string.strcmp(attr_name, "CLOBBER_SI") == 0: return "si" - if string.strcmp(attr_name, "CLOBBER_DI") == 0: return "di" - - # Output 输出约束 - if string.strcmp(attr_name, "OUTPUT_REG") == 0: return "=r" - if string.strcmp(attr_name, "OUTPUT_MEM") == 0: return "=m" - if string.strcmp(attr_name, "OUTPUT_EAX") == 0: return "=a" - if string.strcmp(attr_name, "OUTPUT_EBX") == 0: return "=b" - if string.strcmp(attr_name, "OUTPUT_ECX") == 0: return "=c" - if string.strcmp(attr_name, "OUTPUT_EDX") == 0: return "=d" - if string.strcmp(attr_name, "OUTPUT_ESI") == 0: return "=S" - if string.strcmp(attr_name, "OUTPUT_EDI") == 0: return "=D" - if string.strcmp(attr_name, "OUTPUT_RAX") == 0: return "=a" - if string.strcmp(attr_name, "OUTPUT_RBX") == 0: return "=b" - if string.strcmp(attr_name, "OUTPUT_RCX") == 0: return "=c" - if string.strcmp(attr_name, "OUTPUT_RDX") == 0: return "=d" - if string.strcmp(attr_name, "OUTPUT_RSI") == 0: return "=S" - if string.strcmp(attr_name, "OUTPUT_RDI") == 0: return "=D" - - # Input/Register 输入约束 - if string.strcmp(attr_name, "REG_ANY") == 0: return "r" - if string.strcmp(attr_name, "REG_EAX") == 0: return "a" - if string.strcmp(attr_name, "REG_EBX") == 0: return "b" - if string.strcmp(attr_name, "REG_ECX") == 0: return "c" - if string.strcmp(attr_name, "REG_EDX") == 0: return "d" - if string.strcmp(attr_name, "REG_ESI") == 0: return "S" - if string.strcmp(attr_name, "REG_EDI") == 0: return "D" - if string.strcmp(attr_name, "REG_RAX") == 0: return "a" - if string.strcmp(attr_name, "REG_RBX") == 0: return "b" - if string.strcmp(attr_name, "REG_RCX") == 0: return "c" - if string.strcmp(attr_name, "REG_RDX") == 0: return "d" - if string.strcmp(attr_name, "REG_RSI") == 0: return "S" - if string.strcmp(attr_name, "REG_RDI") == 0: return "D" - - if string.strcmp(attr_name, "INPUT_REG") == 0: return "r" - if string.strcmp(attr_name, "INPUT_MEM") == 0: return "m" - if string.strcmp(attr_name, "INPUT_EAX") == 0: return "a" - if string.strcmp(attr_name, "INPUT_EBX") == 0: return "b" - if string.strcmp(attr_name, "INPUT_ECX") == 0: return "c" - if string.strcmp(attr_name, "INPUT_EDX") == 0: return "d" - if string.strcmp(attr_name, "INPUT_ESI") == 0: return "S" - if string.strcmp(attr_name, "INPUT_EDI") == 0: return "D" - if string.strcmp(attr_name, "INPUT_RAX") == 0: return "a" - if string.strcmp(attr_name, "INPUT_RBX") == 0: return "b" - if string.strcmp(attr_name, "INPUT_RCX") == 0: return "c" - if string.strcmp(attr_name, "INPUT_RDX") == 0: return "d" - if string.strcmp(attr_name, "INPUT_RSI") == 0: return "S" - if string.strcmp(attr_name, "INPUT_RDI") == 0: return "D" - - return "" - -# ============================================================ -# _resolve_asm_descr — 递归解析约束表达式 -# -# 支持: -# t.ASM_DESCR.XXX → _resolve_register(XXX) -# expr | expr (BinOp BitOr) → 拼接 -# "string" (Constant) → 直接返回 -# ============================================================ -def _resolve_asm_descr(pool: memhub.MemBuddy | t.CPtr, - node: ast.AST | t.CPtr) -> str: - """递归解析约束表达式,返回约束字符串""" - if node is None: - return "" - - k: int = node.kind() - - # BinOp with BitOr: 拼接左右 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if bop.op == ast.OpKind.BitOr: - left_str: str = _resolve_asm_descr(pool, bop.left) - right_str: str = _resolve_asm_descr(pool, bop.right) - llen: t.CSizeT = string.strlen(left_str) - rlen: t.CSizeT = string.strlen(right_str) - buf: str = pool.alloc(llen + rlen + 1) - if buf is None: - return "" - string.strcpy(buf, left_str) - for i in range(rlen): - buf[llen + i] = right_str[i] - buf[llen + rlen] = '\0' - return buf - return "" - - # Attribute: t.ASM_DESCR.XXX 或 t.XXX - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - # t.ASM_DESCR.XXX - if at.value is not None and at.value.kind() == ast.ASTKind.Attribute: - inner: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value) - if inner.value is not None and inner.value.kind() == ast.ASTKind.Name: - mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner.value) - if mod_nm.id is not None and string.strcmp(mod_nm.id, "t") == 0: - if inner.attr is not None and string.strcmp(inner.attr, "ASM_DESCR") == 0: - return _resolve_register(at.attr) - # t.XXX 简化形式 - if at.value is not None and at.value.kind() == ast.ASTKind.Name: - mod_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if mod_nm2.id is not None and string.strcmp(mod_nm2.id, "t") == 0: - return _resolve_register(at.attr) - return "" - - # Constant: 字符串常量 - if k == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - if cn.const_kind == ast.CONST_STR: - return cn.str_val - return "" - - return "" - -# ============================================================ -# _asm_get_operand — 获取操作数数组中第 idx 个元素的指针 -# ============================================================ -def _asm_get_operand(base: AsmOperand | t.CPtr, - idx: int) -> AsmOperand | t.CPtr: - """获取操作数数组中第 idx 个元素的指针""" - entry_size: t.CSizeT = AsmOperand.__sizeof__() - entry_addr: t.CUInt64T = t.CUInt64T(base) + idx * entry_size - return (AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - -# ============================================================ -# _asm_is_c_call — 检查 Call 节点是否是 c.XXX 调用 -# -# 返回 attr_name(如 "AsmInp"/"AsmOut"),不是则返回 None -# ============================================================ -def _asm_is_c_call(node: ast.Call | t.CPtr) -> str: - """检查 Call 节点是否是 c.XXX 调用,返回属性名或 None""" - if node is None or node.func is None: - return None - if node.func.kind() != ast.ASTKind.Attribute: - return None - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node.func) - if at.value is None or at.value.kind() != ast.ASTKind.Name: - return None - mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if mod_nm.id is None or string.strcmp(mod_nm.id, "c") != 0: - return None - return at.attr - -# ============================================================ -# _asm_add_operand — 添加操作数到数组 -# -# 返回 1 成功, 0 失败(数组已满) -# ============================================================ -def _asm_add_operand(operands: AsmOperand | t.CPtr, - count: int, - val: llvmlite.Value | t.CPtr, - constraint: str, - is_output: int) -> int: - """添加操作数到数组,返回新计数(失败返回原计数)""" - if count >= ASM_MAX_OPERANDS: - return count - op: AsmOperand | t.CPtr = _asm_get_operand(operands, count) - op.Value = val - op.Constraint = constraint - op.IsOutput = is_output - return count + 1 - -# ============================================================ -# translate_c_asm — 翻译 c.Asm 内联汇编 -# -# 语法: -# c.Asm("nop", [t.ASM_DESCR.CLOBBER_MEMORY]) -# c.Asm(f"mov rax, {c.AsmInp(val, t.ASM_DESCR.REG_ANY)}", op=[...]) -# c.Asm(f"...", out=[c.AsmOut(var, t.ASM_DESCR.OUTPUT_REG)], op=[...]) -# ============================================================ -def translate_c_asm(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译 c.Asm 内联汇编,返回结果 Value(无输出时返回 None)""" - if cl is None: - return None - - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None or cargs.__len__() < 1: - return None - - # 分配操作数数组 - operand_size: t.CSizeT = AsmOperand.__sizeof__() - operands: AsmOperand | t.CPtr = pool.alloc(operand_size * ASM_MAX_OPERANDS) - if operands is None: - return None - string.memset(operands, 0, operand_size * ASM_MAX_OPERANDS) - - # 分配 clobber 名数组 - clobbers: str | t.CPtr = pool.alloc(8 * ASM_MAX_OPERANDS) - if clobbers is None: - return None - string.memset(clobbers, 0, 8 * ASM_MAX_OPERANDS) - - # 分配 asm 文本缓冲区 - asm_text: t.CChar | t.CPtr = pool.alloc(ASM_TEXT_BUF_SIZE) - if asm_text is None: - return None - asm_text[0] = '\0' - - operand_count: int = 0 - clobber_count: int = 0 - fv_count: int = 0 - - # 分配 fv 索引数组(记录每个 FormattedValue 对应的操作数原始索引) - fv_orig_indices: int | t.CPtr = pool.alloc(4 * ASM_MAX_OPERANDS) - if fv_orig_indices is None: - return None - string.memset(fv_orig_indices, 0, 4 * ASM_MAX_OPERANDS) - - # ============================================================ - # 1. 解析汇编模板(JoinedStr 或 Constant)— 第一遍:收集操作数 - # 不生成 asm 文本(占位符 $N 需在重排后才能确定编号) - # ============================================================ - tmpl_node: ast.AST | t.CPtr = cargs.get(0) - if tmpl_node is not None: - tk: int = tmpl_node.kind() - - if tk == ast.ASTKind.JoinedStr: - js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node) - jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values - if jvalues is not None: - jvlen: t.CSizeT = jvalues.__len__() - for vi in range(jvlen): - part: ast.AST | t.CPtr = jvalues.get(vi) - if part is None: - continue - pk: int = part.kind() - - if pk == ast.ASTKind.FormattedValue: - fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part) - fexpr: ast.AST | t.CPtr = fv.value - if fexpr is None or fexpr.kind() != ast.ASTKind.Call: - continue - fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr) - attr_nm: str = _asm_is_c_call(fcall) - if attr_nm is None: - continue - - is_out: int = 0 - if string.strcmp(attr_nm, "AsmOut") == 0: - is_out = 1 - elif string.strcmp(attr_nm, "AsmInp") == 0: - is_out = 0 - else: - continue - - fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args - if fargs is None or fargs.__len__() < 1: - continue - - val_node: ast.AST | t.CPtr = fargs.get(0) - cons_str: str = "" - if fargs.__len__() >= 2: - cons_str = _resolve_asm_descr(pool, fargs.get(1)) - - if is_out != 0: - # 输出:获取变量 alloca - if val_node is None or val_node.kind() != ast.ASTKind.Name: - continue - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node) - if nm.id is None: - continue - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is None: - continue - operand_count = _asm_add_operand( - operands, operand_count, alloca, cons_str, 1) - else: - # 输入:翻译值 - ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, val_node, None, 0, trans) - if ival is None: - continue - operand_count = _asm_add_operand( - operands, operand_count, ival, cons_str, 0) - - # 记录 fv 的原始操作数索引 - if fv_count < ASM_MAX_OPERANDS: - fv_orig_indices[fv_count] = operand_count - 1 - fv_count += 1 - - # ============================================================ - # 2. 解析关键字参数 out=/inp=/op=/clobber= - # ============================================================ - keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords - if keywords is not None: - kwlen: t.CSizeT = keywords.__len__() - for ki in range(kwlen): - kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) - if kw is None or kw.arg is None or kw.value is None: - continue - kwk: int = kw.value.kind() - - if string.strcmp(kw.arg, "out") == 0: - # 输出操作数列表 - if kwk != ast.ASTKind.List: - continue - out_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) - out_elts: list[ast.AST | t.CPtr] | t.CPtr = out_lst.elts - if out_elts is None: - continue - oelen: t.CSizeT = out_elts.__len__() - for oi in range(oelen): - oelt: ast.AST | t.CPtr = out_elts.get(oi) - if oelt is None or oelt.kind() != ast.ASTKind.Call: - continue - ocall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(oelt) - oattr: str = _asm_is_c_call(ocall) - if oattr is None or string.strcmp(oattr, "AsmOut") != 0: - continue - oargs: list[ast.AST | t.CPtr] | t.CPtr = ocall.args - if oargs is None or oargs.__len__() < 1: - continue - oval_node: ast.AST | t.CPtr = oargs.get(0) - ocons: str = "" - if oargs.__len__() >= 2: - ocons = _resolve_asm_descr(pool, oargs.get(1)) - if oval_node is None or oval_node.kind() != ast.ASTKind.Name: - continue - onm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(oval_node) - if onm.id is None: - continue - oalloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, onm.id) - if oalloca is None: - continue - operand_count = _asm_add_operand( - operands, operand_count, oalloca, ocons, 1) - - elif string.strcmp(kw.arg, "inp") == 0 or string.strcmp(kw.arg, "inputs") == 0: - # 输入操作数列表 - if kwk != ast.ASTKind.List: - continue - in_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) - in_elts: list[ast.AST | t.CPtr] | t.CPtr = in_lst.elts - if in_elts is None: - continue - ielen: t.CSizeT = in_elts.__len__() - for ii in range(ielen): - ielt: ast.AST | t.CPtr = in_elts.get(ii) - if ielt is None or ielt.kind() != ast.ASTKind.Call: - continue - icall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(ielt) - iattr: str = _asm_is_c_call(icall) - if iattr is None or string.strcmp(iattr, "AsmInp") != 0: - continue - iargs: list[ast.AST | t.CPtr] | t.CPtr = icall.args - if iargs is None or iargs.__len__() < 1: - continue - ival_node: ast.AST | t.CPtr = iargs.get(0) - icons: str = "" - if iargs.__len__() >= 2: - icons = _resolve_asm_descr(pool, iargs.get(1)) - ival2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, ival_node, None, 0, trans) - if ival2 is None: - continue - operand_count = _asm_add_operand( - operands, operand_count, ival2, icons, 0) - - elif string.strcmp(kw.arg, "op") == 0 or string.strcmp(kw.arg, "clobber") == 0: - # 破坏列表 - if kwk != ast.ASTKind.List: - continue - cl_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) - cl_elts: list[ast.AST | t.CPtr] | t.CPtr = cl_lst.elts - if cl_elts is None: - continue - clen: t.CSizeT = cl_elts.__len__() - for ci in range(clen): - celt: ast.AST | t.CPtr = cl_elts.get(ci) - if celt is None: - continue - cstr: str = _resolve_asm_descr(pool, celt) - if cstr is None or cstr[0] == '\0': - continue - if clobber_count < ASM_MAX_OPERANDS: - cl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8 - cl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(cl_addr, t.CPtr)) - cl_ptr[0] = cstr - clobber_count += 1 - - # ============================================================ - # 3. 解析第二个位置参数作为破坏列表 - # ============================================================ - if cargs.__len__() >= 2: - pos_node: ast.AST | t.CPtr = cargs.get(1) - if pos_node is not None and pos_node.kind() == ast.ASTKind.List: - pos_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(pos_node) - pos_elts: list[ast.AST | t.CPtr] | t.CPtr = pos_lst.elts - if pos_elts is not None: - plen: t.CSizeT = pos_elts.__len__() - for pi in range(plen): - pelt: ast.AST | t.CPtr = pos_elts.get(pi) - if pelt is None: - continue - pstr: str = _resolve_asm_descr(pool, pelt) - if pstr is None or pstr[0] == '\0': - continue - if clobber_count < ASM_MAX_OPERANDS: - pcl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8 - pcl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(pcl_addr, t.CPtr)) - pcl_ptr[0] = pstr - clobber_count += 1 - - # ============================================================ - # 4. 统计输出/输入数量,确定返回类型 - # ============================================================ - output_count: int = 0 - input_count: int = 0 - first_output_idx: int = -1 - for oi2 in range(operand_count): - op2: AsmOperand | t.CPtr = _asm_get_operand(operands, oi2) - if op2.IsOutput != 0: - if first_output_idx < 0: - first_output_idx = oi2 - output_count += 1 - else: - input_count += 1 - - # 确定返回类型 - ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) - if output_count > 0 and first_output_idx >= 0: - out_op: AsmOperand | t.CPtr = _asm_get_operand(operands, first_output_idx) - if out_op.Value is not None and out_op.Value.Ty is not None: - # alloca 的类型是指针,Pointee 是目标类型 - if out_op.Value.Ty.Pointee is not None: - ret_ty = out_op.Value.Ty.Pointee - else: - ret_ty = llvmlite.Int32(pool) - - # 判断 void — 直接基于 output_count 判断,避免 match 类型匹配问题 - is_void: int = 1 - if output_count > 0: - is_void = 0 - - # ============================================================ - # 4.5 重排操作数:输出在前,输入在后(LLVM IR 要求) - # - # new_order[new_idx] = orig_idx — 新位置对应原索引 - # orig_to_new[orig_idx] = new_idx — 原索引映射到新位置(用于占位符编号) - # ============================================================ - new_order: int | t.CPtr = pool.alloc(4 * (operand_count + 1)) - orig_to_new: int | t.CPtr = pool.alloc(4 * (operand_count + 1)) - if new_order is None or orig_to_new is None: - return None - - new_idx: int = 0 - # 先放输出 - for oi3 in range(operand_count): - op3: AsmOperand | t.CPtr = _asm_get_operand(operands, oi3) - if op3.IsOutput != 0: - new_order[new_idx] = oi3 - new_idx += 1 - # 再放输入 - for oi4 in range(operand_count): - op4: AsmOperand | t.CPtr = _asm_get_operand(operands, oi4) - if op4.IsOutput == 0: - new_order[new_idx] = oi4 - new_idx += 1 - # 建立映射 orig -> new - for ni2 in range(operand_count): - orig_to_new[new_order[ni2]] = ni2 - - # ============================================================ - # 4.6 生成汇编文本(第二遍遍历 f-string,用重排后的索引生成占位符) - # 项目约定使用 Intel 语法,通过 IR 的 inteldialect 关键字启用 - # ============================================================ - if tmpl_node is not None: - tk2: int = tmpl_node.kind() - if tk2 == ast.ASTKind.JoinedStr: - js2: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node) - jvalues2: list[ast.AST | t.CPtr] | t.CPtr = js2.values - if jvalues2 is not None: - jvlen2: t.CSizeT = jvalues2.__len__() - fv_fi: int = 0 - for vi2 in range(jvlen2): - part2: ast.AST | t.CPtr = jvalues2.get(vi2) - if part2 is None: - continue - pk2: int = part2.kind() - if pk2 == ast.ASTKind.Constant: - cn3: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part2) - if cn3.const_kind == ast.CONST_STR and cn3.str_val is not None: - _asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn3.str_val) - elif pk2 == ast.ASTKind.FormattedValue: - if fv_fi < fv_count: - orig_idx2: int = fv_orig_indices[fv_fi] - new_idx2: int = orig_to_new[orig_idx2] - ph_buf2: t.CChar | t.CPtr = pool.alloc(16) - if ph_buf2 is not None: - viperlib.snprintf(ph_buf2, 16, "$%d", new_idx2) - _asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, ph_buf2) - fv_fi += 1 - elif tk2 == ast.ASTKind.Constant: - cn4: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(tmpl_node) - if cn4.const_kind == ast.CONST_STR and cn4.str_val is not None: - _asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn4.str_val) - - # ============================================================ - # 5. 构建约束字符串(按重排后的顺序:输出在前,输入在后) - # ============================================================ - const_buf: t.CChar | t.CPtr = pool.alloc(ASM_CONST_BUF_SIZE) - if const_buf is None: - return None - const_buf[0] = '\0' - - first_const: int = 1 - for ci2 in range(operand_count): - orig_i: int = new_order[ci2] - cop: AsmOperand | t.CPtr = _asm_get_operand(operands, orig_i) - cons_val: str = cop.Constraint - if cons_val is None: - cons_val = "r" - - if first_const == 0: - _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",") - first_const = 0 - - if cop.IsOutput != 0: - # 输出约束:确保以 = 开头 - if cons_val[0] != '=': - _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "=") - _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val) - else: - _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val) - - # 追加 clobber 约束 ~{name} - for cidx in range(clobber_count): - cl_addr2: t.CUInt64T = t.CUInt64T(clobbers) + cidx * 8 - cname: str = (str | t.CPtr)(t.CVoid(cl_addr2, t.CPtr))[0] - if cname is None or cname[0] == '\0': - continue - if first_const == 0: - _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",") - first_const = 0 - _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "~{") - _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cname) - _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "}") - - # ============================================================ - # 6. 构建参数列表文本(仅输入操作数) - # ============================================================ - args_buf: t.CChar | t.CPtr = pool.alloc(ASM_ARGS_BUF_SIZE) - if args_buf is None: - return None - args_buf[0] = '\0' - - first_arg: int = 1 - for ai3 in range(operand_count): - orig_i2: int = new_order[ai3] - aop: AsmOperand | t.CPtr = _asm_get_operand(operands, orig_i2) - if aop.IsOutput != 0: - continue - aval: llvmlite.Value | t.CPtr = aop.Value - if aval is None or aval.Ty is None or aval.Name is None: - continue - - if first_arg == 0: - _asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ", ") - first_arg = 0 - - # 类型文本 - ty_buf: t.CChar | t.CPtr = pool.alloc(64) - if ty_buf is not None: - ty_buf[0] = '\0' - llvmlite.TypePrint(ty_buf, 64, aval.Ty, pool) - _asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ty_buf) - _asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, " ") - _asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, aval.Name) - - # ============================================================ - # 7. 转义汇编文本 - # ============================================================ - escaped_asm: t.CChar | t.CPtr = _asm_escape_for_ir(pool, asm_text) - if escaped_asm is None: - return None - - # ============================================================ - # 8. 生成 IR 行并发射 - # ============================================================ - line: t.CChar | t.CPtr = pool.alloc(ASM_LINE_BUF_SIZE) - if line is None: - return None - line[0] = '\0' - - ssa_name: t.CChar | t.CPtr = None - if is_void == 0: - ssa_name = pool.alloc(16) - if ssa_name is not None: - viperlib.snprintf(ssa_name, 16, "%%%d", builder.Counter) - builder.Counter += 1 - - # 获取返回类型文本 - ret_ty_buf: t.CChar | t.CPtr = pool.alloc(64) - if ret_ty_buf is not None: - ret_ty_buf[0] = '\0' - llvmlite.TypePrint(ret_ty_buf, 64, ret_ty, pool) - - if is_void == 1: - viperlib.snprintf(line, ASM_LINE_BUF_SIZE, - "call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)", - ret_ty_buf, escaped_asm, const_buf, args_buf) - else: - viperlib.snprintf(line, ASM_LINE_BUF_SIZE, - "%s = call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)", - ssa_name, ret_ty_buf, escaped_asm, const_buf, args_buf) - - # 发射 IR 到当前块 - llvmlite.block_append_text(pool, builder.CurBlock, line) - - # ============================================================ - # 9. 处理输出:存储结果到输出变量 - # ============================================================ - if is_void == 0 and first_output_idx >= 0: - result_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, ret_ty, ssa_name) - out_op2: AsmOperand | t.CPtr = _asm_get_operand(operands, first_output_idx) - if out_op2.Value is not None: - llvmlite.build_store(builder, result_val, out_op2.Value) - return result_val - - return None - -# ============================================================ -# c.LLVMIR — 内联 LLVM IR 支持 -# -# 语法: -# c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) -# c.LLVMIR(f"%{c.LOut(result)} = add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) -# -# c.LInp(expr) - 输入操作数,翻译后替换为对应的 LLVM 值 -# c.LOut(expr) - 输出操作数,翻译后结果存储到该变量 -# -# 支持的指令: add/sub/mul/sdiv/udiv/srem/urem/and/or/xor/shl/lshr/ashr -# fadd/fsub/fmul/fdiv -# icmp eq/ne/sgt/sge/slt/sle/ugt/uge/ult/ule -# fcmp oeq/one/olt/ogt/ole/oge -# zext/sext/trunc/bitcast/ptrtoint/inttoptr -# load/store -# ============================================================ - -LLVMIR_MAX_OPS: t.CDefine = 16 -LLVMIR_TEMPLATE_BUF: t.CDefine = 512 - -# ============================================================ -# _llvmir_get_op — 获取第 i 个 AsmOperand 槽位 -# ============================================================ -def _llvmir_get_op(buf: AsmOperand | t.CPtr, i: int) -> AsmOperand | t.CPtr: - """获取第 i 个操作数槽位""" - entry_size: t.CSizeT = AsmOperand.__sizeof__() - entry_addr: t.CUInt64T = t.CUInt64T(buf) + i * entry_size - return (AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - -# ============================================================ -# _llvmir_find_op_marker — 在字符串中查找 %__OP 并返回编号 -# -# 返回 (位置, 编号),未找到返回 (None, 0) -# ============================================================ -def _llvmir_find_op_marker(s: t.CChar | t.CPtr) -> t.CPtr: - """查找 %__OP 标记,返回标记开始位置或 None""" - if s is None: - return None - return string.strstr(s, "%__OP") - -# ============================================================ -# _llvmir_parse_op_num — 从 %__OPN__ 中解析编号 N -# -# 输入: 指向 "%__OP" 的指针 -# 返回: 操作数编号 -# ============================================================ -def _llvmir_parse_op_num(marker: t.CChar | t.CPtr) -> int: - """从 %__OPN__ 标记中解析编号 N""" - if marker is None: - return -1 - # 跳过 "%__OP" (5 字符) - num_start: t.CChar | t.CPtr = marker + 5 - if num_start is None: - return -1 - # 解析数字直到 "__" - num: int = 0 - i: t.CSizeT = 0 - ch: t.CChar = num_start[0] - while '0' <= ch <= '9': - num = num * 10 + (ch - '0') - i += 1 - ch = num_start[i] - return num - -# ============================================================ -# _llvmir_match_icmp_pred — 将预测字符串转为 ICMP 常量 -# ============================================================ -def _llvmir_match_icmp_pred(pred: str) -> int: - """将 icmp 预测字符串转为常量""" - if pred is None: - return 0 - if string.strcmp(pred, "eq") == 0: - return 0 - if string.strcmp(pred, "ne") == 0: - return 1 - if string.strcmp(pred, "sgt") == 0: - return 2 - if string.strcmp(pred, "sge") == 0: - return 3 - if string.strcmp(pred, "slt") == 0: - return 4 - if string.strcmp(pred, "sle") == 0: - return 5 - if string.strcmp(pred, "ugt") == 0: - return 6 - if string.strcmp(pred, "uge") == 0: - return 7 - if string.strcmp(pred, "ult") == 0: - return 8 - if string.strcmp(pred, "ule") == 0: - return 9 - return 0 - -# ============================================================ -# _llvmir_match_fcmp_pred — 将预测字符串转为 FCMP 常量 -# ============================================================ -def _llvmir_match_fcmp_pred(pred: str) -> int: - """将 fcmp 预测字符串转为常量""" - if pred is None: - return 0 - if string.strcmp(pred, "oeq") == 0: - return 0 - if string.strcmp(pred, "ogt") == 0: - return 1 - if string.strcmp(pred, "oge") == 0: - return 2 - if string.strcmp(pred, "olt") == 0: - return 3 - if string.strcmp(pred, "ole") == 0: - return 4 - if string.strcmp(pred, "one") == 0: - return 5 - if string.strcmp(pred, "ord") == 0: - return 6 - if string.strcmp(pred, "uno") == 0: - return 7 - if string.strcmp(pred, "ueq") == 0: - return 8 - if string.strcmp(pred, "ugt") == 0: - return 9 - if string.strcmp(pred, "uge") == 0: - return 10 - if string.strcmp(pred, "ult") == 0: - return 11 - if string.strcmp(pred, "ule") == 0: - return 12 - if string.strcmp(pred, "une") == 0: - return 13 - return 0 - -# ============================================================ -# _llvmir_extract_two_ops — 从模板中提取两个操作数编号 -# -# 通过输出参数返回 op1_num 和 op2_num -# ============================================================ -def _llvmir_extract_two_ops(template: t.CChar | t.CPtr, - out_nums: int | t.CPtr) -> int: - """从模板中提取前两个 %__OP 标记的编号 - - 结果写入 out_nums[0] 和 out_nums[1] - 返回 1 成功, 0 失败 - """ - out_nums[0] = -1 - out_nums[1] = -1 - m1: t.CChar | t.CPtr = _llvmir_find_op_marker(template) - if m1 is None: - return 0 - out_nums[0] = _llvmir_parse_op_num(m1) - - # 跳过第一个标记 "%__OPN__" - next_pos: t.CChar | t.CPtr = m1 + 5 # 跳过 "%__OP" - i: t.CSizeT = 0 - while next_pos[i] >= '0' and next_pos[i] <= '9': - i += 1 - next_pos = next_pos + i + 2 - - m2: t.CChar | t.CPtr = _llvmir_find_op_marker(next_pos) - if m2 is None: - return 1 - out_nums[1] = _llvmir_parse_op_num(m2) - return 1 - -# ============================================================ -# _llvmir_resolve_op — 根据编号解析操作数值 -# ============================================================ -def _llvmir_resolve_op(op_num: int, - all_kinds: int | t.CPtr, - all_indices: int | t.CPtr, - input_ops: AsmOperand | t.CPtr, - output_targets: AsmOperand | t.CPtr) -> llvmlite.Value | t.CPtr: - """根据操作数编号解析实际 Value""" - if op_num < 0 or op_num >= LLVMIR_MAX_OPS: - return None - kind: int = all_kinds[op_num] - idx: int = all_indices[op_num] - if kind == 0: - # 输入操作数 - op: AsmOperand | t.CPtr = _llvmir_get_op(input_ops, idx) - return op.Value - else: - # 输出操作数 - op2: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, idx) - return op2.Value - -# ============================================================ -# _llvmir_store_outputs — 将结果存储到输出变量 -# ============================================================ -def _llvmir_store_outputs(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - result: llvmlite.Value | t.CPtr, - output_targets: AsmOperand | t.CPtr, - output_count: int) -> llvmlite.Value | t.CPtr: - """将结果存储到所有输出变量""" - if output_count == 0: - return result - for oi in range(output_count): - op: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, oi) - if op.Value is not None and result is not None: - llvmlite.build_store(builder, result, op.Value) - return result - -# ============================================================ -# translate_c_llvmir — 翻译 c.LLVMIR 内联 LLVM IR -# ============================================================ -def translate_c_llvmir(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译 c.LLVMIR 内联 LLVM IR,返回结果 Value""" - if cl is None: - return None - - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cargs is None or cargs.__len__() < 1: - return None - - # 分配操作数数组 - op_size: t.CSizeT = AsmOperand.__sizeof__() - input_ops: AsmOperand | t.CPtr = pool.alloc(op_size * LLVMIR_MAX_OPS) - output_targets: AsmOperand | t.CPtr = pool.alloc(op_size * LLVMIR_MAX_OPS) - if input_ops is None or output_targets is None: - return None - string.memset(input_ops, 0, op_size * LLVMIR_MAX_OPS) - string.memset(output_targets, 0, op_size * LLVMIR_MAX_OPS) - - # all_ops 映射: kinds[i]=0(inp)/1(out), indices[i]=在对应数组中的索引 - all_kinds: int | t.CPtr = pool.alloc(4 * LLVMIR_MAX_OPS) - all_indices: int | t.CPtr = pool.alloc(4 * LLVMIR_MAX_OPS) - if all_kinds is None or all_indices is None: - return None - string.memset(all_kinds, 0, 4 * LLVMIR_MAX_OPS) - string.memset(all_indices, 0, 4 * LLVMIR_MAX_OPS) - - input_count: int = 0 - output_count: int = 0 - op_seq: int = 0 - - # 分配模板缓冲区 - template: t.CChar | t.CPtr = pool.alloc(LLVMIR_TEMPLATE_BUF) - if template is None: - return None - template[0] = '\0' - - # 解析返回类型(默认 i32) - ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if cargs.__len__() >= 2: - ret_type_node: ast.AST | t.CPtr = cargs.get(1) - if ret_type_node is not None: - resolved_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, ret_type_node, trans._imported_modules, trans._from_imports, trans) - if resolved_ty is not None: - ret_ty = resolved_ty - - # ============================================================ - # 1. 解析 IR 模板(JoinedStr 或 Constant)— 收集操作数 - # ============================================================ - first_arg: ast.AST | t.CPtr = cargs.get(0) - if first_arg is None: - return None - - tk: int = first_arg.kind() - - if tk == ast.ASTKind.JoinedStr: - js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(first_arg) - jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values - if jvalues is not None: - jvlen: t.CSizeT = jvalues.__len__() - for vi in range(jvlen): - part: ast.AST | t.CPtr = jvalues.get(vi) - if part is None: - continue - pk: int = part.kind() - - if pk == ast.ASTKind.Constant: - # 字符串字面量片段 - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part) - if cn.str_val is not None: - _asm_append_cstr(template, LLVMIR_TEMPLATE_BUF, cn.str_val) - - elif pk == ast.ASTKind.FormattedValue: - fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part) - fexpr: ast.AST | t.CPtr = fv.value - if fexpr is None or fexpr.kind() != ast.ASTKind.Call: - continue - fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr) - attr_nm: str = _asm_is_c_call(fcall) - if attr_nm is None: - # 非 c.LInp/c.LOut 调用,作为普通输入处理 - ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, fexpr, None, 0, trans) - if ival is not None and input_count < LLVMIR_MAX_OPS: - op_in: AsmOperand | t.CPtr = _llvmir_get_op(input_ops, input_count) - op_in.Value = ival - all_kinds[op_seq] = 0 - all_indices[op_seq] = input_count - input_count += 1 - op_seq += 1 - # 追加占位符 - viperlib.snprintf( - template + string.strlen(template), - LLVMIR_TEMPLATE_BUF - string.strlen(template), - "%%__OP%d__", op_seq - 1) - continue - - # 处理 c.LInp / c.LOut - fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args - if fargs is None or fargs.__len__() < 1: - continue - val_node: ast.AST | t.CPtr = fargs.get(0) - - if string.strcmp(attr_nm, "LInp") == 0: - # 输入操作数:翻译值 - inp_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, val_node, None, 0, trans) - if inp_val is not None and input_count < LLVMIR_MAX_OPS: - op_inp: AsmOperand | t.CPtr = _llvmir_get_op(input_ops, input_count) - op_inp.Value = inp_val - all_kinds[op_seq] = 0 - all_indices[op_seq] = input_count - input_count += 1 - op_seq += 1 - viperlib.snprintf( - template + string.strlen(template), - LLVMIR_TEMPLATE_BUF - string.strlen(template), - "%%__OP%d__", op_seq - 1) - - elif string.strcmp(attr_nm, "LOut") == 0: - # 输出操作数:获取变量 alloca - if val_node is not None and val_node.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node) - if nm.id is not None: - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is not None and output_count < LLVMIR_MAX_OPS: - op_out: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, output_count) - op_out.Value = alloca - all_kinds[op_seq] = 1 - all_indices[op_seq] = output_count - output_count += 1 - op_seq += 1 - viperlib.snprintf( - template + string.strlen(template), - LLVMIR_TEMPLATE_BUF - string.strlen(template), - "%%__OP%d__", op_seq - 1) - - elif tk == ast.ASTKind.Constant: - cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(first_arg) - if cn2.str_val is not None: - string.strcpy(template, cn2.str_val) - - # ============================================================ - # 2. 解析模板并生成 LLVM 指令 - # ============================================================ - - # 检查是否为赋值形式: %__OPN__ = <指令> - # 如果是,去掉赋值前缀,记录输出操作数编号 - assign_out_num: int = -1 - assign_marker: t.CChar | t.CPtr = _llvmir_find_op_marker(template) - if assign_marker is not None and assign_marker == template: - # 模板以 %__OP 开头 - # 查找 "=" 号 - eq_pos: t.CChar | t.CPtr = string.strchr(template, 61) # '=' = 61 - if eq_pos is not None: - # 确认 "%__OPN__ = " 格式 - assign_out_num = _llvmir_parse_op_num(assign_marker) - # 跳过 "%__OP__ = " 到实际指令开始 - # 找到 "=" 后第一个非空格字符 - instr_start: t.CChar | t.CPtr = eq_pos + 1 - while instr_start[0] == ' ' or instr_start[0] == '\t': - instr_start += 1 - # 将剩余部分复制到新模板 - tmpl2: t.CChar | t.CPtr = pool.alloc(LLVMIR_TEMPLATE_BUF) - if tmpl2 is not None: - string.strcpy(tmpl2, instr_start) - template = tmpl2 - - # 去除前导空格 - while template[0] == ' ' or template[0] == '\t': - template += 1 - - # 提取指令关键字(第一个单词) - instr_kw: t.CChar | t.CPtr = pool.alloc(32) - if instr_kw is None: - return None - instr_kw[0] = '\0' - ki: t.CSizeT = 0 - while template[ki] != ' ' and template[ki] != '\t' and template[ki] != '\0' and ki < 31: - instr_kw[ki] = template[ki] - ki += 1 - instr_kw[ki] = '\0' - - # ============================================================ - # 二元运算: add/sub/mul/sdiv/udiv/srem/urem/and/or/xor/shl/lshr/ashr - # ============================================================ - binop_result: llvmlite.Value | t.CPtr = None - - # 提取两个操作数编号 - op_nums: int | t.CPtr = pool.alloc(8) - if op_nums is not None: - string.memset(op_nums, 0, 8) - _llvmir_extract_two_ops(template, op_nums) - op1_num: int = -1 - op2_num: int = -1 - if op_nums is not None: - op1_num = op_nums[0] - op2_num = op_nums[1] - - lhs: llvmlite.Value | t.CPtr = _llvmir_resolve_op( - op1_num, all_kinds, all_indices, input_ops, output_targets) - rhs: llvmlite.Value | t.CPtr = _llvmir_resolve_op( - op2_num, all_kinds, all_indices, input_ops, output_targets) - - if lhs is not None and rhs is not None: - if string.strcmp(instr_kw, "add") == 0: - binop_result = llvmlite.build_add(builder, lhs, rhs) - elif string.strcmp(instr_kw, "sub") == 0: - binop_result = llvmlite.build_sub(builder, lhs, rhs) - elif string.strcmp(instr_kw, "mul") == 0: - binop_result = llvmlite.build_mul(builder, lhs, rhs) - elif string.strcmp(instr_kw, "sdiv") == 0: - binop_result = llvmlite.build_sdiv(builder, lhs, rhs) - elif string.strcmp(instr_kw, "udiv") == 0: - binop_result = llvmlite.build_udiv(builder, lhs, rhs) - elif string.strcmp(instr_kw, "srem") == 0: - binop_result = llvmlite.build_srem(builder, lhs, rhs) - elif string.strcmp(instr_kw, "urem") == 0: - binop_result = llvmlite.build_urem(builder, lhs, rhs) - elif string.strcmp(instr_kw, "and") == 0: - binop_result = llvmlite.build_and(builder, lhs, rhs) - elif string.strcmp(instr_kw, "or") == 0: - binop_result = llvmlite.build_or(builder, lhs, rhs) - elif string.strcmp(instr_kw, "xor") == 0: - binop_result = llvmlite.build_xor(builder, lhs, rhs) - elif string.strcmp(instr_kw, "shl") == 0: - binop_result = llvmlite.build_shl(builder, lhs, rhs) - elif string.strcmp(instr_kw, "lshr") == 0: - binop_result = llvmlite.build_lshr(builder, lhs, rhs) - elif string.strcmp(instr_kw, "ashr") == 0: - binop_result = llvmlite.build_ashr(builder, lhs, rhs) - elif string.strcmp(instr_kw, "fadd") == 0: - binop_result = llvmlite.build_fadd(builder, lhs, rhs) - elif string.strcmp(instr_kw, "fsub") == 0: - binop_result = llvmlite.build_fsub(builder, lhs, rhs) - elif string.strcmp(instr_kw, "fmul") == 0: - binop_result = llvmlite.build_fmul(builder, lhs, rhs) - elif string.strcmp(instr_kw, "fdiv") == 0: - binop_result = llvmlite.build_fdiv(builder, lhs, rhs) - - # ============================================================ - # icmp 比较: icmp %__OP0__, %__OP1__ - # ============================================================ - if binop_result is None and string.strcmp(instr_kw, "icmp") == 0: - # 提取预测(第二个单词) - pred_start: t.CChar | t.CPtr = template + ki + 1 - while pred_start[0] == ' ' or pred_start[0] == '\t': - pred_start += 1 - pred_str: t.CChar | t.CPtr = pool.alloc(16) - if pred_str is not None: - pred_str[0] = '\0' - pi: t.CSizeT = 0 - while pred_start[pi] != ' ' and pred_start[pi] != '\t' and pred_start[pi] != '\0' and pi < 15: - pred_str[pi] = pred_start[pi] - pi += 1 - pred_str[pi] = '\0' - pred_val: int = _llvmir_match_icmp_pred(pred_str) - if lhs is not None and rhs is not None: - binop_result = llvmlite.build_icmp(builder, pred_val, lhs, rhs) - - # ============================================================ - # fcmp 比较: fcmp %__OP0__, %__OP1__ - # ============================================================ - if binop_result is None and string.strcmp(instr_kw, "fcmp") == 0: - pred_start2: t.CChar | t.CPtr = template + ki + 1 - while pred_start2[0] == ' ' or pred_start2[0] == '\t': - pred_start2 += 1 - pred_str2: t.CChar | t.CPtr = pool.alloc(16) - if pred_str2 is not None: - pred_str2[0] = '\0' - pi2: t.CSizeT = 0 - while pred_start2[pi2] != ' ' and pred_start2[pi2] != '\t' and pred_start2[pi2] != '\0' and pi2 < 15: - pred_str2[pi2] = pred_start2[pi2] - pi2 += 1 - pred_str2[pi2] = '\0' - pred_val2: int = _llvmir_match_fcmp_pred(pred_str2) - if lhs is not None and rhs is not None: - binop_result = llvmlite.build_fcmp(builder, pred_val2, lhs, rhs) - - # ============================================================ - # store 指令: store %__OP0__, %__OP1__ - # ============================================================ - if binop_result is None and string.strcmp(instr_kw, "store") == 0: - if lhs is not None and rhs is not None: - llvmlite.build_store(builder, lhs, rhs) - return None - - # ============================================================ - # load 指令: load , %__OP0__ - # ============================================================ - if binop_result is None and string.strcmp(instr_kw, "load") == 0: - if lhs is not None: - # 从指针加载,类型由 ret_ty 指定 - binop_result = llvmlite.build_load(builder, ret_ty, lhs) - - # ============================================================ - # 类型转换: zext/sext/trunc/bitcast/ptrtoint/inttoptr - # ============================================================ - if binop_result is None: - if string.strcmp(instr_kw, "zext") == 0: - if lhs is not None: - binop_result = llvmlite.build_zext(builder, lhs, ret_ty) - elif string.strcmp(instr_kw, "sext") == 0: - if lhs is not None: - binop_result = llvmlite.build_sext(builder, lhs, ret_ty) - elif string.strcmp(instr_kw, "trunc") == 0: - if lhs is not None: - binop_result = llvmlite.build_trunc(builder, lhs, ret_ty) - elif string.strcmp(instr_kw, "bitcast") == 0: - if lhs is not None: - binop_result = llvmlite.build_bitcast(builder, lhs, ret_ty) - elif string.strcmp(instr_kw, "ptrtoint") == 0: - if lhs is not None: - binop_result = llvmlite.build_ptrtoint(builder, lhs, ret_ty) - elif string.strcmp(instr_kw, "inttoptr") == 0: - if lhs is not None: - binop_result = llvmlite.build_inttoptr(builder, lhs, ret_ty) - - # ============================================================ - # 3. 处理输出 - # ============================================================ - if binop_result is not None: - # 如果有赋值形式(%__OPN__ = ...),存储到对应输出 - if assign_out_num >= 0: - target: llvmlite.Value | t.CPtr = _llvmir_resolve_op( - assign_out_num, all_kinds, all_indices, input_ops, output_targets) - if target is not None: - llvmlite.build_store(builder, binop_result, target) - - # 存储到所有输出操作数 - _llvmir_store_outputs(pool, builder, binop_result, output_targets, output_count) - return binop_result - - # 未识别的指令,返回 0 - fb_li: t.CChar | t.CPtr = VLogger.fmt_buf() - if fb_li is not None: - viperlib.snprintf(fb_li, 1024, "unsupported instruction: %s", instr_kw) - VLogger.error(fb_li, "LLVMIR") - return None - -# ============================================================ -# _apply_struct_defaults — 应用结构体字段的默认值 -# -# 在 zeroinitializer 之后、显式参数之前调用 -# 遍历所有字段,对有默认值的字段翻译并 store -# 显式参数(位置/关键字)后续会覆盖默认值 -# ============================================================ -def _apply_struct_defaults(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str, - tmp: llvmlite.Value | t.CPtr, - trans: HT.Translator | t.CPtr): - """应用结构体字段的默认值""" - # 用类型指针定位 entry,规避跨模块同名 find_struct 找错 - entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) - if entry is None: - # fast-fail: 结构体类型未注册,静默 return 会导致字段未初始化 - VLogger.error( - f"结构体类型未注册,无法应用默认值: {class_name}", - "HandlesExprCall") - return - for fi in range(entry.FieldCount): - fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( - entry, fi) - if fe is None: - # fast-fail: 字段索引越界(entry.FieldCount 与实际不一致) - VLogger.error( - f"字段索引越界,无法获取字段 entry: {class_name}", - "HandlesExprCall") - continue - if fe.DefaultVal is None: - continue # 合理跳过:无默认值的字段 - default_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, fe.DefaultVal, None, 0, trans) - if default_val is None: - # fast-fail: 默认值翻译失败(如引用了未定义符号) - VLogger.error( - f"字段默认值翻译失败: {class_name}", - "HandlesExprCall") - continue - field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, fe.Ty, tmp, fe.Index) - if field_ptr is None: - # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) - VLogger.error( - f"字段 GEP 失败,类型不匹配: {class_name}", - "HandlesExprCall") - continue - default_val = HandlesExpr.coerce_to_type(builder, default_val, fe.Ty) - llvmlite.build_store(builder, default_val, field_ptr) - -# ============================================================ -# _translate_struct_ctor — 结构体构造函数 Point(10, 20) -# -# 生成: -# %tmp = alloca {i32, i32} -# store {i32, i32} zeroinitializer, {i32, i32}* %tmp -# %f0 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 0 -# store i32 10, i32* %f0 -# %f1 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 1 -# store i32 20, i32* %f1 -# %result = load {i32, i32}, {i32, i32}* %tmp -# ============================================================ -def _translate_struct_ctor(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """结构体构造函数:按字段顺序 store 参数值,返回结构体值 - - OOP 结构体:alloca → call __before_init__(ptr) → call __init__(ptr, args) 或 store 参数 → load - 普通结构体:alloca → zero + defaults → store 参数 → load - """ - # 创建临时 alloca - # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) - HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) - tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) - if tmp is None: - return llvmlite.ConstZero(pool, struct_ty) - - # 检查是否为 OOP 结构体(用类型指针定位 entry,规避跨模块同名 find_struct 找错) - ctor_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) - is_oop: int = 0 - if ctor_entry is not None: - is_oop = ctor_entry.IsOOP - - # 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods) - # 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入) - # 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠) - if is_oop == 0 and class_name is not None: - init_lookup_name: t.CChar | t.CPtr = pool.alloc(128) - if init_lookup_name is not None: - viperlib.snprintf(init_lookup_name, 128, "%s.__init__", class_name) - # 方案1: 检查当前模块的函数声明 - init_found_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, init_lookup_name) - if init_found_func is not None: - is_oop = 1 - if ctor_entry is not None: - ctor_entry.IsOOP = 1 - ctor_entry.HasInit = 1 - else: - # 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入) - init_defaults_entry: FuncDefaultsEntry | t.CPtr = find_func_defaults(init_lookup_name) - if init_defaults_entry is not None: - is_oop = 1 - if ctor_entry is not None: - ctor_entry.IsOOP = 1 - ctor_entry.HasInit = 1 - - if is_oop != 0: - # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 - storage_ptr: llvmlite.Value | t.CPtr = tmp - - # 如果有 __new__,调用 __new__(tmp, args...) 获取实际存储指针 - # __new__ 签名与 __init__ 一样(self + args),返回 Ptr(struct_ty) - has_new_flag: int = 0 - if ctor_entry is not None: - has_new_flag = ctor_entry.HasNew - # 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法) - if has_new_flag != 0: - new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if new_arg_vals is not None: - string.memset(new_arg_vals, 0, 8 * 32) - new_arg_count: int = 0 - for nai in range(can): - new_arg_node: ast.AST | t.CPtr = cargs.get(nai) - if new_arg_node is None: - continue - new_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, new_arg_node, None, 0, trans) - if new_av is not None: - if new_arg_count < 32: - new_arg_vals[new_arg_count] = t.CSizeT(new_av) - new_arg_count += 1 - - new_ptr: llvmlite.Value | t.CPtr = _call_method_on_ptr( - pool, builder, mod, class_name, - "__new__", tmp, new_arg_vals, new_arg_count, trans) - if new_ptr is not None: - storage_ptr = new_ptr - - # OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值 - _call_method_on_ptr(pool, builder, mod, class_name, - "__before_init__", storage_ptr, None, 0, trans) - - # 如果有 __init__,调用 __init__(ptr, args...) - # 注意: 仅依据 ctor_entry.HasInit 判断,不强制推断 - # (JsonValue 等类有 __new__ 但无 __init__,强制推断会导致 undefined reference) - has_init_flag: int = 0 - if ctor_entry is not None: - has_init_flag = ctor_entry.HasInit - if has_init_flag != 0: - # 翻译构造函数参数 - arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if arg_vals is not None: - string.memset(arg_vals, 0, 8 * 32) - real_arg_count: int = 0 - for ai in range(can): - arg_node: ast.AST | t.CPtr = cargs.get(ai) - if arg_node is None: - continue - av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg_node, None, 0, trans) - if av is not None: - if real_arg_count < 32: - arg_vals[real_arg_count] = t.CSizeT(av) - real_arg_count += 1 - - _call_method_on_ptr(pool, builder, mod, class_name, - "__init__", storage_ptr, arg_vals, real_arg_count, trans) - elif has_new_flag == 0: - # 无 __init__ 且无 __new__:逐字段 store 参数值 - # (有 __new__ 时参数已由 __new__ 消费,不应存入字段) - for ai in range(can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is None: - continue - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is None: - # fast-fail: 参数翻译失败 - VLogger.error( - f"构造函数参数翻译失败: {class_name}", - "HandlesExprCall") - continue - fe: HandlesStruct.FieldEntry | t.CPtr = None - if ctor_entry is not None: - fe = HandlesStruct._get_field_entry(ctor_entry, ai) - else: - fe = HandlesStruct.get_field_by_index(class_name, ai) - if fe is None: - # fast-fail: 字段索引越界(用户传了多余参数) - VLogger.error( - f"构造函数参数过多,字段索引越界: {class_name}", - "HandlesExprCall") - continue - field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, fe.Ty, storage_ptr, fe.Index) - if field_ptr is None: - # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) - VLogger.error( - f"构造函数字段 GEP 失败: {class_name}", - "HandlesExprCall") - continue - arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty) - llvmlite.build_store(builder, arg_val, field_ptr) - - # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load - return storage_ptr - - # 普通结构体:先 store zeroinitializer 清零(确保未赋值字段为零) - zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) - llvmlite.build_store(builder, zero, tmp) - - # 应用默认值(显式参数会覆盖默认值) - _apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans) - - # 逐字段 store 参数值(覆盖默认值) - for ai in range(can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is None: - continue - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is None: - # fast-fail: 参数翻译失败 - VLogger.error( - f"构造函数参数翻译失败: {class_name}", - "HandlesExprCall") - continue - # 获取字段信息(用 ctor_entry 规避跨模块同名 find_struct 找错) - fe: HandlesStruct.FieldEntry | t.CPtr = None - if ctor_entry is not None: - fe = HandlesStruct._get_field_entry(ctor_entry, ai) - else: - fe = HandlesStruct.get_field_by_index(class_name, ai) - if fe is None: - # fast-fail: 字段索引越界(用户传了多余参数) - VLogger.error( - f"构造函数参数过多,字段索引越界: {class_name}", - "HandlesExprCall") - continue - # GEP 到字段 ai - field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, fe.Ty, tmp, fe.Index) - if field_ptr is None: - # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) - VLogger.error( - f"构造函数字段 GEP 失败: {class_name}", - "HandlesExprCall") - continue - # 类型转换并 store - arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty) - 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 声明 - - 若模块中已存在同名 declare 且参数数量较少(例如 File.__init__ 的 - stub 仅 3 个参数,而实际调用传入 4 个),则向现有 declare 追加缺失 - 参数,避免 llc 报 `argument invalid for parameter type` 之类的错误。 - 已存在的 define 不修改(其参数由定义决定)。 - """ - if pool is None or mod is None or call_name is None: - return - # 检查模块中是否已有同名函数(declare 或 define) - existing: llvmlite.Function | t.CPtr = mod.FuncHead - while existing is not None: - if existing.Name is not None: - if string.strcmp(existing.Name, call_name) == 0: - # 已存在:仅当是 declare 且参数数量不足时追加缺失参数 - if existing.IsDeclared == 1: - # 遍历现有参数链表计数(避免依赖 GSList.Count 字段的类型推断) - cur_count: int = 0 - cur_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(existing) - while cur_p is not None: - cur_count += 1 - cur_p = cur_p.Next - # 只追加缺失的参数(cur_count < param_count 时) - if cur_count < param_count: - # 定位到 param_head 的第 cur_count 个节点开始追加 - pnode2: llvmlite.ParamNode | t.CPtr = param_head - pi2: int = 0 - # 跳过已有的 cur_count 个参数 - while pnode2 is not None and pi2 < cur_count: - pnode2 = pnode2.Next - pi2 += 1 - # 追加剩余参数 - while pnode2 is not None and pi2 < param_count: - if pnode2.Ty is not None: - param2: llvmlite.Param | t.CPtr = llvmlite.new_param(pool, pnode2.Ty, None) - if param2 is not None: - llvmlite.function_add_param(existing, param2) - pnode2 = pnode2.Next - pi2 += 1 - return - existing = existing.Next - # 创建函数声明 - func: llvmlite.Function | t.CPtr = llvmlite.new_function(pool, call_name, ret_ty) - if func is None: - return - func.IsDeclared = 1 - # 添加参数(declare 中参数名无意义,设为 None 只输出类型) - pnode: llvmlite.ParamNode | t.CPtr = param_head - pi: int = 0 - while pnode is not None and pi < param_count: - if pnode.Ty is not None: - param: llvmlite.Param | t.CPtr = llvmlite.new_param(pool, pnode.Ty, None) - if param is not None: - llvmlite.function_add_param(func, param) - pnode = pnode.Next - pi += 1 - llvmlite.module_add_function(mod, func) - - -# ============================================================ -# _infer_method_ret_ty - 根据方法名推断返回类型 -# -# stub 未注入时,find_func_in_module 返回 None, -# 需要根据方法名推断返回类型避免指针被截断为 i32。 -# ============================================================ -def _infer_method_ret_ty(pool: memhub.MemBuddy | t.CPtr, - method_name: str) -> llvmlite.LLVMType | t.CPtr: - """根据方法名推断返回类型(stub 未注入时的回退方案)""" - if pool is None or method_name is None: - return llvmlite.Int32(pool) - - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - - # 返回 i8* 的方法(分配/返回指针) - if string.strcmp(method_name, "alloc") == 0: - return i8_ptr_ty - if string.strcmp(method_name, "calloc") == 0: - return i8_ptr_ty - if string.strcmp(method_name, "realloc") == 0: - return i8_ptr_ty - if string.strcmp(method_name, "alloc_buf") == 0: - return i8_ptr_ty - if string.strcmp(method_name, "_fl_pop") == 0: - return i8_ptr_ty - if string.strcmp(method_name, "_buddy_of") == 0: - return i8_ptr_ty - if string.strcmp(method_name, "_split_to_order") == 0: - return i8_ptr_ty - if string.strcmp(method_name, "__enter__") == 0: - return i8_ptr_ty - # 工厂方法:返回对象指针(截断会导致后续方法调用崩溃) - if string.strcmp(method_name, "parse_args") == 0: - return i8_ptr_ty - # 魔术方法:返回对象指针(如 JsonValue.__getitem__ 返回 JsonValue*) - if string.strcmp(method_name, "__getitem__") == 0: - return i8_ptr_ty - - # 返回 i8* 的方法(返回字符串/类型名/描述) - if string.strcmp(method_name, "type_name") == 0: - return i8_ptr_ty - if string.strcmp(method_name, "get_name") == 0: - return i8_ptr_ty - if string.strcmp(method_name, "get_str") == 0: - return i8_ptr_ty - if string.strcmp(method_name, "get_path") == 0: - return i8_ptr_ty - if string.strcmp(method_name, "get_buf") == 0: - return i8_ptr_ty - if string.strcmp(method_name, "to_string") == 0: - return i8_ptr_ty - if string.strcmp(method_name, "as_string") == 0: - return i8_ptr_ty - if string.strcmp(method_name, "__repr__") == 0: - return i8_ptr_ty - if string.strcmp(method_name, "__str__") == 0: - return i8_ptr_ty - # 返回 i8* 的方法(返回对象指针,如 JsonValue.get_item → JsonValue*) - if string.strcmp(method_name, "get_item") == 0: - return i8_ptr_ty - - # 返回 void 的方法 - if string.strcmp(method_name, "__before_init__") == 0: - return llvmlite.Void(pool) - if string.strcmp(method_name, "__init__") == 0: - return llvmlite.Void(pool) - if string.strcmp(method_name, "__exit__") == 0: - return llvmlite.Void(pool) - - # 默认 i32(整数):与本模块函数定义的默认返回类型一致(HandlesFunctions.py line 324) - # 已知返回指针的方法在上方显式列出(返回 i8*),已知返回 void 的方法也显式列出 - # 避免使用 i64 导致 stub 声明(declare i64)与实际定义(define i32)类型不匹配 - # x86-64 ABI 中 i32 返回值在 rax 低 32 位,与 define i32 完全一致 - # 与 _infer_external_func_ret_ty 的默认策略保持一致 - # WARNING: 未登记的方法返回类型默认推断为 i32,若实际返回指针/i64 会被截断 - VLogger.warning( - f"方法返回类型未登记,默认推断为 i32(可能截断指针/i64): {method_name}", - "HandlesExprCall") - return llvmlite.Int32(pool) - - -# ============================================================ -# 跨模块方法返回类型查找(从 text.ll) -# -# Phase A 翻译每个源文件后生成 text.ll,其中 define 行包含 -# 方法的实际返回类型。当 Phase A 翻译后续文件调用跨模块方法时, -# _infer_method_ret_ty 默认返回 i32,导致指针返回值被截断。 -# _LookupMethodRetTyFromTextLL 读取依赖模块的 text.ll,从 define -# 行提取实际返回类型,避免指针截断。 -# ============================================================ - -_g_temp_dir: str = None -_g_temp_dir_len: t.CSizeT = 0 - -# text.ll 读取缓冲区大小 -_TEXT_LL_READ_BUF_SIZE: t.CDefine = 262144 - - -# ============================================================ -# SetTempDir - 设置 temp 目录路径 -# -# 在 Phase2.py 的 Phase A 翻译前调用,使 HandlesExprCall -# 能够读取依赖模块的 text.ll 文件。 -# ============================================================ -def SetTempDir(temp_dir: str): - """设置 temp 目录路径(供跨模块方法返回类型查找使用)""" - global _g_temp_dir - global _g_temp_dir_len - _g_temp_dir = temp_dir - if temp_dir is not None: - _g_temp_dir_len = string.strlen(temp_dir) - else: - _g_temp_dir_len = 0 - - -# ============================================================ -# _ParseLLVMRetTyStr - 将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType -# -# 从 define 行中提取的返回类型字符串(define 与 @ 之间的内容), -# 转换为 llvmlite.LLVMType 对象。 -# -# 支持的类型: -# void → Void -# i8/i16/i32/i64 → Int8/Int16/Int32/Int64 -# double → Double, float → Float -# 任何含 * 的类型 → Ptr(Int8)(通用指针,保留 64 位地址) -# -# Args: -# pool: 内存池 -# buf: 包含类型字符串的缓冲区 -# start: 类型字符串起始位置 -# end: 类型字符串结束位置(不含) -# -# Returns: -# LLVM 类型对象,或 None(无法解析) -# ============================================================ -def _ParseLLVMRetTyStr(pool: memhub.MemBuddy | t.CPtr, - buf: bytes, - start: t.CSizeT, - end: t.CSizeT) -> llvmlite.LLVMType | t.CPtr: - """将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType""" - if pool is None or buf is None or start >= end: - return None - - # 去除前导空白 - s: t.CSizeT = start - while s < end: - c: int = buf[s] - if c != ' ' and c != '\t': - break - s += 1 - # 去除尾部空白 - e: t.CSizeT = end - while e > s: - c2: int = buf[e - 1] - if c2 != ' ' and c2 != '\t': - break - e -= 1 - - ty_len: t.CSizeT = e - s - if ty_len == 0: - return None - - # 检查是否含 * (指针类型) → 返回 i8* (通用指针) - # 包括 i8*, i32*, %"name"*, { i32, i8 }* 等 - ci: t.CSizeT = s - while ci < e: - if buf[ci] == '*': - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - ci += 1 - - # void - if ty_len == 4 and string.strncmp(buf + s, "void", 4) == 0: - return llvmlite.Void(pool) - - # double - if ty_len == 6 and string.strncmp(buf + s, "double", 6) == 0: - return llvmlite.Double(pool) - - # float - if ty_len == 5 and string.strncmp(buf + s, "float", 5) == 0: - return llvmlite.Float(pool) - - # iN (i8, i16, i32, i64) - if ty_len >= 2 and buf[s] == 'i': - bits: int = 0 - di: t.CSizeT = s + 1 - valid: int = 1 - while di < e: - d: int = buf[di] - if d >= '0' and d <= '9': - bits = bits * 10 + (d - '0') - else: - valid = 0 - break - di += 1 - if valid != 0 and bits > 0: - if bits == 8: - return llvmlite.Int8(pool) - if bits == 16: - return llvmlite.Int16(pool) - if bits == 32: - return llvmlite.Int32(pool) - if bits == 64: - return llvmlite.Int64(pool) - - # 无法解析 - return None - - -# ============================================================ -# _LookupMethodRetTyFromTextLL - 从依赖模块的 text.ll 查找方法返回类型 -# -# 读取 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll (level=1),搜索 -# define 行中包含 "{sha1}.{class_name}.{method_name}" 的函数, -# 提取返回类型并转换为 llvmlite.LLVMType。 -# -# 解决问题: _infer_method_ret_ty 默认返回 i32,导致指针返回值 -# 被 inttoptr 截断为 32 位(coerce_to_type line 238-239)。 -# 本函数从 text.ll 获取实际返回类型,避免截断。 -# -# Args: -# pool: 内存池 -# class_sha1: 类所属模块的 SHA1 -# class_name: 类名 -# method_name: 方法名 -# -# Returns: -# LLVM 类型对象,或 None(未找到/text.ll 不存在) -# ============================================================ -def _LookupMethodRetTyFromTextLL(pool: memhub.MemBuddy | t.CPtr, - class_sha1: str, - class_name: str, - method_name: str) -> llvmlite.LLVMType | t.CPtr: - """从依赖模块的 text.ll 中查找方法返回类型""" - if pool is None or class_sha1 is None or class_name is None or method_name is None: - return None - if _g_temp_dir is None or _g_temp_dir_len == 0: - return None - - sha1_len: t.CSizeT = string.strlen(class_sha1) - if sha1_len < 2: - return None - - # 构造 text.ll 路径 (level=1): {temp_dir}/{sha1[0:2]}/{sha1}.text.ll - # 使用 subdir 缓冲区避免 %c 格式化问题(与 StubMerger._sliced_path 一致) - path_len: t.CSizeT = _g_temp_dir_len + sha1_len + 14 - path_buf: bytes = stdlib.malloc(path_len) - if path_buf is None: - return None - subdir_buf: bytes = stdlib.malloc(3) - if subdir_buf is None: - stdlib.free(path_buf) - return None - subdir_buf[0] = class_sha1[0] - subdir_buf[1] = class_sha1[1] - subdir_buf[2] = '\0' - viperlib.snprintf(path_buf, path_len, "%s/%s/%s.text.ll", - _g_temp_dir, subdir_buf, class_sha1) - stdlib.free(subdir_buf) - - # 读取 text.ll - read_buf: bytes = stdlib.malloc(_TEXT_LL_READ_BUF_SIZE) - if read_buf is None: - stdlib.free(path_buf) - return None - - tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R) - if tf.closed: - stdlib.free(path_buf) - stdlib.free(read_buf) - return None - text_len: t.CInt64T = tf.read_all(read_buf, _TEXT_LL_READ_BUF_SIZE) - tf.close() - stdlib.free(path_buf) - - if text_len <= 0: - stdlib.free(read_buf) - return None - if text_len < _TEXT_LL_READ_BUF_SIZE: - read_buf[text_len] = '\0' - else: - read_buf[_TEXT_LL_READ_BUF_SIZE - 1] = '\0' - - # 构造搜索模式: "{sha1}.{class_name}.{method_name}" - cls_len: t.CSizeT = string.strlen(class_name) - meth_len: t.CSizeT = string.strlen(method_name) - search_len: t.CSizeT = sha1_len + cls_len + meth_len + 3 - search_buf: bytes = stdlib.malloc(search_len) - if search_buf is None: - stdlib.free(read_buf) - return None - viperlib.snprintf(search_buf, search_len, "%s.%s.%s", - class_sha1, class_name, method_name) - search_str_len: t.CSizeT = string.strlen(search_buf) - - # 在 text.ll 中搜索 define 行包含 search_buf - buf_len: t.CSizeT = string.strlen(read_buf) - pos: t.CSizeT = 0 - result_ty: llvmlite.LLVMType | t.CPtr = None - - while pos < buf_len and result_ty is None: - ls: t.CSizeT = pos - le: t.CSizeT = pos - while le < buf_len: - if read_buf[le] == '\n': - break - le += 1 - ll: t.CSizeT = le - ls - - # 检查是否是 define 行 - if ll >= 7 and string.strncmp(read_buf + ls, "define ", 7) == 0: - # 找 @ 符号 - at_pos: t.CSizeT = ls + 7 - while at_pos < ls + ll: - if read_buf[at_pos] == '@': - break - at_pos += 1 - if at_pos < ls + ll: - # 跳过可选引号 - name_start: t.CSizeT = at_pos + 1 - if name_start < ls + ll and read_buf[name_start] == '"': - name_start += 1 - # 检查是否匹配 search_buf - if name_start + search_str_len <= ls + ll: - if string.strncmp(read_buf + name_start, search_buf, search_str_len) == 0: - # 匹配!提取返回类型: [ls+7, at_pos) - result_ty = _ParseLLVMRetTyStr(pool, read_buf, ls + 7, at_pos) - - pos = le + 1 - - stdlib.free(search_buf) - stdlib.free(read_buf) - return result_ty - - -# ============================================================ -# _translate_method_call - 翻译方法调用 obj.method(args) -# -# 生成: call @SHA1.ClassName.method_name(Ptr(StructTy) %obj, args...) -# -# obj_ptr 是对象变量的 alloca(Ptr(StructTy)),作为 self 参数传入 -# ============================================================ -def _translate_method_call(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - method_name: str, - obj_ptr: llvmlite.Value | t.CPtr, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """翻译方法调用,返回 call 结果 Value""" - if pool is None or builder is None or class_name is None or method_name is None: - return None - if obj_ptr is None or cl is None: - return None - - # 提前获取结构体 entry(用 find_struct_by_type 规避跨模块同名 find_struct 找错) - # 用于继承链遍历、SHA1 查找和虚表分派 - mc_entry: HandlesStruct.StructEntry | t.CPtr = None - mc_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(obj_ptr) - if mc_struct_ty is not None: - mc_entry = HandlesStruct.find_struct_by_type(mc_struct_ty) - if mc_entry is None: - mc_entry = HandlesStruct.find_struct(class_name) - - # 构造方法查找名: ClassName.method_name - lookup_name: t.CChar | t.CPtr = pool.alloc(128) - if lookup_name is None: - return None - viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name) - - # 查找函数(支持 SHA1 后缀匹配) - found_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, lookup_name) - - # 沿继承链查找父类方法(子类未覆盖时回退到父类) - if found_func is None: - cur_parent: str = None - if mc_entry is not None: - cur_parent = mc_entry.ParentName - else: - cur_parent = HandlesStruct.get_parent_name(class_name) - while cur_parent is not None: - parent_lookup: t.CChar | t.CPtr = pool.alloc(128) - if parent_lookup is not None: - viperlib.snprintf(parent_lookup, 128, "%s.%s", cur_parent, method_name) - parent_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, parent_lookup) - if parent_func is not None: - found_func = parent_func - break - # 后续父类按名查找(无 ParentSha1,只能按名回退) - cur_parent = HandlesStruct.get_parent_name(cur_parent) - - # 确定调用名 - call_name: str = lookup_name - if found_func is not None: - found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) - if found_name is not None: - call_name = found_name - else: - # found_func 为 None(stub 未注入):用类所属模块的 SHA1 构造调用名 - # 沿继承链查找第一个有 SHA1 的类 - cls_sha1_mc: str = None - if mc_entry is not None: - cls_sha1_mc = mc_entry.ModuleSha1 - else: - cls_sha1_mc = HandlesStruct.get_struct_sha1(class_name) - if cls_sha1_mc is None: - cur_p: str = None - if mc_entry is not None: - cur_p = mc_entry.ParentName - else: - cur_p = HandlesStruct.get_parent_name(class_name) - while cur_p is not None and cls_sha1_mc is None: - cls_sha1_mc = HandlesStruct.get_struct_sha1(cur_p) - cur_p = HandlesStruct.get_parent_name(cur_p) - if cls_sha1_mc is not None: - mangled_len_mc: t.CSizeT = string.strlen(cls_sha1_mc) + string.strlen(lookup_name) + 2 - mangled_mc: str = pool.alloc(mangled_len_mc) - if mangled_mc is not None: - viperlib.snprintf(mangled_mc, mangled_len_mc, "%s.%s", cls_sha1_mc, lookup_name) - call_name = mangled_mc - - # 确定返回类型 - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if found_func is not None: - frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) - if frt is not None: - call_ret_ty = frt - else: - # found_func 为 None(stub 未注入):尝试从 text.ll 查找实际返回类型 - # 避免指针返回值被 _infer_method_ret_ty 默认为 i32 导致 inttoptr 截断 - looked_up_ty: llvmlite.LLVMType | t.CPtr = _LookupMethodRetTyFromTextLL( - pool, cls_sha1_mc, class_name, method_name) - if looked_up_ty is not None: - call_ret_ty = looked_up_ty - else: - call_ret_ty = _infer_method_ret_ty(pool, method_name) - - # 翻译调用参数 - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - can: t.CSizeT = 0 - if cargs is not None: - can = cargs.__len__() - - # 构建参数链表: 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 - - # 默认参数填充:如果调用点参数少于函数定义参数,用默认值填充缺失参数 - # 查找函数的 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) - # can = 已提供的非 self 参数数量 - # mdf_param_count = 函数定义的非 self 参数数量 - if mdf_param_count > can: - mdf_offset: int = mdf_param_count - mdf_default_count - mdf_pi: int = can - 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 - - # 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用 - # (不依赖 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 - - # 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods) - # 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入) - # 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠) - if is_oop == 0 and class_name is not None: - kw_init_lookup: t.CChar | t.CPtr = pool.alloc(128) - if kw_init_lookup is not None: - viperlib.snprintf(kw_init_lookup, 128, "%s.__init__", class_name) - # 方案1: 检查当前模块的函数声明 - kw_init_found: llvmlite.Function | t.CPtr = find_func_in_module(mod, kw_init_lookup) - if kw_init_found is not None: - is_oop = 1 - if kw_entry is not None: - kw_entry.IsOOP = 1 - kw_entry.HasInit = 1 - else: - # 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入) - kw_init_defaults: FuncDefaultsEntry | t.CPtr = find_func_defaults(kw_init_lookup) - if kw_init_defaults is not None: - is_oop = 1 - if kw_entry is not None: - kw_entry.IsOOP = 1 - kw_entry.HasInit = 1 - - if is_oop != 0: - _call_method_on_ptr(pool, builder, mod, class_name, - "__before_init__", tmp, None, 0, trans) - else: - # 普通结构体:store zeroinitializer + 应用默认值 - zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) - llvmlite.build_store(builder, zero, tmp) - _apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans) - - # OOP 结构体且有 __init__:调用 __init__ 而非逐字段 store - # 关键字构造调用此前总是逐字段 store,导致 __init__ 方法体不执行 - # (如 self._args = mb.alloc(...) 不执行 → self._args 为 NULL → add_argument 崩溃) - has_init_flag: int = 0 - has_new_flag: int = 0 - if kw_entry is not None: - has_init_flag = kw_entry.HasInit - has_new_flag = kw_entry.HasNew - - # 跨模块 OOP 类: HasInit 可能未设置(_translate_oop_methods 未被调用) - # 但 IsOOP=1 说明类有方法,推断 HasInit=1(__init__ 在目标模块中存在) - # 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法) - if is_oop != 0 and has_init_flag == 0: - has_init_flag = 1 - - if is_oop != 0 and has_init_flag != 0: - # 有 __init__:构建参数数组并调用 __init__ - storage_ptr: llvmlite.Value | t.CPtr = tmp - - # 如果有 __new__,调用 __new__ 获取实际存储指针 - if has_new_flag != 0: - new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if new_arg_vals is not None: - string.memset(new_arg_vals, 0, 8 * 32) - new_arg_count: int = 0 - for nai in range(can): - new_arg_node: ast.AST | t.CPtr = cargs.get(nai) - if new_arg_node is None: - continue - new_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, new_arg_node, None, 0, trans) - if new_av is not None: - if new_arg_count < 32: - new_arg_vals[new_arg_count] = t.CSizeT(new_av) - new_arg_count += 1 - # 关键字参数也传递给 __new__ - for nki in range(kw_count): - nkw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(nki)) - if nkw is None or nkw.value is None: - continue - nkw_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, nkw.value, None, 0, trans) - if nkw_av is not None: - if new_arg_count < 32: - new_arg_vals[new_arg_count] = t.CSizeT(nkw_av) - new_arg_count += 1 - new_ptr: llvmlite.Value | t.CPtr = _call_method_on_ptr( - pool, builder, mod, class_name, - "__new__", tmp, new_arg_vals, new_arg_count, trans) - if new_ptr is not None: - storage_ptr = new_ptr - - # 构建 __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 string.strcmp(func_name, "memcpy") == 0 and actual_count >= 3: - return _emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst1, mc_src1, mc_num1) - return llvmlite.build_call(builder, call_name, head, actual_count, call_ret_ty, 0) - -# ============================================================ -# _translate_t_type_cast - 翻译 t.XXX(value) 类型转换 -# -# 当 func 是 t.XXX 形式且 XXX 是已知类型名(map_t_type 能映射)时, -# 将 value 转换为目标类型: -# - 指针 → 整数: ptrtoint (如 t.CUInt64T(ptr) → i64) -# - 整数 → 指针: inttoptr (如 t.CPtr(int_val) → i8*) -# - 整数 → 整数: trunc/zext (如 t.CInt8T(i32_val) → i8) -# - 指针 → 指针: bitcast (如 t.CPtr(ptr_val) → i8*) -# - 整数 → 浮点: sitofp (如 t.CDouble(i32_val) → double) -# - 浮点 → 整数: fptosi (如 t.CInt(double_val) → i32) -# - 浮点 → 浮点: fpext/fptrunc (如 t.CFloat(double_val) → float) -# ============================================================ -def _translate_t_type_cast(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - val: llvmlite.Value | t.CPtr, - target_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: - """类型转换:根据参数类型和目标类型选择转换方式""" - if val is None or target_ty is None: - return None - - val_bits: int = HandlesExpr.get_llvm_type_bits(val.Ty) - target_bits: int = HandlesExpr.get_llvm_type_bits(target_ty) - val_fbits: int = HandlesExpr.get_llvm_float_bits(val.Ty) - target_fbits: int = HandlesExpr.get_llvm_float_bits(target_ty) - - # 整数 → 整数: trunc/zext - if val_bits != 0 and target_bits != 0: - if val_bits == target_bits: - return val - elif val_bits < target_bits: - return llvmlite.build_zext(builder, val, target_ty) - else: - return llvmlite.build_trunc(builder, val, target_ty) - - # 整数 → 浮点: sitofp - if val_bits != 0 and target_fbits != 0: - return llvmlite.build_si2fp(builder, val, target_ty) - - # 浮点 → 整数: fptosi - if val_fbits != 0 and target_bits != 0: - return llvmlite.build_fp2si(builder, val, target_ty) - - # 浮点 → 浮点: fpext/fptrunc - if val_fbits != 0 and target_fbits != 0: - if val_fbits == target_fbits: - return val - elif val_fbits < target_fbits: - return llvmlite.build_fpext(builder, val, target_ty) - else: - return llvmlite.build_fptrunc(builder, val, target_ty) - - # 指针 → 整数: ptrtoint - if val_bits == 0 and val_fbits == 0 and target_bits != 0: - return llvmlite.build_ptrtoint(builder, val, target_ty) - - # 整数 → 指针: inttoptr(必须排除浮点 target,浮点 target_bits 也是 0) - if val_bits != 0 and target_bits == 0 and target_fbits == 0: - return llvmlite.build_inttoptr(builder, val, target_ty) - - # 指针 → 指针: bitcast - return llvmlite.build_bitcast(builder, val, target_ty) - -# ============================================================ -# 泛型实例化辅助:从 Subscript slice 提取类型实参名 -# ============================================================ -# _get_type_name_from_annotation 已移至 HandlesType.py(支持 BinOp/Attribute) -# HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用 - -def _extract_type_args_from_slice(pool: memhub.MemBuddy | t.CPtr, - slice_node: ast.AST | t.CPtr) -> list[str] | t.CPtr: - """从 Subscript.slice 提取类型实参名列表 - - list[int] -> ["int"] - dict[str, int] -> ["str", "int"] - list[AST | t.CPtr] -> ["AST|t.CPtr"] - """ - if slice_node is None or pool is None: - return None - result: list[str] | t.CPtr = list[str](pool, 4) - k: int = slice_node.kind() - if k == ast.ASTKind.Tuple: - tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(slice_node) - elts: list[ast.AST | t.CPtr] | t.CPtr = tp.elts - if elts is not None: - n: t.CSizeT = elts.__len__() - i: t.CSizeT - for i in range(n): - elt: ast.AST | t.CPtr = elts.get(i) - tn: str = HandlesType._get_type_name_from_annotation(pool, elt) - if tn is not None: - result.append(tn) - else: - tn: str = HandlesType._get_type_name_from_annotation(pool, slice_node) - if tn is not None: - result.append(tn) - return result - -# ============================================================ -# 泛型类构造调用辅助: list[str](pool, 8) → __new__ + __before_init__ + __init__ -# -# 复用 translate_list_literal 的构造逻辑: -# 1. alloca tmp(特化类临时空间,作为 __new__ 的 self) -# 2. 翻译 cl.args 为参数指针数组 -# 3. call __new__(tmp, *args) → storage_ptr -# 4. call __before_init__(storage_ptr) -# 5. call __init__(storage_ptr, *args) -# 6. return storage_ptr -# -# 必须独立于 translate_call 的普通函数路径:spec_name 是类名不是函数名, -# 走裸名路径会被 _lookup_mod_sha1 的 star import 回退误导,用错误的 SHA1 -# 且缺少 __new__ 方法名后缀,导致链接报 undefined reference。 -# ============================================================ -def _translate_generic_ctor_call(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - spec_name: str, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__""" - if pool is None or builder is None or mod is None or spec_name is None or cl is None: - return None - - # 查找 struct entry 获取类型 - struct_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) - if struct_entry is None: - HandlesType.fatal_error(cl, "泛型类构造调用: 特化类未注册") - return None - struct_ty: llvmlite.LLVMType | t.CPtr = struct_entry.Ty - if struct_ty is None: - return None - - # 确保结构体定义在当前模块中可用(供 alloca 分配空间) - HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) - - # alloca tmp(self 指针) - tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) - if tmp is None: - return None - - # 翻译 cl.args 为参数指针数组(extra_args[i] = Value 指针) - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - can: t.CSizeT = 0 - if cargs is not None: - can = cargs.__len__() - - extra_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if extra_args is None: - return None - string.memset(extra_args, 0, 8 * 32) - - ai: t.CSizeT = 0 - while ai < can: - arg_node: ast.AST | t.CPtr = cargs.get(ai) - if arg_node is not None: - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg_node, None, 0, trans) - if arg_val is not None: - extra_args[ai] = t.CSizeT(arg_val) - ai += 1 - - # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 - # __new__ 是可选的,仅当泛型类模板定义了 __new__ 方法时才调用 - # (与 _translate_struct_ctor 保持一致,避免为无 __new__ 的类生成过度声明) - storage_ptr: llvmlite.Value | t.CPtr = tmp - has_new_flag: int = 0 - if struct_entry is not None: - has_new_flag = struct_entry.HasNew - if has_new_flag != 0: - new_ptr: llvmlite.Value | t.CPtr = _call_method_on_ptr( - pool, builder, mod, spec_name, "__new__", tmp, extra_args, can, trans) - if new_ptr is not None: - storage_ptr = new_ptr - - # 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__() - - # 内置强转函数: str(x)/bytes(x) → i8*, int(x) → i32 - # 等价于 (t.CChar | t.CPtr)(x) / (t.CInt32T)(x) - # 单参数:str(val) → bitcast val to i8* - # int(val) → trunc/sext val to i32 - if func_name is not None and can == 1: - if string.strcmp(func_name, "str") == 0 or string.strcmp(func_name, "bytes") == 0: - # str(x) / bytes(x) → i8* (bitcast) - cast_arg: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) - if cast_arg is not None: - i8_ptr_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - return _translate_t_type_cast(pool, builder, cast_arg, i8_ptr_ty_builtin) - return None - elif string.strcmp(func_name, "int") == 0: - # int(x) → i32 - cast_arg_int: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) - if cast_arg_int is not None: - i32_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - return _translate_t_type_cast(pool, builder, cast_arg_int, i32_ty_builtin) - return None - elif string.strcmp(func_name, "bool") == 0: - # bool(x) → i1(严格 != 0 归一化) - # 整数: icmp ne x, 0 → i1 - # 浮点: fcmp one x, 0.0 → i1 - # 指针: icmp ne x, null → i1 - cast_arg_bool: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) - if cast_arg_bool is not None: - arg_bits: int = HandlesExpr.get_llvm_type_bits(cast_arg_bool.Ty) - arg_fbits: int = HandlesExpr.get_llvm_float_bits(cast_arg_bool.Ty) - # 整数: icmp ne x, 0 - if arg_bits != 0: - zero_int: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, arg_bits, 0) - if zero_int is not None: - return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, zero_int) - return None - # 浮点: fcmp one x, 0.0 - if arg_fbits != 0: - zero_ty: llvmlite.LLVMType | t.CPtr = cast_arg_bool.Ty - zero_flt: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, zero_ty, 0.0) - if zero_flt is not None: - return llvmlite.build_fcmp(builder, llvmlite.FCMP_ONE, cast_arg_bool, zero_flt) - return None - # 指针: icmp ne x, null - ptr_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cast_arg_bool.Ty, "null") - if ptr_null is not None: - return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, ptr_null) - return None - return None - - # 检测 t.XXX 类型转换: t.CUInt64T(ptr), t.CPtr(val), t.CInt(val) 等 - # 当 func 是 t.XXX 形式且 XXX 是已知类型名时,当作类型转换处理(而非函数调用) - # 支持: - # 单参数: t.CInt(val) → 目标类型 = map_t_type(func_name) - # 双参数: t.CInt(val, t.CPtr) → 目标类型 = Ptr(map_t_type(func_name)) - # t 是内部库,一旦确认为类型转换,绝不跌落到跨模块调用 FATAL 路径 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - tc_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if tc_at.value is not None and tc_at.value.kind() == ast.ASTKind.Name: - tc_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_at.value) - if tc_mod_nm.id is not None and string.strcmp(tc_mod_nm.id, "t") == 0: - target_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, func_name) - if target_ty is not None: - tc_effective_can: t.CSizeT = can - # 双参数形式: t.CInt(val, t.CPtr) → Ptr(target_ty) - # 注意: void* 在 LLVM 中非法,CVoid* 应表示为 i8* - if can == 2: - tc_arg2_node: ast.AST | t.CPtr = cargs.get(1) - if tc_arg2_node is not None and tc_arg2_node.kind() == ast.ASTKind.Attribute: - tc_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tc_arg2_node) - if tc_arg2_at.attr is not None and string.strcmp(tc_arg2_at.attr, "CPtr") == 0: - if tc_arg2_at.value is not None and tc_arg2_at.value.kind() == ast.ASTKind.Name: - tc_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_at.value) - if tc_arg2_nm.id is not None and string.strcmp(tc_arg2_nm.id, "t") == 0: - # CVoid* → i8*(LLVM 中 void* 表示为 i8*) - match target_ty: - case llvmlite.LLVMType.Void(): - target_ty = llvmlite.Int8(pool) - case _: - pass - target_ty = llvmlite.Ptr(pool, target_ty) - tc_effective_can = 1 - if tc_effective_can == 1: - tc_arg_node: ast.AST | t.CPtr = cargs.get(0) - if tc_arg_node is not None: - tc_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, tc_arg_node, None, 0, trans) - if tc_arg_val is not None: - return _translate_t_type_cast(pool, builder, tc_arg_val, target_ty) - # t.XXX 类型转换已确认但不满足参数条件:返回 None,不跌落到跨模块 FATAL - return None - - # 裸名 typedef 调用: BYTEPTR(ptr1), HANDLE(val), CHARPTR(str) 等 - # 用户通过 `from stdint import *` 导入 typedef 后,可直接用裸名做类型转换 - # map_t_type 包含所有内置 typedef 名称(BYTEPTR/HANDLE/LPCSTR/size_t 等) - if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - bare_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, func_name) - if bare_ty is not None and can == 1: - bare_arg_node: ast.AST | t.CPtr = cargs.get(0) - if bare_arg_node is not None: - bare_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, bare_arg_node, None, 0, trans) - if bare_arg_val is not None: - return _translate_t_type_cast(pool, builder, bare_arg_val, bare_ty) - - # 检测 ClassName.__sizeof__() — 返回结构体大小常量(i64) - # __sizeof__ 是内置方法,不走跨模块调用路径 - # 支持: Argument.__sizeof__() 和 w32.win32file.WIN32_FIND_DATAA.__sizeof__() - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - sz_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if sz_at.attr is not None and string.strcmp(sz_at.attr, "__sizeof__") == 0: - if sz_at.value is not None and can == 0: - sz_cls_name: str = None - sz_vk: int = sz_at.value.kind() - if sz_vk == ast.ASTKind.Name: - sz_cls_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sz_at.value) - sz_cls_name = sz_cls_nm2.id - elif sz_vk == ast.ASTKind.Attribute: - sz_inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sz_at.value) - sz_cls_name = sz_inner_at.attr - if sz_cls_name is not None: - # 泛型类型参数 T 替换: T.__sizeof__() → int.__sizeof__() - sz_cls_name = HandlesType.resolve_generic_type_name(sz_cls_name) - # 去除模块前缀: Viper 解析器将 t.CInt 解析为 Name(id="t.CInt") - # 而非 Attribute(value=Name("t"), attr="CInt"),需要手动提取最后的类名分量 - # "t.CInt" → "CInt", "w32.win32file.WIN32_FIND_DATAA" → "WIN32_FIND_DATAA" - dot_pos: str = string.strrchr(sz_cls_name, '.') - if dot_pos is not None: - sz_cls_name = dot_pos + 1 - # 联合类型(如 AST|t.CPtr)按指针大小处理(8 字节) - # 联合类型在 TPV 中表示指针,可以指向多种类型 - # 对应 TPC 中对 BinOp/BitOr 联合类型的特殊处理 - if string.strstr(sz_cls_name, "|") is not None: - return llvmlite.const_int64(pool, 8) - # 内置类型 sizeof(int=4, str/bytes=8 指针, double=8 等) - sz_builtin: int = -1 - if string.strcmp(sz_cls_name, "int") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "str") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "bytes") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CInt") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "CInt8T") == 0: - sz_builtin = 1 - elif string.strcmp(sz_cls_name, "CInt16T") == 0: - sz_builtin = 2 - elif string.strcmp(sz_cls_name, "CInt32T") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "CInt64T") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CChar") == 0: - sz_builtin = 1 - elif string.strcmp(sz_cls_name, "CDouble") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CFloat") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "CPtr") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CSizeT") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CBool") == 0: - sz_builtin = 1 - elif string.strcmp(sz_cls_name, "bool") == 0: - sz_builtin = 1 - if sz_builtin >= 0: - # 注意: 必须用 const_int64 而非 ConstInt(...,"0") - # ConstInt 的 name 参数是 IR 文本表示,ValuePrint 输出时使用 Name 而非 IntVal - # 硬编码 "0" 会导致 IR 输出 i64 0 而非实际值 - return llvmlite.const_int64(pool, sz_builtin) - sz_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type( - sz_cls_name) - if sz_struct_ty is not None: - sz_val: int = HandlesClassDef._get_type_size(sz_struct_ty) - if sz_val > 0: - return llvmlite.const_int64(pool, sz_val) - # 类型已注册但大小为 0(opaque struct 或字段链表未填充):报错终止 - fb_sz1: t.CChar | t.CPtr = VLogger.fmt_buf() - if fb_sz1 is not None: - viperlib.snprintf(fb_sz1, 1024, - "类型 '%s' 已注册但大小为 0(字段链表未填充),立即终止编译", - sz_cls_name) - VLogger.critical(fb_sz1, "__sizeof__") - 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 - # 注意: 必须用 translate_value 而非 translate_name_value,因为 len_at.value - # 可能是 Attribute 节点(如 md_ags.args),translate_name_value 只处理 Name 节点, - # 对 Attribute 会错误返回 i32 0,导致 GEP base 不是指针(base of getelementptr must be a pointer) - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - len_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if len_at.attr is not None and string.strcmp(len_at.attr, "__len__") == 0: - if len_at.value is not None and can == 0: - obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, len_at.value, funcs_ptr, func_count, trans) - if obj_val is not None and obj_val.Ty is not None: - # 防御性类型检查: obj_val 必须是指针类型才能做 GEP - # 如果 translate_value 返回 i32 (如 CDefine 常量被误解析、 - # 模块属性前向引用回退为 i32),GEP base 会是 i32 而非指针, - # 导致 llc 报错 "base of getelementptr must be a pointer" - if HandlesExpr.is_ptr_type(obj_val.Ty) == 0: - return llvmlite.const_int64(pool, 0) - i64_ty_len: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - # 注意: 必须用 const_int64 而非 ConstInt(...,"0") - # ConstInt 的 name 参数 "0" 会被当作 IR 文本值输出 i64 0 - # 导致 GEP 索引为 0(访问 __data__)而非 1(访问 __count__) - idx_one: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) - count_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i64_ty_len, obj_val, idx_one) - if count_ptr is not None: - return llvmlite.build_load(builder, i64_ty_len, count_ptr) - - # 检测 len() 内置函数调用 — 转换为 strlen 调用 - # len(s) 对 str 类型调用 strlen,返回 i64 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - if func_name is not None and string.strcmp(func_name, "len") == 0: - if can == 1: - len_arg_node: ast.AST | t.CPtr = cargs.get(0) - if len_arg_node is not None: - len_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, len_arg_node, None, 0, trans) - if len_val is not None: - # 确保 strlen 在模块中有声明 - strlen_fn: llvmlite.Function | t.CPtr = find_func_in_module(mod, "strlen") - if strlen_fn is None: - i64_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ptr_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - strlen_fn = llvmlite.create_declare(pool, mod, "strlen", i64_ty_ln) - if strlen_fn is not None: - llvmlite.add_param(pool, strlen_fn, i8_ptr_ty_ln, "s") - # 参数类型转换为 i8* - i8_ptr_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - len_arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(len_val) - len_coerced: llvmlite.Value | t.CPtr = len_val - if HandlesExpr.is_ptr_type(len_arg_ty) != 0: - len_coerced = llvmlite.build_bitcast(builder, len_val, i8_ptr_ty_ln2) - # 构建单参数链表并调用 strlen - len_coerced.Next = None - i64_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - return llvmlite.build_call(builder, "strlen", len_coerced, 1, i64_ty_ln2, 0) - - # 检测方法调用: obj.method(args) - # 当 cl.func 是 Attribute 且 obj 是已注册的结构体变量时,翻译为方法调用 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if method_at is not None and method_at.value is not None: - if method_at.value.kind() == ast.ASTKind.Name and trans is not None: - method_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(method_at.value) - if method_obj_nm.id is not None: - # 查找对象变量 - obj_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, method_obj_nm.id) - if obj_var is not None and obj_var.Ty is not None: - # 检查是否为 Ptr(Struct(...))(结构体值变量) - # 或 Ptr(Ptr(Struct(...)))(指针变量,需 load) - match obj_var.Ty: - case llvmlite.LLVMType.Ptr(obj_struct_ty): - class_nm: str = HandlesStruct.get_class_name_by_type( - pool, obj_struct_ty) - if class_nm is not None: - return _translate_method_call( - pool, builder, mod, class_nm, func_name, - obj_var, cl, trans) - # 指针变量: alloca 类型是 Ptr(Ptr(Struct)) - # load 获取实际指针 Ptr(Struct) 后再查找 - match obj_struct_ty: - case llvmlite.LLVMType.Ptr(inner_struct_ty): - inner_nm: str = HandlesStruct.get_class_name_by_type( - pool, inner_struct_ty) - if inner_nm is not None: - obj_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, obj_struct_ty, obj_var) - if obj_ptr is not None: - return _translate_method_call( - pool, builder, mod, inner_nm, func_name, - obj_ptr, cl, trans) - # AnnotClassName 回退:联合类型简化为 Ptr(i8) 时, - # 通过原始类型注解的类名查找结构体 - var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, method_obj_nm.id) - if var_entry is not None and var_entry.AnnotClassName is not None: - annot_val: str = var_entry.AnnotClassName - # 解析模块限定名 "memhub.MemBuddy" → mod_nm="memhub", cls_nm="MemBuddy" - dot_ptr: t.CChar | t.CPtr = string.strrchr(annot_val, '.') - cls_nm2: str = annot_val - mod_nm2: str = None - if dot_ptr is not None: - cls_nm2 = dot_ptr + 1 - total_len_av: t.CSizeT = string.strlen(annot_val) - cls_len_av: t.CSizeT = string.strlen(cls_nm2) - mod_len2: t.CSizeT = total_len_av - cls_len_av - 1 - mod_nm2 = pool.alloc(mod_len2 + 1) - if mod_nm2 is not None: - string.strncpy(mod_nm2, annot_val, mod_len2) - mod_nm2[mod_len2] = '\0' - # 检查结构体是否已注册 - if HandlesStruct.get_struct_type(cls_nm2) is not None: - # 结构体已注册:load obj_ptr 走方法调用 - i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - obj_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i8_ptr_ty2, obj_var) - if obj_ptr2 is not None: - return _translate_method_call( - pool, builder, mod, cls_nm2, func_name, - obj_ptr2, cl, trans) - else: - # 结构体未注册(跨模块依赖未翻译): - # 用模块名查 SHA1 构造方法调用名 - sha1_fc: str = None - if mod_nm2 is not None: - sha1_fc = _lookup_module_sha1(mod_nm2) - if sha1_fc is not None: - # 构造 "{sha1}.{cls_nm2}.{func_name}" 调用名 - mlen3: t.CSizeT = string.strlen(sha1_fc) + string.strlen(cls_nm2) + string.strlen(func_name) + 3 - mangled3: str = pool.alloc(mlen3) - if mangled3 is not None: - viperlib.snprintf(mangled3, mlen3, "%s.%s.%s", sha1_fc, cls_nm2, func_name) - # load obj_ptr (self) - i8_ptr_ty3: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - obj_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i8_ptr_ty3, obj_var) - if obj_ptr3 is not None: - # 构建参数链表: obj_ptr3 (self) → 其他参数 - llvmlite.value_set_next(obj_ptr3, None) - head3: llvmlite.Value | t.CPtr = obj_ptr3 - tail3: llvmlite.Value | t.CPtr = obj_ptr3 - for ai3 in range(can): - arg3: ast.AST | t.CPtr = cargs.get(ai3) - if arg3 is not None: - arg_val3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg3, None, 0, trans) - if arg_val3 is not None: - llvmlite.value_set_next(arg_val3, None) - llvmlite.value_set_next(tail3, arg_val3) - tail3 = arg_val3 - total3: int = 1 + can - ret_ty3: llvmlite.LLVMType | t.CPtr = _LookupMethodRetTyFromTextLL( - pool, sha1_fc, cls_nm2, func_name) - if ret_ty3 is None: - ret_ty3 = _infer_method_ret_ty(pool, func_name) - _ensure_method_declare(pool, mod, mangled3, ret_ty3, head3, total3) - return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0) - - # ============================================================ - # 检测 self.field.method() 调用 - # - # 当 method_at.value 是 Attribute(字段访问,如 self.__pool__)时, - # 翻译字段值获取对象指针,然后走方法调用路径。 - # - # 路径1: 从字段值的 LLVM 类型获取类名(字段类型为 Ptr(Struct("MemManager"))) - # 路径2: 从字段的 AnnotClassName 回退查找(字段类型被简化为 Ptr(i8) 时) - # ============================================================ - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - attr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if attr_method_at is not None and attr_method_at.value is not None: - if attr_method_at.value.kind() == ast.ASTKind.Attribute and trans is not None: - inner_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(attr_method_at.value) - if inner_attr is not None and inner_attr.attr is not None: - # 翻译 self.__pool__ 获取字段值(已 load 的对象指针) - field_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, attr_method_at.value, funcs_ptr, func_count, trans) - if field_obj is not None and field_obj.Ty is not None: - field_cls_nm: str = None - # 路径1: 从字段值的 LLVM 类型获取类名 - match field_obj.Ty: - case llvmlite.LLVMType.Ptr(field_struct_ty): - field_cls_nm = HandlesStruct.get_class_name_by_type( - pool, field_struct_ty) - # 路径2: 从字段注解类名回退查找 - if field_cls_nm is None: - if inner_attr.value is not None and inner_attr.value.kind() == ast.ASTKind.Name: - inner_name_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_attr.value) - if inner_name_node is not None and inner_name_node.id is not None: - inner_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, inner_name_node.id) - if inner_var is not None and inner_var.Ty is not None: - match inner_var.Ty: - case llvmlite.LLVMType.Ptr(field_owner_struct_ty): - field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - field_owner_struct_ty, inner_attr.attr) - if field_info is not None: - field_annot: str = HandlesStruct.get_field_annot_class_name(field_info) - if field_annot is not None: - dot_p: t.CChar | t.CPtr = string.strrchr(field_annot, 46) - if dot_p is not None: - field_cls_nm = dot_p + 1 - else: - field_cls_nm = field_annot - if field_cls_nm is not None: - return _translate_method_call( - pool, builder, mod, field_cls_nm, func_name, - field_obj, cl, trans) - - # ============================================================ - # 检测 list 内置方法调用: lst.get(i), lst.set(i,v), lst.pop(), lst.clear(), lst.__iter__() - # list[T] 是泛型类不注册 struct,方法调用处理器(上方)无法处理, - # 需要在此特殊处理。 - # list 结构布局 (6 字段 × 8 字节): - # __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) - # ============================================================ - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - lm_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if lm_at is not None and lm_at.attr is not None and lm_at.value is not None: - lm_name: str = lm_at.attr - # 判断是否是 list 方法名 - lm_is_list: int = 0 - if string.strcmp(lm_name, "get") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "__getitem__") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "set") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "__setitem__") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "pop") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "clear") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "__iter__") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "append") == 0: lm_is_list = 1 - - if lm_is_list == 1 and trans is not None: - # 翻译 list 对象 - lm_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, lm_at.value, funcs_ptr, func_count, trans) - if lm_obj is not None: - # 防御性类型检查: lm_obj 必须是指针类型才能做 GEP - # translate_value 对某些 Attribute 节点(如 ast.Arguments 的属性) - # 可能返回 i32 0 (非指针),直接 GEP 会导致 - # "base of getelementptr must be a pointer" 错误 - if lm_obj.Ty is None or HandlesExpr.is_ptr_type(lm_obj.Ty) == 0: - lm_node_kind: int = lm_at.value.kind() - fb_lm: t.CChar | t.CPtr = VLogger.fmt_buf() - if fb_lm is not None: - viperlib.snprintf(fb_lm, 1024, - "list 方法 '%s' 的目标对象非指针 (node kind=%d)," - "translate_value 类型推断失败", - lm_name, lm_node_kind) - VLogger.critical(fb_lm, "LIST-METHOD") - return None - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - # get / __getitem__: 返回 index 处的元素 - if string.strcmp(lm_name, "get") == 0 or string.strcmp(lm_name, "__getitem__") == 0: - if can >= 1: - # 加载 __data__ (偏移 0) - g_idx0: llvmlite.Value | t.CPtr = llvmlite.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 - # 原始函数名(别名导入时记录,如 from X import parse as json_parse → orig_func_name="parse") - # 用于在别名处理后重新推断返回类型,避免 _infer_external_func_ret_ty 用别名匹配失败 - orig_func_name: str = None - if found_func is not None: - found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) - if found_name is not None: - call_name = found_name - else: - # 跨模块函数调用:found_func 为 None 时,检查是否是模块限定调用 - # 如 string.strchr(...) → @{sha1_of_string}.strchr - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - xmod_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if xmod_at.value is not None and xmod_at.value.kind() == ast.ASTKind.Name: - xmod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(xmod_at.value) - if xmod_nm.id is not None: - mod_sha1: str = _lookup_module_sha1(xmod_nm.id) - if mod_sha1 is not None: - # 检查是否是 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 - # 记录原始函数名,供后续重新推断返回类型 - # 例如 from json.__parser import parse as json_parse - # func_name="json_parse", bare_func_name="parse" - # _infer_external_func_ret_ty 用 "parse" 能正确匹配,用 "json_parse" 则返回默认 i32 - orig_func_name = bare_func_name - if is_cexport_func(bare_sha1, bare_func_name) != 0: - call_name = bare_func_name - else: - bare_mangled_len: t.CSizeT = string.strlen(bare_sha1) + string.strlen(bare_func_name) + 2 - bare_mangled: str = pool.alloc(bare_mangled_len) - if bare_mangled is not None: - viperlib.snprintf(bare_mangled, bare_mangled_len, "%s.%s", bare_sha1, bare_func_name) - call_name = bare_mangled - else: - err_msg3: t.CChar | t.CPtr = pool.alloc(256) - if err_msg3 is not None: - viperlib.snprintf(err_msg3, 256, "裸名调用 '%s' 未定义且未导入", func_name) - HandlesType.fatal_error(node, err_msg3) - HandlesType.fatal_error(node, "裸名调用未定义且未导入") - else: - err_msg4: t.CChar | t.CPtr = pool.alloc(256) - if err_msg4 is not None: - viperlib.snprintf(err_msg4, 256, "裸名调用 '%s' 未定义且未导入", func_name) - HandlesType.fatal_error(node, err_msg4) - HandlesType.fatal_error(node, "裸名调用未定义且未导入") - - # 直接调用 - # memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失) - if string.strcmp(func_name, "memcpy") == 0 and can >= 3: - return _emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst2, mc_src2, mc_num2) - # 别名导入重新推断返回类型: - # from X import parse as json_parse → func_name="json_parse" 时 _infer_external_func_ret_ty 返回默认 i32 - # 用 orig_func_name="parse" 重新推断,能正确匹配返回 i8*(JsonValue*) - # 避免指针被截断为 i32 后 inttoptr 丢失高 32 位导致崩溃 - if orig_func_name is not None and orig_func_name != func_name: - re_inferred_ty: llvmlite.LLVMType | t.CPtr = _infer_external_func_ret_ty(pool, orig_func_name) - if re_inferred_ty is not None: - call_ret_ty = re_inferred_ty - # 跨模块调用:创建 declare 声明,避免 llc 报 undefined value - _ensure_method_declare(pool, mod, call_name, call_ret_ty, head, can) - 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 +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import w32.fileio as fileio +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.StubMerger as StubMerger + + +# ============================================================ +# _ddebug_exit - DDEBUG 拦截退出辅助函数 +# +# 刷新 stderr 缓冲区并通过 VLogger 输出可见消息后退出。 +# 解决 sys.exit(1) 不刷新缓冲区导致 DDEBUG 消息丢失的问题。 +# ============================================================ +def _ddebug_exit() -> None: + stdio.fflush(stdio.stderr) + VLogger.error("DDEBUG intercept triggered - check stderr for details") + + +# ============================================================ +# 模块 SHA1 查询(委托给 StubMerger 全局存储器) +# +# 翻译时用于跨模块函数调用名混淆: +# string.strchr(...) → call @{sha1_of_string}.strchr(...) +# +# 数据来源是 StubMerger.PopulateSha1MapStore/AppendToSha1MapStore +# 填充的全局存储器,不再维护独立的 SHA1 映射表副本。 +# ============================================================ + +def _lookup_module_sha1(mod_name: str) -> str: + """查找模块名对应的 SHA1,找不到返回 None + + 委托给 StubMerger.LookupSha1ByModName(精确匹配 + 包名回退)。 + """ + return StubMerger.LookupSha1ByModName(mod_name) + +def _lookup_module_sha1_suffix(mod_suffix: str) -> str: + """后缀匹配查找模块 SHA1,如 mod_suffix="__types" 匹配 "llvmlite.__types" + + 用于 from .X import Y 的相对导入:impf.module 是 ".X"(带前导点), + 去掉前导点后为 "X",SHA1 映射表中键是 "pkg.X",需要后缀匹配。 + 委托给 StubMerger.LookupSha1ByModNameSuffix(精确 + 后缀 + 反向后缀)。 + """ + return StubMerger.LookupSha1ByModNameSuffix(mod_suffix) + +# ============================================================ +# 全局 CExport 函数表(module_sha1 + func_name) +# +# t.CExport 函数定义时不加 SHA1 前缀(如 @strlen), +# 跨模块调用时需要查表确认目标函数是否是 CExport 函数。 +# 若是,使用裸名调用(@strlen);否则使用 @{sha1}.func。 +# 必须包含模块 SHA1 记录,避免同名跨模块函数冲突 +# (一个模块有 CExport 的 strlen→@strlen,另一个没有→@{sha1}.strlen)。 +# ============================================================ +_g_cexport_sha1_arr: bytes = None +_g_cexport_func_arr: bytes = None +_g_cexport_count: int = 0 +_CEXPORT_MAX: t.CDefine = 256 + +def register_cexport_func(sha1: str, func_name: str) -> int: + """注册 CExport 函数到全局表(sha1+func_name 二元组)""" + global _g_cexport_sha1_arr + global _g_cexport_func_arr + global _g_cexport_count + if sha1 is None or func_name is None: + return 0 + if _g_cexport_sha1_arr is None: + _g_cexport_sha1_arr = stdlib.malloc(_CEXPORT_MAX * 17) + _g_cexport_func_arr = stdlib.malloc(_CEXPORT_MAX * 64) + if _g_cexport_sha1_arr is None or _g_cexport_func_arr is None: + return 0 + string.memset(_g_cexport_sha1_arr, 0, _CEXPORT_MAX * 17) + string.memset(_g_cexport_func_arr, 0, _CEXPORT_MAX * 64) + if _g_cexport_count < _CEXPORT_MAX: + idx: t.CSizeT = t.CSizeT(_g_cexport_count) * 17 + string.strcpy(_g_cexport_sha1_arr + idx, sha1) + idx2: t.CSizeT = t.CSizeT(_g_cexport_count) * 64 + string.strcpy(_g_cexport_func_arr + idx2, func_name) + _g_cexport_count += 1 + return 1 + return 0 + +def is_cexport_func(sha1: str, func_name: str) -> int: + """检查 (sha1, func_name) 是否是 CExport 函数""" + if sha1 is None or func_name is None: + return 0 + if _g_cexport_sha1_arr is None: + return 0 + for i in range(_g_cexport_count): + idx: t.CSizeT = t.CSizeT(i) * 17 + if string.strcmp(_g_cexport_sha1_arr + idx, sha1) == 0: + idx2: t.CSizeT = t.CSizeT(i) * 64 + if string.strcmp(_g_cexport_func_arr + idx2, func_name) == 0: + return 1 + return 0 + +# ============================================================ +# _lookup_mod_sha1 - 从 from_imports 查找类所属模块的 SHA1 +# +# lookup_from_import 返回指向 from_imports 内部的指针,不是 null 终止 +# (如 "namespace_defs Gadget:namespace_defs ...")。此函数手动截断 +# 模块名,复制到新缓冲区,再查找 SHA1(精确+后缀匹配)。 +# ============================================================ +def _lookup_mod_sha1(pool: memhub.MemBuddy | t.CPtr, + from_imports: str, class_name: str, + allow_star_fallback: int = 1) -> str: + """从 from_imports 查找类所属模块的 SHA1,返回 None=未找到 + + allow_star_fallback: 传 0 禁用 star import 回退(用于明确模块名/函数名查找) + """ + mod_name_raw: str = HandlesImports.lookup_from_import( + from_imports, class_name, allow_star_fallback) + if mod_name_raw is None: + return None + # 手动找到模块名结束位置(空格、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) + # DDEBUG: 检测 _lookup_mod_sha1 返回的 sha1 是否带尾随点(17 字符),发现问题立即终止 + if sha1 is not None: + _sl: t.CSizeT = string.strlen(sha1) + if _sl >= 17: + stdio.printf("[DDEBUG] _lookup_mod_sha1 sha1 too long: len=%d sha1='%s' (class='%s' mod='%s')\n", _sl, sha1, class_name, base_mod) + _ddebug_exit() + return sha1 + +# ============================================================ +# HandlesExprCall - 函数调用表达式处理(Mixin 继承模式) +# +# 工具函数和 FuncEntry 保留为模块级,ExprCallHandle 提供 trans 接口 +# ============================================================ + +# ============================================================ +# 在模块函数链表中按名称查找函数 +# ============================================================ +def find_func_in_module(mod: llvmlite.LLVMModule | t.CPtr, + name: str) -> llvmlite.Function | t.CPtr: + """在模块的函数链表中按名称查找函数 + + 查找策略: + 1. 精确匹配(如 "strlen" 匹配 @strlen,有 t.CExport 的函数) + 2. 后缀匹配(如 "atoi" 匹配 @"83210a72e829a086.atoi",无 t.CExport 的函数) + + 使用 llvmlite.function_get_name/next 访问器绕过 stub 类型限制 + (stub 类型字段不足且字段类型可能错误,直接字段访问会被静默跳过)。 + """ + if mod is None or name is None: + return None + name_len: t.CSizeT = string.strlen(name) + cur: llvmlite.Function | t.CPtr = mod.FuncHead + # 第一遍:精确匹配 + while cur is not None: + cur_name: t.CChar | t.CPtr = llvmlite.function_get_name(cur) + if cur_name is not None: + if string.strcmp(cur_name, name) == 0: + return cur + cur = llvmlite.function_get_next(cur) + # 第二遍:后缀匹配(.name) + # 不跳过 declare:方法 stub 也是 declare,需要通过后缀匹配找到 + # 调用处(translate_call 等)负责判断 IsDeclared 并决定使用裸名还是 sha1 前缀名 + cur = mod.FuncHead + while cur is not None: + cur_name2: t.CChar | t.CPtr = llvmlite.function_get_name(cur) + if cur_name2 is not None: + cur_len: t.CSizeT = string.strlen(cur_name2) + if cur_len > name_len + 1: + suffix_start: t.CSizeT = cur_len - name_len + if cur_name2[suffix_start - 1] == '.': + match: int = 1 + for i in range(name_len): + if cur_name2[suffix_start + i] != name[i]: + match = 0 + break + if match == 1: + return cur + cur = llvmlite.function_get_next(cur) + return None + +# ============================================================ +# _ensure_c_lib_declare - 为已知的 C 库函数创建 declare 声明 +# +# 对应 TPC 的 _C_LIB_FUNCS 机制。当裸名调用 memset/memmove/memcmp/ +# strcmp/strlen 等已知 C 库函数时,自动在当前模块创建 declare, +# 避免报 "裸名调用未定义且未导入" 错误。 +# memcpy 不在此处理(已有 _emit_llvm_memcpy_intrinsic 映射到 @llvm.memcpy)。 +# +# Args: +# pool: 内存池 +# mod: LLVM 模块 +# name: 函数名 +# +# Returns: +# Function 指针(已创建 declare),或 None 如果不是已知 C 库函数 +# ============================================================ +def _ensure_c_lib_declare(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + name: str) -> llvmlite.Function | t.CPtr: + """为已知的 C 库函数创建 declare 声明""" + if pool is None or mod is None or name is None: + return None + + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + ret_ty: llvmlite.LLVMType | t.CPtr = None + params: int = 0 # 参数数量 + + if string.strcmp(name, "strlen") == 0 or string.strcmp(name, "strlength") == 0: + ret_ty = i64_ty + params = 1 + elif string.strcmp(name, "memset") == 0: + ret_ty = i8_ptr_ty + params = 3 + elif string.strcmp(name, "memcpy") == 0: + ret_ty = i8_ptr_ty + params = 3 + elif string.strcmp(name, "memmove") == 0: + ret_ty = i8_ptr_ty + params = 3 + elif string.strcmp(name, "memcmp") == 0: + ret_ty = i32_ty + params = 3 + elif string.strcmp(name, "strcmp") == 0: + ret_ty = i32_ty + params = 2 + elif string.strcmp(name, "strncmp") == 0: + ret_ty = i32_ty + params = 3 + elif string.strcmp(name, "strcpy") == 0: + ret_ty = i8_ptr_ty + params = 2 + elif string.strcmp(name, "strncpy") == 0: + ret_ty = i8_ptr_ty + params = 3 + elif string.strcmp(name, "strcat") == 0: + ret_ty = i8_ptr_ty + params = 2 + elif string.strcmp(name, "puts") == 0: + ret_ty = i32_ty + params = 1 + elif string.strcmp(name, "atoi") == 0: + ret_ty = i32_ty + params = 1 + elif string.strcmp(name, "atol") == 0: + ret_ty = i64_ty + params = 1 + elif string.strcmp(name, "abs") == 0: + ret_ty = i32_ty + params = 1 + elif string.strcmp(name, "labs") == 0: + ret_ty = i64_ty + params = 1 + else: + return None + + # 创建 declare + fn: llvmlite.Function | t.CPtr = llvmlite.create_declare(pool, mod, name, ret_ty) + if fn is None: + return None + # 添加参数 + if params == 1: + if string.strcmp(name, "abs") == 0: + llvmlite.add_param(pool, fn, i32_ty, "n") + elif string.strcmp(name, "labs") == 0: + llvmlite.add_param(pool, fn, i64_ty, "n") + else: + llvmlite.add_param(pool, fn, i8_ptr_ty, "s") + elif params == 2: + llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") + llvmlite.add_param(pool, fn, i8_ptr_ty, "src") + elif params == 3: + if string.strcmp(name, "memset") == 0: + llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") + llvmlite.add_param(pool, fn, i32_ty, "c") + llvmlite.add_param(pool, fn, i64_ty, "n") + else: + llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") + llvmlite.add_param(pool, fn, i8_ptr_ty, "src") + llvmlite.add_param(pool, fn, i64_ty, "n") + return fn + +# ============================================================ +# _infer_external_func_ret_ty - 根据函数名推断外部函数返回类型 +# +# stubs 在翻译后才注入 IR,翻译时模块中无 stub 函数声明, +# 因此对 includes 库函数(如 string.strchr 返回 i8*)需根据 +# 函数名推断返回类型,避免指针被截断为 i32。 +# +# 覆盖 includes/string.py 所有导出函数: +# i8*: strcpy, strncpy, strchr, strrchr, strstr, memset, memset32, memcpy, memmove +# i64: strlen, atoll +# double: atof +# i8: samestr +# i32(默认): strcmp, strncmp, memcmp, strspn, atoi, split +# ============================================================ +def _infer_external_func_ret_ty(pool: memhub.MemBuddy | t.CPtr, + func_name: str) -> llvmlite.LLVMType | t.CPtr: + """根据函数名推断外部 includes 函数的返回类型 + + 支持三种函数名形式: + 1. 裸名: "parse", "strlen" + 2. 别名: "json_parse"(from X import parse as json_parse) + 3. 带 SHA1 前缀: "240a9a4157959a9f.parse"(跨模块调用 mangled name) + """ + if pool is None or func_name is None: + return llvmlite.Int32(pool) + + # 提取裸函数名:去掉 SHA1 前缀(如 "240a9a4157959a9f.parse" → "parse") + # SHA1 前缀是 16 位十六进制 + '.',检查是否有 '.' 分隔 + bare_name: str = func_name + dot_pos: str = string.strrchr(func_name, 46) # 46 = ord('.') + if dot_pos is not None: + # '.' 后的部分是裸函数名 + bare_name = dot_pos + 1 + + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + + # 返回 i8* 的函数(指针返回值,截断会导致错误) + if string.strcmp(bare_name, "strchr") == 0 or string.strcmp(func_name, "strchr") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "strrchr") == 0 or string.strcmp(func_name, "strrchr") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "strstr") == 0 or string.strcmp(func_name, "strstr") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "strcpy") == 0 or string.strcmp(func_name, "strcpy") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "strncpy") == 0 or string.strcmp(func_name, "strncpy") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "memset") == 0 or string.strcmp(func_name, "memset") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "memset32") == 0 or string.strcmp(func_name, "memset32") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "memcpy") == 0 or string.strcmp(func_name, "memcpy") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "memmove") == 0 or string.strcmp(func_name, "memmove") == 0: + return i8_ptr_ty + # JSON 解析函数返回 JsonValue*(指针) + # from json.__parser import parse as json_parse → 别名 json_parse 也需覆盖 + if string.strcmp(bare_name, "parse") == 0 or string.strcmp(func_name, "parse") == 0 or string.strcmp(func_name, "json_parse") == 0: + return i8_ptr_ty + # MemBuddy 方法(当类型信息丢失时可能走外部函数路径) + if string.strcmp(func_name, "alloc") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if string.strcmp(func_name, "calloc") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if string.strcmp(func_name, "realloc") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if string.strcmp(func_name, "alloc_buf") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + # VLogger 模块函数(跨模块调用时 stub 未注入,返回指针被截断为 i32 导致崩溃) + if string.strcmp(func_name, "get_logger") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if string.strcmp(func_name, "fmt_buf") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + # Config 模块函数(跨模块调用时 stub 未注入,返回 i8* 被 inttoptr i32 截断导致路径损坏) + if string.strcmp(func_name, "get_includes_binary_dir") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + # HandlesType 模块函数(返回 ast.AST|t.CPtr 联合类型,跨模块推断为 i32 导致指针截断) + if string.strcmp(bare_name, "_parse_type_string") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + + # 返回 i64 的函数 + if string.strcmp(func_name, "strlen") == 0: + return llvmlite.Int64(pool) + if string.strcmp(func_name, "atoll") == 0: + return llvmlite.Int64(pool) + + # 返回 double 的函数 + if string.strcmp(func_name, "atof") == 0: + return llvmlite.Double(pool) + + # 返回 i8 的函数 + if string.strcmp(func_name, "samestr") == 0: + return llvmlite.Int8(pool) + + # Win32 API 返回指针(VOIDPTR/HANDLE)的函数 + # stubs 翻译时未注入,需推断返回 i8* 避免指针被截断为 i32 导致解引用崩溃 + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if string.strcmp(func_name, "VirtualAlloc") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "HeapAlloc") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "HeapReAlloc") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "HeapCreate") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GetProcessHeap") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GlobalAlloc") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GlobalFree") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GlobalLock") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "LocalAlloc") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "LocalFree") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GetProcAddress") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GetModuleHandleA") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GetModuleHandleW") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "LoadLibraryA") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "LoadLibraryW") == 0: + return i8_ptr_ty + # Win32 Handle 返回函数(HANDLE = void* = i8*) + if string.strcmp(func_name, "GetStdHandle") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "CreateFileA") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "CreateFileW") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "FindFirstFileA") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "FindFirstFileW") == 0: + return i8_ptr_ty + + # Win32 API 返回 i64 (SIZE_T) 的函数 + if string.strcmp(func_name, "VirtualQuery") == 0: + return llvmlite.Int64(pool) + if string.strcmp(func_name, "HeapSize") == 0: + return llvmlite.Int64(pool) + if string.strcmp(func_name, "HeapCompact") == 0: + return llvmlite.Int64(pool) + if string.strcmp(func_name, "GlobalSize") == 0: + return llvmlite.Int64(pool) + + # llvmlite build_* 函数返回类型推断 + # stubs 翻译时未注入,需推断返回类型避免指针被截断为 i32 + # 大多数 build_* 函数返回 Value*(指针),少数终止指令返回 void + if string.strncmp(func_name, "build_", 6) == 0: + # 返回 void 的 build_* 函数(终止指令和无返回值指令) + if string.strcmp(func_name, "build_ret") == 0 or string.strcmp(func_name, "build_ret_void") == 0 or \ + string.strcmp(func_name, "build_store") == 0 or string.strcmp(func_name, "build_br") == 0 or \ + string.strcmp(func_name, "build_cond_br") == 0 or string.strcmp(func_name, "build_unreachable") == 0 or \ + string.strcmp(func_name, "build_switch") == 0: + return llvmlite.Void(pool) + # 其他 build_* 函数返回 Value*(指针) + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + + # llvmlite 类型工厂函数返回 LLVMType*(指针) + # Int1/Int8/Int16/Int32/Int64/Ptr/Func/Array/Struct/Void/Half/Float/Double/FP128/Label + # new_param_node/new_phi_incoming 返回 ParamNode*/PhiIncoming*(指针) + # const_int32/const_int64/ConstFloat/ConstZero/ConstNull/ConstInt 返回 Value*(指针) + # function_get_name/param_get_ty 等访问器返回指针 + if string.strcmp(func_name, "Int1") == 0 or string.strcmp(func_name, "Int8") == 0 or string.strcmp(func_name, "Int16") == 0 or \ + string.strcmp(func_name, "Int32") == 0 or string.strcmp(func_name, "Int64") == 0 or string.strcmp(func_name, "Ptr") == 0 or \ + string.strcmp(func_name, "Func") == 0 or string.strcmp(func_name, "Array") == 0 or string.strcmp(func_name, "Struct") == 0 or \ + string.strcmp(func_name, "Void") == 0 or string.strcmp(func_name, "Half") == 0 or string.strcmp(func_name, "Float") == 0 or \ + string.strcmp(func_name, "Double") == 0 or string.strcmp(func_name, "FP128") == 0 or string.strcmp(func_name, "Label") == 0 or \ + string.strcmp(func_name, "new_param_node") == 0 or string.strcmp(func_name, "new_phi_incoming") == 0 or \ + string.strcmp(func_name, "const_int32") == 0 or string.strcmp(func_name, "const_int64") == 0 or \ + string.strcmp(func_name, "ConstFloat") == 0 or string.strcmp(func_name, "ConstZero") == 0 or \ + string.strcmp(func_name, "ConstNull") == 0 or string.strcmp(func_name, "ConstInt") == 0 or \ + string.strcmp(func_name, "function_get_name") == 0 or string.strcmp(func_name, "param_get_ty") == 0 or \ + string.strcmp(func_name, "value_get_ty") == 0 or string.strcmp(func_name, "value_get_next") == 0 or \ + string.strcmp(func_name, "function_get_ret_ty") == 0 or string.strcmp(func_name, "function_get_params") == 0 or \ + string.strcmp(func_name, "function_get_param_head") == 0 or string.strcmp(func_name, "param_get_next") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + + # 默认 i32(整数):与本模块函数定义的默认返回类型一致(HandlesFunctions.py line 324) + # 已知返回指针的函数在上方显式列出(返回 i8*),已知返回 i64 的函数也显式列出 + # 避免使用 i64 导致 stub 声明(declare i64)与实际定义(define i32)类型不匹配 + # x86-64 ABI 中 i32 返回值在 rax 低 32 位,与 define i32 完全一致 + # 与 _infer_method_ret_ty 的默认策略保持一致 + # WARNING: 未登记的外部函数返回类型默认推断为 i32,若实际返回指针/i64 会被截断 + VLogger.warning( + f"外部函数返回类型未登记,默认推断为 i32(可能截断指针/i64): {func_name}", + "HandlesExprCall") + return llvmlite.Int32(pool) + +# ============================================================ +# _get_external_func_param_ty - 获取外部函数第 idx 个参数的期望类型 +# +# stubs 翻译时未注入,需推断参数类型以提升字面量(如 i32→i64), +# 避免 declare(i64) 与 call(i32) 类型不匹配。 +# +# 注意:stubs 翻译时 ULONG(t.CUnsignedLong) 在 LLVM IR 中被翻译为 i64 +# (因为 LLVM 中 long 是 64 位),因此 Win32 API 中所有 ULONG/DWORD/SIZE_T +# 参数在 declare 中都是 i64。call 时必须匹配,否则类型不匹配。 +# +# 策略:对 Win32 API 函数的所有非指针参数(字面量)都提升为 i64, +# 以匹配 declare 中 ULONG 被翻译为 i64 的情况。 +# +# 指针参数(VOIDPTR/HANDLE)不在此处理,由调用点的 inttoptr 处理。 +# ============================================================ +def _get_external_func_param_ty(pool: memhub.MemBuddy | t.CPtr, + func_name: str, + param_idx: int) -> llvmlite.LLVMType | t.CPtr: + """获取外部函数第 param_idx 个参数的期望类型,None 表示用字面量原类型 + + 对 Win32 API 函数的所有非指针参数返回 i64,匹配 declare 中 + ULONG/SIZE_T 被统一翻译为 i64 的情况。 + """ + if pool is None or func_name is None: + return None + + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + + # Win32 API 函数列表:所有非指针参数在 declare 中都是 i64 + # (因为 ULONG/DWORD/SIZE_T 在 LLVM stubs 翻译时都被映射为 i64) + win32_apis: list[str] | t.CPtr = [ + "VirtualAlloc", "VirtualFree", "VirtualProtect", "VirtualQuery", + "VirtualLock", "VirtualUnlock", + "HeapCreate", "HeapDestroy", "HeapAlloc", "HeapReAlloc", + "HeapFree", "HeapSize", "HeapValidate", "HeapCompact", + "GlobalAlloc", "GlobalFree", "GlobalLock", "GlobalUnlock", "GlobalSize", + "LocalAlloc", "LocalFree", + "GetLastError", "SetLastError", + "Sleep", "SleepEx", + "GetTickCount", "GetProcessHeap" + ] + + # list 迭代不支持,用 range + get 替代 + api_count: t.CSizeT = win32_apis.__len__() + for ai in range(api_count): + api_name: str = win32_apis.get(ai) + if string.strcmp(api_name, func_name) == 0: + return i64_ty + + return None + +# ============================================================ +# _emit_llvm_memcpy_intrinsic — 将 memcpy 调用映射到 @llvm.memcpy 内联函数 +# +# 背景: string.memcpy 是 t.CExport 函数,跨模块调用生成 @memcpy 裸名调用。 +# 但在 monomorphization 场景下,目标模块的 deps.txt 可能不含 string, +# 导致 @memcpy 声明缺失,链接器报 undefined value。 +# +# 解决: 将 memcpy 调用映射到 LLVM 内联函数 @llvm.memcpy, +# 该内联函数在当前模块内声明,无需跨模块依赖。 +# +# @llvm.memcpy 签名: void (i8* dst, i8* src, i64 len, i1 isvolatile) +# C memcpy 签名: i8* (i8* dst, i8* src, i64 len) — 返回 dst +# +# Args: +# args_head: 参数链表头(dst, src, num),通过 Value.Next 链接 +# arg_count: 参数数量(应为 3) +# +# Returns: +# dst 值(匹配 C memcpy 语义: 返回 dest 指针) +# ============================================================ +def _emit_llvm_memcpy_intrinsic(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + dst_val: llvmlite.Value | t.CPtr, + src_val: llvmlite.Value | t.CPtr, + num_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + """将 memcpy 调用映射到 @llvm.memcpy 内联函数 + + 直接接收三个 Value 参数,避免通过 Next 链表遍历(共享 alloca 对象的 + Next 字段可能被其他操作污染,导致链表断裂)。 + """ + if pool is None or builder is None or mod is None: + return None + if dst_val is None or src_val is None or num_val is None: + return None + + # 在函数顶部声明 void_ty,避免后续遮蔽 + void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + + # 声明 @llvm.memcpy(如未声明) + memcpy_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, "llvm.memcpy") + if memcpy_func is None: + memcpy_func = llvmlite.create_declare(pool, mod, "llvm.memcpy", void_ty) + if memcpy_func is not None: + i8_ptr_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + i64_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i1_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "dst") + llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "src") + llvmlite.add_param(pool, memcpy_func, i64_ty_d, "len") + llvmlite.add_param(pool, memcpy_func, i1_ty_d, "isvolatile") + + # 类型转换: dst, src → i8*; num → i64 + # 注意: 使用 value_get_ty 访问器获取 Ty,避免本地 Value 类型字段索引偏移 + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + + # dst → i8* + dst_coerced: llvmlite.Value | t.CPtr = dst_val + dst_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(dst_val) + if HandlesExpr.is_ptr_type(dst_ty) != 0: + dst_coerced = llvmlite.build_bitcast(builder, dst_val, i8_ptr_ty) + else: + dst_bits: int = HandlesExpr.get_llvm_type_bits(dst_ty) + if dst_bits != 0: + if dst_bits < 64: + dst_coerced = llvmlite.build_zext(builder, dst_val, i64_ty) + dst_coerced = llvmlite.build_inttoptr(builder, dst_coerced, i8_ptr_ty) + + # src → i8* + src_coerced: llvmlite.Value | t.CPtr = src_val + src_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(src_val) + if HandlesExpr.is_ptr_type(src_ty) != 0: + src_coerced = llvmlite.build_bitcast(builder, src_val, i8_ptr_ty) + else: + src_bits: int = HandlesExpr.get_llvm_type_bits(src_ty) + if src_bits != 0: + if src_bits < 64: + src_coerced = llvmlite.build_zext(builder, src_val, i64_ty) + src_coerced = llvmlite.build_inttoptr(builder, src_coerced, i8_ptr_ty) + + # num → i64 + num_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, num_val, i64_ty) + + if dst_coerced is None or src_coerced is None or num_coerced is None: + return None + + # 添加 i1 false 参数(isvolatile)— llvm.memcpy 需要 4 个参数 + false_val: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "false") + + # 使用 includes 中的访问器函数构建参数链表,避免本地 Value 类型字段索引偏移 + # (f26cd4c78b4d554c.Value 缺少 GSListNode 的 Next 字段,直接访问 .Next 会修改 .Ty) + llvmlite.value_set_next(dst_coerced, src_coerced) + llvmlite.value_set_next(src_coerced, num_coerced) + if false_val is not None: + llvmlite.value_set_next(num_coerced, false_val) + llvmlite.value_set_next(false_val, None) + else: + llvmlite.value_set_next(num_coerced, None) + + # 使用 build_call 发射 call 指令(内部用 includes Value 类型访问字段,索引正确) + # _ll_name_needs_quote 已对 llvm. 前缀豁免引号 + result: llvmlite.Value | t.CPtr = llvmlite.build_call(builder, "llvm.memcpy", dst_coerced, 4, void_ty, 0) + + # 返回 dst(匹配 C memcpy 语义: 返回 dest 指针) + return dst_coerced + +# ============================================================ +# c.Deref(ptr) — 解引用指针,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 + + # 两端均为指向同一结构体类型的指针时执行结构体拷贝(*ptr = *val), + # 而非存储指针值。这对 REnum 变体构造(c.DerefAs(ptr, LLVMType.Int(32)))至关重要: + # LLVMType.Int(32) 构造返回 alloca 指针(Ptr(LLVMType)),若直接 store 指针值, + # 只写入 8 字节指针(tag 字段仍是 0x0),导致运行时读 tag 错乱。 + # 对应 TPC HandlesExprCall.py:3696-3701 的 struct 拷贝逻辑。 + if HandlesExpr.is_ptr_type(ptr_val.Ty) != 0 and HandlesExpr.is_ptr_type(val.Ty) != 0: + ptr_pointee: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee + val_pointee: llvmlite.LLVMType | t.CPtr = val.Ty.Pointee + if ptr_pointee is not None and val_pointee is not None: + # ptr_pointee 是已注册结构体类型(用 find_struct_by_type 判断) + if HandlesStruct.find_struct_by_type(ptr_pointee) is not None: + if ptr_pointee is val_pointee: + # 同一结构体类型:load 值再 store(结构体拷贝) + loaded: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, val_pointee, val) + if loaded is not None: + # bitcast ptr 到结构体指针再 store + struct_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, ptr_pointee) + casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, ptr_val, struct_ptr_ty) + if casted_ptr is not None: + llvmlite.build_store(builder, loaded, casted_ptr) + return val + + # bitcast ptr 到 val.Ty* 再 store + val_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, val.Ty) + casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ptr_val, val_ptr_ty) + if casted_ptr is None: + return None + llvmlite.build_store(builder, val, casted_ptr) + return val + +# ============================================================ +# c.Addr(var) — 取变量地址,返回 alloca 指针(不 load) +# +# 用于获取栈变量的可写地址,配合 c.DerefAs 使用 +# ============================================================ +def translate_c_addr(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.Addr(var) → 返回变量的 alloca 指针(不 load)""" + if cl is None: + return None + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or cargs.__len__() < 1: + return None + + arg0: ast.AST | t.CPtr = cargs.get(0) + if arg0 is None: + return None + + # Name 形式: c.Addr(var) → 返回变量的 alloca 指针(不 load) + if arg0.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0) + if nm.id is None: + return None + return HandlesVar.lookup_var(trans.SymTab, nm.id) + + # Attribute 形式: c.Addr(self.field) → 取字段地址(GEP 到字段,不 load) + # 用于 atom.__atomic_test_and_set(c.Addr(self.lock_val), ...) 等锁操作 + if arg0.kind() == ast.ASTKind.Attribute: + if trans is None: + return None + at_addr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg0) + if at_addr is None or at_addr.attr is None or at_addr.value is None: + return None + # 解析 self(Name)→ 查找 alloca + if at_addr.value.kind() != ast.ASTKind.Name: + return None + self_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_addr.value) + if self_nm.id is None: + return None + self_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, self_nm.id) + if self_alloca is None or self_alloca.Ty is None: + return None + # 从 self 类型提取结构体类型(Ptr(Struct) 或 Ptr(Ptr(Struct))) + struct_ty: llvmlite.LLVMType | t.CPtr = None + self_is_ptr_ptr: int = 0 + match self_alloca.Ty: + case llvmlite.LLVMType.Ptr(inner1): + match inner1: + case llvmlite.LLVMType.Ptr(inner2): + struct_ty = inner2 + self_is_ptr_ptr = 1 + case _: + struct_ty = inner1 + case _: + return None + # 查找字段 + fe_addr: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( + struct_ty, at_addr.attr) + if fe_addr is None: + return None + # self_alloca 是 Ptr(Ptr(Struct)) 时先 load 成 Ptr(Struct) 对象指针 + obj_ptr: llvmlite.Value | t.CPtr = self_alloca + if self_is_ptr_ptr == 1: + self_obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) + obj_ptr = llvmlite.build_load(builder, self_obj_ty, self_alloca) + if obj_ptr is None: + return None + # GEP 到字段地址 + return llvmlite.build_gep_struct( + builder, struct_ty, fe_addr.Ty, obj_ptr, fe_addr.Index) + +# ============================================================ +# c.Load(a, b) — 指针间复制: *a = *b +# +# 加载 b 指向的值,存储到 a 指向的地址。 +# 生成: %pc_src = bitcast i8* %src to * +# %loaded = load , * %pc_src +# %pc_dst = bitcast i8* %dst to * +# store %loaded, * %pc_dst +# ============================================================ +def translate_c_load(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.Load(a, b) → *a = *b(加载 b 的值,存储到 a)""" + if cl is None: + return None + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or cargs.__len__() < 2: + return None + + dst_ptr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cargs.get(0), None, 0, trans) + src_ptr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cargs.get(1), None, 0, trans) + if dst_ptr is None or src_ptr is None: + return None + + # 确定 pointee 类型(优先用 src 的 pointee,回退到 dst 的 pointee) + pointee: llvmlite.LLVMType | t.CPtr = None + if src_ptr.Ty is not None: + pointee = src_ptr.Ty.Pointee + if pointee is None and dst_ptr.Ty is not None: + pointee = dst_ptr.Ty.Pointee + if pointee is None: + return None + + # bitcast src 到 pointee* 并 load + target_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, pointee) + src_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, src_ptr, target_ptr_ty) + if src_cast is None: + return None + loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, pointee, src_cast) + if loaded is None: + return None + + # bitcast dst 到 pointee* 并 store + dst_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, dst_ptr, target_ptr_ty) + if dst_cast is None: + return None + llvmlite.build_store(builder, loaded, dst_cast) + return loaded + +# ============================================================ +# c.Asm — 内联汇编支持 +# +# 生成: %N = call asm sideeffect "", ""() +# 或: call void asm sideeffect "", ""() +# +# 操作数按出现顺序编号 $0, $1, ...(用户需按输出在前写 f-string) +# ============================================================ + +ASM_MAX_OPERANDS: t.CDefine = 16 +ASM_TEXT_BUF_SIZE: t.CDefine = 2048 +ASM_CONST_BUF_SIZE: t.CDefine = 512 +ASM_ARGS_BUF_SIZE: t.CDefine = 512 +ASM_LINE_BUF_SIZE: t.CDefine = 4096 + +# ============================================================ +# AsmOperand - 内联汇编操作数条目 +# ============================================================ +@t.NoVTable +class AsmOperand: + """内联汇编操作数条目""" + Value: llvmlite.Value | t.CPtr # 输入值或输出 alloca + Constraint: str # 约束字符串 (如 "r", "=r") + IsOutput: int # 1=输出, 0=输入 + +# ============================================================ +# _asm_append_cstr — 将 C 字符串 src 追加到 dst 末尾 +# ============================================================ +def _asm_append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, + src: t.CChar | t.CPtr): + """将 C 字符串 src 追加到 dst 末尾""" + if dst is None or src is None: + return + dlen: t.CSizeT = string.strlen(dst) + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: + return + i: t.CSizeT = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' + +# ============================================================ +# _asm_escape_for_ir — 将汇编文本转义为 LLVM IR 字符串内容 +# +# \n → \0A, " → \22, \ → \5C +# ============================================================ +def _asm_escape_for_ir(pool: memhub.MemBuddy | t.CPtr, + src: t.CChar | t.CPtr) -> t.CChar | t.CPtr: + """转义汇编文本用于 LLVM IR 字符串字面量""" + if src is None: + return None + slen: t.CSizeT = string.strlen(src) + buf: t.CChar | t.CPtr = pool.alloc(slen * 4 + 8) + if buf is None: + return None + pos: t.CSizeT = 0 + for ch in src: + if ch == '\n': + buf[pos] = '\\' + pos += 1 + buf[pos] = '0' + pos += 1 + buf[pos] = 'A' + pos += 1 + elif ch == '"': + buf[pos] = '\\' + pos += 1 + buf[pos] = '2' + pos += 1 + buf[pos] = '2' + pos += 1 + elif ch == '\\': + buf[pos] = '\\' + pos += 1 + buf[pos] = '5' + pos += 1 + buf[pos] = 'C' + pos += 1 + else: + buf[pos] = ch + pos += 1 + buf[pos] = '\0' + return buf + +# ============================================================ +# _resolve_register — 将 ASM_DESCR 属性名映射到约束字符串 +# ============================================================ +def _resolve_register(attr_name: str) -> str: + """将 t.ASM_DESCR.XXX 的属性名映射到约束字符串值""" + if attr_name is None: + return "" + + # Clobber 破坏描述符 + if string.strcmp(attr_name, "CLOBBER_MEMORY") == 0: return "memory" + if string.strcmp(attr_name, "CLOBBER_CC") == 0: return "cc" + if string.strcmp(attr_name, "CLOBBER_RAX") == 0: return "rax" + if string.strcmp(attr_name, "CLOBBER_RBX") == 0: return "rbx" + if string.strcmp(attr_name, "CLOBBER_RCX") == 0: return "rcx" + if string.strcmp(attr_name, "CLOBBER_RDX") == 0: return "rdx" + if string.strcmp(attr_name, "CLOBBER_RSI") == 0: return "rsi" + if string.strcmp(attr_name, "CLOBBER_RDI") == 0: return "rdi" + if string.strcmp(attr_name, "CLOBBER_RBP") == 0: return "rbp" + if string.strcmp(attr_name, "CLOBBER_RSP") == 0: return "rsp" + if string.strcmp(attr_name, "CLOBBER_R8") == 0: return "r8" + if string.strcmp(attr_name, "CLOBBER_R9") == 0: return "r9" + if string.strcmp(attr_name, "CLOBBER_R10") == 0: return "r10" + if string.strcmp(attr_name, "CLOBBER_R11") == 0: return "r11" + if string.strcmp(attr_name, "CLOBBER_R12") == 0: return "r12" + if string.strcmp(attr_name, "CLOBBER_R13") == 0: return "r13" + if string.strcmp(attr_name, "CLOBBER_R14") == 0: return "r14" + if string.strcmp(attr_name, "CLOBBER_R15") == 0: return "r15" + if string.strcmp(attr_name, "CLOBBER_EAX") == 0: return "eax" + if string.strcmp(attr_name, "CLOBBER_EBX") == 0: return "ebx" + if string.strcmp(attr_name, "CLOBBER_ECX") == 0: return "ecx" + if string.strcmp(attr_name, "CLOBBER_EDX") == 0: return "edx" + if string.strcmp(attr_name, "CLOBBER_ESI") == 0: return "esi" + if string.strcmp(attr_name, "CLOBBER_EDI") == 0: return "edi" + if string.strcmp(attr_name, "CLOBBER_DX") == 0: return "dx" + if string.strcmp(attr_name, "CLOBBER_AX") == 0: return "ax" + if string.strcmp(attr_name, "CLOBBER_CX") == 0: return "cx" + if string.strcmp(attr_name, "CLOBBER_SI") == 0: return "si" + if string.strcmp(attr_name, "CLOBBER_DI") == 0: return "di" + + # Output 输出约束 + if string.strcmp(attr_name, "OUTPUT_REG") == 0: return "=r" + if string.strcmp(attr_name, "OUTPUT_MEM") == 0: return "=m" + if string.strcmp(attr_name, "OUTPUT_EAX") == 0: return "=a" + if string.strcmp(attr_name, "OUTPUT_EBX") == 0: return "=b" + if string.strcmp(attr_name, "OUTPUT_ECX") == 0: return "=c" + if string.strcmp(attr_name, "OUTPUT_EDX") == 0: return "=d" + if string.strcmp(attr_name, "OUTPUT_ESI") == 0: return "=S" + if string.strcmp(attr_name, "OUTPUT_EDI") == 0: return "=D" + if string.strcmp(attr_name, "OUTPUT_RAX") == 0: return "=a" + if string.strcmp(attr_name, "OUTPUT_RBX") == 0: return "=b" + if string.strcmp(attr_name, "OUTPUT_RCX") == 0: return "=c" + if string.strcmp(attr_name, "OUTPUT_RDX") == 0: return "=d" + if string.strcmp(attr_name, "OUTPUT_RSI") == 0: return "=S" + if string.strcmp(attr_name, "OUTPUT_RDI") == 0: return "=D" + + # Input/Register 输入约束 + if string.strcmp(attr_name, "REG_ANY") == 0: return "r" + if string.strcmp(attr_name, "REG_EAX") == 0: return "a" + if string.strcmp(attr_name, "REG_EBX") == 0: return "b" + if string.strcmp(attr_name, "REG_ECX") == 0: return "c" + if string.strcmp(attr_name, "REG_EDX") == 0: return "d" + if string.strcmp(attr_name, "REG_ESI") == 0: return "S" + if string.strcmp(attr_name, "REG_EDI") == 0: return "D" + if string.strcmp(attr_name, "REG_RAX") == 0: return "a" + if string.strcmp(attr_name, "REG_RBX") == 0: return "b" + if string.strcmp(attr_name, "REG_RCX") == 0: return "c" + if string.strcmp(attr_name, "REG_RDX") == 0: return "d" + if string.strcmp(attr_name, "REG_RSI") == 0: return "S" + if string.strcmp(attr_name, "REG_RDI") == 0: return "D" + + if string.strcmp(attr_name, "INPUT_REG") == 0: return "r" + if string.strcmp(attr_name, "INPUT_MEM") == 0: return "m" + if string.strcmp(attr_name, "INPUT_EAX") == 0: return "a" + if string.strcmp(attr_name, "INPUT_EBX") == 0: return "b" + if string.strcmp(attr_name, "INPUT_ECX") == 0: return "c" + if string.strcmp(attr_name, "INPUT_EDX") == 0: return "d" + if string.strcmp(attr_name, "INPUT_ESI") == 0: return "S" + if string.strcmp(attr_name, "INPUT_EDI") == 0: return "D" + if string.strcmp(attr_name, "INPUT_RAX") == 0: return "a" + if string.strcmp(attr_name, "INPUT_RBX") == 0: return "b" + if string.strcmp(attr_name, "INPUT_RCX") == 0: return "c" + if string.strcmp(attr_name, "INPUT_RDX") == 0: return "d" + if string.strcmp(attr_name, "INPUT_RSI") == 0: return "S" + if string.strcmp(attr_name, "INPUT_RDI") == 0: return "D" + + return "" + +# ============================================================ +# _resolve_asm_descr — 递归解析约束表达式 +# +# 支持: +# t.ASM_DESCR.XXX → _resolve_register(XXX) +# expr | expr (BinOp BitOr) → 拼接 +# "string" (Constant) → 直接返回 +# ============================================================ +def _resolve_asm_descr(pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr) -> str: + """递归解析约束表达式,返回约束字符串""" + if node is None: + return "" + + k: int = node.kind() + + # BinOp with BitOr: 拼接左右 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if bop.op == ast.OpKind.BitOr: + left_str: str = _resolve_asm_descr(pool, bop.left) + right_str: str = _resolve_asm_descr(pool, bop.right) + llen: t.CSizeT = string.strlen(left_str) + rlen: t.CSizeT = string.strlen(right_str) + buf: str = pool.alloc(llen + rlen + 1) + if buf is None: + return "" + string.strcpy(buf, left_str) + for i in range(rlen): + buf[llen + i] = right_str[i] + buf[llen + rlen] = '\0' + return buf + return "" + + # Attribute: t.ASM_DESCR.XXX 或 t.XXX + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + # t.ASM_DESCR.XXX + if at.value is not None and at.value.kind() == ast.ASTKind.Attribute: + inner: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value) + if inner.value is not None and inner.value.kind() == ast.ASTKind.Name: + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner.value) + if mod_nm.id is not None and string.strcmp(mod_nm.id, "t") == 0: + if inner.attr is not None and string.strcmp(inner.attr, "ASM_DESCR") == 0: + return _resolve_register(at.attr) + # t.XXX 简化形式 + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + mod_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if mod_nm2.id is not None and string.strcmp(mod_nm2.id, "t") == 0: + return _resolve_register(at.attr) + return "" + + # Constant: 字符串常量 + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn.const_kind == ast.CONST_STR: + return cn.str_val + return "" + + return "" + +# ============================================================ +# _asm_get_operand — 获取操作数数组中第 idx 个元素的指针 +# ============================================================ +def _asm_get_operand(base: AsmOperand | t.CPtr, + idx: int) -> AsmOperand | t.CPtr: + """获取操作数数组中第 idx 个元素的指针""" + entry_size: t.CSizeT = AsmOperand.__sizeof__() + entry_addr: t.CUInt64T = t.CUInt64T(base) + idx * entry_size + return (AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + +# ============================================================ +# _asm_is_c_call — 检查 Call 节点是否是 c.XXX 调用 +# +# 返回 attr_name(如 "AsmInp"/"AsmOut"),不是则返回 None +# ============================================================ +def _asm_is_c_call(node: ast.Call | t.CPtr) -> str: + """检查 Call 节点是否是 c.XXX 调用,返回属性名或 None""" + if node is None or node.func is None: + return None + if node.func.kind() != ast.ASTKind.Attribute: + return None + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node.func) + if at.value is None or at.value.kind() != ast.ASTKind.Name: + return None + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if mod_nm.id is None or string.strcmp(mod_nm.id, "c") != 0: + return None + return at.attr + +# ============================================================ +# _asm_add_operand — 添加操作数到数组 +# +# 返回 1 成功, 0 失败(数组已满) +# ============================================================ +def _asm_add_operand(operands: AsmOperand | t.CPtr, + count: int, + val: llvmlite.Value | t.CPtr, + constraint: str, + is_output: int) -> int: + """添加操作数到数组,返回新计数(失败返回原计数)""" + if count >= ASM_MAX_OPERANDS: + return count + op: AsmOperand | t.CPtr = _asm_get_operand(operands, count) + op.Value = val + op.Constraint = constraint + op.IsOutput = is_output + return count + 1 + +# ============================================================ +# translate_c_asm — 翻译 c.Asm 内联汇编 +# +# 语法: +# c.Asm("nop", [t.ASM_DESCR.CLOBBER_MEMORY]) +# c.Asm(f"mov rax, {c.AsmInp(val, t.ASM_DESCR.REG_ANY)}", op=[...]) +# c.Asm(f"...", out=[c.AsmOut(var, t.ASM_DESCR.OUTPUT_REG)], op=[...]) +# ============================================================ +def translate_c_asm(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译 c.Asm 内联汇编,返回结果 Value(无输出时返回 None)""" + if cl is None: + return None + + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or cargs.__len__() < 1: + return None + + # 分配操作数数组 + operand_size: t.CSizeT = AsmOperand.__sizeof__() + operands: AsmOperand | t.CPtr = pool.alloc(operand_size * ASM_MAX_OPERANDS) + if operands is None: + return None + string.memset(operands, 0, operand_size * ASM_MAX_OPERANDS) + + # 分配 clobber 名数组 + clobbers: str | t.CPtr = pool.alloc(8 * ASM_MAX_OPERANDS) + if clobbers is None: + return None + string.memset(clobbers, 0, 8 * ASM_MAX_OPERANDS) + + # 分配 asm 文本缓冲区 + asm_text: t.CChar | t.CPtr = pool.alloc(ASM_TEXT_BUF_SIZE) + if asm_text is None: + return None + asm_text[0] = '\0' + + operand_count: int = 0 + clobber_count: int = 0 + fv_count: int = 0 + + # 分配 fv 索引数组(记录每个 FormattedValue 对应的操作数原始索引) + fv_orig_indices: int | t.CPtr = pool.alloc(4 * ASM_MAX_OPERANDS) + if fv_orig_indices is None: + return None + string.memset(fv_orig_indices, 0, 4 * ASM_MAX_OPERANDS) + + # ============================================================ + # 1. 解析汇编模板(JoinedStr 或 Constant)— 第一遍:收集操作数 + # 不生成 asm 文本(占位符 $N 需在重排后才能确定编号) + # ============================================================ + tmpl_node: ast.AST | t.CPtr = cargs.get(0) + if tmpl_node is not None: + tk: int = tmpl_node.kind() + + if tk == ast.ASTKind.JoinedStr: + js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node) + jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values + if jvalues is not None: + jvlen: t.CSizeT = jvalues.__len__() + for vi in range(jvlen): + part: ast.AST | t.CPtr = jvalues.get(vi) + if part is None: + continue + pk: int = part.kind() + + if pk == ast.ASTKind.FormattedValue: + fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part) + fexpr: ast.AST | t.CPtr = fv.value + if fexpr is None or fexpr.kind() != ast.ASTKind.Call: + continue + fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr) + attr_nm: str = _asm_is_c_call(fcall) + if attr_nm is None: + continue + + is_out: int = 0 + if string.strcmp(attr_nm, "AsmOut") == 0: + is_out = 1 + elif string.strcmp(attr_nm, "AsmInp") == 0: + is_out = 0 + else: + continue + + fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args + if fargs is None or fargs.__len__() < 1: + continue + + val_node: ast.AST | t.CPtr = fargs.get(0) + cons_str: str = "" + if fargs.__len__() >= 2: + cons_str = _resolve_asm_descr(pool, fargs.get(1)) + + if is_out != 0: + # 输出:获取变量 alloca + if val_node is None or val_node.kind() != ast.ASTKind.Name: + continue + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node) + if nm.id is None: + continue + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) + if alloca is None: + continue + operand_count = _asm_add_operand( + operands, operand_count, alloca, cons_str, 1) + else: + # 输入:翻译值 + ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, val_node, None, 0, trans) + if ival is None: + continue + operand_count = _asm_add_operand( + operands, operand_count, ival, cons_str, 0) + + # 记录 fv 的原始操作数索引 + if fv_count < ASM_MAX_OPERANDS: + fv_orig_indices[fv_count] = operand_count - 1 + fv_count += 1 + + # ============================================================ + # 2. 解析关键字参数 out=/inp=/op=/clobber= + # ============================================================ + keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords + if keywords is not None: + kwlen: t.CSizeT = keywords.__len__() + for ki in range(kwlen): + kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) + if kw is None or kw.arg is None or kw.value is None: + continue + kwk: int = kw.value.kind() + + if string.strcmp(kw.arg, "out") == 0: + # 输出操作数列表 + if kwk != ast.ASTKind.List: + continue + out_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) + out_elts: list[ast.AST | t.CPtr] | t.CPtr = out_lst.elts + if out_elts is None: + continue + oelen: t.CSizeT = out_elts.__len__() + for oi in range(oelen): + oelt: ast.AST | t.CPtr = out_elts.get(oi) + if oelt is None or oelt.kind() != ast.ASTKind.Call: + continue + ocall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(oelt) + oattr: str = _asm_is_c_call(ocall) + if oattr is None or string.strcmp(oattr, "AsmOut") != 0: + continue + oargs: list[ast.AST | t.CPtr] | t.CPtr = ocall.args + if oargs is None or oargs.__len__() < 1: + continue + oval_node: ast.AST | t.CPtr = oargs.get(0) + ocons: str = "" + if oargs.__len__() >= 2: + ocons = _resolve_asm_descr(pool, oargs.get(1)) + if oval_node is None or oval_node.kind() != ast.ASTKind.Name: + continue + onm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(oval_node) + if onm.id is None: + continue + oalloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, onm.id) + if oalloca is None: + continue + operand_count = _asm_add_operand( + operands, operand_count, oalloca, ocons, 1) + + elif string.strcmp(kw.arg, "inp") == 0 or string.strcmp(kw.arg, "inputs") == 0: + # 输入操作数列表 + if kwk != ast.ASTKind.List: + continue + in_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) + in_elts: list[ast.AST | t.CPtr] | t.CPtr = in_lst.elts + if in_elts is None: + continue + ielen: t.CSizeT = in_elts.__len__() + for ii in range(ielen): + ielt: ast.AST | t.CPtr = in_elts.get(ii) + if ielt is None or ielt.kind() != ast.ASTKind.Call: + continue + icall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(ielt) + iattr: str = _asm_is_c_call(icall) + if iattr is None or string.strcmp(iattr, "AsmInp") != 0: + continue + iargs: list[ast.AST | t.CPtr] | t.CPtr = icall.args + if iargs is None or iargs.__len__() < 1: + continue + ival_node: ast.AST | t.CPtr = iargs.get(0) + icons: str = "" + if iargs.__len__() >= 2: + icons = _resolve_asm_descr(pool, iargs.get(1)) + ival2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, ival_node, None, 0, trans) + if ival2 is None: + continue + operand_count = _asm_add_operand( + operands, operand_count, ival2, icons, 0) + + elif string.strcmp(kw.arg, "op") == 0 or string.strcmp(kw.arg, "clobber") == 0: + # 破坏列表 + if kwk != ast.ASTKind.List: + continue + cl_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) + cl_elts: list[ast.AST | t.CPtr] | t.CPtr = cl_lst.elts + if cl_elts is None: + continue + clen: t.CSizeT = cl_elts.__len__() + for ci in range(clen): + celt: ast.AST | t.CPtr = cl_elts.get(ci) + if celt is None: + continue + cstr: str = _resolve_asm_descr(pool, celt) + if cstr is None or cstr[0] == '\0': + continue + if clobber_count < ASM_MAX_OPERANDS: + cl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8 + cl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(cl_addr, t.CPtr)) + cl_ptr[0] = cstr + clobber_count += 1 + + # ============================================================ + # 3. 解析第二个位置参数作为破坏列表 + # ============================================================ + if cargs.__len__() >= 2: + pos_node: ast.AST | t.CPtr = cargs.get(1) + if pos_node is not None and pos_node.kind() == ast.ASTKind.List: + pos_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(pos_node) + pos_elts: list[ast.AST | t.CPtr] | t.CPtr = pos_lst.elts + if pos_elts is not None: + plen: t.CSizeT = pos_elts.__len__() + for pi in range(plen): + pelt: ast.AST | t.CPtr = pos_elts.get(pi) + if pelt is None: + continue + pstr: str = _resolve_asm_descr(pool, pelt) + if pstr is None or pstr[0] == '\0': + continue + if clobber_count < ASM_MAX_OPERANDS: + pcl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8 + pcl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(pcl_addr, t.CPtr)) + pcl_ptr[0] = pstr + clobber_count += 1 + + # ============================================================ + # 4. 统计输出/输入数量,确定返回类型 + # ============================================================ + output_count: int = 0 + input_count: int = 0 + first_output_idx: int = -1 + for oi2 in range(operand_count): + op2: AsmOperand | t.CPtr = _asm_get_operand(operands, oi2) + if op2.IsOutput != 0: + if first_output_idx < 0: + first_output_idx = oi2 + output_count += 1 + else: + input_count += 1 + + # 确定返回类型 + ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + if output_count > 0 and first_output_idx >= 0: + out_op: AsmOperand | t.CPtr = _asm_get_operand(operands, first_output_idx) + if out_op.Value is not None and out_op.Value.Ty is not None: + # alloca 的类型是指针,Pointee 是目标类型 + if out_op.Value.Ty.Pointee is not None: + ret_ty = out_op.Value.Ty.Pointee + else: + ret_ty = llvmlite.Int32(pool) + + # 判断 void — 直接基于 output_count 判断,避免 match 类型匹配问题 + is_void: int = 1 + if output_count > 0: + is_void = 0 + + # ============================================================ + # 4.5 重排操作数:输出在前,输入在后(LLVM IR 要求) + # + # new_order[new_idx] = orig_idx — 新位置对应原索引 + # orig_to_new[orig_idx] = new_idx — 原索引映射到新位置(用于占位符编号) + # ============================================================ + new_order: int | t.CPtr = pool.alloc(4 * (operand_count + 1)) + orig_to_new: int | t.CPtr = pool.alloc(4 * (operand_count + 1)) + if new_order is None or orig_to_new is None: + return None + + new_idx: int = 0 + # 先放输出 + for oi3 in range(operand_count): + op3: AsmOperand | t.CPtr = _asm_get_operand(operands, oi3) + if op3.IsOutput != 0: + new_order[new_idx] = oi3 + new_idx += 1 + # 再放输入 + for oi4 in range(operand_count): + op4: AsmOperand | t.CPtr = _asm_get_operand(operands, oi4) + if op4.IsOutput == 0: + new_order[new_idx] = oi4 + new_idx += 1 + # 建立映射 orig -> new + for ni2 in range(operand_count): + orig_to_new[new_order[ni2]] = ni2 + + # ============================================================ + # 4.6 生成汇编文本(第二遍遍历 f-string,用重排后的索引生成占位符) + # 项目约定使用 Intel 语法,通过 IR 的 inteldialect 关键字启用 + # ============================================================ + if tmpl_node is not None: + tk2: int = tmpl_node.kind() + if tk2 == ast.ASTKind.JoinedStr: + js2: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node) + jvalues2: list[ast.AST | t.CPtr] | t.CPtr = js2.values + if jvalues2 is not None: + jvlen2: t.CSizeT = jvalues2.__len__() + fv_fi: int = 0 + for vi2 in range(jvlen2): + part2: ast.AST | t.CPtr = jvalues2.get(vi2) + if part2 is None: + continue + pk2: int = part2.kind() + if pk2 == ast.ASTKind.Constant: + cn3: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part2) + if cn3.const_kind == ast.CONST_STR and cn3.str_val is not None: + _asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn3.str_val) + elif pk2 == ast.ASTKind.FormattedValue: + if fv_fi < fv_count: + orig_idx2: int = fv_orig_indices[fv_fi] + new_idx2: int = orig_to_new[orig_idx2] + ph_buf2: t.CChar | t.CPtr = pool.alloc(16) + if ph_buf2 is not None: + viperlib.snprintf(ph_buf2, 16, "$%d", new_idx2) + _asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, ph_buf2) + fv_fi += 1 + elif tk2 == ast.ASTKind.Constant: + cn4: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(tmpl_node) + if cn4.const_kind == ast.CONST_STR and cn4.str_val is not None: + _asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn4.str_val) + + # ============================================================ + # 5. 构建约束字符串(按重排后的顺序:输出在前,输入在后) + # ============================================================ + const_buf: t.CChar | t.CPtr = pool.alloc(ASM_CONST_BUF_SIZE) + if const_buf is None: + return None + const_buf[0] = '\0' + + first_const: int = 1 + for ci2 in range(operand_count): + orig_i: int = new_order[ci2] + cop: AsmOperand | t.CPtr = _asm_get_operand(operands, orig_i) + cons_val: str = cop.Constraint + if cons_val is None: + cons_val = "r" + + if first_const == 0: + _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",") + first_const = 0 + + if cop.IsOutput != 0: + # 输出约束:确保以 = 开头 + if cons_val[0] != '=': + _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "=") + _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val) + else: + _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val) + + # 追加 clobber 约束 ~{name} + for cidx in range(clobber_count): + cl_addr2: t.CUInt64T = t.CUInt64T(clobbers) + cidx * 8 + cname: str = (str | t.CPtr)(t.CVoid(cl_addr2, t.CPtr))[0] + if cname is None or cname[0] == '\0': + continue + if first_const == 0: + _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",") + first_const = 0 + _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "~{") + _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cname) + _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "}") + + # ============================================================ + # 6. 构建参数列表文本(仅输入操作数) + # ============================================================ + args_buf: t.CChar | t.CPtr = pool.alloc(ASM_ARGS_BUF_SIZE) + if args_buf is None: + return None + args_buf[0] = '\0' + + first_arg: int = 1 + for ai3 in range(operand_count): + orig_i2: int = new_order[ai3] + aop: AsmOperand | t.CPtr = _asm_get_operand(operands, orig_i2) + if aop.IsOutput != 0: + continue + aval: llvmlite.Value | t.CPtr = aop.Value + if aval is None or aval.Ty is None or aval.Name is None: + continue + + if first_arg == 0: + _asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ", ") + first_arg = 0 + + # 类型文本 + ty_buf: t.CChar | t.CPtr = pool.alloc(64) + if ty_buf is not None: + ty_buf[0] = '\0' + llvmlite.TypePrint(ty_buf, 64, aval.Ty, pool) + _asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ty_buf) + _asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, " ") + _asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, aval.Name) + + # ============================================================ + # 7. 转义汇编文本 + # ============================================================ + escaped_asm: t.CChar | t.CPtr = _asm_escape_for_ir(pool, asm_text) + if escaped_asm is None: + return None + + # ============================================================ + # 8. 生成 IR 行并发射 + # ============================================================ + line: t.CChar | t.CPtr = pool.alloc(ASM_LINE_BUF_SIZE) + if line is None: + return None + line[0] = '\0' + + ssa_name: t.CChar | t.CPtr = None + if is_void == 0: + ssa_name = pool.alloc(16) + if ssa_name is not None: + viperlib.snprintf(ssa_name, 16, "%%%d", builder.Counter) + builder.Counter += 1 + + # 获取返回类型文本 + ret_ty_buf: t.CChar | t.CPtr = pool.alloc(64) + if ret_ty_buf is not None: + ret_ty_buf[0] = '\0' + llvmlite.TypePrint(ret_ty_buf, 64, ret_ty, pool) + + if is_void == 1: + viperlib.snprintf(line, ASM_LINE_BUF_SIZE, + "call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)", + ret_ty_buf, escaped_asm, const_buf, args_buf) + else: + viperlib.snprintf(line, ASM_LINE_BUF_SIZE, + "%s = call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)", + ssa_name, ret_ty_buf, escaped_asm, const_buf, args_buf) + + # 发射 IR 到当前块 + llvmlite.block_append_text(pool, builder.CurBlock, line) + + # ============================================================ + # 9. 处理输出:存储结果到输出变量 + # ============================================================ + if is_void == 0 and first_output_idx >= 0: + result_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, ret_ty, ssa_name) + out_op2: AsmOperand | t.CPtr = _asm_get_operand(operands, first_output_idx) + if out_op2.Value is not None: + llvmlite.build_store(builder, result_val, out_op2.Value) + return result_val + + return None + +# ============================================================ +# c.LLVMIR — 内联 LLVM IR 支持 +# +# 语法: +# c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) +# c.LLVMIR(f"%{c.LOut(result)} = add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) +# +# c.LInp(expr) - 输入操作数,翻译后替换为对应的 LLVM 值 +# c.LOut(expr) - 输出操作数,翻译后结果存储到该变量 +# +# 支持的指令: add/sub/mul/sdiv/udiv/srem/urem/and/or/xor/shl/lshr/ashr +# fadd/fsub/fmul/fdiv +# icmp eq/ne/sgt/sge/slt/sle/ugt/uge/ult/ule +# fcmp oeq/one/olt/ogt/ole/oge +# zext/sext/trunc/bitcast/ptrtoint/inttoptr +# load/store +# ============================================================ + +LLVMIR_MAX_OPS: t.CDefine = 16 +LLVMIR_TEMPLATE_BUF: t.CDefine = 512 + +# ============================================================ +# _llvmir_get_op — 获取第 i 个 AsmOperand 槽位 +# ============================================================ +def _llvmir_get_op(buf: AsmOperand | t.CPtr, i: int) -> AsmOperand | t.CPtr: + """获取第 i 个操作数槽位""" + entry_size: t.CSizeT = AsmOperand.__sizeof__() + entry_addr: t.CUInt64T = t.CUInt64T(buf) + i * entry_size + return (AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + +# ============================================================ +# _llvmir_find_op_marker — 在字符串中查找 %__OP 并返回编号 +# +# 返回 (位置, 编号),未找到返回 (None, 0) +# ============================================================ +def _llvmir_find_op_marker(s: t.CChar | t.CPtr) -> t.CPtr: + """查找 %__OP 标记,返回标记开始位置或 None""" + if s is None: + return None + return string.strstr(s, "%__OP") + +# ============================================================ +# _llvmir_parse_op_num — 从 %__OPN__ 中解析编号 N +# +# 输入: 指向 "%__OP" 的指针 +# 返回: 操作数编号 +# ============================================================ +def _llvmir_parse_op_num(marker: t.CChar | t.CPtr) -> int: + """从 %__OPN__ 标记中解析编号 N""" + if marker is None: + return -1 + # 跳过 "%__OP" (5 字符) + num_start: t.CChar | t.CPtr = marker + 5 + if num_start is None: + return -1 + # 解析数字直到 "__" + num: int = 0 + i: t.CSizeT = 0 + ch: t.CChar = num_start[0] + while '0' <= ch <= '9': + num = num * 10 + (ch - '0') + i += 1 + ch = num_start[i] + return num + +# ============================================================ +# _llvmir_match_icmp_pred — 将预测字符串转为 ICMP 常量 +# ============================================================ +def _llvmir_match_icmp_pred(pred: str) -> int: + """将 icmp 预测字符串转为常量""" + if pred is None: + return 0 + if string.strcmp(pred, "eq") == 0: + return 0 + if string.strcmp(pred, "ne") == 0: + return 1 + if string.strcmp(pred, "sgt") == 0: + return 2 + if string.strcmp(pred, "sge") == 0: + return 3 + if string.strcmp(pred, "slt") == 0: + return 4 + if string.strcmp(pred, "sle") == 0: + return 5 + if string.strcmp(pred, "ugt") == 0: + return 6 + if string.strcmp(pred, "uge") == 0: + return 7 + if string.strcmp(pred, "ult") == 0: + return 8 + if string.strcmp(pred, "ule") == 0: + return 9 + return 0 + +# ============================================================ +# _llvmir_match_fcmp_pred — 将预测字符串转为 FCMP 常量 +# ============================================================ +def _llvmir_match_fcmp_pred(pred: str) -> int: + """将 fcmp 预测字符串转为常量""" + if pred is None: + return 0 + if string.strcmp(pred, "oeq") == 0: + return 0 + if string.strcmp(pred, "ogt") == 0: + return 1 + if string.strcmp(pred, "oge") == 0: + return 2 + if string.strcmp(pred, "olt") == 0: + return 3 + if string.strcmp(pred, "ole") == 0: + return 4 + if string.strcmp(pred, "one") == 0: + return 5 + if string.strcmp(pred, "ord") == 0: + return 6 + if string.strcmp(pred, "uno") == 0: + return 7 + if string.strcmp(pred, "ueq") == 0: + return 8 + if string.strcmp(pred, "ugt") == 0: + return 9 + if string.strcmp(pred, "uge") == 0: + return 10 + if string.strcmp(pred, "ult") == 0: + return 11 + if string.strcmp(pred, "ule") == 0: + return 12 + if string.strcmp(pred, "une") == 0: + return 13 + return 0 + +# ============================================================ +# _llvmir_extract_two_ops — 从模板中提取两个操作数编号 +# +# 通过输出参数返回 op1_num 和 op2_num +# ============================================================ +def _llvmir_extract_two_ops(template: t.CChar | t.CPtr, + out_nums: int | t.CPtr) -> int: + """从模板中提取前两个 %__OP 标记的编号 + + 结果写入 out_nums[0] 和 out_nums[1] + 返回 1 成功, 0 失败 + """ + out_nums[0] = -1 + out_nums[1] = -1 + m1: t.CChar | t.CPtr = _llvmir_find_op_marker(template) + if m1 is None: + return 0 + out_nums[0] = _llvmir_parse_op_num(m1) + + # 跳过第一个标记 "%__OPN__" + next_pos: t.CChar | t.CPtr = m1 + 5 # 跳过 "%__OP" + i: t.CSizeT = 0 + while next_pos[i] >= '0' and next_pos[i] <= '9': + i += 1 + next_pos = next_pos + i + 2 + + m2: t.CChar | t.CPtr = _llvmir_find_op_marker(next_pos) + if m2 is None: + return 1 + out_nums[1] = _llvmir_parse_op_num(m2) + return 1 + +# ============================================================ +# _llvmir_resolve_op — 根据编号解析操作数值 +# ============================================================ +def _llvmir_resolve_op(op_num: int, + all_kinds: int | t.CPtr, + all_indices: int | t.CPtr, + input_ops: AsmOperand | t.CPtr, + output_targets: AsmOperand | t.CPtr) -> llvmlite.Value | t.CPtr: + """根据操作数编号解析实际 Value""" + if op_num < 0 or op_num >= LLVMIR_MAX_OPS: + return None + kind: int = all_kinds[op_num] + idx: int = all_indices[op_num] + if kind == 0: + # 输入操作数 + op: AsmOperand | t.CPtr = _llvmir_get_op(input_ops, idx) + return op.Value + else: + # 输出操作数 + op2: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, idx) + return op2.Value + +# ============================================================ +# _llvmir_store_outputs — 将结果存储到输出变量 +# ============================================================ +def _llvmir_store_outputs(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + result: llvmlite.Value | t.CPtr, + output_targets: AsmOperand | t.CPtr, + output_count: int) -> llvmlite.Value | t.CPtr: + """将结果存储到所有输出变量""" + if output_count == 0: + return result + for oi in range(output_count): + op: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, oi) + if op.Value is not None and result is not None: + llvmlite.build_store(builder, result, op.Value) + return result + +# ============================================================ +# translate_c_llvmir — 翻译 c.LLVMIR 内联 LLVM IR +# ============================================================ +def translate_c_llvmir(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译 c.LLVMIR 内联 LLVM IR,返回结果 Value""" + if cl is None: + return None + + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or cargs.__len__() < 1: + return None + + # 分配操作数数组 + op_size: t.CSizeT = AsmOperand.__sizeof__() + input_ops: AsmOperand | t.CPtr = pool.alloc(op_size * LLVMIR_MAX_OPS) + output_targets: AsmOperand | t.CPtr = pool.alloc(op_size * LLVMIR_MAX_OPS) + if input_ops is None or output_targets is None: + return None + string.memset(input_ops, 0, op_size * LLVMIR_MAX_OPS) + string.memset(output_targets, 0, op_size * LLVMIR_MAX_OPS) + + # all_ops 映射: kinds[i]=0(inp)/1(out), indices[i]=在对应数组中的索引 + all_kinds: int | t.CPtr = pool.alloc(4 * LLVMIR_MAX_OPS) + all_indices: int | t.CPtr = pool.alloc(4 * LLVMIR_MAX_OPS) + if all_kinds is None or all_indices is None: + return None + string.memset(all_kinds, 0, 4 * LLVMIR_MAX_OPS) + string.memset(all_indices, 0, 4 * LLVMIR_MAX_OPS) + + input_count: int = 0 + output_count: int = 0 + op_seq: int = 0 + + # 分配模板缓冲区 + template: t.CChar | t.CPtr = pool.alloc(LLVMIR_TEMPLATE_BUF) + if template is None: + return None + template[0] = '\0' + + # 解析返回类型(默认 i32) + ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if cargs.__len__() >= 2: + ret_type_node: ast.AST | t.CPtr = cargs.get(1) + if ret_type_node is not None: + resolved_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, ret_type_node, trans._imported_modules, trans._from_imports, trans) + if resolved_ty is not None: + ret_ty = resolved_ty + + # ============================================================ + # 1. 解析 IR 模板(JoinedStr 或 Constant)— 收集操作数 + # ============================================================ + first_arg: ast.AST | t.CPtr = cargs.get(0) + if first_arg is None: + return None + + tk: int = first_arg.kind() + + if tk == ast.ASTKind.JoinedStr: + js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(first_arg) + jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values + if jvalues is not None: + jvlen: t.CSizeT = jvalues.__len__() + for vi in range(jvlen): + part: ast.AST | t.CPtr = jvalues.get(vi) + if part is None: + continue + pk: int = part.kind() + + if pk == ast.ASTKind.Constant: + # 字符串字面量片段 + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part) + if cn.str_val is not None: + _asm_append_cstr(template, LLVMIR_TEMPLATE_BUF, cn.str_val) + + elif pk == ast.ASTKind.FormattedValue: + fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part) + fexpr: ast.AST | t.CPtr = fv.value + if fexpr is None or fexpr.kind() != ast.ASTKind.Call: + continue + fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr) + attr_nm: str = _asm_is_c_call(fcall) + if attr_nm is None: + # 非 c.LInp/c.LOut 调用,作为普通输入处理 + ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, fexpr, None, 0, trans) + if ival is not None and input_count < LLVMIR_MAX_OPS: + op_in: AsmOperand | t.CPtr = _llvmir_get_op(input_ops, input_count) + op_in.Value = ival + all_kinds[op_seq] = 0 + all_indices[op_seq] = input_count + input_count += 1 + op_seq += 1 + # 追加占位符 + viperlib.snprintf( + template + string.strlen(template), + LLVMIR_TEMPLATE_BUF - string.strlen(template), + "%%__OP%d__", op_seq - 1) + continue + + # 处理 c.LInp / c.LOut + fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args + if fargs is None or fargs.__len__() < 1: + continue + val_node: ast.AST | t.CPtr = fargs.get(0) + + if string.strcmp(attr_nm, "LInp") == 0: + # 输入操作数:翻译值 + inp_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, val_node, None, 0, trans) + if inp_val is not None and input_count < LLVMIR_MAX_OPS: + op_inp: AsmOperand | t.CPtr = _llvmir_get_op(input_ops, input_count) + op_inp.Value = inp_val + all_kinds[op_seq] = 0 + all_indices[op_seq] = input_count + input_count += 1 + op_seq += 1 + viperlib.snprintf( + template + string.strlen(template), + LLVMIR_TEMPLATE_BUF - string.strlen(template), + "%%__OP%d__", op_seq - 1) + + elif string.strcmp(attr_nm, "LOut") == 0: + # 输出操作数:获取变量 alloca + if val_node is not None and val_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node) + if nm.id is not None: + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) + if alloca is not None and output_count < LLVMIR_MAX_OPS: + op_out: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, output_count) + op_out.Value = alloca + all_kinds[op_seq] = 1 + all_indices[op_seq] = output_count + output_count += 1 + op_seq += 1 + viperlib.snprintf( + template + string.strlen(template), + LLVMIR_TEMPLATE_BUF - string.strlen(template), + "%%__OP%d__", op_seq - 1) + + elif tk == ast.ASTKind.Constant: + cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(first_arg) + if cn2.str_val is not None: + string.strcpy(template, cn2.str_val) + + # ============================================================ + # 2. 解析模板并生成 LLVM 指令 + # ============================================================ + + # 检查是否为赋值形式: %__OPN__ = <指令> + # 如果是,去掉赋值前缀,记录输出操作数编号 + assign_out_num: int = -1 + assign_marker: t.CChar | t.CPtr = _llvmir_find_op_marker(template) + if assign_marker is not None and assign_marker == template: + # 模板以 %__OP 开头 + # 查找 "=" 号 + eq_pos: t.CChar | t.CPtr = string.strchr(template, 61) # '=' = 61 + if eq_pos is not None: + # 确认 "%__OPN__ = " 格式 + assign_out_num = _llvmir_parse_op_num(assign_marker) + # 跳过 "%__OP__ = " 到实际指令开始 + # 找到 "=" 后第一个非空格字符 + instr_start: t.CChar | t.CPtr = eq_pos + 1 + while instr_start[0] == ' ' or instr_start[0] == '\t': + instr_start += 1 + # 将剩余部分复制到新模板 + tmpl2: t.CChar | t.CPtr = pool.alloc(LLVMIR_TEMPLATE_BUF) + if tmpl2 is not None: + string.strcpy(tmpl2, instr_start) + template = tmpl2 + + # 去除前导空格 + while template[0] == ' ' or template[0] == '\t': + template += 1 + + # 提取指令关键字(第一个单词) + instr_kw: t.CChar | t.CPtr = pool.alloc(32) + if instr_kw is None: + return None + instr_kw[0] = '\0' + ki: t.CSizeT = 0 + while template[ki] != ' ' and template[ki] != '\t' and template[ki] != '\0' and ki < 31: + instr_kw[ki] = template[ki] + ki += 1 + instr_kw[ki] = '\0' + + # ============================================================ + # 二元运算: add/sub/mul/sdiv/udiv/srem/urem/and/or/xor/shl/lshr/ashr + # ============================================================ + binop_result: llvmlite.Value | t.CPtr = None + + # 提取两个操作数编号 + op_nums: int | t.CPtr = pool.alloc(8) + if op_nums is not None: + string.memset(op_nums, 0, 8) + _llvmir_extract_two_ops(template, op_nums) + op1_num: int = -1 + op2_num: int = -1 + if op_nums is not None: + op1_num = op_nums[0] + op2_num = op_nums[1] + + lhs: llvmlite.Value | t.CPtr = _llvmir_resolve_op( + op1_num, all_kinds, all_indices, input_ops, output_targets) + rhs: llvmlite.Value | t.CPtr = _llvmir_resolve_op( + op2_num, all_kinds, all_indices, input_ops, output_targets) + + if lhs is not None and rhs is not None: + if string.strcmp(instr_kw, "add") == 0: + binop_result = llvmlite.build_add(builder, lhs, rhs) + elif string.strcmp(instr_kw, "sub") == 0: + binop_result = llvmlite.build_sub(builder, lhs, rhs) + elif string.strcmp(instr_kw, "mul") == 0: + binop_result = llvmlite.build_mul(builder, lhs, rhs) + elif string.strcmp(instr_kw, "sdiv") == 0: + binop_result = llvmlite.build_sdiv(builder, lhs, rhs) + elif string.strcmp(instr_kw, "udiv") == 0: + binop_result = llvmlite.build_udiv(builder, lhs, rhs) + elif string.strcmp(instr_kw, "srem") == 0: + binop_result = llvmlite.build_srem(builder, lhs, rhs) + elif string.strcmp(instr_kw, "urem") == 0: + binop_result = llvmlite.build_urem(builder, lhs, rhs) + elif string.strcmp(instr_kw, "and") == 0: + binop_result = llvmlite.build_and(builder, lhs, rhs) + elif string.strcmp(instr_kw, "or") == 0: + binop_result = llvmlite.build_or(builder, lhs, rhs) + elif string.strcmp(instr_kw, "xor") == 0: + binop_result = llvmlite.build_xor(builder, lhs, rhs) + elif string.strcmp(instr_kw, "shl") == 0: + binop_result = llvmlite.build_shl(builder, lhs, rhs) + elif string.strcmp(instr_kw, "lshr") == 0: + binop_result = llvmlite.build_lshr(builder, lhs, rhs) + elif string.strcmp(instr_kw, "ashr") == 0: + binop_result = llvmlite.build_ashr(builder, lhs, rhs) + elif string.strcmp(instr_kw, "fadd") == 0: + binop_result = llvmlite.build_fadd(builder, lhs, rhs) + elif string.strcmp(instr_kw, "fsub") == 0: + binop_result = llvmlite.build_fsub(builder, lhs, rhs) + elif string.strcmp(instr_kw, "fmul") == 0: + binop_result = llvmlite.build_fmul(builder, lhs, rhs) + elif string.strcmp(instr_kw, "fdiv") == 0: + binop_result = llvmlite.build_fdiv(builder, lhs, rhs) + + # ============================================================ + # icmp 比较: icmp %__OP0__, %__OP1__ + # ============================================================ + if binop_result is None and string.strcmp(instr_kw, "icmp") == 0: + # 提取预测(第二个单词) + pred_start: t.CChar | t.CPtr = template + ki + 1 + while pred_start[0] == ' ' or pred_start[0] == '\t': + pred_start += 1 + pred_str: t.CChar | t.CPtr = pool.alloc(16) + if pred_str is not None: + pred_str[0] = '\0' + pi: t.CSizeT = 0 + while pred_start[pi] != ' ' and pred_start[pi] != '\t' and pred_start[pi] != '\0' and pi < 15: + pred_str[pi] = pred_start[pi] + pi += 1 + pred_str[pi] = '\0' + pred_val: int = _llvmir_match_icmp_pred(pred_str) + if lhs is not None and rhs is not None: + binop_result = llvmlite.build_icmp(builder, pred_val, lhs, rhs) + + # ============================================================ + # fcmp 比较: fcmp %__OP0__, %__OP1__ + # ============================================================ + if binop_result is None and string.strcmp(instr_kw, "fcmp") == 0: + pred_start2: t.CChar | t.CPtr = template + ki + 1 + while pred_start2[0] == ' ' or pred_start2[0] == '\t': + pred_start2 += 1 + pred_str2: t.CChar | t.CPtr = pool.alloc(16) + if pred_str2 is not None: + pred_str2[0] = '\0' + pi2: t.CSizeT = 0 + while pred_start2[pi2] != ' ' and pred_start2[pi2] != '\t' and pred_start2[pi2] != '\0' and pi2 < 15: + pred_str2[pi2] = pred_start2[pi2] + pi2 += 1 + pred_str2[pi2] = '\0' + pred_val2: int = _llvmir_match_fcmp_pred(pred_str2) + if lhs is not None and rhs is not None: + binop_result = llvmlite.build_fcmp(builder, pred_val2, lhs, rhs) + + # ============================================================ + # store 指令: store %__OP0__, %__OP1__ + # ============================================================ + if binop_result is None and string.strcmp(instr_kw, "store") == 0: + if lhs is not None and rhs is not None: + llvmlite.build_store(builder, lhs, rhs) + return None + + # ============================================================ + # load 指令: load , %__OP0__ + # ============================================================ + if binop_result is None and string.strcmp(instr_kw, "load") == 0: + if lhs is not None: + # 从指针加载,类型由 ret_ty 指定 + binop_result = llvmlite.build_load(builder, ret_ty, lhs) + + # ============================================================ + # 类型转换: zext/sext/trunc/bitcast/ptrtoint/inttoptr + # ============================================================ + if binop_result is None: + if string.strcmp(instr_kw, "zext") == 0: + if lhs is not None: + binop_result = llvmlite.build_zext(builder, lhs, ret_ty) + elif string.strcmp(instr_kw, "sext") == 0: + if lhs is not None: + binop_result = llvmlite.build_sext(builder, lhs, ret_ty) + elif string.strcmp(instr_kw, "trunc") == 0: + if lhs is not None: + binop_result = llvmlite.build_trunc(builder, lhs, ret_ty) + elif string.strcmp(instr_kw, "bitcast") == 0: + if lhs is not None: + binop_result = llvmlite.build_bitcast(builder, lhs, ret_ty) + elif string.strcmp(instr_kw, "ptrtoint") == 0: + if lhs is not None: + binop_result = llvmlite.build_ptrtoint(builder, lhs, ret_ty) + elif string.strcmp(instr_kw, "inttoptr") == 0: + if lhs is not None: + binop_result = llvmlite.build_inttoptr(builder, lhs, ret_ty) + + # ============================================================ + # 3. 处理输出 + # ============================================================ + if binop_result is not None: + # 如果有赋值形式(%__OPN__ = ...),存储到对应输出 + if assign_out_num >= 0: + target: llvmlite.Value | t.CPtr = _llvmir_resolve_op( + assign_out_num, all_kinds, all_indices, input_ops, output_targets) + if target is not None: + llvmlite.build_store(builder, binop_result, target) + + # 存储到所有输出操作数 + _llvmir_store_outputs(pool, builder, binop_result, output_targets, output_count) + return binop_result + + # 未识别的指令,返回 0 + fb_li: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_li is not None: + viperlib.snprintf(fb_li, 1024, "unsupported instruction: %s", instr_kw) + VLogger.error(fb_li, "LLVMIR") + return None + +# ============================================================ +# _apply_struct_defaults — 应用结构体字段的默认值 +# +# 在 zeroinitializer 之后、显式参数之前调用 +# 遍历所有字段,对有默认值的字段翻译并 store +# 显式参数(位置/关键字)后续会覆盖默认值 +# ============================================================ +def _apply_struct_defaults(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str, + tmp: llvmlite.Value | t.CPtr, + trans: HT.Translator | t.CPtr): + """应用结构体字段的默认值""" + # 用类型指针定位 entry,规避跨模块同名 find_struct 找错 + entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) + if entry is None: + # fast-fail: 结构体类型未注册,静默 return 会导致字段未初始化 + VLogger.error( + f"结构体类型未注册,无法应用默认值: {class_name}", + "HandlesExprCall") + return + for fi in range(entry.FieldCount): + fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( + entry, fi) + if fe is None: + # fast-fail: 字段索引越界(entry.FieldCount 与实际不一致) + VLogger.error( + f"字段索引越界,无法获取字段 entry: {class_name}", + "HandlesExprCall") + continue + if fe.DefaultVal is None: + continue # 合理跳过:无默认值的字段 + default_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, fe.DefaultVal, None, 0, trans) + if default_val is None: + # fast-fail: 默认值翻译失败(如引用了未定义符号) + VLogger.error( + f"字段默认值翻译失败: {class_name}", + "HandlesExprCall") + continue + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, tmp, fe.Index) + if field_ptr is None: + # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) + VLogger.error( + f"字段 GEP 失败,类型不匹配: {class_name}", + "HandlesExprCall") + continue + default_val = HandlesExpr.coerce_to_type(builder, default_val, fe.Ty, fe.DefaultVal) + llvmlite.build_store(builder, default_val, field_ptr) + +# ============================================================ +# _translate_struct_ctor — 结构体构造函数 Point(10, 20) +# +# 生成: +# %tmp = alloca {i32, i32} +# store {i32, i32} zeroinitializer, {i32, i32}* %tmp +# %f0 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 0 +# store i32 10, i32* %f0 +# %f1 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 1 +# store i32 20, i32* %f1 +# %result = load {i32, i32}, {i32, i32}* %tmp +# ============================================================ +def _translate_struct_ctor(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """结构体构造函数:按字段顺序 store 参数值,返回结构体值 + + OOP 结构体:alloca → call __before_init__(ptr) → call __init__(ptr, args) 或 store 参数 → load + 普通结构体:alloca → zero + defaults → store 参数 → load + """ + # 创建临时 alloca + # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) + HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) + tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) + if tmp is None: + return llvmlite.ConstZero(pool, struct_ty) + + # 检查是否为 OOP 结构体(用类型指针定位 entry,规避跨模块同名 find_struct 找错) + ctor_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) + is_oop: int = 0 + if ctor_entry is not None: + is_oop = ctor_entry.IsOOP + + # 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods) + # 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入) + # 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠) + if is_oop == 0 and class_name is not None: + init_lookup_name: t.CChar | t.CPtr = pool.alloc(128) + if init_lookup_name is not None: + viperlib.snprintf(init_lookup_name, 128, "%s.__init__", class_name) + # 方案1: 检查当前模块的函数声明 + init_found_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, init_lookup_name) + if init_found_func is not None: + is_oop = 1 + if ctor_entry is not None: + ctor_entry.IsOOP = 1 + ctor_entry.HasInit = 1 + else: + # 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入) + init_defaults_entry: FuncDefaultsEntry | t.CPtr = find_func_defaults(init_lookup_name) + if init_defaults_entry is not None: + is_oop = 1 + if ctor_entry is not None: + ctor_entry.IsOOP = 1 + ctor_entry.HasInit = 1 + + if is_oop != 0: + # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 + storage_ptr: llvmlite.Value | t.CPtr = tmp + + # 如果有 __new__,调用 __new__(tmp, args...) 获取实际存储指针 + # __new__ 签名与 __init__ 一样(self + args),返回 Ptr(struct_ty) + has_new_flag: int = 0 + if ctor_entry is not None: + has_new_flag = ctor_entry.HasNew + # 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法) + if has_new_flag != 0: + new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if new_arg_vals is not None: + string.memset(new_arg_vals, 0, 8 * 32) + new_arg_count: int = 0 + for nai in range(can): + new_arg_node: ast.AST | t.CPtr = cargs.get(nai) + if new_arg_node is None: + continue + new_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, new_arg_node, None, 0, trans) + if new_av is not None: + if new_arg_count < 32: + new_arg_vals[new_arg_count] = t.CSizeT(new_av) + new_arg_count += 1 + + new_ptr: llvmlite.Value | t.CPtr = _call_method_on_ptr( + pool, builder, mod, class_name, + "__new__", tmp, new_arg_vals, new_arg_count, trans) + if new_ptr is not None: + storage_ptr = new_ptr + + # OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值 + _call_method_on_ptr(pool, builder, mod, class_name, + "__before_init__", storage_ptr, None, 0, trans) + + # 如果有 __init__,调用 __init__(ptr, args...) + # 注意: 仅依据 ctor_entry.HasInit 判断,不强制推断 + # (JsonValue 等类有 __new__ 但无 __init__,强制推断会导致 undefined reference) + has_init_flag: int = 0 + if ctor_entry is not None: + has_init_flag = ctor_entry.HasInit + if has_init_flag != 0: + # 翻译构造函数参数 + arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if arg_vals is not None: + string.memset(arg_vals, 0, 8 * 32) + real_arg_count: int = 0 + for ai in range(can): + arg_node: ast.AST | t.CPtr = cargs.get(ai) + if arg_node is None: + continue + av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg_node, None, 0, trans) + if av is not None: + if real_arg_count < 32: + arg_vals[real_arg_count] = t.CSizeT(av) + real_arg_count += 1 + + _call_method_on_ptr(pool, builder, mod, class_name, + "__init__", storage_ptr, arg_vals, real_arg_count, trans) + elif has_new_flag == 0: + # 无 __init__ 且无 __new__:逐字段 store 参数值 + # (有 __new__ 时参数已由 __new__ 消费,不应存入字段) + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None: + # fast-fail: 参数翻译失败 + VLogger.error( + f"构造函数参数翻译失败: {class_name}", + "HandlesExprCall") + continue + fe: HandlesStruct.FieldEntry | t.CPtr = None + if ctor_entry is not None: + fe = HandlesStruct._get_field_entry(ctor_entry, ai) + else: + fe = HandlesStruct.get_field_by_index(class_name, ai) + if fe is None: + # fast-fail: 字段索引越界(用户传了多余参数) + VLogger.error( + f"构造函数参数过多,字段索引越界: {class_name}", + "HandlesExprCall") + continue + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, storage_ptr, fe.Index) + if field_ptr is None: + # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) + VLogger.error( + f"构造函数字段 GEP 失败: {class_name}", + "HandlesExprCall") + continue + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg) + llvmlite.build_store(builder, arg_val, field_ptr) + + # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load + return storage_ptr + + # 普通结构体:先 store zeroinitializer 清零(确保未赋值字段为零) + zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) + llvmlite.build_store(builder, zero, tmp) + + # 应用默认值(显式参数会覆盖默认值) + _apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans) + + # 逐字段 store 参数值(覆盖默认值) + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None: + # fast-fail: 参数翻译失败 + VLogger.error( + f"构造函数参数翻译失败: {class_name}", + "HandlesExprCall") + continue + # 获取字段信息(用 ctor_entry 规避跨模块同名 find_struct 找错) + fe: HandlesStruct.FieldEntry | t.CPtr = None + if ctor_entry is not None: + fe = HandlesStruct._get_field_entry(ctor_entry, ai) + else: + fe = HandlesStruct.get_field_by_index(class_name, ai) + if fe is None: + # fast-fail: 字段索引越界(用户传了多余参数) + VLogger.error( + f"构造函数参数过多,字段索引越界: {class_name}", + "HandlesExprCall") + continue + # GEP 到字段 ai + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, tmp, fe.Index) + if field_ptr is None: + # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) + VLogger.error( + f"构造函数字段 GEP 失败: {class_name}", + "HandlesExprCall") + continue + # 类型转换并 store + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg) + llvmlite.build_store(builder, arg_val, field_ptr) + + # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load + return tmp + + +# ============================================================ +# _translate_renum_construct — REnum 变体构造函数 +# +# 语法: ClassName.VariantName(args...) +# 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体,__tag=0,_p1=1 +# +# 生成 IR: +# %tmp = alloca {i32, i32, ...} ; REnum 类型 +# store zeroinitializer, %tmp ; 清零 +# %tag_ptr = gep %tmp, 0, 0 ; __tag 字段 +# store i32 , %tag_ptr ; 写入 tag +# %p1_ptr = gep %tmp, 0, 1 ; _p1 字段 +# store , %p1_ptr ; 写入 payload[0] +# ... (更多 payload 字段) +# return %tmp ; 返回指针 +# +# 对应 TPC 的 _HandleREnumConstructLlvm +# ============================================================ +def _translate_renum_construct(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + variant_name: str, + tag_value: int, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """构造 REnum 变体实例,返回指向 alloca 的指针 + + class_name: REnum 类名(如 "LLVMType") + variant_name: 变体名(如 "Int") + tag_value: 变体的 tag 值(变体在类中的索引) + cargs: 参数 AST 列表 + can: 参数数量 + """ + if pool is None or builder is None or class_name is None: + return None + + # 查找 REnum 结构体类型(用 find_struct_by_module 规避跨模块同名) + renum_entry: HandlesStruct.StructEntry | t.CPtr = None + if trans is not None: + renum_entry = HandlesStruct.find_struct_by_module(class_name, trans.ModuleSha1) + if renum_entry is None: + renum_entry = HandlesStruct.find_struct(class_name) + if renum_entry is None: + fb_re: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_re is not None: + viperlib.snprintf(fb_re, 1024, "REnum construct: type %s not registered", class_name) + VLogger.error(fb_re, "RENUM") + return None + + renum_ty: llvmlite.LLVMType | t.CPtr = renum_entry.Ty + if renum_ty is None: + return None + + # alloca REnum 类型 + # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) + HandlesStruct.ensure_struct_def_in_module(pool, mod, renum_ty) + tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, renum_ty) + if tmp is None: + return llvmlite.ConstZero(pool, renum_ty) + + # 清零(确保未赋值的 payload 位置为零) + zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, renum_ty) + llvmlite.build_store(builder, zero, tmp) + + # 写入 __tag 字段(索引 0) + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + tag_name_buf: t.CChar | t.CPtr = pool.alloc(32) + if tag_name_buf is not None: + viperlib.snprintf(tag_name_buf, 32, "%d", tag_value) + tag_const: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, i32_ty, tag_value, + tag_name_buf if tag_name_buf is not None else "0") + tag_field: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(renum_entry, 0) + tag_field_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if tag_field is not None and tag_field.Ty is not None: + tag_field_ty = tag_field.Ty + tag_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, renum_ty, tag_field_ty, tmp, 0) + if tag_ptr is not None: + llvmlite.build_store(builder, tag_const, tag_ptr) + + # 写入 payload 字段(索引 1, 2, ... 对应 _p1, _p2, ...) + # 参数按位置顺序填充 payload,跳过 __tag(索引 0) + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None: + continue + # payload 字段索引 = ai + 1(跳过 __tag) + payload_idx: int = ai + 1 + if payload_idx >= renum_entry.FieldCount: + break + pfe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( + renum_entry, payload_idx) + if pfe is None: + continue + payload_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, renum_ty, pfe.Ty, tmp, payload_idx) + if payload_ptr is None: + continue + # 类型转换并 store(payload 位置可能是 i32 或 i64,按字段类型 coerce) + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, pfe.Ty, arg) + llvmlite.build_store(builder, arg_val, payload_ptr) + + # 返回指针(与 _translate_struct_ctor 一致,赋值时由 coerce_to_type 决定是否 load) + return tmp + + +# ============================================================ +# _do_virtual_call — 通过虚表间接调用虚方法 +# +# IR 模式: +# %1 = getelementptr StructTy, StructTy* %self, i32 0, i32 0 ; i8** +# %2 = load i8*, i8** %1 ; i8* (vtable ptr) +# %3 = bitcast i8* %2 to {i8*, ...}* ; vtable typed ptr +# %4 = getelementptr {i8*, ...}, {i8*, ...}* %3, i32 0, i32 N ; i8** +# %5 = load i8*, i8** %4 ; i8* (func ptr) +# %6 = bitcast i8* %5 to RetTy(Params)* ; func typed ptr +# call RetTy %6(Params %self, ...) +# +# 参数: +# args_head — 已构建好的参数链表头(self_ptr 为首节点) +# args_count — 参数总数(含 self) +# found_func — 方法对应的 Function 对象(用于推断函数签名) +# ret_ty — 返回类型 +# ============================================================ +def _do_virtual_call(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + method_name: str, + self_ptr: llvmlite.Value | t.CPtr, + args_head: llvmlite.Value | t.CPtr, + args_count: int, + found_func: llvmlite.Function | t.CPtr, + ret_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """通过虚表间接调用虚方法,返回 call 结果(void 方法返回 None)""" + if pool is None or builder is None or class_name is None or method_name is None: + return None + if self_ptr is None or args_head is None: + return None + + # 1. 获取结构体类型(用 find_struct_by_type 规避跨模块同名 find_struct 找错) + vc_entry: HandlesStruct.StructEntry | t.CPtr = None + struct_ty: llvmlite.LLVMType | t.CPtr = None + if self_ptr.Ty is not None: + vc_entry = HandlesStruct.get_struct_type_from_value(self_ptr) + if vc_entry is not None: + # vc_entry 是 struct_ty(LLVMType),需要找 StructEntry + vc_entry = HandlesStruct.find_struct_by_type(vc_entry) + if vc_entry is not None: + struct_ty = vc_entry.Ty + if struct_ty is None: + struct_ty = HandlesStruct.get_struct_type(class_name) + if struct_ty is None: + return None + + # 2. 获取方法在虚表中的索引(用 entry 直接查找) + method_index: int = -1 + if vc_entry is not None and vc_entry.VTableMethods is not None: + methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(vc_entry.VTableMethods, t.CPtr)) + for mi in range(vc_entry.VTableMethodCount): + mname_addr: t.CSizeT = methods_arr[mi] + if mname_addr == 0: + continue + mname: str = (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr)) + if mname is not None and string.strcmp(mname, method_name) == 0: + method_index = mi + break + else: + method_index = HandlesStruct.get_vtable_method_index(class_name, method_name) + if method_index < 0: + return None + + # 3. 基础类型 + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) + + # 4. bitcast 到 i8** 访问 __vtable__ 字段(索引 0) + # vtable 指针总是在对象第一个字段,无需 GEP,直接 bitcast 到 i8** 即可。 + # 这样即使 struct_ty 是 opaque(跨模块未加载完整定义)也能正常工作。 + vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, self_ptr, i8_ptr_ptr_ty) + if vtable_slot is None: + return None + + # 5. load vtable 指针 (i8*) + vtable_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot) + if vtable_ptr is None: + return None + + # 6. 构造 vtable 类型 {i8*, i8*, ...} + method_count: int = 0 + if vc_entry is not None: + method_count = vc_entry.VTableMethodCount + else: + method_count = HandlesStruct.get_vtable_method_count(class_name) + if method_count <= 0: + return None + + vt_first: llvmlite.ParamNode | t.CPtr = None + vt_prev: llvmlite.ParamNode | t.CPtr = None + for vi in range(method_count): + pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) + if pn is None: + continue + if vt_first is None: + vt_first = pn + if vt_prev is not None: + llvmlite.paramnode_set_next(vt_prev, pn) + vt_prev = pn + + vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first, method_count, None) + if vtable_ty is None: + return None + vtable_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vtable_ty) + + # 7. bitcast i8* 到 vtable 类型指针 + vtable_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, vtable_ptr, vtable_ptr_ty) + if vtable_typed is None: + return None + + # 8. GEP 到方法槽位 + func_slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, vtable_ty, i8_ptr_ty, vtable_typed, method_index) + if func_slot is None: + return None + + # 9. load 函数指针 (i8*) + func_i8: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, func_slot) + if func_i8 is None: + return None + + # 10. 从 args_head 构造函数类型 RetTy(Param1, Param2, ...) + # 直接遍历 Value 链表提取参数类型,避免跨模块访问 found_func(stub 字段偏移问题) + fp_first: llvmlite.ParamNode | t.CPtr = None + fp_prev: llvmlite.ParamNode | t.CPtr = None + fp_count: int = 0 + cur_val: llvmlite.Value | t.CPtr = args_head + for vi in range(args_count): + if cur_val is None: + break + cur_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(cur_val) + fpn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, cur_ty) + if fpn is not None: + if fp_first is None: + fp_first = fpn + if fp_prev is not None: + llvmlite.paramnode_set_next(fp_prev, fpn) + fp_prev = fpn + cur_val = llvmlite.value_get_next(cur_val) + fp_count += 1 + + func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, ret_ty, fp_first, fp_count) + if func_ty is None: + return None + func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty) + + # 11. bitcast i8* 到函数指针类型 + func_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, func_i8, func_ptr_ty) + if func_ptr is None: + return None + + # 12. 间接调用 + return llvmlite.build_call_indirect(builder, func_ptr, args_head, args_count, ret_ty) + +# ============================================================ +# _call_method_on_ptr — 在结构体指针上调用方法 +# +# 辅助函数:构造 ClassName.method_name 调用,self 指针为首个参数 +# 如果该方法在虚表中,则走虚方法分发路径(间接调用) +# ============================================================ +def _call_method_on_ptr(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + method_name: str, + self_ptr: llvmlite.Value | t.CPtr, + extra_args: t.CSizeT | t.CPtr, + extra_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """在结构体指针上调用方法,返回 call 结果(void 方法返回 None)""" + if pool is None or builder is None or class_name is None or method_name is None: + return None + if self_ptr is None: + return None + + # 提前获取结构体 entry(用 find_struct_by_type 规避跨模块同名 find_struct 找错) + # 用于 SHA1 查找和虚表分派 + cmop_entry: HandlesStruct.StructEntry | t.CPtr = None + cmop_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(self_ptr) + if cmop_struct_ty is not None: + cmop_entry = HandlesStruct.find_struct_by_type(cmop_struct_ty) + if cmop_entry is None: + cmop_entry = HandlesStruct.find_struct(class_name) + # fallback: 若 cmop_struct_ty 为 None 但 entry 存在,从 entry 获取类型 + # 用于跨模块调用时 self_ptr 类型信息丢失的情况 + if cmop_struct_ty is None and cmop_entry is not None: + cmop_struct_ty = cmop_entry.Ty + + # 构造方法查找名: ClassName.method_name + lookup_name: t.CChar | t.CPtr = pool.alloc(128) + if lookup_name is None: + return None + viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name) + + # 查找函数(支持 SHA1 后缀匹配) + found_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, lookup_name) + + # 确定调用名 + call_name: str = lookup_name + if found_func is not None: + found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) + if found_name is not None: + call_name = found_name + else: + # found_func 为 None(stub 未注入):用类所属模块的 SHA1 构造调用名 + # 优先从 entry 获取 SHA1(规避跨模块同名 find_struct 找错) + cls_sha1: str = None + if cmop_entry is not None: + cls_sha1 = cmop_entry.ModuleSha1 + else: + cls_sha1 = HandlesStruct.get_struct_sha1(class_name) + if cls_sha1 is None and trans is not None: + # fallback: 从 from_imports 查找类所属模块的 SHA1(含截断处理) + cls_sha1 = _lookup_mod_sha1(pool, trans._from_imports, class_name) + if cls_sha1 is None: + err_msg: t.CChar | t.CPtr = pool.alloc(256) + if err_msg is not None: + viperlib.snprintf(err_msg, 256, "类 '%s' 方法 '%s' 找不到模块 SHA1", class_name, method_name) + HandlesType.fatal_error(None, err_msg) + HandlesType.fatal_error(None, "找不到模块 SHA1") + mangled_len2: t.CSizeT = string.strlen(cls_sha1) + string.strlen(lookup_name) + 2 + mangled2: str = pool.alloc(mangled_len2) + if mangled2 is not None: + viperlib.snprintf(mangled2, mangled_len2, "%s.%s", cls_sha1, lookup_name) + call_name = mangled2 + + # 确定返回类型(__before_init__ 和 __init__ 返回 void) + void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + call_ret_ty: llvmlite.LLVMType | t.CPtr = void_ty + if found_func is not None: + frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) + if frt is not None: + call_ret_ty = frt + 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 声明 + + 若模块中已存在同名 declare 且参数数量较少(例如 File.__init__ 的 + stub 仅 3 个参数,而实际调用传入 4 个),则向现有 declare 追加缺失 + 参数,避免 llc 报 `argument invalid for parameter type` 之类的错误。 + 已存在的 define 不修改(其参数由定义决定)。 + """ + if pool is None or mod is None or call_name is None: + return + # 检查模块中是否已有同名函数(declare 或 define) + existing: llvmlite.Function | t.CPtr = mod.FuncHead + while existing is not None: + if existing.Name is not None: + if string.strcmp(existing.Name, call_name) == 0: + # 已存在:仅当是 declare 且参数数量不足时追加缺失参数 + if existing.IsDeclared == 1: + # 遍历现有参数链表计数(避免依赖 GSList.Count 字段的类型推断) + cur_count: int = 0 + cur_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(existing) + while cur_p is not None: + cur_count += 1 + cur_p = cur_p.Next + # 只追加缺失的参数(cur_count < param_count 时) + if cur_count < param_count: + # 定位到 param_head 的第 cur_count 个节点开始追加 + pnode2: llvmlite.ParamNode | t.CPtr = param_head + pi2: int = 0 + # 跳过已有的 cur_count 个参数 + while pnode2 is not None and pi2 < cur_count: + pnode2 = pnode2.Next + pi2 += 1 + # 追加剩余参数 + while pnode2 is not None and pi2 < param_count: + if pnode2.Ty is not None: + param2: llvmlite.Param | t.CPtr = llvmlite.new_param(pool, pnode2.Ty, None) + if param2 is not None: + llvmlite.function_add_param(existing, param2) + pnode2 = pnode2.Next + pi2 += 1 + return + existing = existing.Next + # 创建函数声明 + func: llvmlite.Function | t.CPtr = llvmlite.new_function(pool, call_name, ret_ty) + if func is None: + return + func.IsDeclared = 1 + # 添加参数(declare 中参数名无意义,设为 None 只输出类型) + pnode: llvmlite.ParamNode | t.CPtr = param_head + pi: int = 0 + while pnode is not None and pi < param_count: + if pnode.Ty is not None: + param: llvmlite.Param | t.CPtr = llvmlite.new_param(pool, pnode.Ty, None) + if param is not None: + llvmlite.function_add_param(func, param) + pnode = pnode.Next + pi += 1 + llvmlite.module_add_function(mod, func) + + +# ============================================================ +# _infer_method_ret_ty - 根据方法名推断返回类型 +# +# stub 未注入时,find_func_in_module 返回 None, +# 需要根据方法名推断返回类型避免指针被截断为 i32。 +# ============================================================ +def _infer_method_ret_ty(pool: memhub.MemBuddy | t.CPtr, + method_name: str) -> llvmlite.LLVMType | t.CPtr: + """根据方法名推断返回类型(stub 未注入时的回退方案)""" + if pool is None or method_name is None: + return llvmlite.Int32(pool) + + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + + # 返回 i8* 的方法(分配/返回指针) + if string.strcmp(method_name, "alloc") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "calloc") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "realloc") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "alloc_buf") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "_fl_pop") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "_buddy_of") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "_split_to_order") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "__enter__") == 0: + return i8_ptr_ty + # 工厂方法:返回对象指针(截断会导致后续方法调用崩溃) + if string.strcmp(method_name, "parse_args") == 0: + return i8_ptr_ty + # 魔术方法:返回对象指针(如 JsonValue.__getitem__ 返回 JsonValue*) + if string.strcmp(method_name, "__getitem__") == 0: + return i8_ptr_ty + + # 返回 i8* 的方法(返回字符串/类型名/描述) + if string.strcmp(method_name, "type_name") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "get_name") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "get_str") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "get_path") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "get_buf") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "to_string") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "as_string") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "__repr__") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "__str__") == 0: + return i8_ptr_ty + # 返回 i8* 的方法(返回对象指针,如 JsonValue.get_item → JsonValue*) + if string.strcmp(method_name, "get_item") == 0: + return i8_ptr_ty + + # 返回 void 的方法 + if string.strcmp(method_name, "__before_init__") == 0: + return llvmlite.Void(pool) + if string.strcmp(method_name, "__init__") == 0: + return llvmlite.Void(pool) + if string.strcmp(method_name, "__exit__") == 0: + return llvmlite.Void(pool) + + # 默认 i32(整数):与本模块函数定义的默认返回类型一致(HandlesFunctions.py line 324) + # 已知返回指针的方法在上方显式列出(返回 i8*),已知返回 void 的方法也显式列出 + # 避免使用 i64 导致 stub 声明(declare i64)与实际定义(define i32)类型不匹配 + # x86-64 ABI 中 i32 返回值在 rax 低 32 位,与 define i32 完全一致 + # 与 _infer_external_func_ret_ty 的默认策略保持一致 + # WARNING: 未登记的方法返回类型默认推断为 i32,若实际返回指针/i64 会被截断 + VLogger.warning( + f"方法返回类型未登记,默认推断为 i32(可能截断指针/i64): {method_name}", + "HandlesExprCall") + return llvmlite.Int32(pool) + + +# ============================================================ +# 跨模块方法返回类型查找(从 text.ll) +# +# Phase A 翻译每个源文件后生成 text.ll,其中 define 行包含 +# 方法的实际返回类型。当 Phase A 翻译后续文件调用跨模块方法时, +# _infer_method_ret_ty 默认返回 i32,导致指针返回值被截断。 +# _LookupMethodRetTyFromTextLL 读取依赖模块的 text.ll,从 define +# 行提取实际返回类型,避免指针截断。 +# ============================================================ + +_g_temp_dir: str = None +_g_temp_dir_len: t.CSizeT = 0 + +# text.ll 读取缓冲区大小 +_TEXT_LL_READ_BUF_SIZE: t.CDefine = 262144 + + +# ============================================================ +# SetTempDir - 设置 temp 目录路径 +# +# 在 Phase2.py 的 Phase A 翻译前调用,使 HandlesExprCall +# 能够读取依赖模块的 text.ll 文件。 +# ============================================================ +def SetTempDir(temp_dir: str): + """设置 temp 目录路径(供跨模块方法返回类型查找使用)""" + global _g_temp_dir + global _g_temp_dir_len + _g_temp_dir = temp_dir + if temp_dir is not None: + _g_temp_dir_len = string.strlen(temp_dir) + else: + _g_temp_dir_len = 0 + + +# ============================================================ +# _ParseLLVMRetTyStr - 将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType +# +# 从 define 行中提取的返回类型字符串(define 与 @ 之间的内容), +# 转换为 llvmlite.LLVMType 对象。 +# +# 支持的类型: +# void → Void +# i8/i16/i32/i64 → Int8/Int16/Int32/Int64 +# double → Double, float → Float +# 任何含 * 的类型 → Ptr(Int8)(通用指针,保留 64 位地址) +# +# Args: +# pool: 内存池 +# buf: 包含类型字符串的缓冲区 +# start: 类型字符串起始位置 +# end: 类型字符串结束位置(不含) +# +# Returns: +# LLVM 类型对象,或 None(无法解析) +# ============================================================ +def _ParseLLVMRetTyStr(pool: memhub.MemBuddy | t.CPtr, + buf: bytes, + start: t.CSizeT, + end: t.CSizeT) -> llvmlite.LLVMType | t.CPtr: + """将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType""" + if pool is None or buf is None or start >= end: + return None + + # 去除前导空白 + s: t.CSizeT = start + while s < end: + c: int = buf[s] + if c != ' ' and c != '\t': + break + s += 1 + # 去除尾部空白 + e: t.CSizeT = end + while e > s: + c2: int = buf[e - 1] + if c2 != ' ' and c2 != '\t': + break + e -= 1 + + ty_len: t.CSizeT = e - s + if ty_len == 0: + return None + + # 检查是否含 * (指针类型) → 返回 i8* (通用指针) + # 包括 i8*, i32*, %"name"*, { i32, i8 }* 等 + ci: t.CSizeT = s + while ci < e: + if buf[ci] == '*': + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + ci += 1 + + # void + if ty_len == 4 and string.strncmp(buf + s, "void", 4) == 0: + return llvmlite.Void(pool) + + # double + if ty_len == 6 and string.strncmp(buf + s, "double", 6) == 0: + return llvmlite.Double(pool) + + # float + if ty_len == 5 and string.strncmp(buf + s, "float", 5) == 0: + return llvmlite.Float(pool) + + # iN (i8, i16, i32, i64) + if ty_len >= 2 and buf[s] == 'i': + bits: int = 0 + di: t.CSizeT = s + 1 + valid: int = 1 + while di < e: + d: int = buf[di] + if d >= '0' and d <= '9': + bits = bits * 10 + (d - '0') + else: + valid = 0 + break + di += 1 + if valid != 0 and bits > 0: + if bits == 8: + return llvmlite.Int8(pool) + if bits == 16: + return llvmlite.Int16(pool) + if bits == 32: + return llvmlite.Int32(pool) + if bits == 64: + return llvmlite.Int64(pool) + + # 无法解析 + return None + + +# ============================================================ +# _LookupMethodRetTyFromTextLL - 从依赖模块的 text.ll 查找方法返回类型 +# +# 读取 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll (level=1),搜索 +# define 行中包含 "{sha1}.{class_name}.{method_name}" 的函数, +# 提取返回类型并转换为 llvmlite.LLVMType。 +# +# 解决问题: _infer_method_ret_ty 默认返回 i32,导致指针返回值 +# 被 inttoptr 截断为 32 位(coerce_to_type line 238-239)。 +# 本函数从 text.ll 获取实际返回类型,避免截断。 +# +# Args: +# pool: 内存池 +# class_sha1: 类所属模块的 SHA1 +# class_name: 类名 +# method_name: 方法名 +# +# Returns: +# LLVM 类型对象,或 None(未找到/text.ll 不存在) +# ============================================================ +def _LookupMethodRetTyFromTextLL(pool: memhub.MemBuddy | t.CPtr, + class_sha1: str, + class_name: str, + method_name: str) -> llvmlite.LLVMType | t.CPtr: + """从依赖模块的 text.ll 中查找方法返回类型""" + if pool is None or class_sha1 is None or class_name is None or method_name is None: + return None + if _g_temp_dir is None or _g_temp_dir_len == 0: + return None + + sha1_len: t.CSizeT = string.strlen(class_sha1) + if sha1_len < 2: + return None + + # 构造 text.ll 路径 (level=1): {temp_dir}/{sha1[0:2]}/{sha1}.text.ll + # 使用 subdir 缓冲区避免 %c 格式化问题(与 StubMerger._sliced_path 一致) + path_len: t.CSizeT = _g_temp_dir_len + sha1_len + 14 + path_buf: bytes = stdlib.malloc(path_len) + if path_buf is None: + return None + subdir_buf: bytes = stdlib.malloc(3) + if subdir_buf is None: + stdlib.free(path_buf) + return None + subdir_buf[0] = class_sha1[0] + subdir_buf[1] = class_sha1[1] + subdir_buf[2] = '\0' + viperlib.snprintf(path_buf, path_len, "%s/%s/%s.text.ll", + _g_temp_dir, subdir_buf, class_sha1) + stdlib.free(subdir_buf) + + # 读取 text.ll + read_buf: bytes = stdlib.malloc(_TEXT_LL_READ_BUF_SIZE) + if read_buf is None: + stdlib.free(path_buf) + return None + + tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R) + if tf.closed: + stdlib.free(path_buf) + stdlib.free(read_buf) + return None + text_len: t.CInt64T = tf.read_all(read_buf, _TEXT_LL_READ_BUF_SIZE) + tf.close() + stdlib.free(path_buf) + + if text_len <= 0: + stdlib.free(read_buf) + return None + if text_len < _TEXT_LL_READ_BUF_SIZE: + read_buf[text_len] = '\0' + else: + read_buf[_TEXT_LL_READ_BUF_SIZE - 1] = '\0' + + # 构造搜索模式: "{sha1}.{class_name}.{method_name}" + cls_len: t.CSizeT = string.strlen(class_name) + meth_len: t.CSizeT = string.strlen(method_name) + search_len: t.CSizeT = sha1_len + cls_len + meth_len + 3 + search_buf: bytes = stdlib.malloc(search_len) + if search_buf is None: + stdlib.free(read_buf) + return None + viperlib.snprintf(search_buf, search_len, "%s.%s.%s", + class_sha1, class_name, method_name) + search_str_len: t.CSizeT = string.strlen(search_buf) + + # 在 text.ll 中搜索 define 行包含 search_buf + buf_len: t.CSizeT = string.strlen(read_buf) + pos: t.CSizeT = 0 + result_ty: llvmlite.LLVMType | t.CPtr = None + + while pos < buf_len and result_ty is None: + ls: t.CSizeT = pos + le: t.CSizeT = pos + while le < buf_len: + if read_buf[le] == '\n': + break + le += 1 + ll: t.CSizeT = le - ls + + # 检查是否是 define 行 + if ll >= 7 and string.strncmp(read_buf + ls, "define ", 7) == 0: + # 找 @ 符号 + at_pos: t.CSizeT = ls + 7 + while at_pos < ls + ll: + if read_buf[at_pos] == '@': + break + at_pos += 1 + if at_pos < ls + ll: + # 跳过可选引号 + name_start: t.CSizeT = at_pos + 1 + if name_start < ls + ll and read_buf[name_start] == '"': + name_start += 1 + # 检查是否匹配 search_buf + if name_start + search_str_len <= ls + ll: + if string.strncmp(read_buf + name_start, search_buf, search_str_len) == 0: + # 匹配!提取返回类型: [ls+7, at_pos) + result_ty = _ParseLLVMRetTyStr(pool, read_buf, ls + 7, at_pos) + + pos = le + 1 + + stdlib.free(search_buf) + stdlib.free(read_buf) + return result_ty + + +# ============================================================ +# _translate_method_call - 翻译方法调用 obj.method(args) +# +# 生成: call @SHA1.ClassName.method_name(Ptr(StructTy) %obj, args...) +# +# obj_ptr 是对象变量的 alloca(Ptr(StructTy)),作为 self 参数传入 +# ============================================================ +def _translate_method_call(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + method_name: str, + obj_ptr: llvmlite.Value | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """翻译方法调用,返回 call 结果 Value""" + if pool is None or builder is None or class_name is None or method_name is None: + return None + if obj_ptr is None or cl is None: + return None + + # 提前获取结构体 entry(用 find_struct_by_type 规避跨模块同名 find_struct 找错) + # 用于继承链遍历、SHA1 查找和虚表分派 + mc_entry: HandlesStruct.StructEntry | t.CPtr = None + mc_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(obj_ptr) + if mc_struct_ty is not None: + mc_entry = HandlesStruct.find_struct_by_type(mc_struct_ty) + if mc_entry is None: + mc_entry = HandlesStruct.find_struct(class_name) + + # 构造方法查找名: ClassName.method_name + lookup_name: t.CChar | t.CPtr = pool.alloc(128) + if lookup_name is None: + return None + viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name) + + # 查找函数(支持 SHA1 后缀匹配) + found_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, lookup_name) + + # 沿继承链查找父类方法(子类未覆盖时回退到父类) + if found_func is None: + cur_parent: str = None + if mc_entry is not None: + cur_parent = mc_entry.ParentName + else: + cur_parent = HandlesStruct.get_parent_name(class_name) + while cur_parent is not None: + parent_lookup: t.CChar | t.CPtr = pool.alloc(128) + if parent_lookup is not None: + viperlib.snprintf(parent_lookup, 128, "%s.%s", cur_parent, method_name) + parent_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, parent_lookup) + if parent_func is not None: + found_func = parent_func + break + # 后续父类按名查找(无 ParentSha1,只能按名回退) + cur_parent = HandlesStruct.get_parent_name(cur_parent) + + # 确定调用名 + call_name: str = lookup_name + if found_func is not None: + found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) + if found_name is not None: + call_name = found_name + else: + # found_func 为 None(stub 未注入):用类所属模块的 SHA1 构造调用名 + # 沿继承链查找第一个有 SHA1 的类 + cls_sha1_mc: str = None + if mc_entry is not None: + cls_sha1_mc = mc_entry.ModuleSha1 + else: + cls_sha1_mc = HandlesStruct.get_struct_sha1(class_name) + if cls_sha1_mc is None: + cur_p: str = None + if mc_entry is not None: + cur_p = mc_entry.ParentName + else: + cur_p = HandlesStruct.get_parent_name(class_name) + while cur_p is not None and cls_sha1_mc is None: + cls_sha1_mc = HandlesStruct.get_struct_sha1(cur_p) + cur_p = HandlesStruct.get_parent_name(cur_p) + if cls_sha1_mc is not None: + mangled_len_mc: t.CSizeT = string.strlen(cls_sha1_mc) + string.strlen(lookup_name) + 2 + mangled_mc: str = pool.alloc(mangled_len_mc) + if mangled_mc is not None: + viperlib.snprintf(mangled_mc, mangled_len_mc, "%s.%s", cls_sha1_mc, lookup_name) + call_name = mangled_mc + + # 确定返回类型 + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if found_func is not None: + frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) + if frt is not None: + call_ret_ty = frt + else: + # found_func 为 None(stub 未注入):尝试从 text.ll 查找实际返回类型 + # 避免指针返回值被 _infer_method_ret_ty 默认为 i32 导致 inttoptr 截断 + looked_up_ty: llvmlite.LLVMType | t.CPtr = _LookupMethodRetTyFromTextLL( + pool, cls_sha1_mc, class_name, method_name) + if looked_up_ty is not None: + call_ret_ty = looked_up_ty + else: + call_ret_ty = _infer_method_ret_ty(pool, method_name) + + # 翻译调用参数 + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + can: t.CSizeT = 0 + if cargs is not None: + can = cargs.__len__() + + # 构建参数链表: 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 + # 按形参类型 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1) + # 修复: CDefine/i32 常量传给 i64 形参(如 MemBuddy.__init__ 的 size: t.CSizeT) + # 未提升导致 call(i32) 与 define(i64) 不匹配,运行时读到垃圾高 32 位崩溃 + if found_func is not None: + pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + pi: int = 0 + while pp is not None and pi < ai + 1: + if pi == ai + 1: + break + pp = llvmlite.param_get_next(pp) + pi += 1 + if pp is not None: + pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp) + if pty is not None: + arg_val = HandlesExpr.coerce_to_type( + builder, arg_val, pty, arg_node) + llvmlite.value_set_next(arg_val, None) + llvmlite.value_set_next(tail, arg_val) + tail = arg_val + + total_count: int = 1 + can + + # 默认参数填充:如果调用点参数少于函数定义参数,用默认值填充缺失参数 + # 查找函数的 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) + # can = 已提供的非 self 参数数量 + # mdf_param_count = 函数定义的非 self 参数数量 + if mdf_param_count > can: + mdf_offset: int = mdf_param_count - mdf_default_count + mdf_pi: int = can + 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 + + # 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用 + # (不依赖 found_func — 继承的虚方法可能没有子类实现) + # 复用前面已获取的 mc_entry(find_struct_by_type 规避跨模块同名找错) + mc_has_vt: int = 0 + mc_method_idx: int = -1 + if mc_entry is not None: + mc_has_vt = mc_entry.HasVTable + if mc_has_vt == 1 and mc_entry.VTableMethods is not None: + mc_methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(mc_entry.VTableMethods, t.CPtr)) + for mc_mi in range(mc_entry.VTableMethodCount): + mc_mname_addr: t.CSizeT = mc_methods_arr[mc_mi] + if mc_mname_addr == 0: + continue + mc_mname: str = (str | t.CPtr)(t.CVoid(mc_mname_addr, t.CPtr)) + if mc_mname is not None and string.strcmp(mc_mname, method_name) == 0: + mc_method_idx = mc_mi + break + if mc_has_vt == 1 and mc_method_idx >= 0: + return _do_virtual_call(pool, builder, mod, class_name, method_name, + obj_ptr, head, total_count, found_func, call_ret_ty) + + # 跨模块调用:创建 declare 声明,避免 llc 报 undefined value + _ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count) + # 检查变长函数 + C ABI 提升 + is_variadic_3441: int = _check_and_promote_variadic_call(pool, builder, mod, call_name, head, total_count) + return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, is_variadic_3441) + +# ============================================================ +# _kwarg_name_matches — 检查关键字参数名是否匹配函数参数名 +# +# 函数参数名在 LLVM IR 中带 % 前缀(如 "%a"),关键字参数名无前缀(如 "a") +# 跳过 % 前缀后逐字符比较 +# ============================================================ +def _kwarg_name_matches(kw_arg: str, + param_name: t.CChar | t.CPtr) -> int: + """检查关键字参数名 kw_arg 是否匹配参数名 param_name(跳过 % 前缀)""" + if kw_arg is None or param_name is None: + return 0 + start: t.CSizeT = 0 + if param_name[0] == '%': + start = 1 + for i, ch in enumerate(kw_arg): + c: t.CChar = param_name[start + i] + if c == '\0' or c != ch: + return 0 + if param_name[start + i + 1] != '\0': + return 0 + return 1 + +# ============================================================ +# _translate_struct_ctor_kw — 结构体构造函数(关键字参数) +# +# 支持两种语法: +# Point(x=10, y=20) — 全关键字 +# Point(10, y=20) — 混合(位置 + 关键字) +# +# 位置参数按字段索引赋值,关键字参数按字段名查找赋值 +# ============================================================ +def _translate_struct_ctor_kw(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + keywords: list[ast.AST | t.CPtr] | t.CPtr, + kw_count: t.CSizeT, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """结构体构造函数(关键字参数版本)""" + # 创建临时 alloca + # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) + HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) + tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) + if tmp is None: + return llvmlite.ConstZero(pool, struct_ty) + + # OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值 + # 用 find_struct_by_type 规避跨模块同名 find_struct 找错 + kw_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) + is_oop: int = 0 + if kw_entry is not None: + is_oop = kw_entry.IsOOP + + # 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods) + # 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入) + # 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠) + if is_oop == 0 and class_name is not None: + kw_init_lookup: t.CChar | t.CPtr = pool.alloc(128) + if kw_init_lookup is not None: + viperlib.snprintf(kw_init_lookup, 128, "%s.__init__", class_name) + # 方案1: 检查当前模块的函数声明 + kw_init_found: llvmlite.Function | t.CPtr = find_func_in_module(mod, kw_init_lookup) + if kw_init_found is not None: + is_oop = 1 + if kw_entry is not None: + kw_entry.IsOOP = 1 + kw_entry.HasInit = 1 + else: + # 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入) + kw_init_defaults: FuncDefaultsEntry | t.CPtr = find_func_defaults(kw_init_lookup) + if kw_init_defaults is not None: + is_oop = 1 + if kw_entry is not None: + kw_entry.IsOOP = 1 + kw_entry.HasInit = 1 + + if is_oop != 0: + _call_method_on_ptr(pool, builder, mod, class_name, + "__before_init__", tmp, None, 0, trans) + else: + # 普通结构体:store zeroinitializer + 应用默认值 + zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) + llvmlite.build_store(builder, zero, tmp) + _apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans) + + # OOP 结构体且有 __init__:调用 __init__ 而非逐字段 store + # 关键字构造调用此前总是逐字段 store,导致 __init__ 方法体不执行 + # (如 self._args = mb.alloc(...) 不执行 → self._args 为 NULL → add_argument 崩溃) + has_init_flag: int = 0 + has_new_flag: int = 0 + if kw_entry is not None: + has_init_flag = kw_entry.HasInit + has_new_flag = kw_entry.HasNew + + # 跨模块 OOP 类: HasInit 可能未设置(_translate_oop_methods 未被调用) + # 但 IsOOP=1 说明类有方法,推断 HasInit=1(__init__ 在目标模块中存在) + # 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法) + if is_oop != 0 and has_init_flag == 0: + has_init_flag = 1 + + if is_oop != 0 and has_init_flag != 0: + # 有 __init__:构建参数数组并调用 __init__ + storage_ptr: llvmlite.Value | t.CPtr = tmp + + # 如果有 __new__,调用 __new__ 获取实际存储指针 + if has_new_flag != 0: + new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if new_arg_vals is not None: + string.memset(new_arg_vals, 0, 8 * 32) + new_arg_count: int = 0 + for nai in range(can): + new_arg_node: ast.AST | t.CPtr = cargs.get(nai) + if new_arg_node is None: + continue + new_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, new_arg_node, None, 0, trans) + if new_av is not None: + if new_arg_count < 32: + new_arg_vals[new_arg_count] = t.CSizeT(new_av) + new_arg_count += 1 + # 关键字参数也传递给 __new__ + for nki in range(kw_count): + nkw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(nki)) + if nkw is None or nkw.value is None: + continue + nkw_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, nkw.value, None, 0, trans) + if nkw_av is not None: + if new_arg_count < 32: + new_arg_vals[new_arg_count] = t.CSizeT(nkw_av) + new_arg_count += 1 + new_ptr: llvmlite.Value | t.CPtr = _call_method_on_ptr( + pool, builder, mod, class_name, + "__new__", tmp, new_arg_vals, new_arg_count, trans) + if new_ptr is not None: + storage_ptr = new_ptr + + # 构建 __init__ 参数数组:位置参数按顺序 + 关键字参数追加 + init_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if init_arg_vals is not None: + string.memset(init_arg_vals, 0, 8 * 32) + init_arg_count: int = 0 + # 位置参数 + for ai_init in range(can): + arg_node_init: ast.AST | t.CPtr = cargs.get(ai_init) + if arg_node_init is None: + continue + av_init: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg_node_init, None, 0, trans) + if av_init is not None: + if init_arg_count < 32: + init_arg_vals[init_arg_count] = t.CSizeT(av_init) + init_arg_count += 1 + # 关键字参数(追加到末尾,按出现顺序) + for ki_init in range(kw_count): + kw_init: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki_init)) + if kw_init is None or kw_init.value is None: + continue + kw_av_init: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, kw_init.value, None, 0, trans) + if kw_av_init is not None: + if init_arg_count < 32: + init_arg_vals[init_arg_count] = t.CSizeT(kw_av_init) + init_arg_count += 1 + + # 调用 __init__(storage_ptr, *args) + _call_method_on_ptr(pool, builder, mod, class_name, + "__init__", storage_ptr, init_arg_vals, init_arg_count, trans) + + # 返回指针 + return storage_ptr + + # 无 __init__(或非 OOP):逐字段 store 参数值 + # 先处理位置参数(按字段索引,覆盖默认值) + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None: + continue + fe: HandlesStruct.FieldEntry | t.CPtr = None + if kw_entry is not None: + fe = HandlesStruct._get_field_entry(kw_entry, ai) + else: + fe = HandlesStruct.get_field_by_index(class_name, ai) + if fe is None: + continue + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, tmp, fe.Index) + if field_ptr is None: + continue + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg) + llvmlite.build_store(builder, arg_val, field_ptr) + + # 处理关键字参数(按字段名查找) + # SHA1 从 kw_entry 获取(规避跨模块同名 find_struct 找错) + kw_sha1: str = None + if kw_entry is not None: + kw_sha1 = kw_entry.ModuleSha1 + for ki in range(kw_count): + kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) + if kw is None or kw.arg is None or kw.value is None: + continue + fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field_by_class( + class_name, kw.arg, kw_sha1) + if fe is None: + continue + kw_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, kw.value, None, 0, trans) + if kw_val is None: + continue + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, tmp, fe.Index) + if field_ptr is None: + continue + kw_val = HandlesExpr.coerce_to_type(builder, kw_val, fe.Ty, kw.value) + llvmlite.build_store(builder, kw_val, field_ptr) + + # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load + return tmp + +# ============================================================ +# _translate_call_with_kwargs — 带关键字参数的函数调用 +# +# 支持两种语法: +# add(b=4, a=3) — 全关键字乱序 +# greet("Hello", name="World") — 位置 + 关键字混合 +# +# 策略: 遍历 found_func.Params 链表,对每个参数: +# 1. 若位置参数仍有剩余(param_idx < can),取位置参数 +# 2. 否则按参数名匹配关键字参数 +# 3. 按参数顺序构建调用参数链表 +# ============================================================ +def _translate_call_with_kwargs(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + func_name: str, + found_func: llvmlite.Function | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + keywords: list[ast.AST | t.CPtr] | t.CPtr, + kw_count: t.CSizeT, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """带关键字参数的函数调用,按参数顺序构建调用链表 + + 使用 llvmlite 访问器函数绕过 stub 类型限制: + found_func.Params/RetTy/Name 和 cur_param.Name/Ty/Next 在 stub + 类型中字段不足,直接访问会被 TransPyC 静默跳过。 + """ + head: llvmlite.Value | t.CPtr = None + tail: llvmlite.Value | t.CPtr = None + actual_count: t.CSizeT = 0 + # memcpy 专用: 收集前三个 Value 的独立引用(避免共享 alloca 对象的 Next 被污染) + mc_dst1: llvmlite.Value | t.CPtr = None + mc_src1: llvmlite.Value | t.CPtr = None + mc_num1: llvmlite.Value | t.CPtr = None + + # 遍历函数参数链表(使用访问器获取 Head) + param_idx: t.CSizeT = 0 + cur_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + + while cur_param is not None: + arg_val: llvmlite.Value | t.CPtr = None + if param_idx < can: + # 优先使用位置参数 + arg: ast.AST | t.CPtr = cargs.get(param_idx) + if arg is not None: + arg_val = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + else: + # 查找匹配的关键字参数 + param_name: t.CChar | t.CPtr = llvmlite.param_get_name(cur_param) + if param_name is not None: + for ki in range(kw_count): + kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) + if kw is None or kw.arg is None or kw.value is None: + continue + if _kwarg_name_matches(kw.arg, param_name) == 1: + arg_val = HandlesExpr.translate_value( + builder, pool, mod, kw.value, None, 0, trans) + break + + if arg_val is not None: + # 类型转换(按参数类型,使用访问器) + param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param) + if param_ty is not None: + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, param_ty) + arg_val.Next = None + if head is None: + head = arg_val + else: + tail.Next = arg_val + tail = arg_val + # memcpy 专用: 保存前三个参数的独立引用 + if actual_count == 0: + mc_dst1 = arg_val + elif actual_count == 1: + mc_src1 = arg_val + elif actual_count == 2: + mc_num1 = arg_val + actual_count += 1 + + param_idx += 1 + cur_param = llvmlite.param_get_next(cur_param) + + # 使用模块中的实际函数名(可能带 SHA1 前缀,使用访问器) + # declare 和 define 统一用 found_func.Name: + # - 普通函数的 declare/define 都带 SHA1 前缀(forward_declare_functions 和 stub 注入都用 mangled_name) + # - t.CExtern/t.State/t.CExport 函数的 declare/define 都用裸名 + # 旧逻辑(IsDeclared==1 时用 func_name 裸名)是错误的:stub 注入的 declare Name 已带 SHA1 前缀, + # 用裸名会导致 call @_PathToModuleName 而 define 是 @"sha1._PathToModuleName",链接报 undefined reference + call_name: str = func_name + found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) + if found_name is not None: + call_name = found_name + + # 返回类型(使用访问器) + call_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) + if call_ret_ty is None: + call_ret_ty = _infer_external_func_ret_ty(pool, func_name) + + # memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失) + if string.strcmp(func_name, "memcpy") == 0 and actual_count >= 3: + return _emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst1, mc_src1, mc_num1) + return llvmlite.build_call(builder, call_name, head, actual_count, call_ret_ty, 0) + +# ============================================================ +# _translate_t_type_cast - 翻译 t.XXX(value) 类型转换 +# +# 当 func 是 t.XXX 形式且 XXX 是已知类型名(map_t_type 能映射)时, +# 将 value 转换为目标类型: +# - 指针 → 整数: ptrtoint (如 t.CUInt64T(ptr) → i64) +# - 整数 → 指针: inttoptr (如 t.CPtr(int_val) → i8*) +# - 整数 → 整数: trunc/zext (如 t.CInt8T(i32_val) → i8) +# - 指针 → 指针: bitcast (如 t.CPtr(ptr_val) → i8*) +# - 整数 → 浮点: sitofp (如 t.CDouble(i32_val) → double) +# - 浮点 → 整数: fptosi (如 t.CInt(double_val) → i32) +# - 浮点 → 浮点: fpext/fptrunc (如 t.CFloat(double_val) → float) +# ============================================================ +def _translate_t_type_cast(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + val: llvmlite.Value | t.CPtr, + target_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """类型转换:根据参数类型和目标类型选择转换方式""" + if val is None or target_ty is None: + return None + + val_bits: int = HandlesExpr.get_llvm_type_bits(val.Ty) + target_bits: int = HandlesExpr.get_llvm_type_bits(target_ty) + val_fbits: int = HandlesExpr.get_llvm_float_bits(val.Ty) + target_fbits: int = HandlesExpr.get_llvm_float_bits(target_ty) + + # 整数 → 整数: trunc/zext + if val_bits != 0 and target_bits != 0: + if val_bits == target_bits: + return val + elif val_bits < target_bits: + return llvmlite.build_zext(builder, val, target_ty) + else: + return llvmlite.build_trunc(builder, val, target_ty) + + # 整数 → 浮点: sitofp + if val_bits != 0 and target_fbits != 0: + return llvmlite.build_si2fp(builder, val, target_ty) + + # 浮点 → 整数: fptosi + if val_fbits != 0 and target_bits != 0: + return llvmlite.build_fp2si(builder, val, target_ty) + + # 浮点 → 浮点: fpext/fptrunc + if val_fbits != 0 and target_fbits != 0: + if val_fbits == target_fbits: + return val + elif val_fbits < target_fbits: + return llvmlite.build_fpext(builder, val, target_ty) + else: + return llvmlite.build_fptrunc(builder, val, target_ty) + + # 指针 → 整数: ptrtoint + if val_bits == 0 and val_fbits == 0 and target_bits != 0: + return llvmlite.build_ptrtoint(builder, val, target_ty) + + # 整数 → 指针: inttoptr(必须排除浮点 target,浮点 target_bits 也是 0) + if val_bits != 0 and target_bits == 0 and target_fbits == 0: + return llvmlite.build_inttoptr(builder, val, target_ty) + + # 指针 → 指针: bitcast + return llvmlite.build_bitcast(builder, val, target_ty) + +# ============================================================ +# 泛型实例化辅助:从 Subscript slice 提取类型实参名 +# ============================================================ +# _get_type_name_from_annotation 已移至 HandlesType.py(支持 BinOp/Attribute) +# HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用 + +def _extract_type_args_from_slice(pool: memhub.MemBuddy | t.CPtr, + slice_node: ast.AST | t.CPtr) -> list[str] | t.CPtr: + """从 Subscript.slice 提取类型实参名列表 + + list[int] -> ["int"] + dict[str, int] -> ["str", "int"] + list[AST | t.CPtr] -> ["AST|t.CPtr"] + """ + if slice_node is None or pool is None: + return None + result: list[str] | t.CPtr = list[str](pool, 4) + k: int = slice_node.kind() + if k == ast.ASTKind.Tuple: + tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(slice_node) + elts: list[ast.AST | t.CPtr] | t.CPtr = tp.elts + if elts is not None: + n: t.CSizeT = elts.__len__() + i: t.CSizeT + for i in range(n): + elt: ast.AST | t.CPtr = elts.get(i) + tn: str = HandlesType._get_type_name_from_annotation(pool, elt) + if tn is not None: + result.append(tn) + else: + tn: str = HandlesType._get_type_name_from_annotation(pool, slice_node) + if tn is not None: + result.append(tn) + return result + +# ============================================================ +# 泛型类构造调用辅助: list[str](pool, 8) → __new__ + __before_init__ + __init__ +# +# 复用 translate_list_literal 的构造逻辑: +# 1. alloca tmp(特化类临时空间,作为 __new__ 的 self) +# 2. 翻译 cl.args 为参数指针数组 +# 3. call __new__(tmp, *args) → storage_ptr +# 4. call __before_init__(storage_ptr) +# 5. call __init__(storage_ptr, *args) +# 6. return storage_ptr +# +# 必须独立于 translate_call 的普通函数路径:spec_name 是类名不是函数名, +# 走裸名路径会被 _lookup_mod_sha1 的 star import 回退误导,用错误的 SHA1 +# 且缺少 __new__ 方法名后缀,导致链接报 undefined reference。 +# ============================================================ +def _translate_generic_ctor_call(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + spec_name: str, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__""" + if pool is None or builder is None or mod is None or spec_name is None or cl is None: + return None + + # 查找 struct entry 获取类型 + struct_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) + if struct_entry is None: + HandlesType.fatal_error(cl, "泛型类构造调用: 特化类未注册") + return None + struct_ty: llvmlite.LLVMType | t.CPtr = struct_entry.Ty + if struct_ty is None: + return None + + # 确保结构体定义在当前模块中可用(供 alloca 分配空间) + HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) + + # alloca tmp(self 指针) + tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) + if tmp is None: + return None + + # 翻译 cl.args 为参数指针数组(extra_args[i] = Value 指针) + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + can: t.CSizeT = 0 + if cargs is not None: + can = cargs.__len__() + + extra_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if extra_args is None: + return None + string.memset(extra_args, 0, 8 * 32) + + ai: t.CSizeT = 0 + while ai < can: + arg_node: ast.AST | t.CPtr = cargs.get(ai) + if arg_node is not None: + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg_node, None, 0, trans) + if arg_val is not None: + extra_args[ai] = t.CSizeT(arg_val) + ai += 1 + + # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 + # __new__ 是可选的,仅当泛型类模板定义了 __new__ 方法时才调用 + # (与 _translate_struct_ctor 保持一致,避免为无 __new__ 的类生成过度声明) + storage_ptr: llvmlite.Value | t.CPtr = tmp + has_new_flag: int = 0 + if struct_entry is not None: + has_new_flag = struct_entry.HasNew + if has_new_flag != 0: + new_ptr: llvmlite.Value | t.CPtr = _call_method_on_ptr( + pool, builder, mod, spec_name, "__new__", tmp, extra_args, can, trans) + if new_ptr is not None: + storage_ptr = new_ptr + + # call __before_init__(storage_ptr)(TransPyV 自动生成,零值填充) + _call_method_on_ptr( + pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans) + + # call __init__(storage_ptr, *args) + _call_method_on_ptr( + pool, builder, mod, spec_name, "__init__", storage_ptr, extra_args, can, trans) + + return storage_ptr + + +# ============================================================ +# 翻译函数调用 Call(func, args) — 模块级版本 +# ============================================================ +def translate_call(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译函数调用,返回 call 结果 Value""" + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cl is None: + return None + + func_name: str = HandlesExpr.get_func_name(cl.func) + if func_name is None: + # 检查是否是 list[int](pool) 形式的泛型实例化调用 + # Subscript 节点作为 Call func: 泛型类构造函数 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Subscript and trans is not None: + sub_node: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(cl.func) + if sub_node.value is not None and sub_node.value.kind() == ast.ASTKind.Name: + gen_nm_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_node.value) + gen_class_name: str = gen_nm_node.id + # 检查是否是泛型类模板 + template_cd: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(gen_class_name) + if template_cd is not None: + # 提取类型实参 + gen_type_args: list[str] | t.CPtr = _extract_type_args_from_slice(pool, sub_node.slice) + if gen_type_args is not None and gen_type_args.__len__() > 0: + # 特化泛型类,返回特化类名 + spec_name: str = HandlesClassDef._specialize_generic_class( + trans, gen_class_name, gen_type_args) + if spec_name is not None: + # 泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__ + # 不能直接用 spec_name 作为 func_name(会走裸名调用路径, + # 被 star import 回退误导用错误的 SHA1,且缺少 __new__ 方法名后缀) + return _translate_generic_ctor_call( + pool, builder, mod, spec_name, cl, trans) + else: + # 泛型类模板未找到:可能未 import 定义模块 + gt_err: str = pool.alloc(256) + if gt_err is not None: + viperlib.snprintf(gt_err, 256, "泛型类 '%s' 未找到模板,可能未 import 定义模块", gen_class_name) + HandlesType.fatal_error(gen_nm_node, gt_err) + HandlesType.fatal_error(gen_nm_node, "泛型类模板未找到") + if func_name is None: + # 检查是否是 (A | t.CPtr)(value) 形式的类型转换 + # BinOp 节点作为 Call func: 联合类型注解用作类型转换 + if cl.func is not None and cl.func.kind() == ast.ASTKind.BinOp and trans is not None: + binop_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, cl.func, trans._imported_modules, trans._from_imports, trans) + if binop_ty is not None: + binop_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if binop_args is not None and binop_args.__len__() == 1: + binop_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, binop_args.get(0), funcs_ptr, func_count, trans) + if binop_arg_val is not None: + return _translate_t_type_cast(pool, builder, binop_arg_val, binop_ty) + return None + + # 检测 c.Deref / c.DerefAs / c.Addr 等特殊调用(内联 IR,不生成 call) + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + at_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at_node.value is not None and at_node.value.kind() == ast.ASTKind.Name: + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_node.value) + if mod_nm.id is not None and string.strcmp(mod_nm.id, "c") == 0: + if string.strcmp(func_name, "Deref") == 0: + return translate_c_deref(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "DerefAs") == 0: + return translate_c_derefas(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "Addr") == 0: + return translate_c_addr(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "Load") == 0: + return translate_c_load(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "Asm") == 0: + return translate_c_asm(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "LLVMIR") == 0: + return translate_c_llvmir(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "LInp") == 0 or string.strcmp(func_name, "LOut") == 0: + # c.LInp/c.LOut 独立调用时返回 0(仅在 c.LLVMIR 的 f-string 内有意义) + return llvmlite.ConstInt(pool, llvmlite.Int32(pool), 0, "0") + + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + can: t.CSizeT = 0 + if cargs is not None: + can = cargs.__len__() + + # ============================================================ + # stdarg 糖函数处理: va_arg / arg / va_start / va_end + # 这些函数在 stdarg.vp 中声明为 pass 体,由编译器在翻译期处理: + # va_arg(ap, type) → %N = va_arg , (LLVM 指令) + # va_arg(ap) → 同上,类型从赋值上下文推断(默认 i32) + # arg(type) → 同上,使用当前函数的隐式 va_list (trans._va_list_ptr) + # va_start(ap, _) → call void @llvm.va_start(i8* %ap) (LLVM intrinsic) + # va_end(ap) → call void @llvm.va_end(i8* %ap) (LLVM intrinsic) + # ============================================================ + if func_name is not None and trans is not None: + if string.strcmp(func_name, "va_arg") == 0: + return _translate_va_arg_sugar(pool, builder, mod, cl, cargs, can, + funcs_ptr, func_count, trans) + elif string.strcmp(func_name, "arg") == 0: + return _translate_arg_sugar(pool, builder, mod, cl, cargs, can, + funcs_ptr, func_count, trans) + elif string.strcmp(func_name, "va_start") == 0: + return _translate_va_start_sugar(pool, builder, mod, cargs, can, + funcs_ptr, func_count, trans) + elif string.strcmp(func_name, "va_end") == 0: + return _translate_va_end_sugar(pool, builder, mod, cargs, can, + funcs_ptr, func_count, trans) + + # 内置强转函数: str(x)/bytes(x) → i8*, int(x) → i32 + # 等价于 (t.CChar | t.CPtr)(x) / (t.CInt32T)(x) + # 单参数:str(val) → bitcast val to i8* + # int(val) → trunc/sext val to i32 + if func_name is not None and can == 1: + if string.strcmp(func_name, "str") == 0 or string.strcmp(func_name, "bytes") == 0: + # str(x) / bytes(x) → i8* (bitcast) + cast_arg: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) + if cast_arg is not None: + i8_ptr_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + return _translate_t_type_cast(pool, builder, cast_arg, i8_ptr_ty_builtin) + return None + elif string.strcmp(func_name, "int") == 0: + # int(x) → i32 + cast_arg_int: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) + if cast_arg_int is not None: + i32_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + return _translate_t_type_cast(pool, builder, cast_arg_int, i32_ty_builtin) + return None + elif string.strcmp(func_name, "bool") == 0: + # bool(x) → i1(严格 != 0 归一化) + # 整数: icmp ne x, 0 → i1 + # 浮点: fcmp one x, 0.0 → i1 + # 指针: icmp ne x, null → i1 + cast_arg_bool: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) + if cast_arg_bool is not None: + arg_bits: int = HandlesExpr.get_llvm_type_bits(cast_arg_bool.Ty) + arg_fbits: int = HandlesExpr.get_llvm_float_bits(cast_arg_bool.Ty) + # 整数: icmp ne x, 0 + if arg_bits != 0: + zero_int: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, arg_bits, 0) + if zero_int is not None: + return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, zero_int) + return None + # 浮点: fcmp one x, 0.0 + if arg_fbits != 0: + zero_ty: llvmlite.LLVMType | t.CPtr = cast_arg_bool.Ty + zero_flt: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, zero_ty, 0.0) + if zero_flt is not None: + return llvmlite.build_fcmp(builder, llvmlite.FCMP_ONE, cast_arg_bool, zero_flt) + return None + # 指针: icmp ne x, null + ptr_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cast_arg_bool.Ty, "null") + if ptr_null is not None: + return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, ptr_null) + return None + return None + + # 检测 t.XXX 类型转换: t.CUInt64T(ptr), t.CPtr(val), t.CInt(val) 等 + # 当 func 是 t.XXX 形式且 XXX 是已知类型名时,当作类型转换处理(而非函数调用) + # 支持: + # 单参数: t.CInt(val) → 目标类型 = map_t_type(func_name) + # 双参数: t.CInt(val, t.CPtr) → 目标类型 = Ptr(map_t_type(func_name)) + # t 是内部库,一旦确认为类型转换,绝不跌落到跨模块调用 FATAL 路径 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + tc_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if tc_at.value is not None and tc_at.value.kind() == ast.ASTKind.Name: + tc_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_at.value) + if tc_mod_nm.id is not None and string.strcmp(tc_mod_nm.id, "t") == 0: + target_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, func_name) + if target_ty is not None: + tc_effective_can: t.CSizeT = can + # 双参数形式: t.CInt(val, t.CPtr) → Ptr(target_ty) + # 注意: void* 在 LLVM 中非法,CVoid* 应表示为 i8* + if can == 2: + tc_arg2_node: ast.AST | t.CPtr = cargs.get(1) + if tc_arg2_node is not None and tc_arg2_node.kind() == ast.ASTKind.Attribute: + tc_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tc_arg2_node) + if tc_arg2_at.attr is not None and string.strcmp(tc_arg2_at.attr, "CPtr") == 0: + if tc_arg2_at.value is not None and tc_arg2_at.value.kind() == ast.ASTKind.Name: + tc_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_at.value) + if tc_arg2_nm.id is not None and string.strcmp(tc_arg2_nm.id, "t") == 0: + # CVoid* → i8*(LLVM 中 void* 表示为 i8*) + match target_ty: + case llvmlite.LLVMType.Void(): + target_ty = llvmlite.Int8(pool) + case _: + pass + target_ty = llvmlite.Ptr(pool, target_ty) + tc_effective_can = 1 + if tc_effective_can == 1: + tc_arg_node: ast.AST | t.CPtr = cargs.get(0) + if tc_arg_node is not None: + tc_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, tc_arg_node, None, 0, trans) + if tc_arg_val is not None: + return _translate_t_type_cast(pool, builder, tc_arg_val, target_ty) + # t.XXX 类型转换已确认但不满足参数条件:返回 None,不跌落到跨模块 FATAL + return None + + # 裸名 typedef 调用: BYTEPTR(ptr1), HANDLE(val), CHARPTR(str) 等 + # 用户通过 `from stdint import *` 导入 typedef 后,可直接用裸名做类型转换 + # map_t_type 包含所有内置 typedef 名称(BYTEPTR/HANDLE/LPCSTR/size_t 等) + if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + bare_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, func_name) + if bare_ty is not None and can == 1: + bare_arg_node: ast.AST | t.CPtr = cargs.get(0) + if bare_arg_node is not None: + bare_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, bare_arg_node, None, 0, trans) + if bare_arg_val is not None: + return _translate_t_type_cast(pool, builder, bare_arg_val, bare_ty) + + # 检测 ClassName.__sizeof__() — 返回结构体大小常量(i64) + # __sizeof__ 是内置方法,不走跨模块调用路径 + # 支持: Argument.__sizeof__() 和 w32.win32file.WIN32_FIND_DATAA.__sizeof__() + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + sz_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if sz_at.attr is not None and string.strcmp(sz_at.attr, "__sizeof__") == 0: + if sz_at.value is not None and can == 0: + sz_cls_name: str = None + sz_vk: int = sz_at.value.kind() + if sz_vk == ast.ASTKind.Name: + sz_cls_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sz_at.value) + sz_cls_name = sz_cls_nm2.id + elif sz_vk == ast.ASTKind.Attribute: + sz_inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sz_at.value) + sz_cls_name = sz_inner_at.attr + if sz_cls_name is not None: + # 泛型类型参数 T 替换: T.__sizeof__() → int.__sizeof__() + sz_cls_name = HandlesType.resolve_generic_type_name(sz_cls_name) + # 去除模块前缀: Viper 解析器将 t.CInt 解析为 Name(id="t.CInt") + # 而非 Attribute(value=Name("t"), attr="CInt"),需要手动提取最后的类名分量 + # "t.CInt" → "CInt", "w32.win32file.WIN32_FIND_DATAA" → "WIN32_FIND_DATAA" + dot_pos: str = string.strrchr(sz_cls_name, '.') + if dot_pos is not None: + sz_cls_name = dot_pos + 1 + # 联合类型(如 AST|t.CPtr)按指针大小处理(8 字节) + # 联合类型在 TPV 中表示指针,可以指向多种类型 + # 对应 TPC 中对 BinOp/BitOr 联合类型的特殊处理 + if string.strstr(sz_cls_name, "|") is not None: + return llvmlite.const_int64(pool, 8) + # 内置类型 sizeof(int=4, str/bytes=8 指针, double=8 等) + sz_builtin: int = -1 + if string.strcmp(sz_cls_name, "int") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "str") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "bytes") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CInt") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "CInt8T") == 0: + sz_builtin = 1 + elif string.strcmp(sz_cls_name, "CInt16T") == 0: + sz_builtin = 2 + elif string.strcmp(sz_cls_name, "CInt32T") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "CInt64T") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CChar") == 0: + sz_builtin = 1 + elif string.strcmp(sz_cls_name, "CDouble") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CFloat") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "CPtr") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CSizeT") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CBool") == 0: + sz_builtin = 1 + elif string.strcmp(sz_cls_name, "bool") == 0: + sz_builtin = 1 + if sz_builtin >= 0: + # 注意: 必须用 const_int64 而非 ConstInt(...,"0") + # ConstInt 的 name 参数是 IR 文本表示,ValuePrint 输出时使用 Name 而非 IntVal + # 硬编码 "0" 会导致 IR 输出 i64 0 而非实际值 + return llvmlite.const_int64(pool, sz_builtin) + sz_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type( + sz_cls_name) + if sz_struct_ty is not None: + sz_val: int = HandlesClassDef._get_type_size(sz_struct_ty) + if sz_val > 0: + return llvmlite.const_int64(pool, sz_val) + # 类型已注册但大小为 0(opaque struct 或字段链表未填充):报错终止 + fb_sz1: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_sz1 is not None: + viperlib.snprintf(fb_sz1, 1024, + "类型 '%s' 已注册但大小为 0(字段链表未填充),立即终止编译", + sz_cls_name) + VLogger.critical(fb_sz1, "__sizeof__") + _ddebug_exit() + # 类型未注册:报错终止,不静默返回 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__") + _ddebug_exit() + + # 检测 obj.__len__() — 返回 list 对象的 __count__ 字段(偏移 8,i64) + # __len__ 是 list[T] 的内置方法,list 是泛型类不注册 struct + # 注意: 必须用 translate_value 而非 translate_name_value,因为 len_at.value + # 可能是 Attribute 节点(如 md_ags.args),translate_name_value 只处理 Name 节点, + # 对 Attribute 会错误返回 i32 0,导致 GEP base 不是指针(base of getelementptr must be a pointer) + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + len_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if len_at.attr is not None and string.strcmp(len_at.attr, "__len__") == 0: + if len_at.value is not None and can == 0: + obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, len_at.value, funcs_ptr, func_count, trans) + if obj_val is not None and obj_val.Ty is not None: + # 防御性类型检查: obj_val 必须是指针类型才能做 GEP + # 如果 translate_value 返回 i32 (如 CDefine 常量被误解析、 + # 模块属性前向引用回退为 i32),GEP base 会是 i32 而非指针, + # 导致 llc 报错 "base of getelementptr must be a pointer" + if HandlesExpr.is_ptr_type(obj_val.Ty) == 0: + return llvmlite.const_int64(pool, 0) + i64_ty_len: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + # 注意: 必须用 const_int64 而非 ConstInt(...,"0") + # ConstInt 的 name 参数 "0" 会被当作 IR 文本值输出 i64 0 + # 导致 GEP 索引为 0(访问 __data__)而非 1(访问 __count__) + idx_one: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + count_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i64_ty_len, obj_val, idx_one) + if count_ptr is not None: + return llvmlite.build_load(builder, i64_ty_len, count_ptr) + + # 检测 len() 内置函数调用 — 转换为 strlen 调用 + # len(s) 对 str 类型调用 strlen,返回 i64 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + if func_name is not None and string.strcmp(func_name, "len") == 0: + if can == 1: + len_arg_node: ast.AST | t.CPtr = cargs.get(0) + if len_arg_node is not None: + len_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, len_arg_node, None, 0, trans) + if len_val is not None: + # 确保 strlen 在模块中有声明 + strlen_fn: llvmlite.Function | t.CPtr = find_func_in_module(mod, "strlen") + if strlen_fn is None: + i64_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ptr_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + strlen_fn = llvmlite.create_declare(pool, mod, "strlen", i64_ty_ln) + if strlen_fn is not None: + llvmlite.add_param(pool, strlen_fn, i8_ptr_ty_ln, "s") + # 参数类型转换为 i8* + i8_ptr_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + len_arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(len_val) + len_coerced: llvmlite.Value | t.CPtr = len_val + if HandlesExpr.is_ptr_type(len_arg_ty) != 0: + len_coerced = llvmlite.build_bitcast(builder, len_val, i8_ptr_ty_ln2) + # 构建单参数链表并调用 strlen + len_coerced.Next = None + i64_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + return llvmlite.build_call(builder, "strlen", len_coerced, 1, i64_ty_ln2, 0) + + # 检测方法调用: obj.method(args) + # 当 cl.func 是 Attribute 且 obj 是已注册的结构体变量时,翻译为方法调用 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if method_at is not None and method_at.value is not None: + if method_at.value.kind() == ast.ASTKind.Name and trans is not None: + method_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(method_at.value) + if method_obj_nm.id is not None: + # 查找对象变量 + obj_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, method_obj_nm.id) + if obj_var is not None and obj_var.Ty is not None: + # 检查是否为 Ptr(Struct(...))(结构体值变量) + # 或 Ptr(Ptr(Struct(...)))(指针变量,需 load) + match obj_var.Ty: + case llvmlite.LLVMType.Ptr(obj_struct_ty): + class_nm: str = HandlesStruct.get_class_name_by_type( + pool, obj_struct_ty) + if class_nm is not None: + return _translate_method_call( + pool, builder, mod, class_nm, func_name, + obj_var, cl, trans) + # 指针变量: alloca 类型是 Ptr(Ptr(Struct)) + # load 获取实际指针 Ptr(Struct) 后再查找 + match obj_struct_ty: + case llvmlite.LLVMType.Ptr(inner_struct_ty): + inner_nm: str = HandlesStruct.get_class_name_by_type( + pool, inner_struct_ty) + if inner_nm is not None: + obj_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, obj_struct_ty, obj_var) + if obj_ptr is not None: + return _translate_method_call( + pool, builder, mod, inner_nm, func_name, + obj_ptr, cl, trans) + # AnnotClassName 回退:联合类型简化为 Ptr(i8) 时, + # 通过原始类型注解的类名查找结构体 + var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, method_obj_nm.id) + if var_entry is not None and var_entry.AnnotClassName is not None: + annot_val: str = var_entry.AnnotClassName + # 解析模块限定名 "memhub.MemBuddy" → mod_nm="memhub", cls_nm="MemBuddy" + dot_ptr: t.CChar | t.CPtr = string.strrchr(annot_val, '.') + cls_nm2: str = annot_val + mod_nm2: str = None + if dot_ptr is not None: + cls_nm2 = dot_ptr + 1 + total_len_av: t.CSizeT = string.strlen(annot_val) + cls_len_av: t.CSizeT = string.strlen(cls_nm2) + mod_len2: t.CSizeT = total_len_av - cls_len_av - 1 + mod_nm2 = pool.alloc(mod_len2 + 1) + if mod_nm2 is not None: + string.strncpy(mod_nm2, annot_val, mod_len2) + mod_nm2[mod_len2] = '\0' + # 检查结构体是否已注册 + if HandlesStruct.get_struct_type(cls_nm2) is not None: + # 结构体已注册:load obj_ptr 走方法调用 + i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + obj_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty2, obj_var) + if obj_ptr2 is not None: + return _translate_method_call( + pool, builder, mod, cls_nm2, func_name, + obj_ptr2, cl, trans) + else: + # 结构体未注册(跨模块依赖未翻译): + # 用模块名查 SHA1 构造方法调用名 + sha1_fc: str = None + if mod_nm2 is not None: + sha1_fc = _lookup_module_sha1(mod_nm2) + if sha1_fc is not None: + # 构造 "{sha1}.{cls_nm2}.{func_name}" 调用名 + mlen3: t.CSizeT = string.strlen(sha1_fc) + string.strlen(cls_nm2) + string.strlen(func_name) + 3 + mangled3: str = pool.alloc(mlen3) + if mangled3 is not None: + viperlib.snprintf(mangled3, mlen3, "%s.%s.%s", sha1_fc, cls_nm2, func_name) + # load obj_ptr (self) + i8_ptr_ty3: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + obj_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty3, obj_var) + if obj_ptr3 is not None: + # 构建参数链表: obj_ptr3 (self) → 其他参数 + llvmlite.value_set_next(obj_ptr3, None) + head3: llvmlite.Value | t.CPtr = obj_ptr3 + tail3: llvmlite.Value | t.CPtr = obj_ptr3 + for ai3 in range(can): + arg3: ast.AST | t.CPtr = cargs.get(ai3) + if arg3 is not None: + arg_val3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg3, None, 0, trans) + if arg_val3 is not None: + llvmlite.value_set_next(arg_val3, None) + llvmlite.value_set_next(tail3, arg_val3) + tail3 = arg_val3 + total3: int = 1 + can + ret_ty3: llvmlite.LLVMType | t.CPtr = _LookupMethodRetTyFromTextLL( + pool, sha1_fc, cls_nm2, func_name) + if ret_ty3 is None: + ret_ty3 = _infer_method_ret_ty(pool, func_name) + _ensure_method_declare(pool, mod, mangled3, ret_ty3, head3, total3) + return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0) + + # ============================================================ + # 检测 self.field.method() 调用 + # + # 当 method_at.value 是 Attribute(字段访问,如 self.__pool__)时, + # 翻译字段值获取对象指针,然后走方法调用路径。 + # + # 路径1: 从字段值的 LLVM 类型获取类名(字段类型为 Ptr(Struct("MemManager"))) + # 路径2: 从字段的 AnnotClassName 回退查找(字段类型被简化为 Ptr(i8) 时) + # ============================================================ + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + attr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if attr_method_at is not None and attr_method_at.value is not None: + if attr_method_at.value.kind() == ast.ASTKind.Attribute and trans is not None: + inner_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(attr_method_at.value) + if inner_attr is not None and inner_attr.attr is not None: + # 翻译 self.__pool__ 获取字段值(已 load 的对象指针) + field_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, attr_method_at.value, funcs_ptr, func_count, trans) + if field_obj is not None and field_obj.Ty is not None: + field_cls_nm: str = None + # 路径1: 从字段值的 LLVM 类型获取类名 + match field_obj.Ty: + case llvmlite.LLVMType.Ptr(field_struct_ty): + field_cls_nm = HandlesStruct.get_class_name_by_type( + pool, field_struct_ty) + # 路径2: 从字段注解类名回退查找 + if field_cls_nm is None: + if inner_attr.value is not None and inner_attr.value.kind() == ast.ASTKind.Name: + inner_name_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_attr.value) + if inner_name_node is not None and inner_name_node.id is not None: + inner_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, inner_name_node.id) + if inner_var is not None and inner_var.Ty is not None: + match inner_var.Ty: + case llvmlite.LLVMType.Ptr(field_owner_struct_ty): + field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( + field_owner_struct_ty, inner_attr.attr) + if field_info is not None: + field_annot: str = HandlesStruct.get_field_annot_class_name(field_info) + if field_annot is not None: + dot_p: t.CChar | t.CPtr = string.strrchr(field_annot, 46) + if dot_p is not None: + field_cls_nm = dot_p + 1 + else: + field_cls_nm = field_annot + if field_cls_nm is not None: + return _translate_method_call( + pool, builder, mod, field_cls_nm, func_name, + field_obj, cl, trans) + + # ============================================================ + # 检测 list 内置方法调用: lst.get(i), lst.set(i,v), lst.pop(), lst.clear(), lst.__iter__() + # list[T] 是泛型类不注册 struct,方法调用处理器(上方)无法处理, + # 需要在此特殊处理。 + # list 结构布局 (6 字段 × 8 字节): + # __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) + # ============================================================ + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + lm_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if lm_at is not None and lm_at.attr is not None and lm_at.value is not None: + lm_name: str = lm_at.attr + # 判断是否是 list 方法名 + lm_is_list: int = 0 + if string.strcmp(lm_name, "get") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "__getitem__") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "set") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "__setitem__") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "pop") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "clear") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "__iter__") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "append") == 0: lm_is_list = 1 + + if lm_is_list == 1 and trans is not None: + # 翻译 list 对象 + lm_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, lm_at.value, funcs_ptr, func_count, trans) + if lm_obj is not None: + # 防御性类型检查: lm_obj 必须是指针类型才能做 GEP + # translate_value 对某些 Attribute 节点(如 ast.Arguments 的属性) + # 可能返回 i32 0 (非指针),直接 GEP 会导致 + # "base of getelementptr must be a pointer" 错误 + if lm_obj.Ty is None or HandlesExpr.is_ptr_type(lm_obj.Ty) == 0: + lm_node_kind: int = lm_at.value.kind() + fb_lm: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_lm is not None: + viperlib.snprintf(fb_lm, 1024, + "list 方法 '%s' 的目标对象非指针 (node kind=%d)," + "translate_value 类型推断失败", + lm_name, lm_node_kind) + VLogger.critical(fb_lm, "LIST-METHOD") + return None + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + # get / __getitem__: 返回 index 处的元素 + if string.strcmp(lm_name, "get") == 0 or string.strcmp(lm_name, "__getitem__") == 0: + if can >= 1: + # 加载 __data__ (偏移 0) + g_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0) + g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp) + # 加载 __elem_size__ (偏移 32, index 4) + g_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) + g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4) + g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp) + # 翻译 index + g_idx_node: ast.AST | t.CPtr = cargs.get(0) + g_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, g_idx_node, None, 0, trans) + if g_data is not None and g_esize is not None and g_idx_val is not None: + g_idx_i64: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( + builder, g_idx_val, i64_ty, g_idx_node) + g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize) + g_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, g_data, g_offset) + if g_addr is not None: + return llvmlite.build_load(builder, i8_ptr_ty, g_addr) + + # set / __setitem__: 设置 index 处的元素 + elif string.strcmp(lm_name, "set") == 0 or string.strcmp(lm_name, "__setitem__") == 0: + if can >= 2: + s_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0) + s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp) + s_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) + s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4) + s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp) + s_idx_node: ast.AST | t.CPtr = cargs.get(0) + s_val_node: ast.AST | t.CPtr = cargs.get(1) + s_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, s_idx_node, None, 0, trans) + s_val_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, s_val_node, None, 0, trans) + if s_data is not None and s_esize is not None and s_idx_val is not None and s_val_val is not None: + s_idx_i64: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( + builder, s_idx_val, i64_ty, s_idx_node) + s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize) + s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset) + if s_addr is not None: + s_val_ptr: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( + builder, s_val_val, i8_ptr_ty, s_val_node) + llvmlite.build_store(builder, s_val_ptr, s_addr) + return None + + # pop: 返回最后一个元素,count-- + elif string.strcmp(lm_name, "pop") == 0: + p_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + p_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx1) + p_count: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_cpp) + p_nc: llvmlite.Value | t.CPtr = llvmlite.build_sub( + builder, p_count, llvmlite.const_int64(pool, 1)) + llvmlite.build_store(builder, p_nc, p_cpp) + p_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + p_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx0) + p_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, p_dpp) + p_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) + p_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx4) + p_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_epp) + if p_data is not None and p_esize is not None and p_nc is not None: + p_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, p_nc, p_esize) + p_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, p_data, p_offset) + if p_addr is not None: + return llvmlite.build_load(builder, i8_ptr_ty, p_addr) + + # clear: count = 0 + elif string.strcmp(lm_name, "clear") == 0: + c_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + c_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, c_idx1) + llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), c_cpp) + return None + + # __iter__: iter_index = 0, return self + elif string.strcmp(lm_name, "__iter__") == 0: + it_idx5: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 5) + it_ipp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, it_idx5) + llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), it_ipp) + return lm_obj + + # append: 直接调用 list.append(self, item) + # append 需要容量检查和内存重分配,逻辑复杂,直接调用 _list.py 中的实现 + elif string.strcmp(lm_name, "append") == 0: + if can >= 1: + ap_sha1: str = _lookup_module_sha1("_list") + if ap_sha1 is not None: + ap_mlen: t.CSizeT = string.strlen(ap_sha1) + 13 + ap_mangled: str = pool.alloc(ap_mlen) + if ap_mangled is not None: + viperlib.snprintf(ap_mangled, ap_mlen, "%s.list.append", ap_sha1) + ap_item_node: ast.AST | t.CPtr = cargs.get(0) + ap_item_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, ap_item_node, None, 0, trans) + if ap_item_val is not None: + llvmlite.value_set_next(lm_obj, None) + llvmlite.value_set_next(ap_item_val, None) + llvmlite.value_set_next(lm_obj, ap_item_val) + ap_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + _ensure_method_declare(pool, mod, ap_mangled, ap_ret_ty, lm_obj, 2) + return llvmlite.build_call(builder, ap_mangled, lm_obj, 2, ap_ret_ty, 0) + + # 获取关键字参数 + keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords + kw_count: t.CSizeT = 0 + if keywords is not None: + kw_count = keywords.__len__() + + # 检查是否是结构体构造函数: Point() / Point(10, 20) / Point(x=10, y=20) + # 命名空间隔离:严格模式下检查结构体可见性 + # - 裸名 Class(): 需要 from X import Class 或本地定义 + # - 模块限定 Module.Class(): 需要 import Module + # 用 find_struct_by_module 规避跨模块同名 find_struct 找错 + struct_ty: llvmlite.LLVMType | t.CPtr = None + gen_ctor_entry: HandlesStruct.StructEntry | t.CPtr = None + vis: int = HandlesStruct.is_struct_visible(func_name) + if vis != 0: + if trans is not None: + gen_ctor_entry = HandlesStruct.find_struct_by_module(func_name, trans.ModuleSha1) + if gen_ctor_entry is None: + gen_ctor_entry = HandlesStruct.find_struct(func_name) + if gen_ctor_entry is not None: + struct_ty = gen_ctor_entry.Ty + elif trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + at_qc: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at_qc.value is not None and at_qc.value.kind() == ast.ASTKind.Name: + mod_nm_qc: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_qc.value) + imp_ok: int = HandlesImports.is_module_imported(trans._imported_modules, mod_nm_qc.id) + if imp_ok != 0: + if trans is not None: + gen_ctor_entry = HandlesStruct.find_struct_by_module(func_name, trans.ModuleSha1) + if gen_ctor_entry is None: + gen_ctor_entry = HandlesStruct.find_struct(func_name) + if gen_ctor_entry is not None: + struct_ty = gen_ctor_entry.Ty + 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) + elif found_func is not None: + # found_func 存在:按形参类型 coerce(如 stdlib.malloc(size: t.CSizeT)) + # 修复: CDefine/i32 常量传给 i64 形参未提升,导致 call(i32) 与 define(i64) 不匹配 + fp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + fpi: int = 0 + while fp is not None and fpi < ai: + fp = llvmlite.param_get_next(fp) + fpi += 1 + if fp is not None: + fpty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(fp) + if fpty is not None: + arg_val = HandlesExpr.coerce_to_type( + builder, arg_val, fpty, arg) + arg_val.Next = None + if head is None: + head = arg_val + else: + tail.Next = arg_val + tail = arg_val + # memcpy 专用: 保存前三个参数的独立引用 + if ai == 0: + mc_dst2 = arg_val + elif ai == 1: + mc_src2 = arg_val + elif ai == 2: + mc_num2 = arg_val + + # 默认参数填充:当实参数量 < 形参数量时,用默认值填充缺失参数 + # defaults 数组右对齐到 args:defaults[0] 对应 args[offset],offset = param_count - default_count + if can > 0 or (can == 0 and cargs is not None): + df_defaults: t.CVoid | t.CPtr = None + df_default_count: int = 0 + df_param_count: int = 0 + # 先从当前模块函数表查找 FuncEntry + if trans is not None and trans._funcs is not None: + df_entry: FuncEntry | t.CPtr = find_func_entry_in_table( + trans._funcs, trans._func_count, func_name) + if df_entry is not None: + df_defaults = df_entry.Defaults + df_default_count = df_entry.DefaultCount + df_param_count = df_entry.ParamCount + # 如果当前模块没有,从全局默认参数表查找(跨模块) + if df_defaults is None: + gd_entry: FuncDefaultsEntry | t.CPtr = find_func_defaults(func_name) + if gd_entry is not None: + df_defaults = gd_entry.Defaults + df_default_count = gd_entry.DefaultCount + df_param_count = gd_entry.ParamCount + # 填充缺失参数 + if df_defaults is not None and df_default_count > 0 and can < df_param_count: + df_offset: int = df_param_count - df_default_count + df_di: int = 0 + while df_di < df_default_count: + df_param_idx: int = df_offset + df_di + if df_param_idx >= can: + 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 + # 原始函数名(别名导入时记录,如 from X import parse as json_parse → orig_func_name="parse") + # 用于在别名处理后重新推断返回类型,避免 _infer_external_func_ret_ty 用别名匹配失败 + orig_func_name: str = None + if found_func is not None: + found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) + if found_name is not None: + call_name = found_name + else: + # 跨模块函数调用:found_func 为 None 时,检查是否是模块限定调用 + # 如 string.strchr(...) → @{sha1_of_string}.strchr + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + xmod_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if xmod_at.value is not None and xmod_at.value.kind() == ast.ASTKind.Name: + xmod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(xmod_at.value) + if xmod_nm.id is not None: + mod_sha1: str = _lookup_module_sha1(xmod_nm.id) + if mod_sha1 is not None: + # 检查是否是 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) + # DDEBUG: 检测连续两个点,发现立即终止 + _md_i: int = 0 + while _md_i < mangled_len - 1: + if mangled[_md_i] == 46 and mangled[_md_i + 1] == 46: + stdio.printf("[DDEBUG] mod mangled double-dot: sha1='%s' func='%s' mangled='%s'\n", mod_sha1, func_name, mangled) + _ddebug_exit() + _md_i += 1 + 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) + # DDEBUG: 检测连续两个点,发现立即终止 + _ad_i: int = 0 + while _ad_i < AliasMangledLen - 1: + if alias_mangled[_ad_i] == 46 and alias_mangled[_ad_i + 1] == 46: + stdio.printf("[DDEBUG] alias mangled double-dot: sha1='%s' func='%s' mangled='%s'\n", alias_sha1, func_name, alias_mangled) + _ddebug_exit() + _ad_i += 1 + 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) + # DDEBUG: 检测连续两个点,发现立即终止 + _fd_i: int = 0 + while _fd_i < fmangled_len - 1: + if fmangled[_fd_i] == 46 and fmangled[_fd_i + 1] == 46: + stdio.printf("[DDEBUG] from mangled double-dot: sha1='%s' func='%s' mangled='%s'\n", from_sha1, func_name, fmangled) + _ddebug_exit() + _fd_i += 1 + call_name = fmangled + else: + err_msg2: t.CChar | t.CPtr = pool.alloc(256) + if err_msg2 is not None: + viperlib.snprintf(err_msg2, 256, "跨模块调用 '%s.%s' 找不到模块 SHA1", xmod_nm.id, func_name) + HandlesType.fatal_error(xmod_nm, err_msg2) + HandlesType.fatal_error(xmod_nm, "跨模块调用找不到模块 SHA1") + else: + # 裸名调用(非 Attribute):检查 from_imports + # 治本修复:函数调用禁用 star import 回退(allow_star_fallback=0)。 + # star import(from stdint import *)本意是导入类型/常量(如 BYTEPTR),而非函数; + # 函数应显式 from import。漏导函数若走 star 回退会被错归到 star 模块,生成错误 SHA1 符号 + # (如 block_insert_text_before_terminator 漏导后被错归 stdint,生成 + # f5522571bcce7bcb.block_insert... 而非 874bac141c97bae9.block_insert...)。 + # 禁用回退后,漏导函数编译期即报"未定义且未导入"(fast-fail),优于链接期 undefined reference。 + if trans is not None and trans._from_imports is not None: + bare_sha1: str = _lookup_mod_sha1(pool, trans._from_imports, func_name, 0) + if bare_sha1 is not None: + # 别名处理: from X import Y as Z → 调用 Z 时需用 Y 作为源模块函数名 + # 例如 from json.__parser import parse as json_parse → 修饰为 SHA1.parse 而非 SHA1.json_parse + bare_orig: str = HandlesImports.lookup_from_import_original( + trans._from_imports, func_name) + bare_func_name: str = func_name + if bare_orig is not None: + # bare_orig 指向 from_imports 内部缓冲区,未 null 终止 + # 需复制到独立缓冲区(截断于空格或 null) + bo_len: t.CSizeT = 0 + while bare_orig[bo_len] != ' ' and bare_orig[bo_len] != '\0': + bo_len += 1 + bo_buf: str = pool.alloc(bo_len + 1) + if bo_buf is not None: + for bo_i in range(bo_len): + bo_buf[bo_i] = bare_orig[bo_i] + bo_buf[bo_len] = '\0' + bare_func_name = bo_buf + # 记录原始函数名,供后续重新推断返回类型 + # 例如 from json.__parser import parse as json_parse + # func_name="json_parse", bare_func_name="parse" + # _infer_external_func_ret_ty 用 "parse" 能正确匹配,用 "json_parse" 则返回默认 i32 + orig_func_name = bare_func_name + if is_cexport_func(bare_sha1, bare_func_name) != 0: + call_name = bare_func_name + else: + bare_mangled_len: t.CSizeT = string.strlen(bare_sha1) + string.strlen(bare_func_name) + 2 + bare_mangled: str = pool.alloc(bare_mangled_len) + if bare_mangled is not None: + viperlib.snprintf(bare_mangled, bare_mangled_len, "%s.%s", bare_sha1, bare_func_name) + # DDEBUG: 检测 bare_mangled 中连续两个点(非路径场景),发现立即终止 + _bd_i: int = 0 + while _bd_i < bare_mangled_len - 1: + if bare_mangled[_bd_i] == 46 and bare_mangled[_bd_i + 1] == 46: + stdio.printf("[DDEBUG] bare_mangled double-dot: sha1='%s' func='%s' mangled='%s'\n", bare_sha1, bare_func_name, bare_mangled) + _ddebug_exit() + _bd_i += 1 + call_name = bare_mangled + else: + err_msg3: t.CChar | t.CPtr = pool.alloc(256) + if err_msg3 is not None: + viperlib.snprintf(err_msg3, 256, "裸名调用 '%s' 未定义且未导入", func_name) + HandlesType.fatal_error(node, err_msg3) + HandlesType.fatal_error(node, "裸名调用未定义且未导入") + else: + err_msg4: t.CChar | t.CPtr = pool.alloc(256) + if err_msg4 is not None: + viperlib.snprintf(err_msg4, 256, "裸名调用 '%s' 未定义且未导入", func_name) + HandlesType.fatal_error(node, err_msg4) + HandlesType.fatal_error(node, "裸名调用未定义且未导入") + + # 直接调用 + # memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失) + if string.strcmp(func_name, "memcpy") == 0 and can >= 3: + return _emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst2, mc_src2, mc_num2) + # 别名导入重新推断返回类型: + # from X import parse as json_parse → func_name="json_parse" 时 _infer_external_func_ret_ty 返回默认 i32 + # 用 orig_func_name="parse" 重新推断,能正确匹配返回 i8*(JsonValue*) + # 避免指针被截断为 i32 后 inttoptr 丢失高 32 位导致崩溃 + if orig_func_name is not None and orig_func_name != func_name: + re_inferred_ty: llvmlite.LLVMType | t.CPtr = _infer_external_func_ret_ty(pool, orig_func_name) + if re_inferred_ty is not None: + call_ret_ty = re_inferred_ty + # 跨模块调用:创建 declare 声明,避免 llc 报 undefined value + _ensure_method_declare(pool, mod, call_name, call_ret_ty, head, can) + # 检查被调用函数是否为变长函数(*args),若是则对变长参数进行 C ABI 提升 + is_variadic_call: int = _check_and_promote_variadic_call(pool, builder, mod, call_name, head, can) + return llvmlite.build_call(builder, call_name, head, can, call_ret_ty, is_variadic_call) + +# ============================================================ +# 翻译闭包调用 — 通过闭包指针间接调用 +# +# 闭包结构: {i8* fn_ptr, i8* env_ptr} (16 字节) +# 调用过程: +# 1. load closure_ptr 从变量 alloca +# 2. load fn_ptr 从 offset 0 +# 3. load env_ptr 从 offset 8 +# 4. bitcast fn_ptr to i32 (i8*)* +# 5. call i32 %fn_typed(i8* %env_ptr) +# ============================================================ +def translate_closure_call(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + closure_alloca: llvmlite.Value | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT) -> llvmlite.Value | t.CPtr: + """通过闭包指针间接调用""" + if builder is None or closure_alloca is None: + return None + + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 1. 加载闭包指针 (i8*) + closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, closure_alloca) + if closure_ptr is None: + return None + + # 2. 加载 fn_ptr (offset 0): bitcast to i8**, load i8* + fn_ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty)) + if fn_ptr_addr is None: + return None + fn_raw: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, fn_ptr_addr) + if fn_raw is None: + return None + + # 3. 加载 env_ptr (offset 8): GEP i8, closure, 8; load i8* + eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8) + env_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, closure_ptr, eight_val) + if env_addr is None: + return None + env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_addr) + if env_ptr is None: + return None + + # 4. bitcast fn_raw to i32 (i8*)* + param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) + func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, param_node, 1) + func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty) + fn_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, fn_raw, func_ptr_ty) + if fn_typed is None: + return None + + # 5. 间接调用: call i32 %fn_typed(i8* %env_ptr) + env_ptr.Next = None + return llvmlite.build_call_indirect(builder, fn_typed, env_ptr, 1, i32_ty) + +# ============================================================ +# 翻译 printf 调用 — 模块级版本 +# ============================================================ +def translate_printf_call(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None): + """翻译 printf 调用(特殊处理格式字符串)""" + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None: + return + can: t.CSizeT = cargs.__len__() + if can == 0: + return + + arg0: ast.AST | t.CPtr = cargs.get(0) + if arg0 is None: + return + + fmt_str: str = None + arg0_kind: int = arg0.kind() + if arg0_kind == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg0) + if cn.const_kind == ast.CONST_STR: + fmt_str = cn.str_val + + if fmt_str is None: + return + + fmt_ptr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string( + builder, pool, mod, fmt_str, trans) + if fmt_ptr is None: + return + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 翻译额外参数并链接 + prev: llvmlite.Value | t.CPtr = fmt_ptr + for ai in range(1, can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is not None: + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is not None: + # C ABI integer promotion: i8/i16 → i32(printf 变参函数要求) + arg_bits: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty) + if arg_bits != 0 and arg_bits < 32: + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, i32_ty, arg) + # C ABI float promotion: float → double(printf 变参函数要求) + arg_fbits: int = HandlesExpr.get_llvm_float_bits(arg_val.Ty) + if arg_fbits != 0 and arg_fbits < 64: + double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, double_ty, arg) + arg_val.Next = None + prev.Next = arg_val + prev = arg_val + prev.Next = None + + # is_variadic=1: 生成带显式函数类型签名的 call(如 call i32 (i8*, ...) @printf), + # 让 llc 识别为 variadic 调用,生成正确的 Win64 ABI 代码(浮点参数同时传 XMM 和整数寄存器) + llvmlite.build_call(builder, "printf", fmt_ptr, can, i32_ty, 1) + + +# ============================================================ +# stdarg 糖函数实现: va_arg / arg / va_start / va_end +# +# 这些函数对应 stdarg.vp 中的 pass 体声明,由编译器在翻译期 +# 转换为 LLVM 指令或 intrinsic 调用,不生成函数 call。 +# +# va_list 在 TPV 中表示为 i8*(与 stdarg.vp 中 va_list = t.CUnsignedChar | t.CPtr 一致)。 +# va_list 对象存储在 alloca 中(i8**),va_arg/va_start/va_end 需要传入 alloca 指针。 +# ============================================================ + +def _va_arg_get_alloca_ptr(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + arg_node: ast.AST | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """获取 va_list 变量的 alloca 指针(不 load) + + va_arg/va_start/va_end 需要的是 va_list 对象的地址(alloca 指针), + 而非 va_list 的值。若 arg_node 是 Name,查符号表获取 alloca; + 否则用 translate_value 翻译(调用者负责确保传入的是指针)。 + """ + if arg_node is None: + return None + # Name 节点:直接查符号表获取 alloca 指针(不 load) + if arg_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg_node) + if nm.id is not None: + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) + if alloca is not None: + return alloca + # 回退:translate_value(可能返回 load 后的值,仅适用于已是指针的情况) + return HandlesExpr.translate_value(builder, pool, mod, arg_node, funcs_ptr, func_count, trans) + + +def _resolve_va_arg_type(pool: memhub.MemBuddy | t.CPtr, + type_node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr: + """解析 va_arg/arg 的类型参数为 LLVMType + + 支持的类型表达式: + t.CInt / t.CInt32T → i32 + t.CInt64T → i64 + t.CDouble → double + t.CPtr / t.CChar | t.CPtr → i8* + str / bytes → i8* + 无类型参数时默认 i32(vsnprintf 中 va_arg(ap) 常用于读取 i32) + """ + if type_node is None: + return llvmlite.Int32(pool) + # 使用 HandlesType.resolve_annotation_type 解析类型表达式 + resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, type_node, trans._imported_modules, trans._from_imports, trans) + if resolved is not None: + return resolved + # 回退为 i32 + return llvmlite.Int32(pool) + + +def _translate_va_arg_sugar(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """va_arg(ap, type) / va_arg(ap) → %N = va_arg , + + 生成 LLVM va_arg 指令,从 va_list 读取下一个变长参数。 + """ + if can == 0 or cargs is None: + return llvmlite.const_int32(pool, 0) + + # 第一个参数:va_list 指针(获取 alloca,不 load) + ap_node: ast.AST | t.CPtr = cargs.get(0) + ap_ptr: llvmlite.Value | t.CPtr = _va_arg_get_alloca_ptr( + pool, builder, mod, ap_node, funcs_ptr, func_count, trans) + if ap_ptr is None: + return llvmlite.const_int32(pool, 0) + + # 第二个参数:目标类型(可选,默认 i32) + arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if can >= 2: + type_node: ast.AST | t.CPtr = cargs.get(1) + arg_ty = _resolve_va_arg_type(pool, type_node, trans) + + # 生成 va_arg 指令 + return llvmlite.build_va_arg(builder, ap_ptr, arg_ty) + + +def _translate_arg_sugar(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """arg(type) → %N = va_arg , + + 使用当前函数的隐式 va_list(trans._va_list_ptr), + 简化 *args 函数体内的 va_arg 调用。 + """ + if trans._va_list_ptr is None: + return llvmlite.const_int32(pool, 0) + + # 第一个参数:目标类型(可选,默认 i32) + arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if can >= 1 and cargs is not None: + type_node: ast.AST | t.CPtr = cargs.get(0) + arg_ty = _resolve_va_arg_type(pool, type_node, trans) + + # 生成 va_arg 指令(使用 trans._va_list_ptr 作为 va_list 指针) + return llvmlite.build_va_arg(builder, trans._va_list_ptr, arg_ty) + + +def _translate_va_start_sugar(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """va_start(ap, last_arg) → call void @llvm.va_start(i8* %ap) + + 初始化 va_list。第二个参数 last_arg 在 LLVM intrinsic 中不使用(C 宏兼容)。 + """ + if can == 0 or cargs is None: + return llvmlite.const_int32(pool, 0) + + # 第一个参数:va_list 指针(获取 alloca,不 load) + ap_node: ast.AST | t.CPtr = cargs.get(0) + ap_ptr: llvmlite.Value | t.CPtr = _va_arg_get_alloca_ptr( + pool, builder, mod, ap_node, funcs_ptr, func_count, trans) + if ap_ptr is None: + return llvmlite.const_int32(pool, 0) + + # bitcast 到 i8*(@llvm.va_start 接受 i8*) + i8_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_vs) + ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_vs) + if ap_i8 is None: + return llvmlite.const_int32(pool, 0) + + void_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + llvmlite.build_call(builder, "llvm.va_start", ap_i8, 1, void_ty_vs, 0) + return llvmlite.const_int32(pool, 0) + + +def _translate_va_end_sugar(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """va_end(ap) → call void @llvm.va_end(i8* %ap) + + 清理 va_list。在大多数平台上是 no-op,但调用它是良好的 C ABI 习惯。 + """ + if can == 0 or cargs is None: + return llvmlite.const_int32(pool, 0) + + # 第一个参数:va_list 指针(获取 alloca,不 load) + ap_node: ast.AST | t.CPtr = cargs.get(0) + ap_ptr: llvmlite.Value | t.CPtr = _va_arg_get_alloca_ptr( + pool, builder, mod, ap_node, funcs_ptr, func_count, trans) + if ap_ptr is None: + return llvmlite.const_int32(pool, 0) + + # bitcast 到 i8*(@llvm.va_end 接受 i8*) + i8_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_ve) + ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_ve) + if ap_i8 is None: + return llvmlite.const_int32(pool, 0) + + void_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + llvmlite.build_call(builder, "llvm.va_end", ap_i8, 1, void_ty_ve, 0) + return llvmlite.const_int32(pool, 0) + + +# ============================================================ +# 变长函数调用支持: 检查 IsVarArg + C ABI 参数提升 +# +# C ABI 要求变长参数(...部分)进行默认提升: +# 整数提升: i8/i16 → i32 (sext/zext) +# 浮点提升: float → double (fpext) +# 固定参数不需要提升(有明确类型签名)。 +# ============================================================ + +def _get_func_fixed_param_count(func: llvmlite.Function | t.CPtr) -> int: + """获取函数的固定参数数量(遍历 Params 链表)""" + if func is None: + return 0 + count: int = 0 + param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) + while param is not None: + count += 1 + param = llvmlite.param_get_next(param) + return count + + +def _check_and_promote_variadic_call(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + call_name: str, + head: llvmlite.Value | t.CPtr, + can: t.CSizeT) -> int: + """检查被调用函数是否为变长函数,若是则对变长参数进行 C ABI 提升 + + 返回: is_variadic (1=变长调用, 0=普通调用) + 副作用: 修改 head 链表中超过固定参数数量的节点(C ABI 提升) + """ + if mod is None or call_name is None or head is None: + return 0 + # 查找函数对象 + func: llvmlite.Function | t.CPtr = find_func_in_module(mod, call_name) + if func is None: + return 0 + if func.IsVarArg != 1: + return 0 + + # 获取固定参数数量 + fixed_count: int = _get_func_fixed_param_count(func) + + # 无变长参数(实参数量 <= 固定参数数量),仍需 is_variadic=1 + if can <= fixed_count: + return 1 + + # 遍历到第 fixed_count 个节点(固定参数的最后一个) + cur: llvmlite.Value | t.CPtr = head + prev: llvmlite.Value | t.CPtr = None + idx: int = 0 + while cur is not None and idx < fixed_count: + prev = cur + cur = cur.Next + idx += 1 + + # cur 指向第 fixed_count+1 个节点(第一个变长参数) + # 对变长参数进行 C ABI 提升 + i32_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + double_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) + while cur is not None: + next_node: llvmlite.Value | t.CPtr = cur.Next + promoted: llvmlite.Value | t.CPtr = cur + # C ABI integer promotion: i8/i16 → i32 + arg_bits: int = HandlesExpr.get_llvm_type_bits(cur.Ty) + if arg_bits != 0 and arg_bits < 32: + promoted = HandlesExpr.coerce_to_type(builder, cur, i32_ty_promote, None) + if promoted is not None: + promoted.Next = next_node + if prev is not None: + prev.Next = promoted + # C ABI float promotion: float → double + arg_fbits: int = HandlesExpr.get_llvm_float_bits(promoted.Ty) + if arg_fbits != 0 and arg_fbits < 64: + promoted = HandlesExpr.coerce_to_type(builder, promoted, double_ty_promote, None) + if promoted is not None: + promoted.Next = next_node + if prev is not None: + prev.Next = promoted + prev = promoted + cur = next_node + + return 1 + + +# ============================================================ +# FuncEntry 结构体(用于函数表) +# ============================================================ +@t.NoVTable +class FuncEntry: + """函数表条目""" + Name: str + Func: llvmlite.Function | t.CPtr + Defaults: t.CVoid | t.CPtr # defaults 列表节点指针 (list[AST | CPtr]),None=无默认值 + DefaultCount: int # 默认值数量 + ParamCount: int # 形参数量(不含 self) + +# ============================================================ +# 初始化函数表 +# ============================================================ +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 diff --git a/App/lib/core/Handles/HandlesExprOps.vp b/App/lib/core/Handles/HandlesExprOps.vp index e28216e..00462f9 100644 --- a/App/lib/core/Handles/HandlesExprOps.vp +++ b/App/lib/core/Handles/HandlesExprOps.vp @@ -222,8 +222,8 @@ def translate_binop(pool: memhub.MemBuddy | t.CPtr, if target_fbits == 32: target_float_ty = llvmlite.Float(pool) # 将两个操作数转换为目标浮点类型(int→float via si2fp, float→float via fpext/fptrunc) - lhs = HandlesExpr.coerce_to_type(builder, lhs, target_float_ty) - rhs = HandlesExpr.coerce_to_type(builder, rhs, target_float_ty) + lhs = HandlesExpr.coerce_to_type(builder, lhs, target_float_ty, node) + rhs = HandlesExpr.coerce_to_type(builder, rhs, target_float_ty, node) if op == ast.OpKind.Add: return llvmlite.build_fadd(builder, lhs, rhs) if op == ast.OpKind.Sub: @@ -243,7 +243,7 @@ def translate_binop(pool: memhub.MemBuddy | t.CPtr, if lhs_bits == 0: # lhs 是指针,rhs 是整数 ptr_as_int: llvmlite.Value | t.CPtr = llvmlite.build_ptrtoint(builder, lhs, i64_ty) - int_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, rhs, i64_ty) + int_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, rhs, i64_ty, node) if op == ast.OpKind.Add: result: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, ptr_as_int, int_val) else: @@ -252,7 +252,7 @@ def translate_binop(pool: memhub.MemBuddy | t.CPtr, else: # rhs 是指针,lhs 是整数(仅 Add 支持交换) ptr_as_int = llvmlite.build_ptrtoint(builder, rhs, i64_ty) - int_val = HandlesExpr.coerce_to_type(builder, lhs, i64_ty) + int_val = HandlesExpr.coerce_to_type(builder, lhs, i64_ty, node) if op == ast.OpKind.Add: result = llvmlite.build_add(builder, int_val, ptr_as_int) else: @@ -260,9 +260,19 @@ def translate_binop(pool: memhub.MemBuddy | t.CPtr, return llvmlite.build_inttoptr(builder, result, rhs.Ty) if lhs_bits > rhs_bits: - rhs = HandlesExpr.coerce_to_type(builder, rhs, lhs.Ty) + rhs = HandlesExpr.coerce_to_type(builder, rhs, lhs.Ty, node) elif rhs_bits > lhs_bits: - lhs = HandlesExpr.coerce_to_type(builder, lhs, rhs.Ty) + lhs = HandlesExpr.coerce_to_type(builder, lhs, rhs.Ty, node) + + # 位运算类型安全检查:两边都是指针(lhs_bits==0 and rhs_bits==0)时, + # 位运算(BitOr/BitAnd/BitXor/LShift/RShift)非法,LLVM 要求整数操作数。 + # 常见触发场景:CDefine 常量查找失败返回指针 null,与另一指针做 `|`。 + if lhs_bits == 0 and rhs_bits == 0: + if op == ast.OpKind.BitOr or op == ast.OpKind.BitAnd or op == ast.OpKind.BitXor or op == ast.OpKind.LShift or op == ast.OpKind.RShift: + VLogger.error( + "位运算操作数类型非法: lhs/rhs 均为非整数类型(指针或结构体),无法执行位运算", + "BinOp") + return None if op == ast.OpKind.Add: return llvmlite.build_add(builder, lhs, rhs) diff --git a/App/lib/core/Handles/HandlesFunctions.vp b/App/lib/core/Handles/HandlesFunctions.vp index aa48ed8..168ceb4 100644 --- a/App/lib/core/Handles/HandlesFunctions.vp +++ b/App/lib/core/Handles/HandlesFunctions.vp @@ -1,995 +1,1043 @@ -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import viperlib -import stdio -import stdlib -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesBody as HandlesBody -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesImports as HandlesImports - - -# 作用域类型常量(本地副本,避免旧编译器跨模块 CDefine 查找 bug) -SCOPE_FUNCTION: t.CDefine = 1 - - -# ============================================================ -# extract_func_attrs - 从 decorator_list 提取 c.Attribute 属性 -# -# 支持 @c.Attribute(t.attr.xxx()) 和 @c.Attribute(t.attr.xxx) 形式 -# 也支持 @c.Attribute(t.attr.llvm.xxx) 形式 -# -# 返回 LLVM IR 属性字符串(如 "alwaysinline nounwind"),无属性返回 None -# ============================================================ -def extract_func_attrs(pool: memhub.MemBuddy | t.CPtr, - decorator_list: list[ast.AST | t.CPtr] | t.CPtr, - imported_modules: str) -> t.CChar | t.CPtr: - """从 decorator_list 提取 c.Attribute 属性,返回 LLVM IR 属性字符串""" - if decorator_list is None: - return None - dn: t.CSizeT = decorator_list.__len__() - if dn == 0: - return None - - attrs_buf: t.CChar | t.CPtr = pool.alloc(256) - if attrs_buf is None: - return None - attrs_buf[0] = '\0' - found_any: int = 0 - - for di in range(dn): - deco: ast.AST | t.CPtr = decorator_list.get(di) - if deco is None or deco.kind() != ast.ASTKind.Call: - continue - call_node: ast.Call | t.CPtr = (ast.Call | t.CPtr)(deco) - if call_node.func is None or call_node.func.kind() != ast.ASTKind.Attribute: - continue - - # 检测 c.Attribute - func_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call_node.func) - if func_attr.attr is None or string.strcmp(func_attr.attr, "Attribute") != 0: - continue - if func_attr.value is None or func_attr.value.kind() != ast.ASTKind.Name: - continue - c_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_attr.value) - if c_name.id is None or string.strcmp(c_name.id, "c") != 0: - continue - if HandlesImports.is_module_imported(imported_modules, "c") == 0: - continue - - # 遍历参数提取属性 - if call_node.args is None: - continue - args_list: list[ast.AST | t.CPtr] | t.CPtr = call_node.args - an: t.CSizeT = args_list.__len__() - for ai in range(an): - arg_node: ast.AST | t.CPtr = args_list.get(ai) - if arg_node is None: - continue - - # 提取属性名(t.attr.xxx / t.attr.xxx() / t.attr.llvm.xxx) - attr_name: str = _get_attr_name_from_node(arg_node) - if attr_name is None: - continue - - # 映射到 LLVM 属性名并追加 - if _append_llvm_attr(attrs_buf, attr_name) != 0: - found_any = 1 - # 追加成功后,如果不是最后一个属性,添加空格分隔 - # 在下一次追加前由 _append_str 处理 - - if found_any == 0: - return None - return attrs_buf - - -def _get_attr_name_from_node(node: ast.AST | t.CPtr) -> str: - """从 AST 节点提取属性名 - - 支持: - - Call(func=Attribute(...)): t.attr.always_inline() -> "always_inline" - - Attribute: t.attr.packed -> "packed" - - Attribute(t.attr.llvm.xxx): t.attr.llvm.nounwind -> "nounwind" - """ - if node is None: - return None - k: int = node.kind() - - # Call 节点: t.attr.always_inline() - if k == ast.ASTKind.Call: - call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if call.func is None or call.func.kind() != ast.ASTKind.Attribute: - return None - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call.func) - return at.attr - - # Attribute 节点: t.attr.packed 或 t.attr.llvm.nounwind - if k == ast.ASTKind.Attribute: - at2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - return at2.attr - - return None - - -def _append_llvm_attr(attrs_buf: t.CChar | t.CPtr, attr_name: str) -> int: - """将属性名映射到 LLVM 属性名并追加到缓冲区 - - 返回 1 表示已追加,0 表示不支持该属性 - """ - if attrs_buf is None or attr_name is None: - return 0 - - # 先确定映射的 LLVM 属性名 - llvm_name: str = None - if string.strcmp(attr_name, "always_inline") == 0: - llvm_name = "alwaysinline" - elif string.strcmp(attr_name, "noinline") == 0: - llvm_name = "noinline" - elif string.strcmp(attr_name, "noreturn") == 0: - llvm_name = "noreturn" - elif string.strcmp(attr_name, "pure") == 0: - llvm_name = "readonly" - elif string.strcmp(attr_name, "const") == 0: - llvm_name = "readnone" - elif string.strcmp(attr_name, "nounwind") == 0: - llvm_name = "nounwind" - elif string.strcmp(attr_name, "noredzone") == 0: - llvm_name = "noredzone" - elif string.strcmp(attr_name, "willreturn") == 0: - llvm_name = "willreturn" - elif string.strcmp(attr_name, "mustprogress") == 0: - llvm_name = "mustprogress" - else: - # packed/aligned/section/visibility/weak 等不支持作为函数内联属性 - return 0 - - # 支持的属性:如果缓冲区非空,先追加空格分隔 - if attrs_buf[0] != '\0': - _append_str(attrs_buf, " ") - _append_str(attrs_buf, llvm_name) - return 1 - - -def _append_str(buf: t.CChar | t.CPtr, s: str) -> None: - """将字符串追加到 buf 末尾(用 strlen+strcpy 模拟 strcat)""" - if buf is None or s is None: - return - cur_len: t.CSizeT = string.strlen(buf) - string.strcpy(buf + cur_len, s) - - -# ============================================================ -# HandlesFunctions - 函数定义处理(trans 单参模式) -# -# 参考 Python 版 TransPyC FunctionHandle -# -# 函数有自己的局部作用域,通过 HandlesVar.enter_scope/exit_scope -# 管理嵌套作用域链,翻译函数体前进入函数作用域,翻译完退出。 -# ============================================================ - - -# ============================================================ -# _mangle_name - 为名称添加 SHA1 前缀 -# -# 返回 "sha1.name" 格式的混淆名。若 ModuleSha1 为 None 或名称已带 -# SHA1 前缀(16 hex + '.'),则原样返回。 -# ============================================================ -def _mangle_name(trans: HT.Translator | t.CPtr, name: str) -> str: - """为任意名称添加 SHA1 前缀(不做 main/export 检查)""" - if trans is None or name is None: - return name - if trans.ModuleSha1 is None: - return name - name_len: t.CSizeT = string.strlen(name) - # 已带 SHA1 前缀(16 hex + '.')则跳过 - if name_len > 17: - is_sha1: int = 1 - for i in range(16): - c: t.CChar = name[i] - if not (('0' <= c <= '9') or ('a' <= c <= 'f')): - is_sha1 = 0 - break - if is_sha1 != 0 and name[16] == '.': - return name - sha1: str = trans.ModuleSha1 - sha1_len: t.CSizeT = string.strlen(sha1) - mangled: str = stdlib.malloc(sha1_len + name_len + 2) - if mangled is None: - return name - string.strcpy(mangled, sha1) - mangled[sha1_len] = '.' - string.strcpy(mangled + sha1_len + 1, name) - return mangled - - -# ============================================================ -# _mangle_name_with_sha1 — 用指定 SHA1 为名称添加前缀 -# -# 用于跨模块 vtable 继承: 继承方法需要用父模块的 SHA1 做 mangling, -# 而非当前模块的 SHA1。 -# ============================================================ -def _mangle_name_with_sha1(sha1: str, name: str) -> str: - """用指定 SHA1 为名称添加前缀(不做 main/export 检查)""" - if sha1 is None or name is None: - return name - name_len: t.CSizeT = string.strlen(name) - # 已带 SHA1 前缀(16 hex + '.')则跳过 - if name_len > 17: - is_sha1: int = 1 - for i in range(16): - c2: t.CChar = name[i] - if not (('0' <= c2 <= '9') or ('a' <= c2 <= 'f')): - is_sha1 = 0 - break - if is_sha1 != 0 and name[16] == '.': - return name - sha1_len: t.CSizeT = string.strlen(sha1) - mangled: str = stdlib.malloc(sha1_len + name_len + 2) - if mangled is None: - return name - string.strcpy(mangled, sha1) - mangled[sha1_len] = '.' - string.strcpy(mangled + sha1_len + 1, name) - return mangled - - -# ============================================================ -# _mangle_func_name - 为函数名添加 SHA1 前缀(含 main/export 检查) -# -# 规则: -# - main 函数不加前缀(程序入口点) -# - has_export 非 0 时不加前缀(t.CExport 导出函数) -# - 已带 SHA1 前缀的不再加 -# - ModuleSha1 为 None 时不加前缀 -# ============================================================ -def _mangle_func_name(trans: HT.Translator | t.CPtr, name: str, - has_export: int) -> str: - """为函数名添加 SHA1 前缀(检查 main/export)""" - if trans is None or name is None: - return name - if has_export != 0: - return name - if string.strcmp(name, "main") == 0: - return name - return _mangle_name(trans, name) - - -# ============================================================ -# forward_declare_functions - 预扫描所有顶层 FunctionDef,创建前向声明 -# -# 解决同模块内前向引用问题:如 viperlib.py 中 sprintf(行15) 调用 -# vsnprintf(行41),但 vsnprintf 定义在后面。 -# -# 对每个顶层 FunctionDef: -# 1. 推断返回类型和参数类型 -# 2. 计算 mangled name(含 SHA1 前缀) -# 3. 创建 declare(IsDeclared=1) -# 4. 添加参数 -# 5. 注册到函数表 -# -# 后续 translate_function_def 会通过 find_func_in_module 找到已有的 declare, -# 复用之(清除 IsDeclared,跳过参数创建,直接添加函数体)。 -# ============================================================ -def forward_declare_functions(trans: HT.Translator | t.CPtr, - tree: ast.AST | t.CPtr) -> int: - """预扫描所有顶层 FunctionDef,创建前向声明""" - if trans is None or tree is None: - return 0 - pool: memhub.MemBuddy | t.CPtr = trans.Pool - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - if pool is None or mod is None: - return 0 - - imported_modules: str = trans._imported_modules - from_imports: str = trans._from_imports - funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children - if ch is None: - return 0 - cn_count: t.CSizeT = ch.__len__() - - for ci in range(cn_count): - child: ast.AST | t.CPtr = ch.get(ci) - if child is None: - continue - if child.kind() != ast.ASTKind.FunctionDef: - continue - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) - if fd is None or fd.name is None: - continue - - # 推断返回类型 - ret_ty: llvmlite.LLVMType | t.CPtr = None - if fd.returns is not None: - ret_ty = HandlesType.resolve_annotation_type( - pool, fd.returns, imported_modules, from_imports, trans) - if ret_ty is None and fd.returns is not None: - if HandlesType.has_decorator_marker(fd.returns, "State") != 0: - ret_ty = llvmlite.Void(pool) - if ret_ty is None: - ret_ty = i32_ty - - # 检测 CExtern/State/CExport - has_extern: int = 0 - has_state: int = 0 - has_export: int = 0 - if fd.returns is not None: - has_extern = HandlesType.has_decorator_marker(fd.returns, "CExtern") - has_state = HandlesType.has_decorator_marker(fd.returns, "State") - has_export = HandlesType.has_decorator_marker(fd.returns, "CExport") - is_extern_decl: int = 0 - if has_extern != 0 or has_state != 0: - is_extern_decl = 1 - - # 计算 mangled name - if has_extern != 0 or has_state != 0 or has_export != 0 or string.strcmp(fd.name, "main") == 0: - mangled_name: str = fd.name - else: - mangled_name = _mangle_func_name(trans, fd.name, 0) - - # 如果函数已存在(如重复定义),跳过 - existing: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name) - if existing is not None: - continue - - # 创建 declare - func: llvmlite.Function | t.CPtr = llvmlite.create_declare( - pool, mod, mangled_name, ret_ty) - if func is None: - continue - - # 提取默认参数信息 - # 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(), - # 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错 - fd_args_node: ast.Arguments | t.CPtr = fd.args - fd_defaults: t.CVoid | t.CPtr = None - fd_default_count: int = 0 - fd_param_count: int = 0 - if fd_args_node is not None: - fd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd_args_node) - if fd_ags.args is not None: - fd_alist: list[ast.AST | t.CPtr] | t.CPtr = fd_ags.args - fd_param_count = fd_alist.__len__() - if fd_ags.defaults is not None: - fd_dlist: list[ast.AST | t.CPtr] | t.CPtr = fd_ags.defaults - fd_defaults = fd_dlist - fd_default_count = fd_dlist.__len__() - - # 注册到函数表(用裸名 fd.name,不是 mangled_name) - max_funcs: int = 256 - cur_count: int = trans._func_count - if HandlesExprCall.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs, - fd_defaults, fd_default_count, fd_param_count) == 0: - trans._func_count = cur_count + 1 - - # 注册 CExport 函数到全局表 - if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None: - HandlesExprCall.register_cexport_func(trans.ModuleSha1, fd.name) - - # 添加参数 - args_node: ast.Arguments | t.CPtr = fd.args - if args_node is not None: - ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - if ags.args is not None: - alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args - an: t.CSizeT = alist.__len__() - for ai in range(an): - arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) - if arg is None or arg.arg is None: - continue - # t.CVoid 表示空参:跳过 - if arg.annotation is not None: - if HandlesType._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0: - continue - param_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if arg.annotation is not None: - resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, arg.annotation, imported_modules, from_imports, trans) - if resolved is not None: - param_ty = resolved - pname: t.CChar | t.CPtr = pool.alloc(32) - if pname is not None: - viperlib.snprintf(pname, 32, "%%%s", arg.arg) - llvmlite.add_param(pool, func, param_ty, pname) - - return 0 - - -# ============================================================ -# 翻译函数定义 FunctionDef(name, args, body, ...) -# -# trans 单参模式:所有共享状态从 trans 获取 -# 函数局部作用域通过 enter_scope/exit_scope 管理 -# ============================================================ -def translate_function_def(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译函数定义,返回新增的变量数(通常为 0,函数定义不增加当前作用域变量)""" - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) - if fd is None or fd.name is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - imported_modules: str = trans._imported_modules - from_imports: str = trans._from_imports - funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs - func_count: int = trans._func_count - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - - # 推断返回类型:优先使用返回类型注解 - ret_ty: llvmlite.LLVMType | t.CPtr = None - if fd.returns is not None: - ret_ty = HandlesType.resolve_annotation_type( - pool, fd.returns, imported_modules, from_imports, trans) - - # 如果返回类型注解纯装饰器标记(如 t.State,无实际类型),使用 void - # 注意:必须在 infer_return_type 之前检测,因为 infer_return_type 至少返回 i32 - if ret_ty is None and fd.returns is not None: - if HandlesType.has_decorator_marker(fd.returns, "State") != 0: - ret_ty = llvmlite.Void(pool) - - # 如果仍然为 None,扫描 return 语句推断(至少返回 i32) - if ret_ty is None: - param_types_str: str = HandlesType.build_param_types_str(pool, fd.args) - ret_ty = HandlesType.infer_return_type( - pool, fd.children, param_types_str) - # 检测是否为外部声明函数(t.CExtern 或 t.State) - # 语义:t.CExtern 忽略 body 体,仅生成 declare(由链接器解析符号) - # t.State = t.CExtern + t.CExport(既是声明又是导出) - # t.CExport 导出函数不加 SHA1 前缀 - # t.CExtern/t.State/t.CExport 都不加 SHA1 前缀,直接映射到 C 标准库函数名 - is_extern_decl: int = 0 - has_export: int = 0 - has_extern: int = 0 - has_state: int = 0 - if fd.returns is not None: - has_extern = HandlesType.has_decorator_marker(fd.returns, "CExtern") - has_state = HandlesType.has_decorator_marker(fd.returns, "State") - has_export = HandlesType.has_decorator_marker(fd.returns, "CExport") - # t.CExtern/t.State 忽略 body 体,仅声明(无论 body 是否为 pass) - if has_extern != 0 or has_state != 0: - is_extern_decl = 1 - - # SHA1 命名空间:t.CExtern/t.State/t.CExport 不加前缀,直接用裸名 - # (裸名映射到 C 标准库符号,带 sha1 前缀会导致 undefined reference) - # main 函数也不加前缀(程序入口点) - if has_extern != 0 or has_state != 0 or has_export != 0 or string.strcmp(fd.name, "main") == 0: - mangled_name: str = fd.name - else: - mangled_name: str = _mangle_func_name(trans, fd.name, 0) - - # 注册 CExport 函数到全局表(供跨模块调用查表) - # t.CExport 函数定义用裸名(@strlen),跨模块调用需查表确认用裸名而非 @{sha1}.func - if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None: - HandlesExprCall.register_cexport_func(trans.ModuleSha1, fd.name) - - if is_extern_decl != 0: - # 外部声明函数:生成 declare(仅声明,不定义) - # 先检查是否已由 forward_declare_functions 创建,避免重复 declare - existing_extern: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name) - if existing_extern is not None: - # 已存在前向声明,复用之,不再重复创建 - return 0 - - func: llvmlite.Function | t.CPtr = llvmlite.create_declare( - pool, mod, mangled_name, ret_ty) - if func is None: - return 0 - - # 注册到函数表 - max_funcs_extern: int = 256 - if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs_extern) == 0: - trans._func_count = func_count + 1 - - # 添加参数(支持类型注解) - args_node_extern: ast.Arguments | t.CPtr = fd.args - if args_node_extern is not None: - ags_e: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node_extern) - if ags_e.args is not None: - alist_e: list[ast.AST | t.CPtr] | t.CPtr = ags_e.args - an_e: t.CSizeT = alist_e.__len__() - for ai_e in range(an_e): - arg_e: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist_e.get(ai_e)) - if arg_e is not None and arg_e.arg is not None: - # t.CVoid 表示空参:跳过,不添加到函数签名 - if arg_e.annotation is not None: - if HandlesType._is_t_attr(arg_e.annotation, "CVoid", imported_modules) != 0: - continue - param_ty_e: llvmlite.LLVMType | t.CPtr = i32_ty - if arg_e.annotation is not None: - resolved_e: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, arg_e.annotation, imported_modules, from_imports, trans) - if resolved_e is not None: - param_ty_e = resolved_e - pname_e: t.CChar | t.CPtr = pool.alloc(32) - if pname_e is not None: - viperlib.snprintf(pname_e, 32, "%%%s", arg_e.arg) - llvmlite.add_param(pool, func, param_ty_e, pname_e) - - # 提取 @c.Attribute 装饰器属性并设置到函数 - func_attrs_e: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules) - if func_attrs_e is not None: - llvmlite.function_set_attrs(func, func_attrs_e) - - return 0 - - # args_node 用于后续 alloca 创建,提前赋值 - args_node: ast.Arguments | t.CPtr = fd.args - - # 检查是否已有前向声明(由 forward_declare_functions 创建) - func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name) - if func is not None and llvmlite.function_is_declared(func) != 0: - # 复用前向声明:清除 IsDeclared 标记,转为 define - func.IsDeclared = 0 - # 装饰器属性设置(前向声明时未设置) - func_attrs_reuse: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules) - if func_attrs_reuse is not None: - llvmlite.function_set_attrs(func, func_attrs_reuse) - else: - # 创建新的 LLVM 函数(使用 SHA1 混淆名) - func = llvmlite.create_function(pool, mod, mangled_name, ret_ty) - if func is None: - fb_cf: t.CChar | t.CPtr = VLogger.fmt_buf() - if fb_cf is not None: - viperlib.snprintf(fb_cf, 1024, "create_function %s failed", fd.name) - VLogger.error(fb_cf, "FUNC") - return 0 - - # 提取 @c.Attribute 装饰器属性并设置到函数 - func_attrs: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules) - if func_attrs is not None: - llvmlite.function_set_attrs(func, func_attrs) - - # 提取默认参数信息 - tfd_defaults: t.CVoid | t.CPtr = None - tfd_default_count: int = 0 - tfd_param_count: int = 0 - if args_node is not None: - tfd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - if tfd_ags.args is not None: - tfd_alist: list[ast.AST | t.CPtr] | t.CPtr = tfd_ags.args - tfd_param_count = tfd_alist.__len__() - if tfd_ags.defaults is not None: - tfd_dlist: list[ast.AST | t.CPtr] | t.CPtr = tfd_ags.defaults - tfd_defaults = tfd_dlist - tfd_default_count = tfd_dlist.__len__() - - # 注册到函数表 - max_funcs: int = 256 - if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs, - tfd_defaults, tfd_default_count, tfd_param_count) == 0: - trans._func_count = func_count + 1 - - # 添加参数(支持类型注解) - if args_node is not None: - ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - if ags.args is not None: - alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args - an: t.CSizeT = alist.__len__() - for ai in range(an): - arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) - if arg is not None and arg.arg is not None: - # t.CVoid 表示空参:跳过,不添加到函数签名 - if arg.annotation is not None: - if HandlesType._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0: - continue - param_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if arg.annotation is not None: - resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, arg.annotation, imported_modules, from_imports, trans) - if resolved is not None: - param_ty = resolved - pname: t.CChar | t.CPtr = pool.alloc(32) - if pname is not None: - viperlib.snprintf(pname, 32, "%%%s", arg.arg) - llvmlite.add_param(pool, func, param_ty, pname) - # 创建 entry 块 - entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") - if entry_blk is None: - return 0 - - # 创建函数专属 builder - func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) - if func_builder is None: - return 0 - llvmlite.position_at_end(func_builder, entry_blk) - - # 进入函数作用域(嵌套符号表) - HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION) - - # 为参数创建 alloca - if args_node is not None: - ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - if ags2.args is not None: - alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args - an2: t.CSizeT = alist2.__len__() - for ai2 in range(an2): - arg2: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist2.get(ai2)) - if arg2 is not None and arg2.arg is not None: - # t.CVoid 表示空参:跳过,不创建 alloca - if arg2.annotation is not None: - if HandlesType._is_t_attr(arg2.annotation, "CVoid", imported_modules) != 0: - continue - param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty - if arg2.annotation is not None: - resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, arg2.annotation, imported_modules, from_imports, trans) - if resolved2 is not None: - param_ty2 = resolved2 - alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2) - if alloca is not None: - HandlesVar.define_var(trans.SymTab, arg2.arg, alloca) - # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) - if arg2.annotation is not None: - cls_nm: str = HandlesType.extract_class_name_from_annotation( - arg2.annotation, imported_modules) - if cls_nm is not None: - HandlesVar.set_var_annot_class_name( - trans.SymTab, arg2.arg, cls_nm) - pname2: t.CChar | t.CPtr = pool.alloc(32) - if pname2 is not None: - viperlib.snprintf(pname2, 32, "%%%s", arg2.arg) - param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, param_ty2, pname2) - llvmlite.build_store(func_builder, param_val, alloca) - # 保存模块级作用域状态(仅非变量表相关) - old_func: llvmlite.Function | t.CPtr = trans._cur_func - old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - old_global_count: int = trans._global_name_count - old_nonlocal_count: int = trans._nonlocal_name_count - old_env_count: int = trans._closure_env_count - - trans._cur_func = func - trans._cur_builder = func_builder - # 清空 global/nonlocal 名称集合(新函数作用域) - HT.clear_scope_names(trans) - - # 预扫描函数体:为局部变量提前创建 alloca - body: list[ast.AST | t.CPtr] | t.CPtr = fd.children - if body is not None: - bn: t.CSizeT = body.__len__() - for bi in range(bn): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.pre_scan_allocas(trans, stmt) - - # 翻译函数体 - if body is not None: - bn2: t.CSizeT = body.__len__() - for bi2 in range(bn2): - stmt2: ast.AST | t.CPtr = body.get(bi2) - if stmt2 is not None: - HandlesBody.translate_stmt(trans, stmt2) - - # 如果函数体最后一条语句不是 Return,添加隐式 ret - last_is_return: int = 0 - if body is not None: - bn3: t.CSizeT = body.__len__() - if bn3 > 0: - last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1) - if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return: - last_is_return = 1 - if last_is_return == 0: - if llvmlite.builder_cur_block_is_terminated(func_builder) == 0: - # 根据返回类型生成正确的零值返回 - _is_void: int = 0 - _is_ptr: int = 0 - if ret_ty is not None: - match ret_ty: - case llvmlite.LLVMType.Void(): - _is_void = 1 - case llvmlite.LLVMType.Ptr(_pe): - _is_ptr = 1 - if _is_void != 0: - llvmlite.build_ret_void(func_builder) - elif _is_ptr != 0: - _null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null") - llvmlite.build_ret(func_builder, _null_val) - else: - _zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - llvmlite.build_ret(func_builder, _zero_val) - - # 恢复模块级作用域(退出函数作用域) - HandlesVar.exit_scope(trans.SymTab) - trans._cur_func = old_func - trans._cur_builder = old_builder - trans._global_name_count = old_global_count - trans._nonlocal_name_count = old_nonlocal_count - trans._closure_env_count = old_env_count - - return 0 - - -# ============================================================ -# translate_nested_function_def - 嵌套函数提升 + 闭包创建 -# -# 将嵌套函数提升为顶层函数 @__closure_{name}(i8* %env) -> i32, -# 在父函数中创建闭包对象 {i8* fn_ptr, i8* env_ptr} 并存储到 -# 以函数名命名的局部变量中。 -# -# 闭包结构: {i8* fn_ptr, i8* env_ptr} (16 字节, malloc 分配) -# Env 结构: {i8* ptr0, i8* ptr1, ...} (每个 nonlocal 变量 8 字节) -# ============================================================ -def translate_nested_function_def(trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """翻译嵌套函数定义:提升为顶层函数 + 创建闭包""" - fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) - if fd is None or fd.name is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - func_name: str = fd.name - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - # 1. 构建提升后的函数名: __closure_{name}(加 SHA1 前缀避免跨模块冲突) - promoted_name: t.CChar | t.CPtr = pool.alloc(64) - if promoted_name is not None: - viperlib.snprintf(promoted_name, 64, "__closure_%s", func_name) - mangled_promoted: str = _mangle_name(trans, promoted_name) - - # 2. 创建提升后的函数: define i32 @__closure_{name}(i8* %env) - func: llvmlite.Function | t.CPtr = llvmlite.create_function( - pool, mod, mangled_promoted, i32_ty) - if func is None: - return 0 - llvmlite.add_param(pool, func, i8_ptr_ty, "%env") - - # 3. 创建 entry 块 + builder - entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") - if entry_blk is None: - return 0 - func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) - if func_builder is None: - return 0 - llvmlite.position_at_end(func_builder, entry_blk) - - # 4. 进入嵌套函数作用域(嵌套符号表) - HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION) - - # 5. 创建 _env_ptr alloca 并存储 %env 参数 - env_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, i8_ptr_ty) - if env_alloca is not None: - HandlesVar.define_var(trans.SymTab, "_env_ptr", env_alloca) - env_param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "%env") - llvmlite.build_store(func_builder, env_param_val, env_alloca) - - # 6. 保存父函数作用域状态(仅非变量表相关) - old_func: llvmlite.Function | t.CPtr = trans._cur_func - old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - old_func_name: str = trans._cur_func_name - old_global_count: int = trans._global_name_count - old_nonlocal_count: int = trans._nonlocal_name_count - old_env_count: int = trans._closure_env_count - - # 7. 切换到嵌套函数作用域 + 清空 scope names - trans._cur_func = func - trans._cur_builder = func_builder - trans._cur_func_name = func_name - HT.clear_scope_names(trans) - - # 8. 预扫描函数体:为局部变量提前创建 alloca - body: list[ast.AST | t.CPtr] | t.CPtr = fd.children - if body is not None: - bn: t.CSizeT = body.__len__() - for bi in range(bn): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.pre_scan_allocas(trans, stmt) - - # 9. 翻译函数体(Nonlocal 语句会填充 _nonlocal_names) - if body is not None: - bn2: t.CSizeT = body.__len__() - for bi2 in range(bn2): - stmt2: ast.AST | t.CPtr = body.get(bi2) - if stmt2 is not None: - HandlesBody.translate_stmt(trans, stmt2) - - # 10. 隐式 ret - last_is_return: int = 0 - if body is not None: - bn3: t.CSizeT = body.__len__() - if bn3 > 0: - last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1) - if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return: - last_is_return = 1 - if last_is_return == 0: - zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - llvmlite.build_ret(func_builder, zero_val) - - # 11. 保存嵌套函数的 nonlocal 信息 - nested_nonlocal_count: int = trans._nonlocal_name_count - - # 12. 退出嵌套函数作用域,回到父函数作用域(保留 _nonlocal_names 用于 env 创建) - HandlesVar.exit_scope(trans.SymTab) - trans._cur_func = old_func - trans._cur_builder = old_builder - # NOTE: _nonlocal_names 和 _nonlocal_name_count 仍为嵌套函数的值 - - # 13. 在父函数中创建闭包对象 - parent_builder: llvmlite.IRBuilder | t.CPtr = old_builder - if parent_builder is None: - # 无 builder(模块级嵌套函数?)→ 无法创建闭包,仅恢复状态 - trans._cur_func_name = old_func_name - trans._global_name_count = old_global_count - trans._nonlocal_name_count = old_nonlocal_count - trans._closure_env_count = old_env_count - return 0 - - # 13a. 创建 env: malloc(4 * nested_nonlocal_count) — env 直接存储 i32 值 - env_ptr: llvmlite.Value | t.CPtr = None - if nested_nonlocal_count > 0: - env_size: t.CInt64T = nested_nonlocal_count * 4 - env_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, env_size) - if env_size_val is not None: - env_size_val.Next = None - env_ptr = llvmlite.build_call( - parent_builder, "malloc", env_size_val, 1, i8_ptr_ty, 0) - - # 为每个 nonlocal 变量存储值到 env - if env_ptr is not None: - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty) - for ni in range(nested_nonlocal_count): - # 从 _nonlocal_names 缓冲区读取名称 - name_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + ni * 8 - nl_slot: str | t.CPtr = (t.CVoid | t.CPtr)(name_addr) - nl_name: str = nl_slot[0] - if nl_name is not None: - # 在父函数作用域中查找(Current 已回到父作用域) - var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, nl_name) - if var_alloca is not None: - # 加载变量值 - var_ty: llvmlite.LLVMType | t.CPtr = None - if var_alloca.Ty is not None: - var_ty = var_alloca.Ty.Pointee - if var_ty is None: - var_ty = i32_ty - var_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - parent_builder, var_ty, var_alloca) - if var_val is not None: - # GEP to env[ni*4] - offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, ni * 4) - slot: llvmlite.Value | t.CPtr = llvmlite.build_gep( - parent_builder, i8_ty, env_ptr, offset_val) - if slot is not None: - # bitcast to i32* and store value - slot_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - parent_builder, slot, i32_ptr_ty) - if slot_typed is not None: - # 类型转换(确保 var_val 是 i32) - coerced_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( - parent_builder, var_val, i32_ty) - if coerced_val is not None: - llvmlite.build_store(parent_builder, coerced_val, slot_typed) - - # 13b. 创建闭包结构: malloc(16) - closure_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 16) - if closure_size_val is not None: - closure_size_val.Next = None - closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_call( - parent_builder, "malloc", closure_size_val, 1, i8_ptr_ty, 0) - if closure_ptr is None: - # malloc 失败,恢复状态 - trans._cur_func_name = old_func_name - trans._global_name_count = old_global_count - trans._nonlocal_name_count = old_nonlocal_count - trans._closure_env_count = old_env_count - return 0 - - # 13c. 存储 fn_ptr 到 offset 0 - # 创建函数指针类型 i32(i8*)* - fn_param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) - fn_func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, fn_param_node, 1) - fn_func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, fn_func_ty) - - # 创建函数引用 Value(类型为 i32(i8*)*,使用 SHA1 混淆名) - fn_ptr_name: t.CChar | t.CPtr = pool.alloc(64) - if fn_ptr_name is not None: - # SHA1 前缀名含 '.' 需要加引号(如 @"sha1.__closure_func") - if string.strchr(mangled_promoted, '.') is not None: - viperlib.snprintf(fn_ptr_name, 64, "@\"%s\"", mangled_promoted) - else: - viperlib.snprintf(fn_ptr_name, 64, "@%s", mangled_promoted) - fn_ptr_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, fn_func_ptr_ty, fn_ptr_name) - - # bitcast 函数指针到 i8*(闭包存储 i8* 类型) - fn_as_i8ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - parent_builder, fn_ptr_val, i8_ptr_ty) - fn_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - parent_builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty)) - if fn_slot is not None and fn_as_i8ptr is not None: - llvmlite.build_store(parent_builder, fn_as_i8ptr, fn_slot) - - # 13d. 存储 env_ptr 到 offset 8 - eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8) - env_slot_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( - parent_builder, i8_ty, closure_ptr, eight_val) - if env_slot_addr is not None: - env_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - parent_builder, env_slot_addr, llvmlite.Ptr(pool, i8_ptr_ty)) - if env_slot is not None: - if env_ptr is not None: - llvmlite.build_store(parent_builder, env_ptr, env_slot) - else: - # 无 nonlocal 变量,存储 null - null_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "null") - llvmlite.build_store(parent_builder, null_val, env_slot) - - # 13e. 将闭包指针存储到父函数的局部变量 {func_name} - closure_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(parent_builder, i8_ptr_ty) - if closure_alloca is not None: - llvmlite.build_store(parent_builder, closure_ptr, closure_alloca) - HandlesVar.define_var(trans.SymTab, func_name, closure_alloca) - - # 14. 恢复 scope names - trans._cur_func_name = old_func_name - trans._global_name_count = old_global_count - trans._nonlocal_name_count = old_nonlocal_count - trans._closure_env_count = old_env_count - - return 1 - - -# ============================================================ -# 创建 LLVM 函数(简单版本,仅声明) -# ============================================================ -def create_function(pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - name: str, - args_node: ast.AST | t.CPtr, - ret_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Function | t.CPtr: - """创建 LLVM 函数并添加参数""" - if name is None or mod is None: - return None - - func: llvmlite.Function | t.CPtr = llvmlite.create_function(pool, mod, name, ret_ty) - if func is None: - return None - - if args_node is not None: - ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) - if ags.args is not None: - alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args - an: t.CSizeT = alist.__len__() - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - for ai in range(an): - arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) - if arg is not None and arg.arg is not None: - # t.CVoid 表示空参:跳过 - if arg.annotation is not None: - if arg.annotation.kind() == ast.ASTKind.Attribute: - at_cf: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg.annotation) - if at_cf.attr is not None and string.strcmp(at_cf.attr, "CVoid") == 0: - continue - param_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if arg.annotation is not None: - resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, arg.annotation, None, None, None) - if resolved is not None: - param_ty = resolved - pname: t.CChar | t.CPtr = pool.alloc(32) - if pname is not None: - viperlib.snprintf(pname, 32, "%%%s", arg.arg) - llvmlite.add_param(pool, func, param_ty, pname) - - return func +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import viperlib +import stdio +import stdlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesBody as HandlesBody +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesImports as HandlesImports + + +# 作用域类型常量(本地副本,避免旧编译器跨模块 CDefine 查找 bug) +SCOPE_FUNCTION: t.CDefine = 1 + + +# ============================================================ +# extract_func_attrs - 从 decorator_list 提取 c.Attribute 属性 +# +# 支持 @c.Attribute(t.attr.xxx()) 和 @c.Attribute(t.attr.xxx) 形式 +# 也支持 @c.Attribute(t.attr.llvm.xxx) 形式 +# +# 返回 LLVM IR 属性字符串(如 "alwaysinline nounwind"),无属性返回 None +# ============================================================ +def extract_func_attrs(pool: memhub.MemBuddy | t.CPtr, + decorator_list: list[ast.AST | t.CPtr] | t.CPtr, + imported_modules: str) -> t.CChar | t.CPtr: + """从 decorator_list 提取 c.Attribute 属性,返回 LLVM IR 属性字符串""" + if decorator_list is None: + return None + dn: t.CSizeT = decorator_list.__len__() + if dn == 0: + return None + + attrs_buf: t.CChar | t.CPtr = pool.alloc(256) + if attrs_buf is None: + return None + attrs_buf[0] = '\0' + found_any: int = 0 + + for di in range(dn): + deco: ast.AST | t.CPtr = decorator_list.get(di) + if deco is None or deco.kind() != ast.ASTKind.Call: + continue + call_node: ast.Call | t.CPtr = (ast.Call | t.CPtr)(deco) + if call_node.func is None or call_node.func.kind() != ast.ASTKind.Attribute: + continue + + # 检测 c.Attribute + func_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call_node.func) + if func_attr.attr is None or string.strcmp(func_attr.attr, "Attribute") != 0: + continue + if func_attr.value is None or func_attr.value.kind() != ast.ASTKind.Name: + continue + c_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_attr.value) + if c_name.id is None or string.strcmp(c_name.id, "c") != 0: + continue + if HandlesImports.is_module_imported(imported_modules, "c") == 0: + continue + + # 遍历参数提取属性 + if call_node.args is None: + continue + args_list: list[ast.AST | t.CPtr] | t.CPtr = call_node.args + an: t.CSizeT = args_list.__len__() + for ai in range(an): + arg_node: ast.AST | t.CPtr = args_list.get(ai) + if arg_node is None: + continue + + # 提取属性名(t.attr.xxx / t.attr.xxx() / t.attr.llvm.xxx) + attr_name: str = _get_attr_name_from_node(arg_node) + if attr_name is None: + continue + + # 映射到 LLVM 属性名并追加 + if _append_llvm_attr(attrs_buf, attr_name) != 0: + found_any = 1 + # 追加成功后,如果不是最后一个属性,添加空格分隔 + # 在下一次追加前由 _append_str 处理 + + if found_any == 0: + return None + return attrs_buf + + +def _get_attr_name_from_node(node: ast.AST | t.CPtr) -> str: + """从 AST 节点提取属性名 + + 支持: + - Call(func=Attribute(...)): t.attr.always_inline() -> "always_inline" + - Attribute: t.attr.packed -> "packed" + - Attribute(t.attr.llvm.xxx): t.attr.llvm.nounwind -> "nounwind" + """ + if node is None: + return None + k: int = node.kind() + + # Call 节点: t.attr.always_inline() + if k == ast.ASTKind.Call: + call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if call.func is None or call.func.kind() != ast.ASTKind.Attribute: + return None + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call.func) + return at.attr + + # Attribute 节点: t.attr.packed 或 t.attr.llvm.nounwind + if k == ast.ASTKind.Attribute: + at2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + return at2.attr + + return None + + +def _append_llvm_attr(attrs_buf: t.CChar | t.CPtr, attr_name: str) -> int: + """将属性名映射到 LLVM 属性名并追加到缓冲区 + + 返回 1 表示已追加,0 表示不支持该属性 + """ + if attrs_buf is None or attr_name is None: + return 0 + + # 先确定映射的 LLVM 属性名 + llvm_name: str = None + if string.strcmp(attr_name, "always_inline") == 0: + llvm_name = "alwaysinline" + elif string.strcmp(attr_name, "noinline") == 0: + llvm_name = "noinline" + elif string.strcmp(attr_name, "noreturn") == 0: + llvm_name = "noreturn" + elif string.strcmp(attr_name, "pure") == 0: + llvm_name = "readonly" + elif string.strcmp(attr_name, "const") == 0: + llvm_name = "readnone" + elif string.strcmp(attr_name, "nounwind") == 0: + llvm_name = "nounwind" + elif string.strcmp(attr_name, "noredzone") == 0: + llvm_name = "noredzone" + elif string.strcmp(attr_name, "willreturn") == 0: + llvm_name = "willreturn" + elif string.strcmp(attr_name, "mustprogress") == 0: + llvm_name = "mustprogress" + else: + # packed/aligned/section/visibility/weak 等不支持作为函数内联属性 + return 0 + + # 支持的属性:如果缓冲区非空,先追加空格分隔 + if attrs_buf[0] != '\0': + _append_str(attrs_buf, " ") + _append_str(attrs_buf, llvm_name) + return 1 + + +def _append_str(buf: t.CChar | t.CPtr, s: str) -> None: + """将字符串追加到 buf 末尾(用 strlen+strcpy 模拟 strcat)""" + if buf is None or s is None: + return + cur_len: t.CSizeT = string.strlen(buf) + string.strcpy(buf + cur_len, s) + + +# ============================================================ +# HandlesFunctions - 函数定义处理(trans 单参模式) +# +# 参考 Python 版 TransPyC FunctionHandle +# +# 函数有自己的局部作用域,通过 HandlesVar.enter_scope/exit_scope +# 管理嵌套作用域链,翻译函数体前进入函数作用域,翻译完退出。 +# ============================================================ + + +# ============================================================ +# _mangle_name - 为名称添加 SHA1 前缀 +# +# 返回 "sha1.name" 格式的混淆名。若 ModuleSha1 为 None 或名称已带 +# SHA1 前缀(16 hex + '.'),则原样返回。 +# ============================================================ +def _mangle_name(trans: HT.Translator | t.CPtr, name: str) -> str: + """为任意名称添加 SHA1 前缀(不做 main/export 检查)""" + if trans is None or name is None: + return name + if trans.ModuleSha1 is None: + return name + name_len: t.CSizeT = string.strlen(name) + # 已带 SHA1 前缀(16 hex + '.')则跳过 + if name_len > 17: + is_sha1: int = 1 + for i in range(16): + c: t.CChar = name[i] + if not (('0' <= c <= '9') or ('a' <= c <= 'f')): + is_sha1 = 0 + break + if is_sha1 != 0 and name[16] == '.': + return name + sha1: str = trans.ModuleSha1 + sha1_len: t.CSizeT = string.strlen(sha1) + mangled: str = stdlib.malloc(sha1_len + name_len + 2) + if mangled is None: + return name + string.strcpy(mangled, sha1) + mangled[sha1_len] = '.' + string.strcpy(mangled + sha1_len + 1, name) + return mangled + + +# ============================================================ +# _mangle_name_with_sha1 — 用指定 SHA1 为名称添加前缀 +# +# 用于跨模块 vtable 继承: 继承方法需要用父模块的 SHA1 做 mangling, +# 而非当前模块的 SHA1。 +# ============================================================ +def _mangle_name_with_sha1(sha1: str, name: str) -> str: + """用指定 SHA1 为名称添加前缀(不做 main/export 检查)""" + if sha1 is None or name is None: + return name + name_len: t.CSizeT = string.strlen(name) + # 已带 SHA1 前缀(16 hex + '.')则跳过 + if name_len > 17: + is_sha1: int = 1 + for i in range(16): + c2: t.CChar = name[i] + if not (('0' <= c2 <= '9') or ('a' <= c2 <= 'f')): + is_sha1 = 0 + break + if is_sha1 != 0 and name[16] == '.': + return name + sha1_len: t.CSizeT = string.strlen(sha1) + mangled: str = stdlib.malloc(sha1_len + name_len + 2) + if mangled is None: + return name + string.strcpy(mangled, sha1) + mangled[sha1_len] = '.' + string.strcpy(mangled + sha1_len + 1, name) + return mangled + + +# ============================================================ +# _mangle_func_name - 为函数名添加 SHA1 前缀(含 main/export 检查) +# +# 规则: +# - main 函数不加前缀(程序入口点) +# - has_export 非 0 时不加前缀(t.CExport 导出函数) +# - 已带 SHA1 前缀的不再加 +# - ModuleSha1 为 None 时不加前缀 +# ============================================================ +def _mangle_func_name(trans: HT.Translator | t.CPtr, name: str, + has_export: int) -> str: + """为函数名添加 SHA1 前缀(检查 main/export)""" + if trans is None or name is None: + return name + if has_export != 0: + return name + if string.strcmp(name, "main") == 0: + return name + return _mangle_name(trans, name) + + +# ============================================================ +# forward_declare_functions - 预扫描所有顶层 FunctionDef,创建前向声明 +# +# 解决同模块内前向引用问题:如 viperlib.py 中 sprintf(行15) 调用 +# vsnprintf(行41),但 vsnprintf 定义在后面。 +# +# 对每个顶层 FunctionDef: +# 1. 推断返回类型和参数类型 +# 2. 计算 mangled name(含 SHA1 前缀) +# 3. 创建 declare(IsDeclared=1) +# 4. 添加参数 +# 5. 注册到函数表 +# +# 后续 translate_function_def 会通过 find_func_in_module 找到已有的 declare, +# 复用之(清除 IsDeclared,跳过参数创建,直接添加函数体)。 +# ============================================================ +def forward_declare_functions(trans: HT.Translator | t.CPtr, + tree: ast.AST | t.CPtr) -> int: + """预扫描所有顶层 FunctionDef,创建前向声明""" + if trans is None or tree is None: + return 0 + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + if pool is None or mod is None: + return 0 + + imported_modules: str = trans._imported_modules + from_imports: str = trans._from_imports + funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children + if ch is None: + return 0 + cn_count: t.CSizeT = ch.__len__() + + for ci in range(cn_count): + child: ast.AST | t.CPtr = ch.get(ci) + if child is None: + continue + if child.kind() != ast.ASTKind.FunctionDef: + continue + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) + if fd is None or fd.name is None: + continue + + # 推断返回类型 + ret_ty: llvmlite.LLVMType | t.CPtr = None + if fd.returns is not None: + ret_ty = HandlesType.resolve_annotation_type( + pool, fd.returns, imported_modules, from_imports, trans) + if ret_ty is None and fd.returns is not None: + if HandlesType.has_decorator_marker(fd.returns, "State") != 0: + ret_ty = llvmlite.Void(pool) + if ret_ty is None: + ret_ty = i32_ty + + # 检测 CExtern/State/CExport + has_extern: int = 0 + has_state: int = 0 + has_export: int = 0 + if fd.returns is not None: + has_extern = HandlesType.has_decorator_marker(fd.returns, "CExtern") + has_state = HandlesType.has_decorator_marker(fd.returns, "State") + has_export = HandlesType.has_decorator_marker(fd.returns, "CExport") + is_extern_decl: int = 0 + if has_extern != 0 or has_state != 0: + is_extern_decl = 1 + + # 计算 mangled name + if has_extern != 0 or has_state != 0 or has_export != 0 or string.strcmp(fd.name, "main") == 0: + mangled_name: str = fd.name + else: + mangled_name = _mangle_func_name(trans, fd.name, 0) + + # 如果函数已存在(如重复定义),跳过 + existing: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name) + if existing is not None: + continue + + # 创建 declare + func: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, mangled_name, ret_ty) + if func is None: + continue + + # 提取默认参数信息 + # 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(), + # 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错 + fd_args_node: ast.Arguments | t.CPtr = fd.args + fd_defaults: t.CVoid | t.CPtr = None + fd_default_count: int = 0 + fd_param_count: int = 0 + if fd_args_node is not None: + fd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd_args_node) + if fd_ags.args is not None: + fd_alist: list[ast.AST | t.CPtr] | t.CPtr = fd_ags.args + fd_param_count = fd_alist.__len__() + if fd_ags.defaults is not None: + fd_dlist: list[ast.AST | t.CPtr] | t.CPtr = fd_ags.defaults + fd_defaults = fd_dlist + fd_default_count = fd_dlist.__len__() + + # 注册到函数表(用裸名 fd.name,不是 mangled_name) + max_funcs: int = 256 + cur_count: int = trans._func_count + if HandlesExprCall.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs, + fd_defaults, fd_default_count, fd_param_count) == 0: + trans._func_count = cur_count + 1 + + # 注册 CExport 函数到全局表 + if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None: + HandlesExprCall.register_cexport_func(trans.ModuleSha1, fd.name) + + # 添加参数 + args_node: ast.Arguments | t.CPtr = fd.args + if args_node is not None: + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags.args is not None: + alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args + an: t.CSizeT = alist.__len__() + for ai in range(an): + arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) + if arg is None or arg.arg is None: + continue + # t.CVoid 表示空参:跳过 + if arg.annotation is not None: + if HandlesType._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0: + continue + param_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if arg.annotation is not None: + resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, arg.annotation, imported_modules, from_imports, trans) + if resolved is not None: + param_ty = resolved + pname: t.CChar | t.CPtr = pool.alloc(32) + if pname is not None: + viperlib.snprintf(pname, 32, "%%%s", arg.arg) + llvmlite.add_param(pool, func, param_ty, pname) + + # *args 变长参数:设置 IsVarArg=1,生成 ... 后缀 + if ags.vararg is not None: + func.IsVarArg = 1 + + return 0 + + +# ============================================================ +# 翻译函数定义 FunctionDef(name, args, body, ...) +# +# trans 单参模式:所有共享状态从 trans 获取 +# 函数局部作用域通过 enter_scope/exit_scope 管理 +# ============================================================ +def translate_function_def(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译函数定义,返回新增的变量数(通常为 0,函数定义不增加当前作用域变量)""" + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) + if fd is None or fd.name is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + imported_modules: str = trans._imported_modules + from_imports: str = trans._from_imports + funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs + func_count: int = trans._func_count + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 推断返回类型:优先使用返回类型注解 + ret_ty: llvmlite.LLVMType | t.CPtr = None + if fd.returns is not None: + ret_ty = HandlesType.resolve_annotation_type( + pool, fd.returns, imported_modules, from_imports, trans) + + # 如果返回类型注解纯装饰器标记(如 t.State,无实际类型),使用 void + # 注意:必须在 infer_return_type 之前检测,因为 infer_return_type 至少返回 i32 + if ret_ty is None and fd.returns is not None: + if HandlesType.has_decorator_marker(fd.returns, "State") != 0: + ret_ty = llvmlite.Void(pool) + + # 如果仍然为 None,扫描 return 语句推断(至少返回 i32) + if ret_ty is None: + param_types_str: str = HandlesType.build_param_types_str(pool, fd.args) + ret_ty = HandlesType.infer_return_type( + pool, fd.children, param_types_str) + # 检测是否为外部声明函数(t.CExtern 或 t.State) + # 语义:t.CExtern 忽略 body 体,仅生成 declare(由链接器解析符号) + # t.State = t.CExtern + t.CExport(既是声明又是导出) + # t.CExport 导出函数不加 SHA1 前缀 + # t.CExtern/t.State/t.CExport 都不加 SHA1 前缀,直接映射到 C 标准库函数名 + is_extern_decl: int = 0 + has_export: int = 0 + has_extern: int = 0 + has_state: int = 0 + if fd.returns is not None: + has_extern = HandlesType.has_decorator_marker(fd.returns, "CExtern") + has_state = HandlesType.has_decorator_marker(fd.returns, "State") + has_export = HandlesType.has_decorator_marker(fd.returns, "CExport") + # t.CExtern/t.State 忽略 body 体,仅声明(无论 body 是否为 pass) + if has_extern != 0 or has_state != 0: + is_extern_decl = 1 + + # SHA1 命名空间:t.CExtern/t.State/t.CExport 不加前缀,直接用裸名 + # (裸名映射到 C 标准库符号,带 sha1 前缀会导致 undefined reference) + # main 函数也不加前缀(程序入口点) + if has_extern != 0 or has_state != 0 or has_export != 0 or string.strcmp(fd.name, "main") == 0: + mangled_name: str = fd.name + else: + mangled_name: str = _mangle_func_name(trans, fd.name, 0) + + # 注册 CExport 函数到全局表(供跨模块调用查表) + # t.CExport 函数定义用裸名(@strlen),跨模块调用需查表确认用裸名而非 @{sha1}.func + if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None: + HandlesExprCall.register_cexport_func(trans.ModuleSha1, fd.name) + + if is_extern_decl != 0: + # 外部声明函数:生成 declare(仅声明,不定义) + # 先检查是否已由 forward_declare_functions 创建,避免重复 declare + existing_extern: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name) + if existing_extern is not None: + # 已存在前向声明,复用之,不再重复创建 + return 0 + + func: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, mangled_name, ret_ty) + if func is None: + return 0 + + # 注册到函数表 + max_funcs_extern: int = 256 + if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs_extern) == 0: + trans._func_count = func_count + 1 + + # 添加参数(支持类型注解) + args_node_extern: ast.Arguments | t.CPtr = fd.args + if args_node_extern is not None: + ags_e: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node_extern) + if ags_e.args is not None: + alist_e: list[ast.AST | t.CPtr] | t.CPtr = ags_e.args + an_e: t.CSizeT = alist_e.__len__() + for ai_e in range(an_e): + arg_e: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist_e.get(ai_e)) + if arg_e is not None and arg_e.arg is not None: + # t.CVoid 表示空参:跳过,不添加到函数签名 + if arg_e.annotation is not None: + if HandlesType._is_t_attr(arg_e.annotation, "CVoid", imported_modules) != 0: + continue + param_ty_e: llvmlite.LLVMType | t.CPtr = i32_ty + if arg_e.annotation is not None: + resolved_e: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, arg_e.annotation, imported_modules, from_imports, trans) + if resolved_e is not None: + param_ty_e = resolved_e + pname_e: t.CChar | t.CPtr = pool.alloc(32) + if pname_e is not None: + viperlib.snprintf(pname_e, 32, "%%%s", arg_e.arg) + llvmlite.add_param(pool, func, param_ty_e, pname_e) + + # 提取 @c.Attribute 装饰器属性并设置到函数 + func_attrs_e: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules) + if func_attrs_e is not None: + llvmlite.function_set_attrs(func, func_attrs_e) + + return 0 + + # args_node 用于后续 alloca 创建,提前赋值 + args_node: ast.Arguments | t.CPtr = fd.args + + # 检查是否已有前向声明(由 forward_declare_functions 创建) + func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name) + if func is not None and llvmlite.function_is_declared(func) != 0: + # 复用前向声明:清除 IsDeclared 标记,转为 define + func.IsDeclared = 0 + # 装饰器属性设置(前向声明时未设置) + func_attrs_reuse: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules) + if func_attrs_reuse is not None: + llvmlite.function_set_attrs(func, func_attrs_reuse) + else: + # 创建新的 LLVM 函数(使用 SHA1 混淆名) + func = llvmlite.create_function(pool, mod, mangled_name, ret_ty) + if func is None: + fb_cf: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_cf is not None: + viperlib.snprintf(fb_cf, 1024, "create_function %s failed", fd.name) + VLogger.error(fb_cf, "FUNC") + return 0 + + # 提取 @c.Attribute 装饰器属性并设置到函数 + func_attrs: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules) + if func_attrs is not None: + llvmlite.function_set_attrs(func, func_attrs) + + # 提取默认参数信息 + tfd_defaults: t.CVoid | t.CPtr = None + tfd_default_count: int = 0 + tfd_param_count: int = 0 + if args_node is not None: + tfd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if tfd_ags.args is not None: + tfd_alist: list[ast.AST | t.CPtr] | t.CPtr = tfd_ags.args + tfd_param_count = tfd_alist.__len__() + if tfd_ags.defaults is not None: + tfd_dlist: list[ast.AST | t.CPtr] | t.CPtr = tfd_ags.defaults + tfd_defaults = tfd_dlist + tfd_default_count = tfd_dlist.__len__() + + # 注册到函数表 + max_funcs: int = 256 + if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs, + tfd_defaults, tfd_default_count, tfd_param_count) == 0: + trans._func_count = func_count + 1 + + # 添加参数(支持类型注解) + if args_node is not None: + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags.args is not None: + alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args + an: t.CSizeT = alist.__len__() + for ai in range(an): + arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) + if arg is not None and arg.arg is not None: + # t.CVoid 表示空参:跳过,不添加到函数签名 + if arg.annotation is not None: + if HandlesType._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0: + continue + param_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if arg.annotation is not None: + resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, arg.annotation, imported_modules, from_imports, trans) + if resolved is not None: + param_ty = resolved + pname: t.CChar | t.CPtr = pool.alloc(32) + if pname is not None: + viperlib.snprintf(pname, 32, "%%%s", arg.arg) + llvmlite.add_param(pool, func, param_ty, pname) + + # *args 变长参数:设置 IsVarArg=1,生成 ... 后缀 + if ags.vararg is not None: + func.IsVarArg = 1 + + # 创建 entry 块 + entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") + if entry_blk is None: + return 0 + + # 创建函数专属 builder + func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) + if func_builder is None: + return 0 + llvmlite.position_at_end(func_builder, entry_blk) + + # 进入函数作用域(嵌套符号表) + HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION) + + # 为参数创建 alloca + if args_node is not None: + ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags2.args is not None: + alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args + an2: t.CSizeT = alist2.__len__() + for ai2 in range(an2): + arg2: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist2.get(ai2)) + if arg2 is not None and arg2.arg is not None: + # t.CVoid 表示空参:跳过,不创建 alloca + if arg2.annotation is not None: + if HandlesType._is_t_attr(arg2.annotation, "CVoid", imported_modules) != 0: + continue + param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty + if arg2.annotation is not None: + resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, arg2.annotation, imported_modules, from_imports, trans) + if resolved2 is not None: + param_ty2 = resolved2 + alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2) + if alloca is not None: + HandlesVar.define_var(trans.SymTab, arg2.arg, alloca) + # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) + if arg2.annotation is not None: + cls_nm: str = HandlesType.extract_class_name_from_annotation( + arg2.annotation, imported_modules) + if cls_nm is not None: + HandlesVar.set_var_annot_class_name( + trans.SymTab, arg2.arg, cls_nm) + pname2: t.CChar | t.CPtr = pool.alloc(32) + if pname2 is not None: + viperlib.snprintf(pname2, 32, "%%%s", arg2.arg) + param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, param_ty2, pname2) + llvmlite.build_store(func_builder, param_val, alloca) + + # *args 变长参数:创建 va_list alloca + 调用 va_start + 注册到符号表 + # 生成 IR: + # %args = alloca i8* ; va_list 存储 + # call void @llvm.va_start(i8* %args) ; 初始化 va_list + # 用户函数体内可通过 args 名字读取 va_list,或用 arg(type) 糖函数 + if ags2.vararg is not None: + vararg_node: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(ags2.vararg) + if vararg_node is not None and vararg_node.arg is not None: + vararg_name_str: str = vararg_node.arg + # va_list 类型为 i8*(与 stdarg.vp 中 va_list = t.CUnsignedChar | t.CPtr 一致) + i8_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_va) + # alloca i8*(存储 va_list 值) + va_list_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, i8_ptr_ty_va) + if va_list_alloca is not None: + # 注册到符号表,函数体内可通过 vararg_name 访问 va_list 指针 + HandlesVar.define_var(trans.SymTab, vararg_name_str, va_list_alloca) + # 调用 @llvm.va_start(i8* %va_list_alloca) + # va_start 需要的是 va_list 本身的地址(即 alloca 返回的 i8**), + # bitcast 到 i8* 后传入 + va_list_arg: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + func_builder, va_list_alloca, i8_ptr_ty_va) + if va_list_arg is not None: + void_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + llvmlite.build_call(func_builder, "llvm.va_start", + va_list_arg, 1, void_ty_va, 0) + # 保存到 trans 供 arg(type) 糖函数使用 + trans._va_list_ptr = va_list_alloca + trans._vararg_name = vararg_name_str + + # 保存模块级作用域状态(仅非变量表相关) + old_func: llvmlite.Function | t.CPtr = trans._cur_func + old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + old_global_count: int = trans._global_name_count + old_nonlocal_count: int = trans._nonlocal_name_count + old_env_count: int = trans._closure_env_count + old_va_list_ptr: llvmlite.Value | t.CPtr = trans._va_list_ptr + old_vararg_name: str = trans._vararg_name + + trans._cur_func = func + trans._cur_builder = func_builder + # 清空 global/nonlocal 名称集合(新函数作用域) + HT.clear_scope_names(trans) + + # 预扫描函数体: + # 1. 先预扫描 Global/Nonlocal 声明(Python 语义:global/nonlocal + # 对整个函数作用域生效,与声明位置无关,故须在任何赋值前注册) + # 2. 再预扫描 AnnAssign 为局部变量提前创建 alloca + body: list[ast.AST | t.CPtr] | t.CPtr = fd.children + if body is not None: + bn: t.CSizeT = body.__len__() + for bi in range(bn): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.pre_scan_scope_decls(trans, stmt) + for bi in range(bn): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.pre_scan_allocas(trans, stmt) + + # 翻译函数体 + if body is not None: + bn2: t.CSizeT = body.__len__() + for bi2 in range(bn2): + stmt2: ast.AST | t.CPtr = body.get(bi2) + if stmt2 is not None: + HandlesBody.translate_stmt(trans, stmt2) + + # 如果函数体最后一条语句不是 Return,添加隐式 ret + last_is_return: int = 0 + if body is not None: + bn3: t.CSizeT = body.__len__() + if bn3 > 0: + last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1) + if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return: + last_is_return = 1 + if last_is_return == 0: + if llvmlite.builder_cur_block_is_terminated(func_builder) == 0: + # 根据返回类型生成正确的零值返回 + _is_void: int = 0 + _is_ptr: int = 0 + if ret_ty is not None: + match ret_ty: + case llvmlite.LLVMType.Void(): + _is_void = 1 + case llvmlite.LLVMType.Ptr(_pe): + _is_ptr = 1 + if _is_void != 0: + llvmlite.build_ret_void(func_builder) + elif _is_ptr != 0: + _null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null") + llvmlite.build_ret(func_builder, _null_val) + else: + _zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + llvmlite.build_ret(func_builder, _zero_val) + + # 恢复模块级作用域(退出函数作用域) + HandlesVar.exit_scope(trans.SymTab) + trans._cur_func = old_func + trans._cur_builder = old_builder + trans._global_name_count = old_global_count + trans._nonlocal_name_count = old_nonlocal_count + trans._closure_env_count = old_env_count + trans._va_list_ptr = old_va_list_ptr + trans._vararg_name = old_vararg_name + + return 0 + + +# ============================================================ +# translate_nested_function_def - 嵌套函数提升 + 闭包创建 +# +# 将嵌套函数提升为顶层函数 @__closure_{name}(i8* %env) -> i32, +# 在父函数中创建闭包对象 {i8* fn_ptr, i8* env_ptr} 并存储到 +# 以函数名命名的局部变量中。 +# +# 闭包结构: {i8* fn_ptr, i8* env_ptr} (16 字节, malloc 分配) +# Env 结构: {i8* ptr0, i8* ptr1, ...} (每个 nonlocal 变量 8 字节,指向父函数 alloca) +# ============================================================ +def translate_nested_function_def(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译嵌套函数定义:提升为顶层函数 + 创建闭包""" + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) + if fd is None or fd.name is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + func_name: str = fd.name + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + # 1. 构建提升后的函数名: __closure_{name}(加 SHA1 前缀避免跨模块冲突) + promoted_name: t.CChar | t.CPtr = pool.alloc(64) + if promoted_name is not None: + viperlib.snprintf(promoted_name, 64, "__closure_%s", func_name) + mangled_promoted: str = _mangle_name(trans, promoted_name) + + # 2. 创建提升后的函数: define i32 @__closure_{name}(i8* %env) + func: llvmlite.Function | t.CPtr = llvmlite.create_function( + pool, mod, mangled_promoted, i32_ty) + if func is None: + return 0 + llvmlite.add_param(pool, func, i8_ptr_ty, "%env") + + # 3. 创建 entry 块 + builder + entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") + if entry_blk is None: + return 0 + func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) + if func_builder is None: + return 0 + llvmlite.position_at_end(func_builder, entry_blk) + + # 4. 进入嵌套函数作用域(嵌套符号表) + HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION) + + # 5. 创建 _env_ptr alloca 并存储 %env 参数 + env_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, i8_ptr_ty) + if env_alloca is not None: + HandlesVar.define_var(trans.SymTab, "_env_ptr", env_alloca) + env_param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "%env") + llvmlite.build_store(func_builder, env_param_val, env_alloca) + + # 6. 保存父函数作用域状态(仅非变量表相关) + old_func: llvmlite.Function | t.CPtr = trans._cur_func + old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + old_func_name: str = trans._cur_func_name + old_global_count: int = trans._global_name_count + old_nonlocal_count: int = trans._nonlocal_name_count + old_env_count: int = trans._closure_env_count + + # 7. 切换到嵌套函数作用域 + 清空 scope names + trans._cur_func = func + trans._cur_builder = func_builder + trans._cur_func_name = func_name + HT.clear_scope_names(trans) + + # 8. 预扫描函数体: + # a. 先预扫描 Global/Nonlocal 声明(Python 语义:对整个函数作用域生效) + # b. 再预扫描 AnnAssign 为局部变量提前创建 alloca + body: list[ast.AST | t.CPtr] | t.CPtr = fd.children + if body is not None: + bn: t.CSizeT = body.__len__() + for bi in range(bn): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.pre_scan_scope_decls(trans, stmt) + for bi in range(bn): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.pre_scan_allocas(trans, stmt) + + # 9. 翻译函数体(Nonlocal 语句会填充 _nonlocal_names) + if body is not None: + bn2: t.CSizeT = body.__len__() + for bi2 in range(bn2): + stmt2: ast.AST | t.CPtr = body.get(bi2) + if stmt2 is not None: + HandlesBody.translate_stmt(trans, stmt2) + + # 10. 隐式 ret + last_is_return: int = 0 + if body is not None: + bn3: t.CSizeT = body.__len__() + if bn3 > 0: + last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1) + if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return: + last_is_return = 1 + if last_is_return == 0: + zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + llvmlite.build_ret(func_builder, zero_val) + + # 11. 保存嵌套函数的 nonlocal 信息 + nested_nonlocal_count: int = trans._nonlocal_name_count + + # 12. 退出嵌套函数作用域,回到父函数作用域(保留 _nonlocal_names 用于 env 创建) + HandlesVar.exit_scope(trans.SymTab) + trans._cur_func = old_func + trans._cur_builder = old_builder + # NOTE: _nonlocal_names 和 _nonlocal_name_count 仍为嵌套函数的值 + + # 13. 在父函数中创建闭包对象 + parent_builder: llvmlite.IRBuilder | t.CPtr = old_builder + if parent_builder is None: + # 无 builder(模块级嵌套函数?)→ 无法创建闭包,仅恢复状态 + trans._cur_func_name = old_func_name + trans._global_name_count = old_global_count + trans._nonlocal_name_count = old_nonlocal_count + trans._closure_env_count = old_env_count + return 0 + + # 13a. 创建 env: malloc(8 * nested_nonlocal_count) — env 存储指针数组 + # 每个 nonlocal 变量占 8 字节(i8*),指向父函数的 alloca(共享存储) + env_ptr: llvmlite.Value | t.CPtr = None + if nested_nonlocal_count > 0: + env_size: t.CInt64T = nested_nonlocal_count * 8 + env_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, env_size) + if env_size_val is not None: + env_size_val.Next = None + env_ptr = llvmlite.build_call( + parent_builder, "malloc", env_size_val, 1, i8_ptr_ty, 0) + + # 为每个 nonlocal 变量存储 alloca 指针到 env(共享存储,修改互相可见) + if env_ptr is not None: + i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) + for ni in range(nested_nonlocal_count): + # 从 _nonlocal_names 缓冲区读取名称 + name_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + ni * 8 + nl_slot: str | t.CPtr = (t.CVoid | t.CPtr)(name_addr) + nl_name: str = nl_slot[0] + if nl_name is not None: + # 在父函数作用域中查找(Current 已回到父作用域) + var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, nl_name) + if var_alloca is not None: + # bitcast alloca 指针为 i8*(擦除类型信息) + alloca_as_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + parent_builder, var_alloca, i8_ptr_ty) + if alloca_as_i8 is not None: + # GEP to env[ni*8] + offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, ni * 8) + slot: llvmlite.Value | t.CPtr = llvmlite.build_gep( + parent_builder, i8_ty, env_ptr, offset_val) + if slot is not None: + # bitcast to i8** and store alloca pointer + slot_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + parent_builder, slot, i8_ptr_ptr_ty) + if slot_typed is not None: + llvmlite.build_store(parent_builder, alloca_as_i8, slot_typed) + + # 13b. 创建闭包结构: malloc(16) + closure_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 16) + if closure_size_val is not None: + closure_size_val.Next = None + closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_call( + parent_builder, "malloc", closure_size_val, 1, i8_ptr_ty, 0) + if closure_ptr is None: + # malloc 失败,恢复状态 + trans._cur_func_name = old_func_name + trans._global_name_count = old_global_count + trans._nonlocal_name_count = old_nonlocal_count + trans._closure_env_count = old_env_count + return 0 + + # 13c. 存储 fn_ptr 到 offset 0 + # 创建函数指针类型 i32(i8*)* + fn_param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) + fn_func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, fn_param_node, 1) + fn_func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, fn_func_ty) + + # 创建函数引用 Value(类型为 i32(i8*)*,使用 SHA1 混淆名) + fn_ptr_name: t.CChar | t.CPtr = pool.alloc(64) + if fn_ptr_name is not None: + # SHA1 前缀名含 '.' 需要加引号(如 @"sha1.__closure_func") + if string.strchr(mangled_promoted, '.') is not None: + viperlib.snprintf(fn_ptr_name, 64, "@\"%s\"", mangled_promoted) + else: + viperlib.snprintf(fn_ptr_name, 64, "@%s", mangled_promoted) + fn_ptr_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, fn_func_ptr_ty, fn_ptr_name) + + # bitcast 函数指针到 i8*(闭包存储 i8* 类型) + fn_as_i8ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + parent_builder, fn_ptr_val, i8_ptr_ty) + fn_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + parent_builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty)) + if fn_slot is not None and fn_as_i8ptr is not None: + llvmlite.build_store(parent_builder, fn_as_i8ptr, fn_slot) + + # 13d. 存储 env_ptr 到 offset 8 + eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8) + env_slot_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + parent_builder, i8_ty, closure_ptr, eight_val) + if env_slot_addr is not None: + env_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + parent_builder, env_slot_addr, llvmlite.Ptr(pool, i8_ptr_ty)) + if env_slot is not None: + if env_ptr is not None: + llvmlite.build_store(parent_builder, env_ptr, env_slot) + else: + # 无 nonlocal 变量,存储 null + null_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "null") + llvmlite.build_store(parent_builder, null_val, env_slot) + + # 13e. 将闭包指针存储到父函数的局部变量 {func_name} + closure_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(parent_builder, i8_ptr_ty) + if closure_alloca is not None: + llvmlite.build_store(parent_builder, closure_ptr, closure_alloca) + HandlesVar.define_var(trans.SymTab, func_name, closure_alloca) + + # 14. 恢复 scope names + trans._cur_func_name = old_func_name + trans._global_name_count = old_global_count + trans._nonlocal_name_count = old_nonlocal_count + trans._closure_env_count = old_env_count + + return 1 + + +# ============================================================ +# 创建 LLVM 函数(简单版本,仅声明) +# ============================================================ +def create_function(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + name: str, + args_node: ast.AST | t.CPtr, + ret_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Function | t.CPtr: + """创建 LLVM 函数并添加参数""" + if name is None or mod is None: + return None + + func: llvmlite.Function | t.CPtr = llvmlite.create_function(pool, mod, name, ret_ty) + if func is None: + return None + + if args_node is not None: + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags.args is not None: + alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args + an: t.CSizeT = alist.__len__() + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + for ai in range(an): + arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) + if arg is not None and arg.arg is not None: + # t.CVoid 表示空参:跳过 + if arg.annotation is not None: + if arg.annotation.kind() == ast.ASTKind.Attribute: + at_cf: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg.annotation) + if at_cf.attr is not None and string.strcmp(at_cf.attr, "CVoid") == 0: + continue + param_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if arg.annotation is not None: + resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, arg.annotation, None, None, None) + if resolved is not None: + param_ty = resolved + pname: t.CChar | t.CPtr = pool.alloc(32) + if pname is not None: + viperlib.snprintf(pname, 32, "%%%s", arg.arg) + llvmlite.add_param(pool, func, param_ty, pname) + + return func diff --git a/App/lib/core/Handles/HandlesMatch.vp b/App/lib/core/Handles/HandlesMatch.vp new file mode 100644 index 0000000..80e5046 --- /dev/null +++ b/App/lib/core/Handles/HandlesMatch.vp @@ -0,0 +1,852 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import viperlib +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.HandlesBody as HandlesBody +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesStruct as HandlesStruct + + +# ============================================================ +# HandlesMatch - match 语句处理(Mixin 继承模式) +# +# 逻辑移植自 TPC 的 HandlesMatch.py,用 Viper 语法重写。 +# 两条路径: +# 1. REnum 路径:bitcast subject 到 i32* 读 __tag + switch 分派 +# 2. 非 REnum 路径:subject ptrtoint 到 i32 + switch 分派 +# +# IR 模式(REnum): +# %tag_ptr = bitcast * %subj to i32* +# %tag = load i32, i32* %tag_ptr +# switch i32 %tag, label %default [ i32 , label %case1 ... ] +# case1: +# ... body ... +# br label %end (若无 c.NoBreak) +# end: +# ============================================================ + +# match case 数量上限 +MAX_MATCH_CASES: t.CDefine = 32 + +# 作用域种类常量(与 HandlesVar 的 Scope.Kind 区分) +SCOPE_MATCH: t.CDefine = 6 + + +@t.NoVTable +class MatchHandle(HandlesBase.Mixin): + """match 语句处理器:REnum + 非 REnum 两条路径""" + + def __init__(self, trans: HT.Translator | t.CPtr): + self.Trans = trans + + # ============================================================ + # Handle - match 语句主入口,返回 0 + # ============================================================ + def Handle(self, node: ast.AST | t.CPtr) -> int: + if node is None: + return 0 + trans: HT.Translator | t.CPtr = self.Trans + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + if builder is None or func is None: + return 0 + + stdio.printf("[MATCHDBG] Handle entry: _renum_class_count=%d\n", + HandlesClassDef._renum_class_count) + dbg_i: int = 0 + while dbg_i < HandlesClassDef._renum_class_count: + dbg_nm: str = HandlesClassDef._renum_class_names[dbg_i] + if dbg_nm is not None: + stdio.printf("[MATCHDBG] REnum[%d]=%s\n", dbg_i, dbg_nm) + dbg_i = dbg_i + 1 + + m_node: ast.Match | t.CPtr = (ast.Match | t.CPtr)(node) + + # 1. 求值 subject + subject_node: ast.AST | t.CPtr = m_node.subject + if subject_node is None: + return 0 + subject_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, subject_node, + trans._funcs, trans._func_count, trans) + if subject_val is None: + stdio.printf("[MATCHDBG] subject_val is None (translate_value failed)\n") + return 0 + + stdio.printf("[MATCHDBG] subject_val OK\n") + + # 2. 检测是否 REnum match + is_renum: int = 0 + renum_name: str = None + subject_ptr: llvmlite.Value | t.CPtr = None + + # 2a. 若 subject 是 Name,查变量注解类名 + if subject_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(subject_node) + if nm.id is not None: + stdio.printf("[MATCHDBG] subject Name='%s'\n", nm.id) + entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, nm.id) + if entry is None: + stdio.printf("[MATCHDBG] VarEntry None for '%s'\n", nm.id) + if entry is not None and entry.AnnotClassName is not None: + stdio.printf("[MATCHDBG] AnnotClassName='%s'\n", + entry.AnnotClassName) + rn_chk: int = HandlesClassDef._is_renum_class_name( + entry.AnnotClassName) + stdio.printf("[MATCHDBG] _is_renum_class_name=%d\n", rn_chk) + if rn_chk != 0: + is_renum = 1 + renum_name = entry.AnnotClassName + subject_ptr = HandlesVar.lookup_var(trans.SymTab, nm.id) + stdio.printf("[MATCHDBG] REnum detected: %s\n", + renum_name) + + # 2b. 若未确定,遍历 cases 查 MatchClass 变体 + if is_renum == 0: + cases_list: list[ast.AST | t.CPtr] | t.CPtr = m_node.cases + if cases_list is not None: + cn: t.CSizeT = cases_list.__len__() + ci: int = 0 + while ci < cn and is_renum == 0: + case_node: ast.AST | t.CPtr = cases_list.get(ci) + if case_node is not None: + if case_node.kind() == ast.ASTKind.MatchCase: + mc: ast.MatchCase | t.CPtr = ( + ast.MatchCase | t.CPtr)(case_node) + pat: ast.AST | t.CPtr = mc.pattern + if pat is not None: + if pat.kind() == ast.ASTKind.MatchClass: + rnm: str = self._extract_renum_name_from_cls(pat) + if rnm is not None: + if HandlesClassDef._is_renum_class_name(rnm) != 0: + is_renum = 1 + renum_name = rnm + if subject_ptr is None: + subject_ptr = subject_val + ci = ci + 1 + + # 3. 分派 + stdio.printf("[MATCHDBG] dispatch: is_renum=%d\n", is_renum) + if is_renum != 0 and subject_ptr is not None: + stdio.printf("[MATCHDBG] -> _handle_renum_match\n") + return self._handle_renum_match(m_node, renum_name, subject_ptr) + stdio.printf("[MATCHDBG] -> _handle_simple_match\n") + return self._handle_simple_match(m_node, subject_val) + + # ============================================================ + # _extract_renum_name_from_cls - 从 MatchClass.cls 提取 REnum 类名 + # + # LLVMType.Ptr -> Attribute(value=Name('LLVMType'), attr='Ptr') -> 'LLVMType' + # llvmlite.LLVMType.Ptr -> Attribute(Attribute(Name('llvmlite'),'LLVMType'),'Ptr') -> 'LLVMType' + # Ptr -> Name('Ptr') -> 遍历查找 + # ============================================================ + def _extract_renum_name_from_cls(self, + pattern: ast.AST | t.CPtr) -> str: + if pattern is None: + return None + mc: ast.MatchClass | t.CPtr = (ast.MatchClass | t.CPtr)(pattern) + cls_node: ast.AST | t.CPtr = mc.cls + if cls_node is None: + return None + # Attribute 形式 + if cls_node.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cls_node) + if at.value is not None: + if at.value.kind() == ast.ASTKind.Name: + inner_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + return inner_nm.id + if at.value.kind() == ast.ASTKind.Attribute: + inner_at: ast.Attribute | t.CPtr = ( + ast.Attribute | t.CPtr)(at.value) + return inner_at.attr + # Name 形式:遍历所有 REnum 类反查 + if cls_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cls_node) + return self._find_renum_class_for_variant(nm.id) + return None + + # ============================================================ + # _extract_variant_name_from_cls - 从 MatchClass.cls 提取变体名 + # ============================================================ + def _extract_variant_name_from_cls(self, + pattern: ast.AST | t.CPtr) -> str: + if pattern is None: + return None + mc: ast.MatchClass | t.CPtr = (ast.MatchClass | t.CPtr)(pattern) + cls_node: ast.AST | t.CPtr = mc.cls + if cls_node is None: + return None + if cls_node.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cls_node) + return at.attr + if cls_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cls_node) + return nm.id + return None + + # ============================================================ + # _find_renum_class_for_variant - 从变体名反查 REnum 类名 + # ============================================================ + def _find_renum_class_for_variant(self, variant_name: str) -> str: + if variant_name is None: + return None + i: int = 0 + while i < HandlesClassDef._renum_class_count: + cls_nm: str = HandlesClassDef._renum_class_names[i] + if cls_nm is not None: + tag: int = HandlesClassDef._lookup_renum_variant_in_class( + cls_nm, variant_name) + if tag >= 0: + return cls_nm + i = i + 1 + return None + + # ============================================================ + # _has_no_break - 检测 case body 是否含 c.NoBreak() 调用 + # + # 遍历 case body 顶层语句,查找 Expr(Call(Attribute(Name('c'), 'NoBreak'))) + # ============================================================ + def _has_no_break(self, body_list: list[ast.AST | t.CPtr] | t.CPtr) -> int: + if body_list is None: + return 0 + n: t.CSizeT = body_list.__len__() + i: int = 0 + while i < n: + stmt: ast.AST | t.CPtr = body_list.get(i) + if stmt is not None: + if stmt.kind() == ast.ASTKind.Expr: + expr_node: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(stmt) + val: ast.AST | t.CPtr = expr_node.value + if val is not None and val.kind() == ast.ASTKind.Call: + call_node: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val) + fn: ast.AST | t.CPtr = call_node.func + if fn is not None and fn.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = ( + ast.Attribute | t.CPtr)(fn) + if at.value is not None: + if at.value.kind() == ast.ASTKind.Name: + base_nm: ast.Name | t.CPtr = ( + ast.Name | t.CPtr)(at.value) + if base_nm.id is not None: + if string.strcmp(base_nm.id, "c") == 0: + if at.attr is not None: + if string.strcmp(at.attr, "NoBreak") == 0: + return 1 + i = i + 1 + return 0 + + # ============================================================ + # _handle_renum_match - REnum 路径 + # + # 1. bitcast subject 到 i32* 读 __tag + # 2. 收集 case 值 + 创建 BB + 构建 SwitchCase 链表 + # 3. 发射 build_switch + # 4. 翻译每个 case body(含作用域隔离 + 变体字段绑定) + # ============================================================ + def _handle_renum_match(self, node: ast.Match | t.CPtr, + renum_name: str, + subject_ptr: llvmlite.Value | t.CPtr) -> int: + trans: HT.Translator | t.CPtr = self.Trans + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + # 0. subject 归一化:确保 subject_ptr 是指向 REnum 结构体的指针 + # (对齐 TPC HandlesMatch.py:238-259 的 _HandleRenumMatchLlvm) + # 情况1: subject_ptr 是 T**(变量 alloca)→ load 一次得 T* + # 情况2: subject_ptr 不是指针(值型,如 REnum payload 槽位 load 出的 i64) + # → alloca REnum 结构体 + store 值 + 用 alloca 指针 + # 情况3: 指针但 pointee 不是结构体 → bitcast 到 REnum 结构体指针 + subj_ty: llvmlite.LLVMType | t.CPtr = subject_ptr.Ty + if subj_ty is not None and HandlesExpr.is_ptr_type(subj_ty) != 0: + pointee_ty: llvmlite.LLVMType | t.CPtr = subj_ty.Pointee + if pointee_ty is not None: + if HandlesExpr.is_ptr_type(pointee_ty) != 0: + # 情况1: T** → load 一次得 T* + load_sub_ty: llvmlite.LLVMType | t.CPtr = pointee_ty + loaded_sub: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, load_sub_ty, subject_ptr) + if loaded_sub is not None: + subject_ptr = loaded_sub + # 情况2: 值型 subject(非指针)→ inttoptr 转回指针 + # 值型 subject 来自 REnum payload 槽位 load(槽位类型 i64,存的是指针), + # 所以直接 inttoptr 到 renum_sty* 即可,无需 alloca+store + if subject_ptr.Ty is None or HandlesExpr.is_ptr_type(subject_ptr.Ty) == 0: + renum_se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct( + renum_name) + renum_sty: llvmlite.LLVMType | t.CPtr = None + if renum_se is not None: + renum_sty = renum_se.Ty + if renum_sty is None: + # 找不到结构体类型时无法构造,直接放弃 REnum 路径 + stdio.printf("[MATCHDBG] renum struct type not found for '%s'\n", + renum_name) + return 0 + i64_ty0: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + int_val: llvmlite.Value | t.CPtr = subject_ptr + # 非 i64 整数值先扩展/截断到 i64(inttoptr 要求同宽) + # 仅当 subj_ty 是已知整数类型时转换;类型未知时保持原值 + if subj_ty is not None and HandlesExpr.get_llvm_type_bits(subj_ty) != 64: + if HandlesExpr.is_ptr_type(subj_ty) == 0: + if HandlesExpr.get_llvm_type_bits(subj_ty) > 64: + int_val = llvmlite.build_trunc(builder, subject_ptr, i64_ty0) + else: + int_val = llvmlite.build_zext(builder, subject_ptr, i64_ty0) + renum_ptr_ty0: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, renum_sty) + subj_ptr0: llvmlite.Value | t.CPtr = llvmlite.build_inttoptr( + builder, int_val, renum_ptr_ty0) + if subj_ptr0 is not None: + subject_ptr = subj_ptr0 + + # 1. bitcast subject 到 i32* 读 __tag + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty) + tag_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, subject_ptr, i32_ptr_ty) + if tag_ptr is None: + stdio.printf("[MATCHDBG] tag_ptr None (bitcast failed)\n") + return 0 + tag_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i32_ty, tag_ptr) + if tag_val is None: + stdio.printf("[MATCHDBG] tag_val None (load failed)\n") + return 0 + stdio.printf("[MATCHDBG] _handle_renum_match: tag loaded OK\n") + + # 2. 创建 default/end BB + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + name_buf: t.CChar | t.CPtr = pool.alloc(32) + if name_buf is None: + return 0 + viperlib.snprintf(name_buf, 32, "match.default.%d", cnt) + default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "match.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + + # 3. 准备收集数组(用 CSizeT 数组存指针) + cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases + if cases_list is None: + return 0 + case_count: t.CSizeT = cases_list.__len__() + + # BB 指针数组、case 值指针数组、default 标记数组、nobreak 标记数组 + bb_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) + cv_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) + def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) + nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) + if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None: + return 0 + + collected: int = 0 + has_default: int = 0 + + # SwitchCase 链表 + sw_head: llvmlite.SwitchCase | t.CPtr = None + sw_tail: llvmlite.SwitchCase | t.CPtr = None + sw_count: int = 0 + + # 4. 第一遍:收集 case 信息 + 创建 BB + 构建链表 + i: int = 0 + while i < case_count: + case_node: ast.AST | t.CPtr = cases_list.get(i) + if case_node is None: + i = i + 1 + continue + if case_node.kind() != ast.ASTKind.MatchCase: + i = i + 1 + continue + mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node) + pat: ast.AST | t.CPtr = mc.pattern + + is_def: int = 0 + cv: llvmlite.Value | t.CPtr = None + + if pat is not None: + pk: int = pat.kind() + if pk == ast.ASTKind.MatchClass: + vnm: str = self._extract_variant_name_from_cls(pat) + if vnm is not None: + tag: int = HandlesClassDef._lookup_renum_variant_in_class( + renum_name, vnm) + stdio.printf("[MATCHDBG] case vnm='%s' renum='%s' -> tag=%d\n", + vnm if vnm is not None else "(null)", + renum_name if renum_name is not None else "(null)", + tag) + if tag >= 0: + tag_buf: t.CChar | t.CPtr = pool.alloc(32) + if tag_buf is not None: + viperlib.snprintf(tag_buf, 32, "%d", tag) + cv = llvmlite.ConstInt(pool, i32_ty, tag, + tag_buf if tag_buf is not None else "0") + elif pk == ast.ASTKind.MatchAs: + ma: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(pat) + if ma.pattern is None: + is_def = 1 + has_default = 1 + elif pk == ast.ASTKind.MatchValue: + mv: ast.MatchValue | t.CPtr = (ast.MatchValue | t.CPtr)(pat) + cv = HandlesExpr.translate_value( + builder, pool, trans.Module, mv.value, + trans._funcs, trans._func_count, trans) + elif pk == ast.ASTKind.MatchOr: + # MatchOr: 多个值共享一个 BB(取第一个值做 case) + mo: ast.MatchOr | t.CPtr = (ast.MatchOr | t.CPtr)(pat) + pats: list[ast.AST | t.CPtr] | t.CPtr = mo.patterns + if pats is not None and pats.__len__() > 0: + first_pat: ast.AST | t.CPtr = pats.get(0) + if first_pat is not None: + if first_pat.kind() == ast.ASTKind.MatchValue: + mv2: ast.MatchValue | t.CPtr = ( + ast.MatchValue | t.CPtr)(first_pat) + cv = HandlesExpr.translate_value( + builder, pool, trans.Module, mv2.value, + trans._funcs, trans._func_count, trans) + + # 创建 case BB + if is_def == 0: + if collected >= MAX_MATCH_CASES: + break + viperlib.snprintf(name_buf, 32, "match.case.%d.%d", cnt, i) + bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + else: + bb = default_bb + + # 检测 NoBreak + body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children + nb: int = self._has_no_break(body_list) + + # 存入数组 + if collected < MAX_MATCH_CASES: + bb_arr[collected] = t.CSizeT(bb) + cv_arr[collected] = t.CSizeT(cv) + def_arr[collected] = is_def + nb_arr[collected] = nb + collected = collected + 1 + + # 构建 SwitchCase 链表(非 default case 且有值) + if is_def == 0 and cv is not None: + sc: llvmlite.SwitchCase | t.CPtr = llvmlite.new_switch_case( + pool, cv, bb) + if sc is not None: + if sw_head is None: + sw_head = sc + sw_tail = sc + else: + sw_tail.Next = sc + sw_tail = sc + sw_count = sw_count + 1 + + i = i + 1 + + # 5. 发射 switch 指令 + llvmlite.build_switch(builder, tag_val, default_bb, sw_head, sw_count) + + # 6. 查找 REnum 结构体类型(用于变体字段绑定的 GEP) + renum_entry: HandlesStruct.StructEntry | t.CPtr = None + renum_ty: llvmlite.LLVMType | t.CPtr = None + se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(renum_name) + if se is not None: + renum_entry = se + renum_ty = se.Ty + + # 7. 第二遍:翻译每个 case body + i = 0 + while i < collected: + case_node: ast.AST | t.CPtr = cases_list.get(i) + if case_node is None: + i = i + 1 + continue + mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node) + pat: ast.AST | t.CPtr = mc.pattern + + # 取 BB + bb_addr: t.CSizeT = bb_arr[i] + case_bb: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)(t.CVoid(bb_addr, t.CPtr)) + is_def: int = def_arr[i] + nb: int = nb_arr[i] + + # default case 的 body 在 step 8 单独翻译,这里跳过避免重复 + if is_def == 1: + i = i + 1 + continue + + # 定位到 case BB + llvmlite.position_at_end(builder, case_bb) + + # 进入 case 作用域(变体字段绑定隔离) + HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH) + + # 变体字段绑定(MatchClass) + if pat is not None and pat.kind() == ast.ASTKind.MatchClass: + if renum_entry is not None and renum_ty is not None: + self._bind_variant_fields( + pat, renum_name, renum_entry, renum_ty, + subject_ptr, trans, pool, builder) + + # 翻译 case body + body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children + if body_list is not None: + bc: t.CSizeT = body_list.__len__() + bi: int = 0 + while bi < bc: + stmt: ast.AST | t.CPtr = body_list.get(bi) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + bi = bi + 1 + + # 退出 case 作用域 + HandlesVar.exit_scope(trans.SymTab) + + # 若未终止且无 NoBreak,跳到 end + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + if nb == 0: + llvmlite.build_br(builder, end_bb) + + i = i + 1 + + # 8. 处理 default 块 + llvmlite.position_at_end(builder, default_bb) + if has_default == 0: + # 无显式 default:default 直接跳 end + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, end_bb) + else: + # 有显式 default:翻译 default case body(找到 is_def==1 的 case) + di: int = 0 + while di < collected: + if def_arr[di] == 1: + dcase: ast.AST | t.CPtr = cases_list.get(di) + if dcase is not None: + dmc: ast.MatchCase | t.CPtr = ( + ast.MatchCase | t.CPtr)(dcase) + HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH) + dbody: list[ast.AST | t.CPtr] | t.CPtr = dmc.children + if dbody is not None: + dn: t.CSizeT = dbody.__len__() + dj: int = 0 + while dj < dn: + stmt: ast.AST | t.CPtr = dbody.get(dj) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + dj = dj + 1 + HandlesVar.exit_scope(trans.SymTab) + break + di = di + 1 + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, end_bb) + + # 9. 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + return 0 + + # ============================================================ + # _bind_variant_fields - 绑定 MatchClass 的变体字段 + # + # case LLVMType.Ptr(pointee) 中的 pointee 绑定到 subject 的 payload 字段 + # ============================================================ + def _bind_variant_fields(self, pat: ast.AST | t.CPtr, + renum_name: str, + renum_entry: HandlesStruct.StructEntry | t.CPtr, + renum_ty: llvmlite.LLVMType | t.CPtr, + subject_ptr: llvmlite.Value | t.CPtr, + trans: HT.Translator | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr): + if pat is None or renum_entry is None or renum_ty is None: + return + mc: ast.MatchClass | t.CPtr = (ast.MatchClass | t.CPtr)(pat) + pats: list[ast.AST | t.CPtr] | t.CPtr = mc.patterns + if pats is None: + return + # bitcast subject_ptr 到 renum_ptr_ty(确保 GEP 类型匹配) + renum_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, renum_ty) + casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, subject_ptr, renum_ptr_ty) + if casted_ptr is None: + casted_ptr = subject_ptr + pn: t.CSizeT = pats.__len__() + j: int = 0 + while j < pn: + sub_pat: ast.AST | t.CPtr = pats.get(j) + if sub_pat is not None: + if sub_pat.kind() == ast.ASTKind.MatchAs: + ma: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(sub_pat) + bind_name: str = ma.name + if bind_name is not None: + # 按位置绑定:MatchClass 第 j 个参数 → payload 索引 j+1 + # 对应 TPC HandlesMatch.py:305-306(不依赖字段名大小写匹配) + payload_idx: int = j + 1 + # 字段名查找作为回退(若字段名与 MatchAs 名一致可直接命中) + if payload_idx >= renum_entry.FieldCount: + alt_idx: int = HandlesClassDef._lookup_renum_field_alias( + renum_name, bind_name) + if alt_idx >= 1: + payload_idx = alt_idx + else: + j = j + 1 + continue + # 获取字段类型 + fe: HandlesStruct.FieldEntry | t.CPtr = ( + HandlesStruct._get_field_entry( + renum_entry, payload_idx)) + field_ty: llvmlite.LLVMType | t.CPtr = None + if fe is not None: + field_ty = fe.Ty + if field_ty is None: + field_ty = llvmlite.Int8(pool) + # GEP 取字段地址 + elem_ptr: llvmlite.Value | t.CPtr = ( + llvmlite.build_gep_struct( + builder, renum_ty, field_ty, + casted_ptr, payload_idx)) + if elem_ptr is not None: + HandlesVar.define_var( + trans.SymTab, bind_name, elem_ptr) + j = j + 1 + + # ============================================================ + # _handle_simple_match - 非 REnum 路径 + # + # subject ptrtoint 到 i32 + switch 分派 + # ============================================================ + def _handle_simple_match(self, node: ast.Match | t.CPtr, + subject_val: llvmlite.Value | t.CPtr) -> int: + trans: HT.Translator | t.CPtr = self.Trans + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + stdio.printf("[MATCHDBG] _handle_simple_match entry\n") + + # 1. subject 转 i32(若已 i32 直接用,否则 ptrtoint) + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + subj_bits: int = HandlesExpr.get_llvm_type_bits(subject_val.Ty) + subj_val: llvmlite.Value | t.CPtr = subject_val + if subj_bits != 32: + if HandlesExpr.is_ptr_type(subject_val.Ty) != 0: + subj_val = llvmlite.build_ptrtoint(builder, subject_val, i32_ty) + elif subj_bits > 32: + # trunc 到 i32 + subj_val = llvmlite.build_trunc(builder, subject_val, i32_ty) + elif subj_bits == 0: + # 未知类型,尝试 ptrtoint + subj_val = llvmlite.build_ptrtoint(builder, subject_val, i32_ty) + if subj_val is None: + return 0 + + # 2. 创建 default/end BB + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + name_buf: t.CChar | t.CPtr = pool.alloc(32) + if name_buf is None: + return 0 + viperlib.snprintf(name_buf, 32, "match.default.%d", cnt) + default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "match.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + + # 3. 收集 case 信息 + cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases + if cases_list is None: + return 0 + case_count: t.CSizeT = cases_list.__len__() + + bb_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) + cv_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) + def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) + nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) + if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None: + return 0 + + collected: int = 0 + has_default: int = 0 + sw_head: llvmlite.SwitchCase | t.CPtr = None + sw_tail: llvmlite.SwitchCase | t.CPtr = None + sw_count: int = 0 + + # 4. 第一遍:收集 + 创建 BB + 构建链表 + i: int = 0 + while i < case_count: + case_node: ast.AST | t.CPtr = cases_list.get(i) + if case_node is None: + i = i + 1 + continue + if case_node.kind() != ast.ASTKind.MatchCase: + i = i + 1 + continue + mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node) + pat: ast.AST | t.CPtr = mc.pattern + + is_def: int = 0 + cv: llvmlite.Value | t.CPtr = None + + if pat is not None: + pk: int = pat.kind() + if pk == ast.ASTKind.MatchValue: + mv: ast.MatchValue | t.CPtr = (ast.MatchValue | t.CPtr)(pat) + cv = HandlesExpr.translate_value( + builder, pool, trans.Module, mv.value, + trans._funcs, trans._func_count, trans) + elif pk == ast.ASTKind.MatchSingleton: + ms: ast.MatchSingleton | t.CPtr = ( + ast.MatchSingleton | t.CPtr)(pat) + # None -> 0 + cv = llvmlite.const_int32(pool, 0) + elif pk == ast.ASTKind.MatchAs: + ma: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(pat) + if ma.pattern is None: + is_def = 1 + has_default = 1 + elif pk == ast.ASTKind.MatchOr: + mo: ast.MatchOr | t.CPtr = (ast.MatchOr | t.CPtr)(pat) + pats: list[ast.AST | t.CPtr] | t.CPtr = mo.patterns + if pats is not None and pats.__len__() > 0: + first_pat: ast.AST | t.CPtr = pats.get(0) + if first_pat is not None: + if first_pat.kind() == ast.ASTKind.MatchValue: + mv2: ast.MatchValue | t.CPtr = ( + ast.MatchValue | t.CPtr)(first_pat) + cv = HandlesExpr.translate_value( + builder, pool, trans.Module, mv2.value, + trans._funcs, trans._func_count, trans) + + if is_def == 0: + if collected >= MAX_MATCH_CASES: + break + viperlib.snprintf(name_buf, 32, "match.case.%d.%d", cnt, i) + bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + else: + bb = default_bb + + body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children + nb: int = self._has_no_break(body_list) + + if collected < MAX_MATCH_CASES: + bb_arr[collected] = t.CSizeT(bb) + cv_arr[collected] = t.CSizeT(cv) + def_arr[collected] = is_def + nb_arr[collected] = nb + collected = collected + 1 + + if is_def == 0 and cv is not None: + sc: llvmlite.SwitchCase | t.CPtr = llvmlite.new_switch_case( + pool, cv, bb) + if sc is not None: + if sw_head is None: + sw_head = sc + sw_tail = sc + else: + sw_tail.Next = sc + sw_tail = sc + sw_count = sw_count + 1 + + i = i + 1 + + # 5. 发射 switch + llvmlite.build_switch(builder, subj_val, default_bb, sw_head, sw_count) + + # 6. 第二遍:翻译 case body + i = 0 + while i < collected: + case_node: ast.AST | t.CPtr = cases_list.get(i) + if case_node is None: + i = i + 1 + continue + mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node) + + bb_addr: t.CSizeT = bb_arr[i] + case_bb: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)(t.CVoid(bb_addr, t.CPtr)) + is_def: int = def_arr[i] + nb: int = nb_arr[i] + + # default case 的 body 在 step 7 单独翻译,这里跳过避免重复 + if is_def == 1: + i = i + 1 + continue + + llvmlite.position_at_end(builder, case_bb) + + HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH) + + body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children + if body_list is not None: + bc: t.CSizeT = body_list.__len__() + bi: int = 0 + while bi < bc: + stmt: ast.AST | t.CPtr = body_list.get(bi) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + bi = bi + 1 + + HandlesVar.exit_scope(trans.SymTab) + + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + if nb == 0: + llvmlite.build_br(builder, end_bb) + + i = i + 1 + + # 7. default 块 + llvmlite.position_at_end(builder, default_bb) + if has_default == 0: + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, end_bb) + else: + di: int = 0 + while di < collected: + if def_arr[di] == 1: + dcase: ast.AST | t.CPtr = cases_list.get(di) + if dcase is not None: + dmc: ast.MatchCase | t.CPtr = ( + ast.MatchCase | t.CPtr)(dcase) + HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH) + dbody: list[ast.AST | t.CPtr] | t.CPtr = dmc.children + if dbody is not None: + dn: t.CSizeT = dbody.__len__() + dj: int = 0 + while dj < dn: + stmt: ast.AST | t.CPtr = dbody.get(dj) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + dj = dj + 1 + HandlesVar.exit_scope(trans.SymTab) + break + di = di + 1 + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, end_bb) + + # 8. 定位到 end + llvmlite.position_at_end(builder, end_bb) + return 0 + + +# ============================================================ +# NewMatchHandle - 工厂函数 +# ============================================================ +def NewMatchHandle(pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr) -> MatchHandle | t.CPtr: + h: MatchHandle | t.CPtr = pool.alloc(MatchHandle.__sizeof__()) + if h is None: + return None + string.memset(h, 0, MatchHandle.__sizeof__()) + h.Trans = trans + return h diff --git a/App/lib/core/Handles/HandlesNonlocal.vp b/App/lib/core/Handles/HandlesNonlocal.vp index 6922f7e..1645058 100644 --- a/App/lib/core/Handles/HandlesNonlocal.vp +++ b/App/lib/core/Handles/HandlesNonlocal.vp @@ -5,6 +5,7 @@ import llvmlite import memhub import string import stdio +import lib.core.VLogger as VLogger import lib.core.Handles.HandlesTranslator as HT import lib.core.Handles.HandlesVar as HandlesVar @@ -13,7 +14,8 @@ import lib.core.Handles.HandlesVar as HandlesVar # HandlesNonlocal - nonlocal 变量访问(通过闭包 env) # # 闭包 env 结构: {i8* ptr0, i8* ptr1, ...} (每个 nonlocal 变量一个 i8* 指针) -# 指针指向原始变量(可能是 alloca 或全局变量) +# 指针指向父函数中变量的 alloca(原始存储位置),父与子共享同一存储, +# 子函数修改对父函数可见(符合 Python nonlocal 语义)。 # # 在提升的嵌套函数中: # 1. 函数签名: define i32 @__closure_{name}(i8* %env) @@ -23,12 +25,32 @@ import lib.core.Handles.HandlesVar as HandlesVar # b. %addr = gep i8, i8* %env_ptr, i32 (index * 8) # c. %ptr_addr = bitcast i8* %addr to i8** # d. %var_ptr_raw = load i8*, i8** %ptr_addr -# e. %var_ptr = bitcast i8* %var_ptr_raw to i32* -# f. read: %val = load i32, i32* %var_ptr -# write: store i32 %new, i32* %var_ptr +# e. %var_ptr = bitcast i8* %var_ptr_raw to * +# f. read: %val = load , * %var_ptr +# write: store %new, * %var_ptr +# +# 变量类型通过 HT.get_nonlocal_type() 获取(注册 nonlocal 时记录)。 # ============================================================ +# ============================================================ +# _is_void_type — 判断是否为 Void 类型(非法用作变量类型) +# +# 由于某些路径(如 c.DerefAs 设置的 Pointee 字段访问异常)可能导致 +# 类型被设为 Void 而非 None,这里显式检测 Void 类型并视为无效, +# 回退为 i32,避免生成 "bitcast ... to void*" / "load void, void*" 的非法 IR。 +# ============================================================ +def _is_void_type(ty: llvmlite.LLVMType | t.CPtr) -> int: + """判断是否为 Void 类型,是则返回 1,否则 0""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Void(): + return 1 + case _: + return 0 + + # ============================================================ # 获取或创建 _env_ptr 变量(存储 env 参数的 alloca) # ============================================================ @@ -51,13 +73,16 @@ def get_env_ptr_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: # ============================================================ -# 加载 nonlocal 变量值 → 返回 i32 Value +# 从 env 加载原始变量指针(i8*)→ 调用方 bitcast 为具体类型 # -# env 直接存储 i32 值(不是指针),每个 nonlocal 变量占 4 字节 +# env 存储指针数组(8 字节/槽),每个指针指向父函数的 alloca。 # ============================================================ -def load_nonlocal_var(trans: HT.Translator | t.CPtr, +def _load_raw_var_ptr(trans: HT.Translator | t.CPtr, name: str) -> llvmlite.Value | t.CPtr: - """从闭包 env 加载 nonlocal 变量值(env 直接存储 i32 值)""" + """从闭包 env 加载 nonlocal 变量的原始指针(i8*) + + 返回 i8* 类型的 Value,调用方需 bitcast 为具体类型指针后 load/store。 + """ idx: int = HT.get_nonlocal_index(trans, name) if idx < 0: return None @@ -66,8 +91,7 @@ def load_nonlocal_var(trans: HT.Translator | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder 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) - i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty) + i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) # 1. 加载 env_ptr env_alloca: llvmlite.Value | t.CPtr = get_env_ptr_var(trans) @@ -77,51 +101,75 @@ def load_nonlocal_var(trans: HT.Translator | t.CPtr, if env_ptr is None: return None - # 2. GEP to offset (idx * 4) — env 直接存储 i32 值 - offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 4) + # 2. GEP to offset (idx * 8) — env 存储指针数组,每槽 8 字节 + offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 8) addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val) if addr is None: return None - # 3. Bitcast to i32* and load - var_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, addr, i32_ptr_ty) + # 3. Bitcast to i8** and load the raw pointer + ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, addr, i8_ptr_ptr_ty) + if ptr_addr is None: + return None + return llvmlite.build_load(builder, i8_ptr_ty, ptr_addr) + + +# ============================================================ +# 加载 nonlocal 变量值 → 返回具体类型的 Value +# +# env 存储指向父函数 alloca 的指针,通过类型恢复 load 正确类型的值。 +# ============================================================ +def load_nonlocal_var(trans: HT.Translator | t.CPtr, + name: str) -> llvmlite.Value | t.CPtr: + """从闭包 env 加载 nonlocal 变量值 + + 通过 HT.get_nonlocal_type 获取变量类型,bitcast 原始指针后 load。 + """ + raw_ptr: llvmlite.Value | t.CPtr = _load_raw_var_ptr(trans, name) + if raw_ptr is None: + return None + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + + # 获取变量类型(从注册时存储的类型信息) + var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name) + if var_ty is None or _is_void_type(var_ty) != 0: + # Void 类型视为无效(会导致 "load void, void*" 非法 IR),回退为 i32 + var_ty = llvmlite.Int32(pool) + + # bitcast raw i8* to var_ty* + var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty) + var_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty) if var_ptr is None: return None - return llvmlite.build_load(builder, i32_ty, var_ptr) + return llvmlite.build_load(builder, var_ty, var_ptr) # ============================================================ # 获取 nonlocal 变量指针(用于 store) # -# 返回 env 中 i32 槽位的地址(i32*),用于直接 store +# 返回具体类型指针(var_ty*),用于直接 store。 # ============================================================ def get_nonlocal_var_ptr(trans: HT.Translator | t.CPtr, name: str) -> llvmlite.Value | t.CPtr: - """获取 nonlocal 变量在 env 中的地址(i32*),用于 store 操作""" - idx: int = HT.get_nonlocal_index(trans, name) - if idx < 0: + """获取 nonlocal 变量的存储指针(var_ty*),用于 store 操作 + + 返回的指针指向父函数的 alloca,store 操作对父函数可见。 + """ + raw_ptr: llvmlite.Value | t.CPtr = _load_raw_var_ptr(trans, name) + if raw_ptr is None: return None pool: memhub.MemBuddy | t.CPtr = trans.Pool builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - 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) - i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty) - # 1. 加载 env_ptr - env_alloca: llvmlite.Value | t.CPtr = get_env_ptr_var(trans) - if env_alloca is None: - return None - env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_alloca) - if env_ptr is None: - return None + # 获取变量类型 + var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name) + if var_ty is None or _is_void_type(var_ty) != 0: + # Void 类型视为无效(会导致 "bitcast ... to void*" 非法 IR),回退为 i32 + var_ty = llvmlite.Int32(pool) - # 2. GEP to offset (idx * 4) — env 直接存储 i32 值 - offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 4) - addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val) - if addr is None: - return None - - # 3. Bitcast to i32* and return (直接指向 env 中的 i32 槽位) - return llvmlite.build_bitcast(builder, addr, i32_ptr_ty) + # bitcast raw i8* to var_ty* + var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty) + return llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty) diff --git a/App/lib/core/Handles/HandlesReturn.vp b/App/lib/core/Handles/HandlesReturn.vp index 8669cdf..cde6062 100644 --- a/App/lib/core/Handles/HandlesReturn.vp +++ b/App/lib/core/Handles/HandlesReturn.vp @@ -105,12 +105,12 @@ class ReturnHandle(HandlesBase.Mixin): ret_is_ptr: int = HandlesExpr.is_ptr_type(ret_ty_rt) # ptr 类型不一致性:val 是整数但 ret 是 ptr(或反之),必须转换 if val_is_ptr != ret_is_ptr: - val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt) + val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt, node) elif val_bits != 0 and ret_bits != 0 and val_bits != ret_bits: if val_bits == 1 and val_bits < ret_bits: val = llvmlite.build_zext(builder, val, ret_ty_rt) else: - val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt) + val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt, node) llvmlite.build_ret(builder, val) return 0 diff --git a/App/lib/core/Handles/HandlesStruct.vp b/App/lib/core/Handles/HandlesStruct.vp index 6611138..0550934 100644 --- a/App/lib/core/Handles/HandlesStruct.vp +++ b/App/lib/core/Handles/HandlesStruct.vp @@ -57,6 +57,7 @@ class StructEntry: VTableMethodCount: int # 虚表中的方法数量 VTableMethods: t.CChar | t.CPtr # 虚表方法名数组(每个方法名 str,VTableMethodCount 个) ModuleSha1: t.CChar | t.CPtr # 定义该类的模块 SHA1(None=无 SHA1) + MethodsEmitted: int # 1=方法体已翻译 / 0=未译(Phase 1a mark_only 未译,Phase B 据此补译) # ============================================================ @@ -134,8 +135,7 @@ def is_struct_visible(name: str) -> int: # ============================================================ def init_struct_table(pool: memhub.MemBuddy | t.CPtr) -> int: """初始化结构体注册表,返回 1 成功""" - global _struct_table - global _struct_count + global _struct_table, _struct_count if _struct_table is not None: return 1 @@ -182,6 +182,7 @@ def register_struct(pool: memhub.MemBuddy | t.CPtr, name: str, struct_ty: llvmlite.LLVMType | t.CPtr, sha1: str = None) -> StructEntry | t.CPtr: + global _struct_count """注册结构体类型,返回 StructEntry 指针 用类型指针去重(is 比较),不用类名去重。 diff --git a/App/lib/core/Handles/HandlesTranslator.vp b/App/lib/core/Handles/HandlesTranslator.vp index 2b7d100..bc8cfc7 100644 --- a/App/lib/core/Handles/HandlesTranslator.vp +++ b/App/lib/core/Handles/HandlesTranslator.vp @@ -19,8 +19,10 @@ import lib.core.Handles.HandlesAugAssign as HandlesAugAssign import lib.core.Handles.HandlesIf as HandlesIf import lib.core.Handles.HandlesWhile as HandlesWhile import lib.core.Handles.HandlesFor as HandlesFor +import lib.core.Handles.HandlesMatch as HandlesMatch import lib.core.Handles.HandlesExpr as HandlesExpr import lib.core.Handles.HandlesFunctions as HandlesFunctions +import lib.core.Handles.HandlesType as HandlesType import lib.Projectrans.Config as Config # ============================================================ @@ -79,10 +81,19 @@ class Translator: # nonlocal 声明的变量名集合(当前函数内) _nonlocal_names: str _nonlocal_name_count: t.CInt + # nonlocal 变量的类型信息(LLVMType 指针数组,与 _nonlocal_names 一一对应) + # 用于 env 指针数组方案:子函数访问 nonlocal 变量时需要知道原始类型 + _nonlocal_types: str # 闭包相关:当前函数名(用于嵌套函数提升命名) _cur_func_name: str + # *args 变长参数支持:当前函数的 va_list 指针(i8* alloca) + # 仅当函数声明了 *args 时设置,供 arg(type) 糖函数使用 + _va_list_ptr: llvmlite.Value | t.CPtr + # *args 参数名(如 "args"),用于符号表注册 + _vararg_name: str + # 模块 SHA1 前缀(16 字符),用于函数名混淆(SHA1 命名空间) ModuleSha1: str # 当前文件所属包名(如 "llvmlite"),用于解析相对导入(from . import ...) @@ -112,6 +123,7 @@ class Translator: ForH: HandlesFor.ForHandle | t.CPtr ExprH: HandlesExpr.ExprHandle | t.CPtr ExprCallH: HandlesExprCall.ExprCallHandle | t.CPtr + MatchH: HandlesMatch.MatchHandle | t.CPtr # 嵌套作用域符号表 SymTab: HandlesVar.SymbolTable | t.CPtr @@ -132,7 +144,10 @@ class Translator: self._global_name_count = 0 self._nonlocal_names = None self._nonlocal_name_count = 0 + self._nonlocal_types = None self._cur_func_name = None + self._va_list_ptr = None + self._vararg_name = None self.ModuleSha1 = None self.CurrentPackage = None self._closure_env_offsets = 0 @@ -150,6 +165,7 @@ class Translator: self.ForH = None self.ExprH = None self.ExprCallH = None + self.MatchH = None self.SymTab = None # ============================================================ @@ -174,6 +190,11 @@ class Translator: if self._nonlocal_names is not None: string.memset(self._nonlocal_names, 0, MAX_GLOBAL_NAMES * 8) self._nonlocal_name_count = 0 + # nonlocal 变量类型数组(LLVMType 指针数组,与 _nonlocal_names 一一对应) + if self._nonlocal_types is None: + self._nonlocal_types = stdlib.malloc(MAX_GLOBAL_NAMES * 8) + if self._nonlocal_types is not None: + string.memset(self._nonlocal_types, 0, MAX_GLOBAL_NAMES * 8) # 创建子 Handle(传入 self 作为 Mixin 回指针) if self.AssignH is None: self.AssignH = HandlesAssign.NewAssignHandle(pool, self) @@ -191,6 +212,8 @@ class Translator: self.WhileH = HandlesWhile.NewWhileHandle(pool, self) if self.ForH is None: self.ForH = HandlesFor.NewForHandle(pool, self) + if self.MatchH is None: + self.MatchH = HandlesMatch.NewMatchHandle(pool, self) if self.ExprH is None: self.ExprH = HandlesExpr.NewExprHandle(pool, self) if self.ExprCallH is None: @@ -238,6 +261,19 @@ class Translator: llvmlite.add_param(pool, printf_func, i8_ptr_ty, "fmt") printf_func.IsVarArg = 1 + # 声明 LLVM va_start/va_end intrinsic(供 *args 函数体内使用) + # declare void @llvm.va_start(i8*) + # declare void @llvm.va_end(i8*) + void_ty_decl: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + va_start_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, "llvm.va_start", void_ty_decl) + if va_start_func is not None: + llvmlite.add_param(pool, va_start_func, i8_ptr_ty, "ap") + va_end_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, "llvm.va_end", void_ty_decl) + if va_end_func is not None: + llvmlite.add_param(pool, va_end_func, i8_ptr_ty, "ap") + # 声明 malloc(闭包分配用) malloc_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( pool, mod, "malloc", i8_ptr_ty) @@ -307,6 +343,17 @@ class Translator: elif kd == ast.ASTKind.ImportFrom: self.ImportsH.HandleImportFromModule(child) self.ImportsH.HandleImportFromNames(child) + # 扫描当前模块的 CTypedef 声明(NAME: t.CTypedef = Type), + # 注册到动态 CTypedef 表,供 resolve_annotation_type 查询 + HandlesType.ScanCTypedefDeclarations(pool, tree) + # 跨模块 .vpi 注入:加载依赖模块的 .vpi 文件, + # 将函数 declare 声明注入到当前模块,解决跨模块函数调用找不到函数的问题 + # 严格保证 declare_only == 0 时才注入(避免 Phase A-pre-inc 死锁) + if self._imported_modules is not None: + import lib.core.StubMerger as StubMerger + StubMerger.LoadDepVpiIntoModule( + pool, mod, self._imported_modules, self._from_imports, + HandlesExprCall._g_temp_dir, self) # 预注册模块级变量(AnnAssign/Assign)到 SymTab # 解决时序问题:class Logger 的 __init__ 引用 _mbuddy 时, # _mbuddy 的 AnnAssign 在 AST 中位于 class Logger 之后, @@ -349,13 +396,22 @@ def add_global_name(trans: HT.Translator | t.CPtr, name: str): """添加一个 global 变量名""" if trans is None or name is None: return - if trans._global_name_count >= MAX_GLOBAL_NAMES: - return if trans._global_names is None: return # 检查是否已存在 if is_global_name(trans, name) != 0: return + if trans._global_name_count >= MAX_GLOBAL_NAMES: + pool_err: memhub.MemBuddy | t.CPtr = trans.Pool + err_buf: str = None + if pool_err is not None: + err_buf = pool_err.alloc(256) + if err_buf is not None: + viperlib.snprintf(err_buf, 256, "global 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 global 声明或增大 MAX_GLOBAL_NAMES", MAX_GLOBAL_NAMES) + VLogger.error(err_buf, "ScopeDecl") + else: + VLogger.error("global 变量数量超过上限,请减少 global 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl") + return entry_addr: t.CUInt64T = t.CUInt64T(trans._global_names) + trans._global_name_count * 8 slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr) slot_ptr[0] = name @@ -376,23 +432,76 @@ def is_global_name(trans: HT.Translator | t.CPtr, name: str) -> int: return 0 -def add_nonlocal_name(trans: HT.Translator | t.CPtr, name: str): - """添加一个 nonlocal 变量名""" +def add_nonlocal_name(trans: HT.Translator | t.CPtr, name: str, + var_ty: llvmlite.LLVMType | t.CPtr = None): + """添加一个 nonlocal 变量名 + + Args: + name: nonlocal 变量名 + var_ty: 变量的 LLVM 类型(用于 env 指针数组方案的类型恢复, + None 时回退为 i32) + """ if trans is None or name is None: return - if trans._nonlocal_name_count >= MAX_GLOBAL_NAMES: - return if trans._nonlocal_names is None: return if is_nonlocal_name(trans, name) != 0: + # 已存在:更新类型信息(可能在预扫描时类型未知,正式翻译时更新) + # _nonlocal_types 每槽 8 字节,存 LLVMType* 指针。 + # 用 str|t.CPtr (i8**) 二级指针存取(与 _nonlocal_names 模式一致), + # [0] 解引用只拷贝 8 字节指针,避免值拷贝 24+ 字节 LLVMType 结构体溢出。 + if var_ty is not None and trans._nonlocal_types is not None: + idx: int = get_nonlocal_index(trans, name) + if idx >= 0: + ty_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + idx * 8 + ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr) + ty_slot[0] = var_ty + return + if trans._nonlocal_name_count >= MAX_GLOBAL_NAMES: + pool_err_nl: memhub.MemBuddy | t.CPtr = trans.Pool + err_buf_nl: str = None + if pool_err_nl is not None: + err_buf_nl = pool_err_nl.alloc(256) + if err_buf_nl is not None: + viperlib.snprintf(err_buf_nl, 256, "nonlocal 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", MAX_GLOBAL_NAMES) + VLogger.error(err_buf_nl, "ScopeDecl") + else: + VLogger.error("nonlocal 变量数量超过上限,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl") return entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + trans._nonlocal_name_count * 8 slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr) slot_ptr[0] = name + # 存储类型信息(用 str|t.CPtr = i8** 二级指针,与 _nonlocal_names 一致) + if trans._nonlocal_types is not None: + ty_addr2: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + trans._nonlocal_name_count * 8 + ty_slot2: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr2) + # var_ty 为 None 时存入 i32 作为默认类型 + stored_ty: llvmlite.LLVMType | t.CPtr = var_ty + if stored_ty is None: + pool: memhub.MemBuddy | t.CPtr = trans.Pool + if pool is not None: + stored_ty = llvmlite.Int32(pool) + ty_slot2[0] = stored_ty trans._nonlocal_name_count += 1 trans._closure_env_count += 1 +def get_nonlocal_type(trans: HT.Translator | t.CPtr, + name: str) -> llvmlite.LLVMType | t.CPtr: + """获取 nonlocal 变量的 LLVM 类型 + + Returns: 找到的类型指针,找不到返回 None + """ + if trans is None or name is None or trans._nonlocal_types is None: + return None + idx: int = get_nonlocal_index(trans, name) + if idx < 0: + return None + ty_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + idx * 8 + ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr) + return (llvmlite.LLVMType | t.CPtr)(ty_slot[0]) + + def is_nonlocal_name(trans: HT.Translator | t.CPtr, name: str) -> int: """检查 name 是否在当前函数的 nonlocal 集合中""" if trans is None or name is None or trans._nonlocal_names is None: diff --git a/App/lib/core/Handles/HandlesType.vp b/App/lib/core/Handles/HandlesType.vp index 3b85855..5ac5344 100644 --- a/App/lib/core/Handles/HandlesType.vp +++ b/App/lib/core/Handles/HandlesType.vp @@ -73,6 +73,7 @@ def _get_trace_frame(i: int) -> TraceFrame | t.CPtr: def push_trace(file_name: str, lineno: int, col_start: int = 0, col_end: int = 0): """压入一个翻译上下文帧(进入新的翻译作用域时调用)""" + global _g_trace_count if _ensure_trace_init() == 0: return if _g_trace_count >= TRACE_MAX: @@ -89,6 +90,7 @@ def push_trace(file_name: str, lineno: int, col_start: int = 0, col_end: int = 0 def pop_trace(): """弹出栈顶帧(退出翻译作用域时调用)""" + global _g_trace_count if _g_trace_count <= 0: return _g_trace_count -= 1 @@ -231,6 +233,208 @@ def clear_cdefine_constants() -> None: _g_cdefine_values = None +# ============================================================ +# 动态 CTypedef 表 +# +# 存储 NAME: t.CTypedef = Type 定义的类型别名, +# 供 resolve_annotation_type 动态解析用户自定义 CTypedef。 +# 每个模块翻译开始时由 clear_ctypedefs 清空(模块级隔离)。 +# 与 CDefine 表类似,但存储类型表达式字符串而非整数。 +# ============================================================ +_g_ctypedef_names: list[str] | t.CPtr = None +_g_ctypedef_type_strs: list[str] | t.CPtr = None + +# CTypedef 查找结果标志(区分"未找到"和"值为空字符串") +_g_ctypedef_found: int = 0 + +# CTypedef 递归解析深度计数器(防止无限递归) +_g_ctypedef_resolve_depth: int = 0 + +# CTypedef 递归解析最大深度 +MAX_CTYPEDEF_DEPTH: t.CDefine = 10 + +# CTypedef 循环检测已访问列表(存储正在解析的 CTypedef 名) +_g_ctypedef_visiting: list[str] | t.CPtr = None + + +def register_ctypedef(pool: memhub.MemBuddy | t.CPtr, + name: str, type_str: str) -> None: + """注册 CTypedef 到本地表 + + Args: + pool: 内存池 + name: CTypedef 名称(如 "HANDLE") + type_str: 类型表达式字符串(如 "VOIDPTR" 或 "t.CVoid | t.CPtr") + """ + global _g_ctypedef_names, _g_ctypedef_type_strs + if name is None or type_str is None or pool is None: + return + if _g_ctypedef_names is None: + _g_ctypedef_names = list[str](pool, 64) + _g_ctypedef_type_strs = list[str](pool, 64) + # 去重:若已存在同名 CTypedef,更新其类型字符串 + if _g_ctypedef_names is not None: + exist_n: t.CSizeT = _g_ctypedef_names.__len__() + ei: t.CSizeT + for ei in range(exist_n): + en: str = _g_ctypedef_names.get(ei) + if en is not None and string.strcmp(en, name) == 0: + # 已存在,更新类型字符串 + _g_ctypedef_type_strs.set(ei, type_str) + return + _g_ctypedef_names.append(name) + _g_ctypedef_type_strs.append(type_str) + + +def lookup_ctypedef(name: str) -> str: + """查找 CTypedef,返回类型表达式字符串 + + 返回找到的类型表达式字符串,未找到返回 None。 + 调用方应在调用后检查 _g_ctypedef_found 标志区分"未找到"和"空字符串"。 + """ + global _g_ctypedef_found + _g_ctypedef_found = 0 + if name is None: + return None + if _g_ctypedef_names is None: + return None + n: t.CSizeT = _g_ctypedef_names.__len__() + i: t.CSizeT + for i in range(n): + nm: str = _g_ctypedef_names.get(i) + if nm is not None and string.strcmp(nm, name) == 0: + ts: str = _g_ctypedef_type_strs.get(i) + _g_ctypedef_found = 1 + return ts + return None + + +def is_ctypedef_found() -> int: + """检查上次 lookup_ctypedef 是否找到值""" + return _g_ctypedef_found + + +def clear_ctypedefs() -> None: + """清空 CTypedef 表(模块切换时调用)""" + global _g_ctypedef_names, _g_ctypedef_type_strs + global _g_ctypedef_resolve_depth, _g_ctypedef_visiting + _g_ctypedef_names = None + _g_ctypedef_type_strs = None + _g_ctypedef_resolve_depth = 0 + _g_ctypedef_visiting = None + + +def _ctypedef_push_visiting(pool: memhub.MemBuddy | t.CPtr, name: str) -> int: + """将 CTypedef 名加入正在解析列表(循环检测) + + Returns: + 0=成功加入(无循环),1=检测到循环 + """ + global _g_ctypedef_visiting + if name is None: + return 0 + if _g_ctypedef_visiting is None: + _g_ctypedef_visiting = list[str](pool, 32) + if _g_ctypedef_visiting is None: + return 0 + vn: t.CSizeT = _g_ctypedef_visiting.__len__() + vi: t.CSizeT + for vi in range(vn): + vs: str = _g_ctypedef_visiting.get(vi) + if vs is not None and string.strcmp(vs, name) == 0: + return 1 # 循环检测 + _g_ctypedef_visiting.append(name) + return 0 + + +def _ctypedef_pop_visiting() -> None: + """从正在解析列表弹出最后一个 CTypedef 名""" + global _g_ctypedef_visiting + if _g_ctypedef_visiting is None: + return + vn: t.CSizeT = _g_ctypedef_visiting.__len__() + if vn > 0: + _g_ctypedef_visiting.pop() + + +def _is_ctypedef_annotation(annotation: ast.AST | t.CPtr) -> int: + """检测类型注解是否为 t.CTypedef + + Args: + annotation: 类型注解 AST 节点 + + Returns: + 1=是 t.CTypedef,0=否 + """ + if annotation is None: + return 0 + if annotation.kind() != ast.ASTKind.Attribute: + return 0 + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annotation) + if at.attr is None: + return 0 + if string.strcmp(at.attr, "CTypedef") != 0: + return 0 + if at.value is None or at.value.kind() != ast.ASTKind.Name: + return 0 + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if mod_nm.id is None: + return 0 + if string.strcmp(mod_nm.id, "t") != 0: + return 0 + return 1 + + +def ScanCTypedefDeclarations(pool: memhub.MemBuddy | t.CPtr, + tree: ast.AST | t.CPtr) -> int: + """扫描 AST 顶层节点,注册所有 NAME: t.CTypedef = Type 声明 + + 在 _translate_module_level 中、模块级变量预注册之前调用, + 确保 CTypedef 名称在类型解析时可用。 + + Args: + pool: 内存池 + tree: 模块 AST 根节点 + + Returns: + 注册的 CTypedef 数量 + """ + if pool is None or tree is None: + return 0 + ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children + if ch is None: + return 0 + n: t.CSizeT = ch.__len__() + count: int = 0 + i: t.CSizeT + for i in range(n): + child: ast.AST | t.CPtr = ch.get(i) + if child is None: + continue + if child.kind() != ast.ASTKind.AnnAssign: + continue + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(child) + # 检测注解是否为 t.CTypedef + if _is_ctypedef_annotation(aa.annotation) == 0: + continue + # 提取目标名称(必须是 Name 节点) + if aa.target is None or aa.target.kind() != ast.ASTKind.Name: + continue + tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) + if tgt.id is None: + continue + # 提取类型表达式字符串(从 value AST 节点) + if aa.value is None: + continue + type_str: str = _get_type_name_from_annotation(pool, aa.value) + if type_str is None: + continue + # 注册 CTypedef + register_ctypedef(pool, tgt.id, type_str) + count += 1 + return count + + # 常量整数表达式计算成功标志(供 _eval_const_int_expr 使用) _g_const_eval_ok: int = 0 @@ -1169,6 +1373,7 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr, if node is None: return None + global _g_ctypedef_resolve_depth k: int = node.kind() # Constant 节点: 字符串注解(如 'MemManager'),当作无引号的 Name/Attribute/BinOp 处理 @@ -1215,12 +1420,30 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr, struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(nm.id) if struct_ty is not None: return struct_ty - # from-import 名称: 查找 from_imports 获取模块名后映射 - mod_name: str = HandlesImports.lookup_from_import(from_imports, nm.id) - if mod_name is not None: - return map_t_type(pool, nm.id) + # CTypedef 动态查表:查动态 CTypedef 表,递归解析类型表达式 + # 用户自定义 CTypedef(如 MyHandle: t.CTypedef = VOIDPTR)在此解析 + # 递归深度限制 MAX_CTYPEDEF_DEPTH 防止无限递归,循环检测防止 A→B→A + if _g_ctypedef_resolve_depth < MAX_CTYPEDEF_DEPTH: + ctypedef_str: str = lookup_ctypedef(nm.id) + if ctypedef_str is not None and _g_ctypedef_found != 0: + # 循环检测:将当前 CTypedef 名加入正在解析列表 + if _ctypedef_push_visiting(pool, nm.id) == 0: + # 用 _parse_type_string 把类型字符串转回 AST,递归解析 + inner_node: ast.AST | t.CPtr = _parse_type_string(pool, ctypedef_str, nm.ctx) + if inner_node is not None: + _g_ctypedef_resolve_depth += 1 + inner_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type( + pool, inner_node, imported_modules, from_imports, trans) + _g_ctypedef_resolve_depth -= 1 + _ctypedef_pop_visiting() + if inner_ty is not None: + return inner_ty + else: + _ctypedef_pop_visiting() # 兜底: 尝试 map_t_type 中的硬编码 typedef 映射(VOIDPTR, HANDLE, ULONG 等) # 这些是跨模块通用的 C typedef 名,即使 from-import 查找失败也能解析 + # 注意:from-import 的结构体名若未注册,get_struct_type 已返回 None, + # 此处 map_t_type 对结构体名也返回 None,由上层 declare_only 机制延迟到下一遍 mapped_ty_fallback: llvmlite.LLVMType | t.CPtr = map_t_type(pool, nm.id) if mapped_ty_fallback is not None: return mapped_ty_fallback @@ -1357,6 +1580,16 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr, # 查找已特化的 struct(特化由实例化调用 list[int](pool) 触发) gen_spec_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(gen_mangled) if gen_spec_ty is not None: + # 治本修复:Phase B 补译泛型特化类方法体 + # Phase 1a(declare_only==1)特化时只注册结构体不译方法体(MethodsEmitted==0), + # Phase B(declare_only==0)解析字段类型命中已注册结构体时本会早返回, + # 导致方法体永远不生成 → GSList[Line].append 等符号只有 declare 无 define → 链接失败。 + # 此处 Phase B 且方法体未译时,调用 _specialize_generic_class 走其已注册分支补译方法体。 + if trans is not None and trans._declare_only == 0: + import lib.core.Handles.HandlesClassDef as HandlesClassDef + gen_spec_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(gen_mangled) + if gen_spec_entry is not None and gen_spec_entry.MethodsEmitted == 0: + HandlesClassDef._specialize_generic_class(trans, gen_nm.id, gen_arg_names) return gen_spec_ty # 未特化:尝试主动触发泛型特化(与 TPC _HandleSubscript 对齐) # 当 trans 可用时,检查是否是泛型模板并触发特化 diff --git a/App/lib/core/Handles/HandlesVar.vp b/App/lib/core/Handles/HandlesVar.vp index 719b587..5717df0 100644 --- a/App/lib/core/Handles/HandlesVar.vp +++ b/App/lib/core/Handles/HandlesVar.vp @@ -387,6 +387,28 @@ def lookup_module_var(symtab: SymbolTable | t.CPtr, return find_var(scope.Vars, scope.VarCount, name) +# ============================================================ +# is_module_scope - 判断当前是否在模块级作用域 +# +# 用于区分模块级代码和函数内代码: +# - 模块级代码:AnnAssign 应修改模块级变量(Python 语义) +# - 函数内代码:无 global 声明时 AnnAssign 应创建局部变量(Python 语义) +# ============================================================ +def is_module_scope(symtab: SymbolTable | t.CPtr) -> int: + """判断当前作用域是否为模块级作用域(Current == Root) + + Returns: 1=模块级作用域, 0=函数内作用域 + """ + if symtab is None: + return 0 + if symtab.Root is None or symtab.Current is None: + return 0 + # 比较指针:Current 与 Root 相同则为模块级 + if t.CUInt64T(symtab.Current) == t.CUInt64T(symtab.Root): + return 1 + return 0 + + # ============================================================ # get_or_create_sym — 查找或创建变量(在当前作用域) # ============================================================ diff --git a/App/lib/core/Phase1.vp b/App/lib/core/Phase1.vp index f22878e..9dc02ea 100644 --- a/App/lib/core/Phase1.vp +++ b/App/lib/core/Phase1.vp @@ -627,6 +627,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, HandlesType.set_current_file(file_path_a) HandlesType.set_current_module_sha1(sha1_a) HandlesType.clear_cdefine_constants() + HandlesType.clear_ctypedefs() HandlesStruct.reset_visible_structs(mb, 0) ret_a: int = tr_a.translate(tree_a) if ret_a != 0: @@ -828,6 +829,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, HandlesType.set_current_file(gen_path) HandlesType.set_current_module_sha1(gen_entry.Sha1) HandlesType.clear_cdefine_constants() + HandlesType.clear_ctypedefs() HandlesStruct.reset_visible_structs(mb, 0) gen_tr.translate(gen_tree) @@ -920,6 +922,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, HandlesType.set_current_file(file_path_r) HandlesType.set_current_module_sha1(sha1_r) HandlesType.clear_cdefine_constants() + HandlesType.clear_ctypedefs() HandlesStruct.reset_visible_structs(mb, 0) ret_r: int = tr_r.translate(tree_r) if ret_r != 0: @@ -1101,6 +1104,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, HandlesType.set_current_file(file_path) HandlesType.set_current_module_sha1(sha1) HandlesType.clear_cdefine_constants() + HandlesType.clear_ctypedefs() HandlesStruct.reset_visible_structs(mb, 0) ret: int = tr.translate(tree) if ret != 0: diff --git a/App/lib/core/Phase2.vp b/App/lib/core/Phase2.vp index 1ed8271..70d0909 100644 --- a/App/lib/core/Phase2.vp +++ b/App/lib/core/Phase2.vp @@ -383,7 +383,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, if string.strlen(ent.Path) > src_dir_len_pa + 1: rel_path_pa: str = ent.Path + src_dir_len_pa + 1 pkg_pa = HandlesImports.compute_package_from_relpath(mb, rel_path_pa) - tr_a: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent.Path, ent.Sha1, pkg_pa) + tr_a: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent.Path, ent.Sha1, pkg_pa, 0, temp_dir) if tr_a is None: continue diff --git a/App/lib/core/StubMerger.vp b/App/lib/core/StubMerger.vp index 5e3d170..e00095b 100644 --- a/App/lib/core/StubMerger.vp +++ b/App/lib/core/StubMerger.vp @@ -17,9 +17,21 @@ import lib.core.Handles.HandlesStruct as HandlesStruct import lib.core.Handles.HandlesImports as HandlesImports import lib.core.Handles.HandlesTranslator as HandlesTranslator import lib.core.BuildPipeline as BuildPipeline +import lib.StubGen.VpiReader as VpiReader import lib.Projectrans.Config as Config +# ============================================================ +# _ddebug_exit - DDEBUG 拦截退出辅助函数 +# +# 刷新 stderr 缓冲区并通过 VLogger 输出可见消息后退出。 +# 解决 sys.exit(1) 不刷新缓冲区导致 DDEBUG 消息丢失的问题。 +# ============================================================ +def _ddebug_exit() -> None: + stdio.fflush(stdio.stderr) + VLogger.error("DDEBUG intercept triggered - check stderr for details") + + # ============================================================ # StubMerger - stub 声明合并模块 # @@ -365,6 +377,11 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in global _sha1_store_arr, _sha1_store_mod, _sha1_store_rel, _sha1_store_count if scan_result is None: return -1 + # [DDEBUG] 诊断:入口输出扫描条目数 + fb_ps_in: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_ps_in is not None: + viperlib.snprintf(fb_ps_in, 1024, "PopulateSha1MapStore 入口: scan_result.Count=%d MAX_INCLUDES=%d", scan_result.Count, MAX_INCLUDES) + VLogger.warning(fb_ps_in, "Reachable") # 释放旧存储器 if _sha1_store_arr is not None: stdlib.free(_sha1_store_arr) @@ -382,21 +399,59 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in string.memset(_sha1_store_rel, 0, MAX_INCLUDES * MAX_REL_PATH_LEN) _sha1_store_count = 0 entry_size_p: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() + # [DDEBUG] 诊断:循环前输出 range 参数和 entry_size + fb_rng: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_rng is not None: + viperlib.snprintf(fb_rng, 1024, "PopulateSha1MapStore 循环前: scan_result.Count=%d entry_size_p=%d", scan_result.Count, entry_size_p) + VLogger.warning(fb_rng, "Reachable") for i in range(scan_result.Count): + if i == 0: + # [DDEBUG] 诊断:确认循环体是否执行 + fb_lp: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_lp is not None: + viperlib.snprintf(fb_lp, 1024, "PopulateSha1MapStore 进入循环体 i=0 (Count=%d)", scan_result.Count) + VLogger.warning(fb_lp, "Reachable") if _sha1_store_count >= MAX_INCLUDES: + # [DDEBUG] 诊断:break 触发 + fb_brk: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_brk is not None: + viperlib.snprintf(fb_brk, 1024, "PopulateSha1MapStore break: _sha1_store_count=%d >= MAX_INCLUDES=%d (i=%d)", _sha1_store_count, MAX_INCLUDES, i) + VLogger.warning(fb_brk, "Reachable") break ea: t.CUInt64T = t.CUInt64T(scan_result.Entries) + i * entry_size_p ent: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea, t.CPtr)) if ent is None or ent.Sha1 is None or ent.RelPath is None: + # [DDEBUG] 诊断:跳过原因 + fb_sk: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_sk is not None: + if ent is None: + viperlib.snprintf(fb_sk, 1024, "PopulateSha1MapStore 跳过[%d]: ent=None", i) + elif ent.Sha1 is None: + viperlib.snprintf(fb_sk, 1024, "PopulateSha1MapStore 跳过[%d]: Sha1=None", i) + else: + viperlib.snprintf(fb_sk, 1024, "PopulateSha1MapStore 跳过[%d]: RelPath=None", i) + VLogger.warning(fb_sk, "Reachable") continue # 构建完整路径 includes/{RelPath}(_PathToModuleName 需要) rp_len: t.CSizeT = string.strlen(ent.RelPath) full_path_buf: bytes = stdlib.malloc(rp_len + 10) if full_path_buf is None: + # [DDEBUG] 诊断:malloc 返回 None 判断 + if i < 3: + fb_fp: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_fp is not None: + viperlib.snprintf(fb_fp, 1024, "PopulateSha1MapStore 跳过[%d]: full_path_buf is None (rp_len=%d)", i, rp_len) + VLogger.warning(fb_fp, "Reachable") continue viperlib.snprintf(full_path_buf, rp_len + 10, "includes/%s", ent.RelPath) mod_name: str = _PathToModuleName(full_path_buf) stdlib.free(full_path_buf) + if mod_name is None: + # [DDEBUG] 诊断:_PathToModuleName 失败 + fb_pn: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_pn is not None: + viperlib.snprintf(fb_pn, 1024, "PopulateSha1MapStore 跳过[%d]: _PathToModuleName 返回 None (RelPath=%s)", i, ent.RelPath) + VLogger.warning(fb_pn, "Reachable") if mod_name is not None: idx: t.CSizeT = t.CSizeT(_sha1_store_count) * 17 string.strcpy(_sha1_store_arr + idx, ent.Sha1) @@ -416,6 +471,17 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in string.strncpy(_sha1_store_rel + idx3, ent.RelPath, MAX_REL_PATH_LEN - 1) _sha1_store_rel[idx3 + MAX_REL_PATH_LEN - 1] = '\0' _sha1_store_count += 1 + # [DDEBUG] 诊断:+= 后的 count(确认是否写入全局) + if i < 3: + fb_inc: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_inc is not None: + viperlib.snprintf(fb_inc, 1024, "PopulateSha1MapStore 填充[%d]: _sha1_store_count=%d", i, _sha1_store_count) + VLogger.warning(fb_inc, "Reachable") + # [DDEBUG] 诊断:出口输出最终计数 + fb_ps_out: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_ps_out is not None: + viperlib.snprintf(fb_ps_out, 1024, "PopulateSha1MapStore 出口: _sha1_store_count=%d", _sha1_store_count) + VLogger.warning(fb_ps_out, "Reachable") return _sha1_store_count @@ -526,6 +592,11 @@ def LookupSha1ByModName(mod_name: str) -> str: idx_em: t.CSizeT = t.CSizeT(i_em) * 64 if string.strcmp(_sha1_store_mod + idx_em, mod_name) == 0: sidx_em: t.CSizeT = t.CSizeT(i_em) * 17 + # DDEBUG: 检测存储的 sha1 是否带尾随点(长度>=17),发现问题立即终止 + _ck_len: t.CSizeT = string.strlen(_sha1_store_arr + sidx_em) + if _ck_len >= 17: + stdio.printf("[DDEBUG] StubMerger sha1 too long: len=%d sha1='%s' mod='%s'\n", _ck_len, _sha1_store_arr + sidx_em, mod_name) + _ddebug_exit() return _sha1_store_arr + sidx_em # 第二遍:包名回退("ast" → "ast.__init__") nm_len_em: t.CSizeT = string.strlen(mod_name) @@ -1352,6 +1423,21 @@ def _BuildIncludesSha1Map(temp_dir: str, td_len: t.CSizeT, temp_dir/td_len 参数保留以兼容现有调用者,但不再使用。 数据来源是 PopulateSha1MapStore 填充的全局存储器。 """ + # [DDEBUG] 诊断:入口输出全局存储器状态(区分填充失败/读取失败) + fb_bim: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_bim is not None: + viperlib.snprintf(fb_bim, 1024, "_BuildIncludesSha1Map 入口: _sha1_store_count=%d", _sha1_store_count) + VLogger.warning(fb_bim, "Reachable") + if _sha1_store_arr is None: + fb_na: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_na is not None: + viperlib.snprintf(fb_na, 1024, "_BuildIncludesSha1Map: _sha1_store_arr is None") + VLogger.warning(fb_na, "Reachable") + if _sha1_store_mod is None: + fb_nm: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_nm is not None: + viperlib.snprintf(fb_nm, 1024, "_BuildIncludesSha1Map: _sha1_store_mod is None") + VLogger.warning(fb_nm, "Reachable") if sha1_list is None or mod_list is None: return 0 if _sha1_store_arr is None or _sha1_store_mod is None: @@ -1994,7 +2080,7 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str, if fb is not None: viperlib.snprintf(fb, 1024, "依赖模块 '%s' (sha1=%s) 的 stub 文件不存在: %s,立即终止编译", mod_nm, found_s, chk_path) VLogger.error(fb, "BuildCombinedIR") - sys.exit(1) + _ddebug_exit() chk_f.close() stdlib.free(chk_path) stdlib.free(mod_nm) @@ -2129,3 +2215,90 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str, stdlib.free(mod_arr) return out_pos + + +# ============================================================ +# LoadDepVpiIntoModule - 加载依赖模块的 .vpi 文件,注入 declare 到当前模块 +# +# 遍历 imported_modules(空格分隔的模块名),对每个模块: +# 1. 用 LookupSha1ByModName 获取 SHA1 +# 2. 用 _sliced_path 构造 .vpi 文件路径 +# 3. 调用 VpiReader.ParseVpiIntoModule 解析 .vpi 并注入 declare +# +# 在 _translate_module_level 中、Import 处理完成后、translate_children +# 之前调用,确保跨模块函数调用时 declare 已存在。 +# +# Args: +# pool: 内存池 +# mod: 当前 LLVM 模块 +# imported_modules: 已导入模块名字符串(空格分隔) +# from_imports: from-import 映射字符串("name:module name:module" 格式) +# temp_dir: temp 目录路径 +# trans: 翻译器对象 +# +# Returns: +# 成功加载的 .vpi 文件数 +# ============================================================ +def LoadDepVpiIntoModule(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + imported_modules: str, + from_imports: str, + temp_dir: str, + trans: HandlesTranslator.Translator | t.CPtr) -> int: + """加载依赖模块的 .vpi 文件,将函数声明注入到当前模块""" + if pool is None or mod is None or temp_dir is None or trans is None: + return 0 + if imported_modules is None: + return 0 + + td_len: t.CSizeT = string.strlen(temp_dir) + total_len: t.CSizeT = string.strlen(imported_modules) + success_count: int = 0 + + # 遍历 imported_modules 中的每个模块名(空格分隔) + ci: t.CSizeT = 0 + while ci < total_len: + # 跳过前导空格 + while ci < total_len and imported_modules[ci] == ' ': + ci += 1 + if ci >= total_len: + break + # 提取模块名(到下一个空格或字符串末尾) + word_start: t.CSizeT = ci + while ci < total_len and imported_modules[ci] != ' ': + ci += 1 + word_len: t.CSizeT = ci - word_start + if word_len == 0: + continue + + # 复制模块名到临时缓冲区并 null 终止 + mod_nm_buf: str = stdlib.malloc(word_len + 1) + if mod_nm_buf is None: + continue + string.strncpy(mod_nm_buf, imported_modules + word_start, word_len) + mod_nm_buf[word_len] = '\0' + + # 用 LookupSha1ByModName 查找模块的 SHA1 + sha1_val: str = LookupSha1ByModName(mod_nm_buf) + + # 如果精确查找失败,尝试包名回退(如 "ast" → "ast.__init__") + # LookupSha1ByModName 内部已处理包名回退,此处无需重复 + + if sha1_val is not None: + # 构造 .vpi 文件路径 + vpi_path: str = _sliced_path(temp_dir, td_len, sha1_val, "vpi") + if vpi_path is not None: + # 检查 .vpi 文件是否存在(可读) + vf: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R) + if not vf.closed: + vf.close() + # 调用 VpiReader 解析 .vpi 并注入 declare + ret: int = VpiReader.ParseVpiIntoModule(pool, mod, vpi_path, trans) + if ret == 1: + success_count += 1 + stdlib.free(vpi_path) + # sha1_val 指向内部存储,无需 free + + stdlib.free(mod_nm_buf) + + return success_count diff --git a/App/main.vp b/App/main.vp index 58bfbb7..6906643 100644 --- a/App/main.vp +++ b/App/main.vp @@ -62,7 +62,7 @@ def main() -> int: # 设置全局 mbuddy 指针(sys 和 argparse 都需要) sys._mbuddy = mb argparse._mbuddy = mb - ast._mbuddy = mb + ast._mbuddy = (memhub.MemBuddy | t.CPtr)(mb) lib._mbuddy = (memhub.MemBuddy | t.CPtr)(mb) Config._mbuddy = (memhub.MemBuddy | t.CPtr)(mb) Utils._mbuddy = (memhub.MemBuddy | t.CPtr)(mb) @@ -255,6 +255,33 @@ def main() -> int: viperlib.snprintf(fb3, 1024, "%s: 删除 %d 个文件", mf_inc_bin_clean, n3) log.info(fb3, "clean") + # === --rebuild-includes: 删除 includes.binary 预编译缓存 === + # 强制下次编译时重新编译所有 includes(不清 temp/output) + if args.get_bool("rebuild-includes"): + if log is not None: + log.info("重建 includes 缓存...", "rebuild-includes") + mf_inc_bin_rb: str = Config.get_includes_binary_dir() + if mf_inc_bin_rb is not None: + n_rb: int = Utils.CleanDir(mf_inc_bin_rb) + if log is not None: + fb_rb: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_rb is not None: + viperlib.snprintf(fb_rb, 1024, "%s: 删除 %d 个文件(includes 将重新编译)", mf_inc_bin_rb, n_rb) + log.info(fb_rb, "rebuild-includes") + + # === --clear-cache: 清除 temp 目录缓存(.vpi/.stub.ll/.text.ll) === + # 强制下次 Phase1 重新生成 stub(不清 output/includes.binary) + if args.get_bool("clear-cache"): + if log is not None: + log.info("清除 temp 缓存...", "clear-cache") + if Config.TempDir is not None: + n_cc: int = Utils.CleanDir(Config.TempDir) + if log is not None: + fb_cc: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_cc is not None: + viperlib.snprintf(fb_cc, 1024, "%s: 删除 %d 个文件(.vpi/.stub.ll 缓存)", Config.TempDir, n_cc) + log.info(fb_cc, "clear-cache") + # === --phase 参数控制 === # phase=1: 仅 stub 分离(生成 .stub.ll/.text.ll),不编译 # phase=2: 仅 stub 合并 + 编译(跳过 stub 分离) diff --git a/Test/App/nested_match_test.vp b/Test/App/nested_match_test.vp index 5bf3450..39541d6 100644 --- a/Test/App/nested_match_test.vp +++ b/Test/App/nested_match_test.vp @@ -25,15 +25,25 @@ _NMATCH_POOL_SIZE: t.CDefine = 65536 def _init_mbuddy() -> int: """初始化内存池,返回 0=成功, 1=失败""" + global _mbuddy + stdio.printf("[DBG] _init_mbuddy: start\n") arena: bytes = stdlib.malloc(_NMATCH_POOL_SIZE) + stdio.printf("[DBG] _init_mbuddy: malloc arena=%d\n", arena is None) if arena is None: stdio.printf("FAIL: malloc for arena failed\n") return 1 - mb: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, _NMATCH_POOL_SIZE) + mb: memhub.MemBuddy | t.CPtr = stdlib.malloc(memhub.MemBuddy.__sizeof__()) + stdio.printf("[DBG] _init_mbuddy: malloc mb=%d\n", mb is None) if mb is None: stdio.printf("FAIL: MemBuddy init failed\n") return 1 + stdio.printf("[DBG] _init_mbuddy: before_init\n") + mb.__before_init__() + stdio.printf("[DBG] _init_mbuddy: init\n") + mb.__init__(arena, t.CSizeT(_NMATCH_POOL_SIZE)) + stdio.printf("[DBG] _init_mbuddy: store\n") _mbuddy = mb + stdio.printf("[DBG] _init_mbuddy: done\n") return 0 @@ -42,6 +52,7 @@ def test_single_match() -> int: stdio.printf("--- Test 1: 单层 match LLVMType ---\n") ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(_mbuddy) + stdio.printf("[DBG] Int32 done: %d\n", ty is None) if ty is None: stdio.printf("FAIL: Int32 returned None\n") return 1