可用的回归测试通过的标准版本

This commit is contained in:
2026-06-18 00:39:43 +08:00
parent bffb0cb6b7
commit e02c867edf
365 changed files with 22562 additions and 24532 deletions

412
lib/core/LLVMCG/BaseGen.py Normal file
View File

@@ -0,0 +1,412 @@
from __future__ import annotations
import re
import ast
import os
import hashlib
import llvmlite.ir as ir
from llvmlite.ir.values import _Undefined
class VaArgInstruction(ir.Instruction):
def descr(self, buf):
ptr = 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):
"""解析目标三元组,返回平台信息字典"""
info = {
'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 = 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=None, datalayout=None):
self.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 = self._parse_triple(self.module.triple)
self.ptr_size = self._platform_info['ptr_size']
# 根据目标平台配置 t 模块中的平台相关类型大小
import t as _t
_t.configure_platform(self.module.triple)
self.builder = None
self.func = None
self.functions = {}
self.variables = {}
self._direct_values = {}
self._reg_values = {}
self.var_signedness = {}
self._unsigned_results = {}
self.string_const_counter = 0
self.Vtables = {}
self.class_methods = {}
self.class_members = {}
self.class_member_defaults = {}
self.class_member_signeds = {}
self.class_member_bitfields = {}
self.class_member_byteorders = {}
self.class_member_element_class = {}
self.class_member_bitoffsets = {}
self.structs = {}
self.typedef_int_widths = {} # typedef名称 -> 底层整数位宽 (如 'UINT' -> 32, 'BYTE' -> 8)
self._cross_module_vtable_classes = set()
self.class_vtable = set()
self.class_parent = {}
# Store member annotations for deferred type resolution (cross-module class references)
self.class_member_annotations = {}
self.loop_break_targets = []
self.loop_continue_targets = []
self.eh_jmp_buf_stack = []
self.eh_except_block_stack = []
self.eh_finally_stack = []
self.global_vars = set()
self.nonlocal_params = {}
self._variable_scope_stack = [] # Stack of outer scope variables for nested function nonlocal lookup
self.var_struct_class = {}
self.global_struct_class = {}
self.var_type_info = {}
self.var_const_flags = {}
self._current_source_file = None
self._current_source_lines = []
self._ns_cache = {}
self._type_cache = {}
self._typedef_cache = {}
self._func_sig_cache = {}
self.var_type_assignments = {}
self._temp_struct_ptrs = []
self._stop_iter_flag_param = None
self._local_heap_ptrs = []
self._var_to_heap_ptr = {}
self.known_return_types = {}
self._current_lineno = 0
self._current_node_info = ""
self.module_sha1 = None
self.ModuleSha1Map = {}
self._temp_dir = None
self._export_funcs = set()
self._export_extern_funcs = set()
self._current_module_func_names = set()
self.class_packed = set()
self._define_constants = {}
pi = 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):
"""根据 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
def _get_or_create_struct(self, name, source_sha1=None, packed=False):
clean_name = name.replace(' *', '').replace('*', '').replace(' ', '_').replace('const', 'const_').replace('volatile', 'volatile_')
if clean_name in self.structs:
existing = self.structs[clean_name]
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 hasattr(self, 'SymbolTable') and self.SymbolTable and clean_name in self.SymbolTable:
Entry = self.SymbolTable[clean_name]
if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef:
resolved_str = self._resolve_typedef(clean_name)
if resolved_str != clean_name:
return self._type_str_to_llvm(resolved_str)
if hasattr(Entry, 'BaseType') and Entry.BaseType:
from lib.includes import t as _t
if not isinstance(Entry.BaseType, (_t._CTypedef,)) or getattr(Entry, 'PtrCount', 0) > 0:
resolved = self._resolve_ctype_to_str(Entry)
if resolved:
return self._type_str_to_llvm(resolved)
if hasattr(Entry, 'IsRenum') and Entry.IsRenum:
if clean_name in self.structs:
return self.structs[clean_name]
if hasattr(Entry, 'IsEnum') and Entry.IsEnum:
return ir.IntType(32)
if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass:
return ir.IntType(32)
if hasattr(Entry, 'BaseType'):
from lib.includes import t as _t
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)
if source_sha1:
ns_name = f"{source_sha1}.{clean_name}"
elif hasattr(self, '_struct_sha1_map') and 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(self.module, name=ns_name, packed=packed)
self.structs[clean_name] = st
# 尝试解析 typedef 的底层整数位宽
width = 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):
"""解析 typedef 名称的底层整数位宽
通过 CTypeRegistry 和 BuiltinTypeMap 动态解析,
替代硬编码的 TYPEDEF_NAMES 映射表。
返回 int 位宽或 None无法解析
"""
from lib.includes.t import CTypeRegistry
from lib.core.Handles.HandlesBase import BuiltinTypeMap
# 1. 先查 BuiltinTypeMap覆盖 BYTEPTR 等指针别名)
bm = BuiltinTypeMap.Get(name)
if bm:
ctype_cls, ptr_count = bm
if ptr_count > 0:
return None # 指针类型,不是整数 typedef
llvm_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 hasattr(self, 'SymbolTable') and self.SymbolTable and name in self.SymbolTable:
Entry = self.SymbolTable[name]
if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef:
if hasattr(Entry, 'BaseType') and Entry.BaseType:
from lib.includes import t as _t
if not isinstance(Entry.BaseType, (_t._CTypedef,)) and getattr(Entry, 'PtrCount', 0) == 0:
llvm_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 hasattr(Entry, 'OriginalType') and Entry.OriginalType:
from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo
if isinstance(Entry.OriginalType, _CTypeInfo) and Entry.OriginalType.BaseType:
if not isinstance(Entry.OriginalType.BaseType, (_t._CTypedef,)) and getattr(Entry.OriginalType, 'PtrCount', 0) == 0:
llvm_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:])
# 3. 尝试 CTypeRegistry 直接按名称查找
ctype_cls = CTypeRegistry.GetClassByName(name)
if ctype_cls:
llvm_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 = {
'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion',
'CStruct', 'enum', 'REnum', 'renum',
'list', 'dict', 'tuple', 'set', 'str', 'bytes', 'array', 'type',
}
if name in _SPECIAL_TYPEDEFS:
return 0 # 标记为 typedef但位宽为 0非整数
return None
def _set_node_info(self, node, extra_info=""):
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):
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 _ns_hash(self):
if 'workspace' in self._ns_cache:
return self._ns_cache['workspace']
cwd = os.getcwd().replace('\\', '/').lower()
digest = hashlib.sha1(cwd.encode('utf-8')).hexdigest()[:12]
self._ns_cache['workspace'] = digest
return digest
def _skip_mangle(self, name):
skip_prefixes = ('llvm.', 'str_const_', 'printf', 'memset_pattern')
if any(name.startswith(p) for p in skip_prefixes):
return True
if '.' in name:
parts = 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):
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):
if name in self.functions:
return self.functions[name]
g = self.module.globals.get(name)
if g and isinstance(g, ir.Function):
self.functions[name] = g
return g
mangled = 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 = 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):
return self._find_function(name) is not None
def _get_or_declare_function(self, mangled_name, func_type):
for g in self.module.globals:
if isinstance(g, ir.Function) and g.name == mangled_name:
return g
return ir.Function(self.module, func_type, name=mangled_name)
def _get_function(self, name):
func = self._find_function(name)
return func
def _mangle_func_name(self, name, module_name=None):
if name in self._export_funcs:
return name
if name in self._export_extern_funcs and name not in self._current_module_func_names:
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 = getattr(self, 'class_sha1_map', {})
if class_sha1_map:
if '.' in name:
base_class = name.split('.')[0]
if base_class in class_sha1_map:
sha1 = class_sha1_map[base_class]
return f"{sha1}.{name}"
elif name in class_sha1_map:
sha1 = 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 = self.ModuleSha1Map[module_name]
return f"{sha1}.{name}"
# Try parent package name (e.g., 'hashlib' -> 'hashlib.__init__')
if module_name:
init_name = f"{module_name}.__init__"
if init_name in self.ModuleSha1Map:
sha1 = 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):
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):
info = ""
if self._current_node_info:
info = f" [{self._current_node_info}]"
if self._current_source_file:
info += f" in {self._current_source_file}"
lineno = self._current_lineno
if lineno > 0:
info += f", line {lineno}:"
source_line = self._get_source_line(lineno)
if source_line:
info += f"\n{source_line}"
return info