Files
TransPyC/lib/core/LLVMCG/BaseGen.py
2026-07-18 19:25:40 +08:00

657 lines
34 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from typing import Any
import ast
import os
import llvmlite.ir as ir
from lib.includes import t as _t
from lib.includes.t import CTypeRegistry
from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo, BuiltinTypeMap
class VaArgInstruction(ir.Instruction):
def descr(self, buf: list[str]) -> None:
ptr: ir.Value = self.operands[0]
buf.append("va_arg {0} {1}, {2}\n".format(
ptr.type, ptr.get_reference(), self.type))
class BaseGenMixin:
@staticmethod
def _parse_triple(triple: str | None) -> dict[str, bool | int]:
"""解析目标三元组,返回平台信息字典"""
info: dict[str, bool | int] = {
'is_windows': False, 'is_linux': False, 'is_macos': False,
'is_x86_64': False, 'is_arm64': False, 'is_32bit': False,
'ptr_size': 8, 'long_size': 8, 'wchar_t_size': 32,
}
if not triple:
return info
triple_lower: str = triple.lower()
# 检测操作系统
if 'windows' in triple_lower or 'win32' in triple_lower or 'mingw' in triple_lower or 'msvc' in triple_lower or 'cygwin' in triple_lower:
info['is_windows'] = True
# Windows LLP64: long = 32 位, wchar_t = 16 位
info['long_size'] = 32
info['wchar_t_size'] = 16
elif 'linux' in triple_lower:
info['is_linux'] = True
elif 'darwin' in triple_lower or 'macos' in triple_lower or 'apple' in triple_lower:
info['is_macos'] = True
# 检测架构
if 'x86_64' in triple_lower or 'amd64' in triple_lower or 'x64' in triple_lower:
info['is_x86_64'] = True
elif 'aarch64' in triple_lower or 'arm64' in triple_lower:
info['is_arm64'] = True
elif 'i386' in triple_lower or 'i686' in triple_lower or 'arm' in triple_lower:
info['is_32bit'] = True
info['ptr_size'] = 4
info['long_size'] = 32
if info['is_windows']:
info['wchar_t_size'] = 16
else:
info['wchar_t_size'] = 32
return info
def __init__(self, triple: str | None = None, datalayout: str | None = None) -> None:
self.module: ir.Module = ir.Module(name="transpyc_module")
if triple:
self.module.triple = triple
else:
self.module.triple = "x86_64-none-elf"
if datalayout:
self.module.data_layout = datalayout
else:
self.module.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
# 解析目标平台信息
self._platform_info: dict[str, bool | int] = self._parse_triple(self.module.triple)
self.ptr_size: int = self._platform_info['ptr_size']
# 根据目标平台配置 t 模块中的平台相关类型大小
_t.configure_platform(self.module.triple)
self.builder: ir.IRBuilder | None = None
self.func: ir.Function | None = None
self.functions: dict[str, ir.Function] = {}
self.variables: dict[str, ir.Value | None] = {}
self._direct_values: dict[str, ir.Value] = {}
self._reg_values: dict[str, ir.Value] = {}
self.var_signedness: dict[str, bool] = {}
self._unsigned_results: set[int] = {}
self.string_const_counter: int = 0
self.Vtables: dict[str, ir.GlobalVariable] = {}
self.class_methods: dict[str, list[str]] = {}
self.class_members: dict[str, list[tuple[str, ir.Type]]] = {}
self.class_member_defaults: dict[str, dict[str, Any]] = {}
self.class_member_signeds: dict[str, dict[str, bool]] = {}
self.class_member_bitfields: dict[str, dict[str, int]] = {}
self.class_member_byteorders: dict[str, dict[str, str]] = {}
self.local_var_byteorders: dict[str, str] = {}
self.class_member_element_class: dict[str, dict[str, str]] = {}
self.class_member_bitoffsets: dict[str, dict[str, int]] = {}
self.structs: dict[str, ir.IdentifiedStructType] = {}
self.typedef_int_widths: dict[str, int] = {} # typedef名称 -> 底层整数位宽 (如 'UINT' -> 32, 'BYTE' -> 8)
self._cross_module_vtable_classes: set[str] = set()
self._cross_module_novtable: set[str] = set()
self.class_vtable: set[str] = set()
self._class_graph: dict[str, Any] = {}
self.class_parent: dict[str, str] = {}
# Store member annotations for deferred type resolution (cross-module class references)
self.class_member_annotations: dict[str, dict[str, Any]] = {}
self.loop_break_targets: list[ir.Block] = []
self.loop_continue_targets: list[ir.Block] = []
self.eh_jmp_buf_stack: list[ir.Value] = []
self.eh_except_block_stack: list[ir.Block] = []
self.eh_finally_stack: list[Any] = []
self.global_vars: set[str] = set()
self.nonlocal_params: dict[str, Any] = {}
self._variable_scope_stack: list[dict[str, Any]] = [] # Stack of outer scope variables for nested function nonlocal lookup
self.var_struct_class: dict[str, str] = {}
self.var_ptr_element: dict[str, bool] = {}
# 全局变量的指针元素标志(持久,不受函数重置影响)
# 用于全局变量 _argv: bytes | t.CPtr 等,使 _argv[index] 使用 8 字节指针步长
self.global_var_ptr_element: dict[str, bool] = {}
self.class_provides: dict[str, list[str]] = {}
self.class_requires: dict[str, list[str]] = {}
self.class_require_must: dict[str, list[str]] = {}
# 编译期 with 上下文栈:记录当前嵌套 with 链中所有可用的 provides 字段名
# 用于 __require_must__ 的纯编译期静态可达性检查
self._with_provides_stack: list[list[str]] = []
# 函数参数自动取地址模式: func_name -> [None, None, 'need', 'always', ...]
# 'need': t.CNeedPtr — 仅对非指针值取地址
# 'always': t.CAutoPtr — 无条件取地址
self._auto_addr_params: dict[str, list[str | None]] = {}
self.global_struct_class: dict[str, str] = {}
self.var_type_info: dict[str, Any] = {}
self.var_const_flags: dict[str, bool] = {}
self._current_source_file: str | None = None
self._current_source_lines: list[str] = []
self._ns_cache: dict[str, str] = {}
self._type_cache: dict[tuple[str, bool], ir.Type] = {}
self._typedef_cache: dict[str, Any] = {}
self._func_sig_cache: dict[str, Any] = {}
self.var_type_assignments: dict[str, Any] = {}
self._temp_struct_ptrs: list[ir.Value] = []
self._stop_iter_flag_param: ir.Value | None = None
self._local_heap_ptrs: list[tuple[ir.Value, str, str | None]] = []
self._var_to_heap_ptr: dict[str, ir.Value] = {}
self.known_return_types: dict[str, ir.Type] = {}
self._current_lineno: int = 0
self._current_node_info: str = ""
self.module_sha1: str | None = None
self.ModuleSha1Map: dict[str, str] = {}
self._temp_dir: str | None = None
self._export_funcs: set[str] = set()
self._export_extern_funcs: dict[str, str] = {}
self._current_module_func_names: set[str] = set()
# __doc__ 魔法字符串注册表symbol_name -> docstring 文本None 表示空/优化剥离)
self._doc_strings: dict[str, str | None] = {}
self.class_packed: set[str] = set()
self._define_constants: dict[str, int] = {}
# 以下属性原先在外部懒注入,此处显式初始化以避免 hasattr/getattr 动态反射
self._struct_sha1_map: dict[str, str] = {}
self.SymbolTable: Any = None
self._Trans: Any = None
self.class_sha1_map: dict[str, str] = {}
# 以下属性原先懒注入,此处显式初始化以消除 hasattr/getattr 动态反射
self._import_handler_ref: Any = None
self._classes_in_progress: set[str] = set()
# 字段收集期间添加当前类名,阻止 CollectAnnAssignMember 触发的嵌套
# _generate_structs 用不完整 class_members 调用 set_bodyset_body 只能调用一次)
# 用集合而非单值,因为嵌套特化类 _EmitClassLlvm 会清除单值,导致外层类被错误设置 body
self._collecting_members_set: set[str] = set()
self._last_var_name: str | None = None
self._variadic_info: dict | None = None
self._vtable_copy_counter: int = 0
self._decorated_funcs: dict = {}
self._current_tree: Any = None
self._DefineConstants: dict = {}
self._all_define_constants: dict = {}
pi: dict[str, bool | int] = self._platform_info
# 根据目标平台设置宏(声明式,从三元组推导)
if pi['is_windows']:
self._define_constants['_WIN32'] = 1
if not pi['is_32bit']:
self._define_constants['_WIN64'] = 1
self._define_constants['WIN64'] = 1
self._define_constants['WIN32'] = 1
if pi['is_linux']:
self._define_constants['__linux__'] = 1
if pi['is_macos']:
self._define_constants['__APPLE__'] = 1
self._define_constants['__MACH__'] = 1
if pi['is_x86_64']:
self._define_constants['__x86_64__'] = 1
self._define_constants['__x86_64'] = 1
self._define_constants['_M_X64'] = 1
elif pi['is_arm64']:
self._define_constants['__aarch64__'] = 1
self._define_constants['_M_ARM64'] = 1
if not pi['is_32bit'] and pi['is_linux']:
self._define_constants['__LP64__'] = 1
elif pi['is_32bit']:
self._define_constants['_ILP32'] = 1
self._define_constants['SIZEOF_VOID_P'] = pi['ptr_size']
self._define_constants['__SIZEOF_POINTER__'] = pi['ptr_size']
def find_struct_by_pointee(self, pointee: ir.Type) -> tuple[str, ir.IdentifiedStructType] | None:
"""根据 pointee 类型查找匹配的结构体,返回 (class_name, struct_type) 或 None"""
for class_name, struct_type in self.structs.items():
if pointee == struct_type:
return (class_name, struct_type)
return None
@staticmethod
def _extract_short_name(name: str) -> str:
"""从结构体类型名中提取短名(去掉 sha1 前缀)。
"6bc91356c652f8ca.Function""Function"
"Function""Function"(无 sha1 前缀时原样返回)
"""
if '.' in name:
prefix: str = name.split('.', 1)[0]
if len(prefix) == 16 and all(c in '0123456789abcdef' for c in prefix):
return name.split('.', 1)[1]
return name
@staticmethod
def _extract_struct_sha1(st: ir.IdentifiedStructType) -> str:
"""从 IdentifiedStructType 的 name 中提取 sha1 前缀16 位十六进制)。
返回空字符串表示无 sha1 前缀。用于同名类冲突检测。
"""
if not isinstance(st, ir.IdentifiedStructType):
return ''
try:
name: str = st.name
except (AssertionError, AttributeError):
return ''
if '.' in name:
prefix: str = name.split('.', 1)[0]
if len(prefix) == 16 and all(c in '0123456789abcdef' for c in prefix):
return prefix
return ''
def _get_or_create_struct(self, name: str, source_sha1: str | None = None, packed: bool = False) -> ir.IdentifiedStructType:
clean_name: str = name.replace(' *', '').replace('*', '').replace(' ', '_').replace('const', 'const_').replace('volatile', 'volatile_')
# 如果名称包含模块前缀(如 "a9fa0f6200c09e65.zbit_writer"
# 先尝试用短名称(如 "zbit_writer")查找已注册的 struct
# 避免为同一 struct 创建多个不同的类型对象导致跨模块引用类型不一致
if '.' in clean_name and clean_name not in self.structs:
parts: list[str] = clean_name.split('.', 1)
if len(parts[0]) == 16 and all(c in '0123456789abcdef' for c in parts[0]):
short_name: str = parts[1]
if short_name in self.structs:
existing_short: ir.IdentifiedStructType = self.structs[short_name]
# 治本修复:同名类 sha1 冲突检测。
# 当请求的 sha1 前缀与现有 struct 的 sha1 前缀不一致时
# (如 stmts.py:Module 与 __module.py:Module 同名冲突),
# 不能复用已有 structset_body 已锁定为错误布局),
# 需创建独立 struct 并以 sha1 前缀全名存储。
_existing_sha1: str = self._extract_struct_sha1(existing_short)
if _existing_sha1 and _existing_sha1 != parts[0]:
if clean_name in self.structs:
return self.structs[clean_name]
st_new: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, name=clean_name, packed=packed)
self.structs[clean_name] = st_new
return st_new
return existing_short
# 优先解析 typedef 整数类型(如 INT/UINT/BYTE避免将其注册为 opaque struct。
# 必须在 `if clean_name in self.structs` 缓存检查之前执行,
# 否则首次调用SymbolTable 未就绪时)会将 typedef 名缓存为 opaque struct
# 后续调用即使 SymbolTable 就绪也只会返回缓存的错误类型。
# 此修复同时解决两个问题:
# 1. alloca unsized type变量声明 `argc: INT = 6` 不再生成 `alloca %"...INT"`
# 2. 下标访问FindStructNameInAnnotation 不再匹配 typedef 名(因不在 Gen.structs
td_width: int | None = self._resolve_typedef_int_width(clean_name)
if td_width is not None:
if td_width > 0:
self.typedef_int_widths[clean_name] = td_width
return ir.IntType(td_width)
# td_width == 0: 特殊 typedef 名称str/bytes/list 等),返回 i8
self.typedef_int_widths[clean_name] = 0
return ir.IntType(8)
if clean_name in self.structs:
existing: ir.IdentifiedStructType = self.structs[clean_name]
# 治本修复:同名类 sha1 冲突检测(短名调用路径)。
# 当 source_sha1 与现有 struct 的 sha1 前缀不一致时(跨模块同名类冲突),
# 不能复用已有 structset_body 已锁定为错误布局),
# 需创建独立 struct 并以 sha1 前缀全名存储,不覆盖短名条目。
if source_sha1:
_existing_sha1: str = self._extract_struct_sha1(existing)
if _existing_sha1 and _existing_sha1 != source_sha1:
full_key: str = f"{source_sha1}.{clean_name}"
if full_key in self.structs:
st_full: ir.IdentifiedStructType = self.structs[full_key]
if packed and isinstance(st_full, ir.IdentifiedStructType) and not st_full.packed:
st_full.packed = True
return st_full
ns_name: str = f"{source_sha1}.{clean_name}"
st_new: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, name=ns_name, packed=packed)
self.structs[full_key] = st_new
return st_new
if packed and isinstance(existing, ir.IdentifiedStructType) and not existing.packed:
existing.packed = True
return existing
if clean_name in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum', 'Void', 'void'}:
return ir.IntType(8)
if self.SymbolTable:
Entry: _CTypeInfo | None = self.SymbolTable.lookup(clean_name)
if Entry and Entry.IsTypedef:
resolved_str: str = self._resolve_typedef(clean_name)
if resolved_str != clean_name:
return self._type_str_to_llvm(resolved_str)
if Entry.BaseType:
if not isinstance(Entry.BaseType, (_t._CTypedef,)) or Entry.PtrCount > 0:
resolved: str = self._resolve_ctype_to_str(Entry)
if resolved:
return self._type_str_to_llvm(resolved)
if Entry and Entry.IsRenum:
if clean_name in self.structs:
return self.structs[clean_name]
# REnum 结构体尚未创建时不能 fall through 到 IsEnum会返回 i32
# 需要继续到下方正常结构体创建路径,创建 opaque 结构体。
# 这对自引用 REnum如 LLVMType 包含 LLVMType*)至关重要:
# _parse_llvm_type 先通过此路径创建 opaque 结构体_TryLoadStructFromStub 再 set_body。
elif Entry and Entry.IsEnum and clean_name not in self.class_methods:
return ir.IntType(32)
if Entry and Entry.IsExceptionClass:
return ir.IntType(32)
if Entry and Entry.IsFunction:
return ir.PointerType(ir.IntType(8))
if Entry and Entry.IsVariable:
return ir.PointerType(ir.IntType(8))
if Entry and Entry.BaseType:
if isinstance(Entry.BaseType, type) and issubclass(Entry.BaseType, _t.CEnum):
return ir.IntType(32)
if Entry.BaseType is _t.CEnum:
return ir.IntType(32)
ns_name: str
if source_sha1:
ns_name = f"{source_sha1}.{clean_name}"
elif clean_name in self._struct_sha1_map:
ns_name = f"{self._struct_sha1_map[clean_name]}.{clean_name}"
else:
ns_name = self._mangle_name(clean_name)
st: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, name=ns_name, packed=packed)
self.structs[clean_name] = st
# 尝试解析 typedef 的底层整数位宽
width: int | None = self._resolve_typedef_int_width(clean_name)
if width is not None:
self.typedef_int_widths[clean_name] = width
return st
def _resolve_typedef_int_width(self, name: str) -> int | None:
"""解析 typedef 名称的底层整数位宽
通过 CTypeRegistry 和 BuiltinTypeMap 动态解析,
替代硬编码的 TYPEDEF_NAMES 映射表。
返回 int 位宽或 None无法解析
"""
# 1. 先查 BuiltinTypeMap覆盖 BYTEPTR 等指针别名)
bm: Any = BuiltinTypeMap.Get(name)
if bm:
ctype_cls: Any
ptr_count: int
ctype_cls, ptr_count = bm
if ptr_count > 0:
return None # 指针类型,不是整数 typedef
llvm_str: str = CTypeRegistry.CTypeToLLVM(ctype_cls)
if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit():
return int(llvm_str[1:])
# 2. 再查 SymbolTable用户定义的 typedef
if self.SymbolTable:
Entry: _CTypeInfo | None = self.SymbolTable.lookup(name)
if Entry and Entry.IsTypedef:
if Entry.BaseType:
if not isinstance(Entry.BaseType, (_t._CTypedef,)) and Entry.PtrCount == 0:
llvm_str: str = CTypeRegistry.CTypeToLLVM(type(Entry.BaseType) if isinstance(Entry.BaseType, _t.CType) else Entry.BaseType)
if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit():
return int(llvm_str[1:])
if Entry.OriginalType:
if isinstance(Entry.OriginalType, _CTypeInfo) and Entry.OriginalType.BaseType:
if not isinstance(Entry.OriginalType.BaseType, (_t._CTypedef,)) and Entry.OriginalType.PtrCount == 0:
llvm_str: str = CTypeRegistry.CTypeToLLVM(type(Entry.OriginalType.BaseType) if isinstance(Entry.OriginalType.BaseType, _t.CType) else Entry.OriginalType.BaseType)
if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit():
return int(llvm_str[1:])
elif isinstance(Entry.OriginalType, str):
# OriginalType 是类型名字符串(如 'CInt', 'CUnsignedInt'
# 通过 CTypeRegistry 解析为整数位宽
cls: Any = CTypeRegistry.GetClassByName(Entry.OriginalType)
if cls:
llvm_str: str = CTypeRegistry.CTypeToLLVM(cls)
if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit():
return int(llvm_str[1:])
# 3. 尝试 CTypeRegistry 直接按名称查找
ctype_cls: Any = CTypeRegistry.GetClassByName(name)
if ctype_cls:
llvm_str: str = CTypeRegistry.CTypeToLLVM(ctype_cls)
if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit():
return int(llvm_str[1:])
# 4. 特殊名称(非整数类型,但需要标记为 typedef 以跳过 opaque 定义)
_SPECIAL_TYPEDEFS: set[str] = {
'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion',
'CStruct', 'enum', 'REnum', 'renum',
'list', 'dict', 'tuple', 'set', 'str', 'bytes', 'array', 'type', 'CArray',
}
if name in _SPECIAL_TYPEDEFS:
return 0 # 标记为 typedef但位宽为 0非整数
return None
def _set_node_info(self, node: ast.AST, extra_info: str = "") -> None:
if hasattr(node, 'lineno'):
self._current_lineno = node.lineno
else:
self._current_lineno = 0
if hasattr(node, 'col_offset'):
self._current_node_info = f"line {self._current_lineno}, col {node.col_offset}"
else:
self._current_node_info = f"line {self._current_lineno}"
if extra_info:
self._current_node_info += f" ({extra_info})"
def _set_source_info(self, filepath: str) -> None:
self._current_source_file = filepath
try:
with open(filepath, 'r', encoding='utf-8') as f:
self._current_source_lines = f.readlines()
except Exception: # 文件读取失败时回退为空行列表
self._current_source_lines = []
def _skip_mangle(self, name: str) -> bool:
skip_prefixes: tuple[str, ...] = ('llvm.', 'str_const_', 'printf', 'memset_pattern')
if any(name.startswith(p) for p in skip_prefixes):
return True
if '.' in name:
parts: list[str] = name.split('.', 1)
if len(parts[0]) >= 8 and all(c in '0123456789abcdef' for c in parts[0]):
return True
return False
def _mangle_name(self, name: str) -> str:
if self._skip_mangle(name):
return name
if name in self._export_funcs:
return name
if self.module_sha1:
return f"{self.module_sha1}.{name}"
return name
def _find_function(self, name: str) -> ir.Function | None:
if name in self.functions:
return self.functions[name]
g: Any = self.module.globals.get(name)
if g and isinstance(g, ir.Function):
self.functions[name] = g
return g
mangled: str = self._mangle_func_name(name)
if mangled != name:
if mangled in self.functions:
self.functions[name] = self.functions[mangled]
return self.functions[mangled]
g = self.module.globals.get(mangled)
if g and isinstance(g, ir.Function):
self.functions[mangled] = g
self.functions[name] = g
return g
for sha1 in self.ModuleSha1Map.values():
prefixed: str = f"{sha1}.{name}"
if prefixed in self.functions:
self.functions[name] = self.functions[prefixed]
return self.functions[prefixed]
g = self.module.globals.get(prefixed)
if g and isinstance(g, ir.Function):
self.functions[prefixed] = g
self.functions[name] = g
return g
return None
def _has_function(self, name: str) -> bool:
return self._find_function(name) is not None
def _get_or_declare_function(self, mangled_name: str, func_type: ir.FunctionType) -> ir.Function:
g = self.module.globals.get(mangled_name)
if g and isinstance(g, ir.Function):
return g
return ir.Function(self.module, func_type, name=mangled_name)
def _get_function(self, name: str) -> ir.Function | None:
func: ir.Function | None = self._find_function(name)
return func
def _mangle_func_name(self, name: str, module_name: str | None = None) -> str:
if name in self._export_funcs and not module_name:
return name
if name in self._export_extern_funcs:
target_sha1: str = self._export_extern_funcs[name]
if module_name:
# 显式带 module_name 调用(如 stdlib.system即使当前模块定义了同名函数
# 也应按模块匹配 extern返回裸名。snprintf 之所以工作而 system 不工作,
# 就是因为 os._win32 定义了自己的 system 包装,导致旧逻辑跳过了 extern 匹配。
if module_name == target_sha1:
return name
if module_name in self.ModuleSha1Map and self.ModuleSha1Map[module_name] == target_sha1:
return name
init_name: str = f"{module_name}.__init__"
if init_name in self.ModuleSha1Map and self.ModuleSha1Map[init_name] == target_sha1:
return name
# 兜底module_name 不在 ModuleSha1Map 中或 sha1 不匹配,
# 但函数在 _export_extern_funcs 中C extern 不应混淆),
# 仅当当前模块未定义同名函数时才返回裸名。
if name not in self._current_module_func_names:
return name
elif name not in self._current_module_func_names:
# 无 module_name 调用(如 from stdlib import system; system()
# 仅当当前模块未定义同名函数时才返回 extern 裸名,
# 否则让本地定义走正常 mangle 路径(本地 def 遮蔽 import 语义)。
return name
# main 函数作为程序入口点,永远不混淆
if name == 'main':
return name
# Try class_sha1_map first for class methods (e.g., 'md5.__init__' -> class 'md5')
class_sha1_map: dict[str, str] = self.class_sha1_map
if class_sha1_map:
if '.' in name:
base_class: str = name.split('.')[0]
if base_class in class_sha1_map:
sha1: str = class_sha1_map[base_class]
return f"{sha1}.{name}"
elif name in class_sha1_map:
sha1: str = class_sha1_map[name]
return f"{sha1}.{name}"
# If module_name is already a SHA1 hash (16 hex chars), use it directly
if module_name and len(module_name) == 16 and all(c in '0123456789abcdef' for c in module_name):
return f"{module_name}.{name}"
if module_name and module_name in self.ModuleSha1Map:
sha1: str = self.ModuleSha1Map[module_name]
return f"{sha1}.{name}"
# Try parent package name (e.g., 'hashlib' -> 'hashlib.__init__')
if module_name:
init_name: str = f"{module_name}.__init__"
if init_name in self.ModuleSha1Map:
sha1: str = self.ModuleSha1Map[init_name]
return f"{sha1}.{name}"
if self._skip_mangle(name):
return name
if self.module_sha1:
return f"{self.module_sha1}.{name}"
return name
def _get_source_line(self, lineno: int) -> str | None:
if 0 < lineno <= len(self._current_source_lines):
return self._current_source_lines[lineno - 1].rstrip('\r\n')
return None
def _get_node_info(self) -> str:
info: str = ""
if self._current_node_info:
info = f" [{self._current_node_info}]"
if self._current_source_file:
info += f" in {self._current_source_file}"
lineno: int = self._current_lineno
if lineno > 0:
info += f", line {lineno}:"
source_line: str | None = self._get_source_line(lineno)
if source_line:
info += f"\n{source_line}"
return info
# ========== 统一工具方法 ==========
def _create_string_global(self, s: str, name: str | None = None) -> ir.Constant:
"""创建字符串全局变量并返回 i8* 指针。
统一字符串全局变量创建模式:编码为 utf-8 + '\\x00' 终止符,
创建 internal linkage 的 GlobalVariable返回 i8* 指针常量。
"""
str_val: str = s + '\x00'
str_bytes: bytes = str_val.encode('utf-8')
arr_type: ir.ArrayType = ir.ArrayType(ir.IntType(8), len(str_bytes))
gv_name: str = name or f"str_const_{self.string_const_counter}"
self.string_const_counter += 1
gv: ir.GlobalVariable = ir.GlobalVariable(self.module, arr_type, name=gv_name)
gv.initializer = ir.Constant(arr_type, bytearray(str_bytes))
gv.linkage = 'internal'
return ir.Constant(ir.PointerType(ir.IntType(8)), gv.get_reference())
def _create_doc_global(self, symbol_name: str, docstring: str | None) -> None:
"""为符号创建 __doc__ 全局常量。
- docstring 为 None 或空字符串时,不创建常量(访问时内联空指针)
- slice_level != 0优化开启内容视为空
- 非空时创建 internal linkage、global_constant=True 的只读字符串常量
- 常量名格式:{module_sha1}.{symbol_name}.__doc__
"""
slice_level: int = getattr(self._Trans, 'SliceLevel', 3)
if slice_level != 0:
docstring = None
if docstring is None or docstring == '':
self._doc_strings[symbol_name] = None
return
self._doc_strings[symbol_name] = docstring
mangled: str = self._mangle_name(f"{symbol_name}.__doc__")
self._create_string_global(docstring, name=mangled)
gv: ir.GlobalVariable | None = self.module.globals.get(mangled)
if gv is not None:
gv.global_constant = True
def _get_doc_ptr(self, symbol_name: str) -> ir.Value | None:
"""获取符号 __doc__ 的 i8* 指针。
- 若符号未注册 __doc__返回 None调用方回退到其他解析
- 若 __doc__ 为空(无 docstring 或优化剥离),返回 i8* null 内联空指针
- 若 __doc__ 非空,返回指向字符串全局常量的 i8* 指针
- 跨模块 docstring在 _doc_strings 中有文本但 module.globals 无对应常量)首次访问时创建本地 internal linkage 只读副本
"""
if symbol_name not in self._doc_strings:
return None
docstring: str | None = self._doc_strings[symbol_name]
if docstring is None or docstring == '':
return ir.Constant(ir.PointerType(ir.IntType(8)), None)
mangled: str = self._mangle_name(f"{symbol_name}.__doc__")
gv: ir.GlobalVariable | None = self.module.globals.get(mangled)
if gv is None:
# 跨模块 docstring创建本地 internal linkage 只读字符串常量副本
self._create_string_global(docstring, name=mangled)
gv = self.module.globals.get(mangled)
if gv is None:
return ir.Constant(ir.PointerType(ir.IntType(8)), None)
gv.global_constant = True
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
return self.builder.gep(gv, [zero, zero], name=f"{symbol_name}_doc_ptr")
def _apply_bswap_if_big(self, val: ir.Value, byte_order: str, name: str) -> ir.Value:
"""大端字节序时对整数应用 bswap否则原值返回。
仅对 16/32/64 位整数生效,统一 bswap 逻辑。
"""
if byte_order == 'big' and isinstance(val.type, ir.IntType) and val.type.width in (16, 32, 64):
return self.builder.bswap(val, name=name)
return val
def _zero_value_for_type(self, llvm_type: ir.Type) -> ir.Constant | None:
"""为指定 LLVM 类型生成零值常量。
合并原 HandlesAssign._zero_value 与 StructGen._zero_value_for_type 的逻辑。
返回 ir.Constant 或 None无法生成零值的类型如 opaque struct
"""
if isinstance(llvm_type, ir.IntType):
return ir.Constant(llvm_type, 0)
elif isinstance(llvm_type, (ir.FloatType, ir.DoubleType)):
return ir.Constant(llvm_type, 0.0)
elif isinstance(llvm_type, ir.PointerType):
return ir.Constant(llvm_type, None)
elif isinstance(llvm_type, ir.ArrayType):
elem_zv: ir.Constant | None = self._zero_value_for_type(llvm_type.element)
if elem_zv is None:
return None
return ir.Constant(llvm_type, [elem_zv] * llvm_type.count)
elif isinstance(llvm_type, ir.BaseStructType):
if llvm_type.elements is not None and len(llvm_type.elements) > 0:
elem_zvs: list[ir.Constant | None] = [self._zero_value_for_type(m) for m in llvm_type.elements]
if any(zv is None for zv in elem_zvs):
return None
return ir.Constant(llvm_type, elem_zvs)
return None
return None