Files
TransPyC/lib/core/LLVMCG/BaseGen.py

781 lines
41 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 = {}
# 闭包追踪:记录返回闭包的函数和变量
# _closure_return_types: func_name -> (fn_return_type, nonlocal_arg_types)
self._closure_return_types: dict[str, tuple[Any, list[Any]]] = {}
# _closure_var_types: var_name -> (fn_return_type, nonlocal_arg_types)
self._closure_var_types: dict[str, tuple[Any, list[Any]]] = {}
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)
# typing.Any 是"任意类型"标记,应解析为 i8*(通用指针),
# 而非创建为 opaque 结构体(否则包含 Any 字段的结构体会变成 unsized
if clean_name == 'Any':
return ir.IntType(8).as_pointer()
# t.CType 的基本类型子类CInt/CChar/CSizeT/CLong/CFloat/CDouble 等,
# position 含 BASE 且 Size>0有具体 LLVM 类型,应直接返回对应的
# ir.IntType/ir.FloatType/ir.DoubleType而非创建结构体。
# _is_ctype_marker_name 对这些类型返回 False不跳过需要在此处拦截。
_basic_llvm_type: ir.Type | None = self._try_resolve_ctype_basic(clean_name)
if _basic_llvm_type is not None:
return _basic_llvm_type
# t.CType 及其子类是"类型强转"标记,不应被编译为真实结构体。
# 动态检查 t 模块中所有 CType 子类名(排除 CStruct/CEnum/CUnion/REnum 子类,
# 因为用户定义的结构体类继承自它们,需要被创建为结构体)。
if self._is_ctype_marker_name(clean_name):
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)
# 治本修复:当 clean_name 是已注册的类(在 class_methods 或 class_members 中)时,
# 不应走 IsExceptionClass/IsFunction/IsVariable 分支返回非结构体类型。
# 否则 _get_or_create_struct 返回指针类型(如 _TypedPointerType而非 IdentifiedStructType
# 导致 _TryLoadStructFromStub 的 set_body 被跳过isinstance 检查失败),
# struct 保持不完整字段数,引发跨模块 GEP 越界崩溃。
_is_class_name: bool = clean_name in self.class_methods or clean_name in self.class_members
if Entry and Entry.IsExceptionClass and not _is_class_name:
return ir.IntType(32)
if Entry and Entry.IsFunction and not _is_class_name:
return ir.PointerType(ir.IntType(8))
if Entry and Entry.IsVariable and not _is_class_name:
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 定义)
# 注意:如果 name 已注册为 struct用户定义了同名 class如 includes/_dict.py 中的 dict
# 则不应视为 typedef应返回 None 让调用方走 struct 创建路径。
# 解决时序问题_parse_llvm_declare 从 stub.ll 解析时 dict 可能尚未注册到 Gen.structs
# 但 SymbolTable 在 .pyi 解析阶段已就绪,可通过 is_struct 检查区分 class 和 typedef。
_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:
if name in self.structs:
return None # 已注册为 struct不视为 typedef
if self.SymbolTable is not None:
try:
if self.SymbolTable.is_struct(name):
return None # SymbolTable 中标记为 struct不视为 typedef
except Exception:
pass
return 0 # 标记为 typedef但位宽为 0非整数
# t.CType 及其子类是"类型强转"标记,不应被创建为结构体。
# 动态检查 t 模块中所有 CType 子类名(排除 CStruct/CEnum/CUnion/REnum 子类)。
# 返回 0 标记为 typedef使 _get_or_create_struct 走 typedef 路径返回 i8。
if self._is_ctype_marker_name(name):
return 0
return None
@staticmethod
def _is_ctype_marker_name(name: str) -> bool:
"""检查名称是否是 t.CType 的"类型强转"标记子类名。
只有 position 不含 BASE 的纯修饰符/标记类型CPtr/CVolatile/CConst/
CInline/CStatic/CExtern/CExport/CRegister/CAuto/_CTypedef/CTypeDefault 等)
才应该跳过结构体创建。有 BASE position 的基本类型CInt/CChar/CSizeT/
CLong/CFloat/CDouble 等)有具体大小,应被正常解析为对应宽度的整数/浮点。
CStruct/CEnum/CUnion/REnum 的用户子类是合法结构体,需要被创建。
注意CTypeRegistry.GetClassByName 会跳过 CType 本身和 CTypeDefault
所以这里直接用 getattr(t, name) 检查 t 模块属性。
Returns:
True 如果 name 是 CType 标记子类名(应跳过结构体创建)
"""
if not name:
return False
# 去除可能的 SHA1 前缀(如 "abc123.CPtr" -> "CPtr"
short_name: str = name.split('.')[-1] if '.' in name else name
# 直接查 t 模块属性CTypeRegistry._build 会跳过 CType/CTypeDefault/BigEndian/LittleEndian
t_cls: Any = getattr(_t, short_name, None)
if not isinstance(t_cls, type) or not issubclass(t_cls, _t.CType):
return False
# 排除 CStruct/CEnum/CUnion/REnum 子类(它们是命名类型的基类,
# 用户定义的结构体继承自它们,需要被创建为结构体)
if issubclass(t_cls, (_t.CStruct, _t.CEnum, _t.REnum, _t.CUnion)):
return False
# 基本类型position 含 BASE 且 Size > 0有具体大小不应跳过
# CInt→i32, CChar→i8, CSizeT→i64, CLong→i64, CFloat→f32 等)
# CVoid 虽含 BASE 但 Size=0CType Size=None仍需跳过
if _t.CType.BASE in t_cls.position:
# 检查实例的 Size类属性可能未设置用实例获取
try:
inst = t_cls()
size_val = getattr(inst, 'Size', None)
if size_val is not None and size_val > 0:
return False
except Exception:
pass
return True
def _try_resolve_ctype_basic(self, name: str) -> ir.Type | None:
"""尝试将 t.CType 的基本类型子类名解析为对应的 LLVM 基本类型。
仅对 t 模块内的 CType 基本类型子类CInt/CChar/CSizeT/CLong/CFloat/
CDouble 等,即 position 含 BASE 且 Size>0生效返回对应的
ir.IntType/ir.FloatType/ir.DoubleType。
CStruct/CEnum/CUnion/REnum 子类不在此处理(用户自定义结构体需要被
创建为结构体。CVoid/CType/CPtr 等无 Size 或 Size=0 的类型也不在此
处理(应通过 _is_ctype_marker_name 跳过结构体创建)。
Returns:
对应的 ir.Type或 None 表示不是基本类型,需要继续走结构体创建路径。
"""
if not name:
return None
short_name: str = name.split('.')[-1] if '.' in name else name
cls: Any = getattr(_t, short_name, None)
if not isinstance(cls, type) or not issubclass(cls, _t.CType):
return None
if issubclass(cls, (_t.CStruct, _t.CEnum, _t.REnum, _t.CUnion)):
return None
if _t.CType.BASE not in getattr(cls, 'position', frozenset()):
return None
try:
inst = cls()
size_val = getattr(inst, 'Size', None)
if size_val is None or size_val <= 0:
return None
except Exception:
return None
llvm_str: str | None = CTypeRegistry.NameToLLVM(short_name)
if not llvm_str:
return None
return self._type_str_to_llvm(llvm_str)
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