snapshot before regression test
This commit is contained in:
657
lib/core/LLVMCG/BaseGen.py
Normal file
657
lib/core/LLVMCG/BaseGen.py
Normal file
@@ -0,0 +1,657 @@
|
||||
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_body(set_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 同名冲突),
|
||||
# 不能复用已有 struct(set_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 前缀不一致时(跨模块同名类冲突),
|
||||
# 不能复用已有 struct(set_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
|
||||
368
lib/core/LLVMCG/ExprGen.py
Normal file
368
lib/core/LLVMCG/ExprGen.py
Normal file
@@ -0,0 +1,368 @@
|
||||
from __future__ import annotations
|
||||
from typing import Any
|
||||
import logging
|
||||
import llvmlite.ir as ir
|
||||
from lib.constants.config import mode as _config_mode
|
||||
|
||||
|
||||
class ExprGenMixin:
|
||||
def emit_constant(self, value: Any, type_name: str = 'int') -> ir.Value:
|
||||
if type_name == 'int':
|
||||
return ir.Constant(ir.IntType(32), int(value))
|
||||
elif type_name == 'uint64_t' or type_name == 'unsigned long long':
|
||||
return ir.Constant(ir.IntType(64), int(value))
|
||||
elif type_name == 'uint32_t' or type_name == 'unsigned int':
|
||||
return ir.Constant(ir.IntType(32), int(value))
|
||||
elif type_name == 'uint16_t' or type_name == 'unsigned short':
|
||||
return ir.Constant(ir.IntType(16), int(value))
|
||||
elif type_name == 'uint8_t' or type_name == 'unsigned char':
|
||||
return ir.Constant(ir.IntType(8), int(value))
|
||||
elif type_name == 'int64_t' or type_name == 'long long':
|
||||
return ir.Constant(ir.IntType(64), int(value))
|
||||
elif type_name == 'int32_t' or type_name == 'int':
|
||||
return ir.Constant(ir.IntType(32), int(value))
|
||||
elif type_name == 'int16_t' or type_name == 'short':
|
||||
return ir.Constant(ir.IntType(16), int(value))
|
||||
elif type_name == 'int8_t' or type_name == 'char':
|
||||
return ir.Constant(ir.IntType(8), int(value))
|
||||
elif type_name == 'float' or type_name == 'float32_t' or type_name == 'FLOAT32':
|
||||
return ir.Constant(ir.FloatType(), float(value))
|
||||
elif type_name == 'double' or type_name == 'float64_t' or type_name == 'FLOAT64':
|
||||
return ir.Constant(ir.DoubleType(), float(value))
|
||||
elif type_name == 'float16_t' or type_name == 'FLOAT16':
|
||||
return ir.Constant(ir.IntType(16), int(value))
|
||||
elif type_name == 'float8_t' or type_name == 'FLOAT8':
|
||||
return ir.Constant(ir.IntType(8), int(value))
|
||||
elif type_name == 'float128_t' or type_name == 'FLOAT128':
|
||||
return ir.Constant(ir.IntType(128), int(value))
|
||||
elif type_name == 'string':
|
||||
encoded: bytes = value.encode('utf-8') + b'\x00'
|
||||
str_type: ir.ArrayType = ir.ArrayType(ir.IntType(8), len(encoded))
|
||||
str_const: ir.Constant = ir.Constant(str_type, bytearray(encoded))
|
||||
global_var: ir.GlobalVariable = ir.GlobalVariable(self.module, str_type, name=f"str_const_{self.string_const_counter}")
|
||||
self.string_const_counter += 1
|
||||
global_var.initializer = str_const
|
||||
global_var.linkage = 'internal'
|
||||
return self.builder.bitcast(global_var, ir.PointerType(ir.IntType(8)), name="str")
|
||||
return ir.Constant(ir.IntType(32), int(value))
|
||||
|
||||
def emit_binary_op(self, op: str, left: ir.Value, right: ir.Value, is_unsigned: bool = False) -> ir.Value:
|
||||
if isinstance(left.type, ir.PointerType) and isinstance(right.type, ir.IntType):
|
||||
# 数组指针需要先 decay 为元素指针,否则 GEP 会以整个数组为步长
|
||||
# 例如 [64 x i8]* + 1 会前进 64 字节而非 1 字节
|
||||
if isinstance(left.type.pointee, ir.ArrayType):
|
||||
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
|
||||
left = self.builder.gep(left, [zero, zero], name="array_decay")
|
||||
right = self.builder.zext(right, ir.IntType(64), name="int2ptrint")
|
||||
if op == '+' or op == 'Add':
|
||||
return self.builder.gep(left, [right], name="ptr_add")
|
||||
elif op == '-' or op == 'Sub':
|
||||
return self.builder.gep(left, [self.builder.neg(right, name="neg")], name="ptr_sub")
|
||||
if isinstance(left.type, ir.IntType) and isinstance(right.type, ir.PointerType):
|
||||
if isinstance(right.type.pointee, ir.ArrayType):
|
||||
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
|
||||
right = self.builder.gep(right, [zero, zero], name="array_decay_rev")
|
||||
left = self.builder.zext(left, ir.IntType(64), name="int2ptrint2")
|
||||
if op == '+' or op == 'Add':
|
||||
return self.builder.gep(right, [left], name="ptr_add_rev")
|
||||
is_float: bool = isinstance(left.type, (ir.FloatType, ir.DoubleType)) or \
|
||||
isinstance(right.type, (ir.FloatType, ir.DoubleType))
|
||||
if is_float:
|
||||
ftype: ir.Type
|
||||
if isinstance(left.type, (ir.FloatType, ir.DoubleType)):
|
||||
ftype = left.type
|
||||
elif isinstance(right.type, (ir.FloatType, ir.DoubleType)):
|
||||
ftype = right.type
|
||||
else:
|
||||
ftype = ir.DoubleType()
|
||||
if not isinstance(left.type, (ir.FloatType, ir.DoubleType)):
|
||||
left = self._to_float(left, ftype)
|
||||
elif left.type != ftype:
|
||||
if isinstance(left.type, ir.FloatType) and isinstance(ftype, ir.DoubleType):
|
||||
left = self.builder.fpext(left, ftype, name="fpext_l")
|
||||
else:
|
||||
left = self.builder.fptrunc(left, ftype, name="fptrunc_l")
|
||||
if not isinstance(right.type, (ir.FloatType, ir.DoubleType)):
|
||||
right = self._to_float(right, ftype)
|
||||
elif right.type != ftype:
|
||||
if isinstance(right.type, ir.FloatType) and isinstance(ftype, ir.DoubleType):
|
||||
right = self.builder.fpext(right, ftype, name="fpext_r")
|
||||
else:
|
||||
right = self.builder.fptrunc(right, ftype, name="fptrunc_r")
|
||||
float_ops: dict[str, Any] = {
|
||||
'+': self.builder.fadd, 'Add': self.builder.fadd,
|
||||
'-': self.builder.fsub, 'Sub': self.builder.fsub,
|
||||
'*': self.builder.fmul, 'Mult': self.builder.fmul,
|
||||
'/': self.builder.fdiv, 'Div': self.builder.fdiv,
|
||||
'%': self.builder.frem, 'Mod': self.builder.frem,
|
||||
}
|
||||
float_cmp_ops: dict[str, str] = {
|
||||
'==': '==', 'Eq': '==', '!=': '!=', 'NotEq': '!=',
|
||||
'<': '<', 'Lt': '<', '<=': '<=', 'LtE': '<=',
|
||||
'>': '>', 'Gt': '>', '>=': '>=', 'GtE': '>=',
|
||||
}
|
||||
if op in float_ops:
|
||||
return float_ops[op](left, right, name=op)
|
||||
if op in float_cmp_ops:
|
||||
return self.builder.fcmp_ordered(float_cmp_ops[op], left, right, name=op)
|
||||
ops: dict[str, Any]
|
||||
if is_unsigned:
|
||||
ops = {
|
||||
'+': self.builder.add, 'Add': self.builder.add,
|
||||
'-': self.builder.sub, 'Sub': self.builder.sub,
|
||||
'*': self.builder.mul, 'Mult': self.builder.mul,
|
||||
'/': self.builder.udiv, 'Div': self.builder.udiv,
|
||||
'%': self.builder.urem, 'Mod': self.builder.urem,
|
||||
'//': self.builder.udiv, 'FloorDiv': self.builder.udiv,
|
||||
}
|
||||
else:
|
||||
ops = {
|
||||
'+': self.builder.add, 'Add': self.builder.add,
|
||||
'-': self.builder.sub, 'Sub': self.builder.sub,
|
||||
'*': self.builder.mul, 'Mult': self.builder.mul,
|
||||
'/': self.builder.sdiv, 'Div': self.builder.sdiv,
|
||||
'%': self.builder.srem, 'Mod': self.builder.srem,
|
||||
'//': self.builder.sdiv, 'FloorDiv': self.builder.sdiv,
|
||||
}
|
||||
cmp_ops: dict[str, str] = {
|
||||
'==': '==', 'Eq': '==', '!=': '!=', 'NotEq': '!=',
|
||||
'<': '<', 'Lt': '<', '<=': '<=', 'LtE': '<=',
|
||||
'>': '>', 'Gt': '>', '>=': '>=', 'GtE': '>=',
|
||||
}
|
||||
logic_ops: dict[str, Any] = {
|
||||
'&&': self.builder.and_, 'And': self.builder.and_,
|
||||
'||': self.builder.or_, 'Or': self.builder.or_,
|
||||
}
|
||||
if op in ('>>', 'RShift') and not is_unsigned:
|
||||
if isinstance(left.type, ir.IntType):
|
||||
if left.type.width == 8:
|
||||
is_unsigned = True
|
||||
elif left.type.width == 16:
|
||||
is_unsigned = True
|
||||
elif left.type.width == 32:
|
||||
if self._last_var_name:
|
||||
is_unsigned = self._is_var_unsigned(self._last_var_name)
|
||||
elif left.type.width == 64:
|
||||
if self._last_var_name:
|
||||
is_unsigned = self._is_var_unsigned(self._last_var_name)
|
||||
shift_ops: dict[str, Any] = {
|
||||
'>>': self.builder.lshr if is_unsigned else self.builder.ashr,
|
||||
'RShift': self.builder.lshr if is_unsigned else self.builder.ashr,
|
||||
'<<': self.builder.shl, 'LShift': self.builder.shl,
|
||||
}
|
||||
bit_ops: dict[str, Any] = {
|
||||
'&': self.builder.and_,
|
||||
'|': self.builder.or_,
|
||||
'^': self.builder.xor,
|
||||
}
|
||||
if op == '**' or op == 'Pow':
|
||||
if isinstance(left, ir.Constant) and isinstance(right, ir.Constant):
|
||||
try:
|
||||
lv: Any = left.constant
|
||||
rv: Any = right.constant
|
||||
if isinstance(lv, int) and isinstance(rv, int) and rv >= 0:
|
||||
result: int = lv ** rv
|
||||
return ir.Constant(left.type, result)
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
logging.warning(f"异常被忽略: {_e}")
|
||||
pass
|
||||
ftype: ir.Type
|
||||
if isinstance(left.type, (ir.FloatType, ir.DoubleType)):
|
||||
ftype = left.type
|
||||
elif isinstance(right.type, (ir.FloatType, ir.DoubleType)):
|
||||
ftype = right.type
|
||||
else:
|
||||
ftype = ir.DoubleType()
|
||||
lf: ir.Value = self._to_float(left, ftype)
|
||||
rf: ir.Value = self._to_float(right, ftype)
|
||||
powf: ir.Function | None = self.module.globals.get('llvm.pow.f64')
|
||||
if not powf:
|
||||
fnty: ir.FunctionType = ir.FunctionType(ir.DoubleType(), [ir.DoubleType(), ir.DoubleType()])
|
||||
powf = ir.Function(self.module, fnty, name='llvm.pow.f64')
|
||||
if lf.type != ir.DoubleType():
|
||||
lf = self.builder.fpext(lf, ir.DoubleType(), name="ext_f64")
|
||||
if rf.type != ir.DoubleType():
|
||||
rf = self.builder.fpext(rf, ir.DoubleType(), name="ext_f64")
|
||||
result: ir.Value = self.builder.call(powf, [lf, rf], name="pow")
|
||||
both_int: bool = isinstance(left.type, ir.IntType) and isinstance(right.type, ir.IntType)
|
||||
right_is_pos_int_const: bool = isinstance(right, ir.Constant) and isinstance(right.constant, int) and right.constant >= 0
|
||||
if both_int and right_is_pos_int_const:
|
||||
return self.builder.fptosi(result, left.type, name="pow2int")
|
||||
if isinstance(left.type, ir.FloatType):
|
||||
return self.builder.fptrunc(result, ir.FloatType(), name="pow2f32")
|
||||
return result
|
||||
if op in ops:
|
||||
try:
|
||||
return ops[op](left, right, name=op)
|
||||
except Exception as e:
|
||||
raise ValueError(f"{e}{self._get_node_info()}")
|
||||
if op in shift_ops:
|
||||
try:
|
||||
return shift_ops[op](left, right, name=op)
|
||||
except Exception as e:
|
||||
raise ValueError(f"{e}{self._get_node_info()}")
|
||||
if op in bit_ops:
|
||||
try:
|
||||
return bit_ops[op](left, right, name=op)
|
||||
except Exception as e:
|
||||
raise ValueError(f"{e}{self._get_node_info()}")
|
||||
if op in cmp_ops:
|
||||
try:
|
||||
if is_unsigned:
|
||||
return self.builder.icmp_unsigned(cmp_ops[op], left, right, name=op)
|
||||
return self.builder.icmp_signed(cmp_ops[op], left, right, name=op)
|
||||
except Exception as e:
|
||||
raise ValueError(f"{e}{self._get_node_info()}")
|
||||
if op in logic_ops:
|
||||
try:
|
||||
return logic_ops[op](left, right, name=op)
|
||||
except Exception as e:
|
||||
raise ValueError(f"{e}{self._get_node_info()}")
|
||||
return left
|
||||
|
||||
def _to_float(self, val: ir.Value, ftype: ir.Type | None = None) -> ir.Value:
|
||||
if ftype is None:
|
||||
ftype = ir.DoubleType()
|
||||
if isinstance(val.type, (ir.FloatType, ir.DoubleType)):
|
||||
if val.type == ftype:
|
||||
return val
|
||||
if isinstance(val.type, ir.FloatType) and isinstance(ftype, ir.DoubleType):
|
||||
return self.builder.fpext(val, ftype, name="fpext")
|
||||
return self.builder.fptrunc(val, ftype, name="fptrunc")
|
||||
if isinstance(val.type, ir.IntType):
|
||||
if val.type.width == 1:
|
||||
val = self.builder.zext(val, ir.IntType(32), name="bool2i32")
|
||||
return self.builder.sitofp(val, ftype, name="int2float")
|
||||
return val
|
||||
|
||||
def emit_return(self, value: ir.Value | None = None) -> None:
|
||||
if not self.builder or self.builder.block.is_terminated:
|
||||
return
|
||||
if value is not None:
|
||||
self._unregister_local_heap_ptr(value)
|
||||
self._emit_local_heap_frees()
|
||||
if self._variadic_info and self._variadic_info.get('va_start_called'):
|
||||
va_list_ptr: ir.Value = self._variadic_info['va_list_ptr']
|
||||
self.emit_va_end(va_list_ptr)
|
||||
if value is None:
|
||||
if self.func and hasattr(self.func, 'ftype'):
|
||||
ret_type: ir.Type = self.func.ftype.return_type
|
||||
if isinstance(ret_type, ir.IntType):
|
||||
self.builder.ret(ir.Constant(ret_type, 0))
|
||||
elif isinstance(ret_type, ir.PointerType):
|
||||
self.builder.ret(ir.Constant(ret_type, None))
|
||||
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
|
||||
self.builder.ret(ir.Constant(ret_type, 0.0))
|
||||
elif isinstance(ret_type, ir.BaseStructType):
|
||||
if ret_type.elements:
|
||||
zero_val: ir.Constant = ir.Constant(ret_type, [ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
|
||||
else:
|
||||
zero_val = ir.Constant(ret_type, None)
|
||||
self.builder.ret(zero_val)
|
||||
elif isinstance(ret_type, ir.ArrayType):
|
||||
self.builder.ret(ir.Constant(ret_type, None))
|
||||
else:
|
||||
self.builder.ret_void()
|
||||
else:
|
||||
self.builder.ret_void()
|
||||
else:
|
||||
if self.func and hasattr(self.func, 'ftype'):
|
||||
ret_type: ir.Type = self.func.ftype.return_type
|
||||
if ret_type != value.type:
|
||||
if isinstance(ret_type, ir.PointerType) and isinstance(value.type, ir.PointerType):
|
||||
value = self.builder.bitcast(value, ret_type, name="ret_cast")
|
||||
elif isinstance(value.type, ir.PointerType) and not isinstance(ret_type, ir.PointerType):
|
||||
if isinstance(value.type.pointee, ir.IntType) and isinstance(ret_type, ir.IntType) and value.type.pointee.width == ret_type.width:
|
||||
value = self._load(value, name="ret_Load")
|
||||
elif isinstance(ret_type, ir.IntType):
|
||||
value = self.builder.ptrtoint(value, ret_type, name="ret_ptrtoint")
|
||||
elif isinstance(value.type.pointee, ret_type.__class__) and not isinstance(value.type.pointee, ir.IntType):
|
||||
value = self._load(value, name="ret_Load")
|
||||
elif isinstance(value.type.pointee, ir.PointerType):
|
||||
Loaded: ir.Value = self._load(value, name="ret_deref")
|
||||
if Loaded.type == ret_type:
|
||||
value = Loaded
|
||||
elif isinstance(ret_type, ir.IntType):
|
||||
value = self.builder.ptrtoint(Loaded, ret_type, name="ret_ptrtoint")
|
||||
elif isinstance(ret_type, ir.IntType) and isinstance(value.type, ir.IntType):
|
||||
if value.type.width < ret_type.width:
|
||||
if value.type.width == 1:
|
||||
# i1 是布尔值(来自 icmp/fcmp/__contains__),无符号语义,必须 zext
|
||||
value = self.builder.zext(value, ret_type, name="ret_zext_bool")
|
||||
else:
|
||||
is_unsigned: bool = id(value) in self._unsigned_results
|
||||
if is_unsigned:
|
||||
value = self.builder.zext(value, ret_type, name="ret_zext")
|
||||
else:
|
||||
value = self.builder.sext(value, ret_type, name="ret_sext")
|
||||
elif value.type.width > ret_type.width:
|
||||
value = self.builder.trunc(value, ret_type, name="ret_trunc")
|
||||
elif isinstance(ret_type, ir.PointerType) and isinstance(value.type, ir.IntType):
|
||||
value = self.builder.inttoptr(value, ret_type, name="ret_inttoptr")
|
||||
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)) and isinstance(value.type, ir.IntType):
|
||||
value = self.builder.sitofp(value, ret_type, name="ret_int2float")
|
||||
elif isinstance(ret_type, ir.IntType) and isinstance(value.type, (ir.FloatType, ir.DoubleType)):
|
||||
value = self.builder.fptosi(value, ret_type, name="ret_float2int")
|
||||
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)) and isinstance(value.type, (ir.FloatType, ir.DoubleType)):
|
||||
if ret_type != value.type:
|
||||
if isinstance(value.type, ir.FloatType) and isinstance(ret_type, ir.DoubleType):
|
||||
value = self.builder.fpext(value, ret_type, name="ret_fpext")
|
||||
elif isinstance(value.type, ir.DoubleType) and isinstance(ret_type, ir.FloatType):
|
||||
value = self.builder.fptrunc(value, ret_type, name="ret_fptrunc")
|
||||
self.builder.ret(value)
|
||||
|
||||
def _emit_printf(self, args: list[ir.Value], unsigned_flags: list[bool] | None = None, sep: str = " ", end: str = "\n") -> ir.Value | None:
|
||||
if not args:
|
||||
return None
|
||||
if unsigned_flags is None:
|
||||
unsigned_flags = []
|
||||
format_str: str = ""
|
||||
cast_args: list[ir.Value] = []
|
||||
for i, arg in enumerate(args):
|
||||
is_u: bool = i < len(unsigned_flags) and unsigned_flags[i]
|
||||
if isinstance(arg.type, ir.IntType):
|
||||
if arg.type.width == 1:
|
||||
# i1 是布尔值(来自 icmp/fcmp/__contains__),zext 到 i32 后用 %d
|
||||
format_str += "%d"
|
||||
ext: ir.Value = self.builder.zext(arg, ir.IntType(32), name="bool2int")
|
||||
cast_args.append(ext)
|
||||
elif arg.type.width == 8:
|
||||
format_str += "%c"
|
||||
ext: ir.Value = self.builder.zext(arg, ir.IntType(32), name="char2int")
|
||||
cast_args.append(ext)
|
||||
elif arg.type.width == 64:
|
||||
format_str += "%llu" if is_u else "%lld"
|
||||
cast_args.append(arg)
|
||||
else:
|
||||
format_str += "%u" if is_u else "%d"
|
||||
cast_args.append(arg)
|
||||
elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)):
|
||||
format_str += "%f"
|
||||
cast_args.append(arg)
|
||||
elif isinstance(arg.type, ir.PointerType):
|
||||
if isinstance(arg.type.pointee, ir.IntType) and arg.type.pointee.width == 8:
|
||||
format_str += "%s"
|
||||
cast_args.append(arg)
|
||||
else:
|
||||
format_str += "%d"
|
||||
int_val: ir.Value = self.builder.ptrtoint(arg, ir.IntType(64), name="ptr2int")
|
||||
trunc_val: ir.Value = self.builder.trunc(int_val, ir.IntType(32), name="trunc")
|
||||
cast_args.append(trunc_val)
|
||||
else:
|
||||
format_str += "%d"
|
||||
cast_args.append(arg)
|
||||
if sep is not None and i < len(args) - 1:
|
||||
format_str += sep
|
||||
if end is not None:
|
||||
format_str += end
|
||||
string_type: ir.ArrayType = ir.ArrayType(ir.IntType(8), len(format_str.encode('utf-8')) + 1)
|
||||
string_const: ir.Constant = ir.Constant(string_type, bytearray(format_str + '\x00', 'utf-8'))
|
||||
global_var: ir.GlobalVariable = ir.GlobalVariable(self.module, string_type, name=f"str_const_{self.string_const_counter}")
|
||||
self.string_const_counter += 1
|
||||
global_var.initializer = string_const
|
||||
global_var.linkage = 'internal'
|
||||
format_ptr: ir.Value = self.builder.bitcast(global_var, ir.PointerType(ir.IntType(8)))
|
||||
call_args: list[ir.Value] = [format_ptr] + cast_args
|
||||
printf_func: ir.Function | None = self.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
|
||||
return self.builder.call(printf_func, call_args, name="call_printf")
|
||||
524
lib/core/LLVMCG/FuncGen.py
Normal file
524
lib/core/LLVMCG/FuncGen.py
Normal file
@@ -0,0 +1,524 @@
|
||||
from __future__ import annotations
|
||||
from typing import Any
|
||||
import ast
|
||||
import os
|
||||
import re
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Handles.HandlesBase import CTypeInfo
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
|
||||
|
||||
class FuncGenMixin:
|
||||
|
||||
def setup_from_symbol_table(self, SymbolTable: Any) -> None:
|
||||
self.SymbolTable: Any = SymbolTable
|
||||
for name, info in SymbolTable.items():
|
||||
if isinstance(info, CTypeInfo):
|
||||
# CTypeInfo 对象:struct/union 由 StructGen 处理,此处只处理 dict 格式
|
||||
continue
|
||||
if not isinstance(info, dict):
|
||||
if hasattr(info, 'get'):
|
||||
info = dict(info) if hasattr(info, '__iter__') else {}
|
||||
else:
|
||||
continue
|
||||
TypeKind: str = info.get('type', '')
|
||||
if TypeKind == 'struct':
|
||||
ClassName: str = name
|
||||
self.class_methods[ClassName] = []
|
||||
self.class_members[ClassName] = []
|
||||
members: dict[str, Any] = info.get('members', {})
|
||||
if members:
|
||||
for MemberName, MemberInfo in members.items():
|
||||
if isinstance(MemberInfo, dict):
|
||||
MemberType: ir.Type = self._type_str_to_llvm(MemberInfo.get('type', 'int'), MemberInfo.get('IsPtr', False))
|
||||
self.class_members[ClassName].append((MemberName, MemberType))
|
||||
elif isinstance(MemberInfo, CTypeInfo):
|
||||
MemberType: ir.Type = self._ctype_to_llvm(MemberInfo)
|
||||
if MemberType is None:
|
||||
MemberType = self._type_str_to_llvm(MemberInfo.ToString(), MemberInfo.IsPtr)
|
||||
self.class_members[ClassName].append((MemberName, MemberType))
|
||||
self._generate_structs()
|
||||
self._create_Vtable_globals()
|
||||
|
||||
def register_method(self, ClassName: str, MethodName: str) -> None:
|
||||
if ClassName not in self.class_methods:
|
||||
self.class_methods[ClassName] = []
|
||||
if ClassName not in self.class_members:
|
||||
self.class_members[ClassName] = []
|
||||
self._generate_structs()
|
||||
self._create_Vtable_globals()
|
||||
# 构造函数(__new__/__init__/__before_init__)不放入 vtable,
|
||||
# 避免子类与基类 vtable 大小不一致导致虚分派索引偏移
|
||||
_short_name: str = MethodName.split('.')[-1] if '.' in MethodName else MethodName
|
||||
if _short_name in ('__new__', '__init__', '__before_init__'):
|
||||
return
|
||||
if MethodName not in self.class_methods[ClassName]:
|
||||
self.class_methods[ClassName].append(MethodName)
|
||||
|
||||
def _apply_auto_addr(self, func_name: str, args: list[ir.Value]) -> list[ir.Value]:
|
||||
"""对函数参数应用自动取地址逻辑(t.CNeedPtr / t.CAutoPtr)。
|
||||
|
||||
在调用前对标记为 auto-addr 的参数自动取地址:
|
||||
- 'need' (t.CNeedPtr): 仅对非指针值取地址(alloca + store + get pointer)
|
||||
- 'always' (t.CAutoPtr): 无条件取地址
|
||||
"""
|
||||
modes: list[str | None] | None = self._auto_addr_params.get(func_name)
|
||||
if not modes:
|
||||
return args
|
||||
new_args: list[ir.Value] = list(args)
|
||||
for i, mode in enumerate(modes):
|
||||
if i >= len(new_args) or mode is None:
|
||||
continue
|
||||
arg: ir.Value = new_args[i]
|
||||
is_ptr: bool = isinstance(arg.type, ir.PointerType)
|
||||
if mode == 'always' or (mode == 'need' and not is_ptr):
|
||||
# alloca + store + get pointer
|
||||
slot: ir.Value = self.builder.alloca(arg.type)
|
||||
self.builder.store(arg, slot)
|
||||
new_args[i] = slot
|
||||
return new_args
|
||||
|
||||
def _adjust_args(self, args: list[ir.Value], func: ir.Function) -> list[ir.Value]:
|
||||
adjusted: list[ir.Value] = []
|
||||
for i, (arg, param) in enumerate(zip(args, func.args)):
|
||||
if arg.type != param.type:
|
||||
if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
|
||||
if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name):
|
||||
# C 语言中数组参数退化为指针,不做 load 而是退化为元素指针
|
||||
if isinstance(param.type, ir.ArrayType):
|
||||
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
|
||||
elem_ptr: ir.Value = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}")
|
||||
adjusted.append(elem_ptr)
|
||||
else:
|
||||
adjusted.append(self._load(arg, name=f"Load_arg_{i}"))
|
||||
continue
|
||||
try:
|
||||
if isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.PointerType):
|
||||
if isinstance(param.type.pointee, ir.IntType) and param.type.pointee.width == 8 and arg.type.width == 8:
|
||||
# 当参数是 i8(字符值)而函数期望 i8*(字符串指针)时
|
||||
# 为字符值分配内存,创建 null-terminated 字符串
|
||||
tmp: ir.AllocaInstr = self._alloca(ir.ArrayType(ir.IntType(8), 2), name=f"char2str_arg_{i}")
|
||||
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
|
||||
char_ptr: ir.Value = self.builder.gep(tmp, [zero, zero], name=f"char2str_ptr_{i}")
|
||||
self._store(arg, char_ptr)
|
||||
null_ptr: ir.Value = self.builder.gep(tmp, [zero, ir.Constant(ir.IntType(32), 1)], name=f"char2str_null_{i}")
|
||||
self._store(ir.Constant(ir.IntType(8), 0), null_ptr)
|
||||
adjusted.append(char_ptr)
|
||||
else:
|
||||
if isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType):
|
||||
# 当参数是指针而函数期望整数时,使用 ptrtoint
|
||||
adjusted.append(self.builder.ptrtoint(arg, param.type, name=f"ptrtoint_arg_{i}"))
|
||||
else:
|
||||
if arg.type.width < 32:
|
||||
arg = self.builder.zext(arg, ir.IntType(32), name=f"zext_arg_{i}")
|
||||
adjusted.append(self.builder.inttoptr(arg, param.type, name=f"inttoptr_arg_{i}"))
|
||||
elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType):
|
||||
# 当参数是指针而函数期望整数时,使用 ptrtoint
|
||||
adjusted.append(self.builder.ptrtoint(arg, param.type, name=f"ptrtoint_arg_{i}"))
|
||||
elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.PointerType):
|
||||
if isinstance(arg.type.pointee, ir.PointerType) and isinstance(param.type.pointee, ir.IntType):
|
||||
Loaded: ir.Value = self._load(arg, name=f"Load_arg_{i}")
|
||||
adjusted.append(Loaded)
|
||||
elif isinstance(arg.type.pointee, ir.ArrayType) and isinstance(param.type.pointee, (ir.IntType, ir.FloatType, ir.DoubleType)):
|
||||
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
|
||||
elem_ptr: ir.Value = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}")
|
||||
if elem_ptr.type != param.type:
|
||||
adjusted.append(self.builder.bitcast(elem_ptr, param.type, name=f"cast_arg_{i}"))
|
||||
else:
|
||||
adjusted.append(elem_ptr)
|
||||
elif isinstance(arg.type.pointee, ir.ArrayType) and isinstance(param.type.pointee, ir.PointerType):
|
||||
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
|
||||
elem_ptr: ir.Value = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}")
|
||||
if elem_ptr.type != param.type:
|
||||
adjusted.append(self.builder.bitcast(elem_ptr, param.type, name=f"cast_arg_{i}"))
|
||||
else:
|
||||
adjusted.append(elem_ptr)
|
||||
else:
|
||||
adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}"))
|
||||
else:
|
||||
if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
|
||||
if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name):
|
||||
adjusted.append(self._load(arg, name=f"Load_arg_{i}"))
|
||||
elif isinstance(arg.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
|
||||
tmp: ir.AllocaInstr = self._alloca(param.type, name=f"temp_arg_{i}")
|
||||
Loaded: ir.Value = self.builder.bitcast(arg, ir.PointerType(param.type), name=f"cast_arg_{i}")
|
||||
Loaded_val: ir.Value = self._load(Loaded, name=f"Load_arg_{i}")
|
||||
self._store(Loaded_val, tmp)
|
||||
adjusted.append(self._load(tmp, name=f"reLoad_arg_{i}"))
|
||||
else:
|
||||
tmp: ir.AllocaInstr = self._alloca(param.type, name=f"temp_arg_{i}")
|
||||
cast_ptr: ir.Value = self.builder.bitcast(arg, ir.PointerType(param.type), name=f"cast_arg_{i}")
|
||||
Loaded_val: ir.Value = self._load(cast_ptr, name=f"Load_arg_{i}")
|
||||
self._store(Loaded_val, tmp)
|
||||
adjusted.append(self._load(tmp, name=f"reLoad_arg_{i}"))
|
||||
elif isinstance(arg.type, ir.PointerType) and arg.type.pointee == param.type:
|
||||
adjusted.append(self._load(arg, name=f"Load_arg_{i}"))
|
||||
elif isinstance(param.type, ir.PointerType) and param.type.pointee == arg.type:
|
||||
tmp: ir.AllocaInstr = self._alloca(arg.type, name=f"temp_arg_{i}")
|
||||
self._store(arg, tmp)
|
||||
adjusted.append(tmp)
|
||||
elif isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.IntType):
|
||||
if arg.type.width < param.type.width:
|
||||
# 整数扩展:使用 sext(符号扩展)以正确处理负数
|
||||
adjusted.append(self.builder.sext(arg, param.type, name=f"sext_arg_{i}"))
|
||||
else:
|
||||
adjusted.append(self.builder.trunc(arg, param.type, name=f"trunc_arg_{i}"))
|
||||
elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)) and isinstance(param.type, (ir.FloatType, ir.DoubleType)):
|
||||
if isinstance(arg.type, ir.DoubleType) and isinstance(param.type, ir.FloatType):
|
||||
adjusted.append(self.builder.fptrunc(arg, param.type, name=f"fptrunc_arg_{i}"))
|
||||
elif isinstance(arg.type, ir.FloatType) and isinstance(param.type, ir.DoubleType):
|
||||
adjusted.append(self.builder.fpext(arg, param.type, name=f"fpext_arg_{i}"))
|
||||
else:
|
||||
adjusted.append(arg)
|
||||
elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)) and isinstance(param.type, ir.IntType):
|
||||
adjusted.append(self.builder.fptosi(arg, param.type, name=f"fptosi_arg_{i}"))
|
||||
elif isinstance(arg.type, ir.IntType) and isinstance(param.type, (ir.FloatType, ir.DoubleType)):
|
||||
adjusted.append(self.builder.sitofp(arg, param.type, name=f"sitofp_arg_{i}"))
|
||||
elif isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.PointerType):
|
||||
# 整数转指针:inttoptr
|
||||
if arg.type.width < 64:
|
||||
i64_val: ir.Value = self.builder.sext(arg, ir.IntType(64), name=f"sext_arg_{i}")
|
||||
adjusted.append(self.builder.inttoptr(i64_val, param.type, name=f"inttoptr_arg_{i}"))
|
||||
else:
|
||||
adjusted.append(self.builder.inttoptr(arg, param.type, name=f"inttoptr_arg_{i}"))
|
||||
elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType):
|
||||
# 指针转整数:ptrtoint
|
||||
i64_val: ir.Value = self.builder.ptrtoint(arg, ir.IntType(64), name=f"ptrtoint_arg_{i}")
|
||||
if i64_val.type.width > param.type.width:
|
||||
adjusted.append(self.builder.trunc(i64_val, param.type, name=f"trunc_arg_{i}"))
|
||||
elif i64_val.type.width < param.type.width:
|
||||
adjusted.append(self.builder.sext(i64_val, param.type, name=f"sext_arg_{i}"))
|
||||
else:
|
||||
adjusted.append(i64_val)
|
||||
else:
|
||||
adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}"))
|
||||
except Exception: # 参数类型调整失败时使用简化回退逻辑
|
||||
if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
|
||||
if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name):
|
||||
adjusted.append(self._load(arg, name=f"Load_arg_{i}"))
|
||||
else:
|
||||
adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}"))
|
||||
elif isinstance(arg.type, ir.PointerType) and arg.type.pointee == param.type:
|
||||
adjusted.append(self._load(arg, name=f"Load_arg_{i}"))
|
||||
elif isinstance(param.type, ir.PointerType) and param.type.pointee == arg.type:
|
||||
tmp: ir.AllocaInstr = self._alloca(arg.type, name=f"temp_arg_{i}")
|
||||
self._store(arg, tmp)
|
||||
adjusted.append(tmp)
|
||||
elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.PointerType):
|
||||
# 任意指针到指针的类型转换(如 struct* -> i8*)
|
||||
adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}"))
|
||||
else:
|
||||
adjusted.append(arg)
|
||||
else:
|
||||
adjusted.append(arg)
|
||||
while len(adjusted) < len(func.args):
|
||||
missing_idx: int = len(adjusted)
|
||||
param: ir.Argument = func.args[missing_idx]
|
||||
param_type: ir.Type = param.type if hasattr(param, 'type') else param
|
||||
if isinstance(param_type, ir.PointerType):
|
||||
adjusted.append(ir.Constant(param_type, None))
|
||||
elif isinstance(param_type, ir.IntType):
|
||||
adjusted.append(ir.Constant(param_type, 0))
|
||||
elif isinstance(param_type, (ir.FloatType, ir.DoubleType)):
|
||||
adjusted.append(ir.Constant(param_type, 0.0))
|
||||
else:
|
||||
adjusted.append(ir.Constant(ir.IntType(32), 0))
|
||||
if func.type.pointee.var_arg:
|
||||
for i in range(len(func.args), len(args)):
|
||||
arg: ir.Value = args[i]
|
||||
adjusted.append(arg)
|
||||
return adjusted
|
||||
|
||||
def _get_member_offset(self, field_name: str, ClassName: str | None = None) -> int | None:
|
||||
# 治本修复:同名类 sha1 冲突检测。
|
||||
# 当 class_sha1_map[ClassName] 的 sha1 与 Gen.structs[ClassName] 的 sha1 不一致时,
|
||||
# class_members[ClassName] 可能存储了错误模块的同名类成员。
|
||||
# 此处检测冲突,加载正确模块的 class_members 并以 sha1 前缀全名缓存。
|
||||
_ResolvedClass: str = ClassName if ClassName else ''
|
||||
if ClassName:
|
||||
_ClassSha1Map: dict[str, str] = getattr(self, 'class_sha1_map', {})
|
||||
_ExpectedSha1: str | None = _ClassSha1Map.get(ClassName)
|
||||
if _ExpectedSha1:
|
||||
_ExistingStruct = self.structs.get(ClassName)
|
||||
if isinstance(_ExistingStruct, ir.IdentifiedStructType):
|
||||
_ExistingSha1: str = self._extract_struct_sha1(_ExistingStruct)
|
||||
if _ExistingSha1 and _ExistingSha1 != _ExpectedSha1:
|
||||
# sha1 冲突:使用全名查找 class_members
|
||||
_FullKey: str = f"{_ExpectedSha1}.{ClassName}"
|
||||
if _FullKey in self.class_members and self.class_members[_FullKey]:
|
||||
_ResolvedClass = _FullKey
|
||||
else:
|
||||
# 从正确 stub 加载 class_members
|
||||
if self._Trans and hasattr(self._Trans, 'ImportHandler'):
|
||||
_StubName: str = f"{_ExpectedSha1}.stub.ll"
|
||||
# 临时保存旧值,清除短名条目以绕过 guard,加载后恢复
|
||||
_OldMembers = self.class_members.get(ClassName)
|
||||
self.class_members[ClassName] = []
|
||||
try:
|
||||
self._Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, _StubName, self)
|
||||
except Exception:
|
||||
pass
|
||||
_NewMembers = self.class_members.get(ClassName)
|
||||
if _NewMembers:
|
||||
self.class_members[_FullKey] = _NewMembers
|
||||
_ResolvedClass = _FullKey
|
||||
# 恢复旧值(避免影响其他代码对短名的依赖)
|
||||
if _OldMembers:
|
||||
self.class_members[ClassName] = _OldMembers
|
||||
else:
|
||||
self.class_members.pop(ClassName, None)
|
||||
has_vtable: bool = ClassName and (ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes)
|
||||
base: int = 1 if has_vtable else 0
|
||||
if ClassName and ClassName in self.structs:
|
||||
struct_type: ir.IdentifiedStructType = self.structs[ClassName]
|
||||
if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None and len(struct_type.elements) > 0:
|
||||
if ClassName in self.class_members:
|
||||
expected_fields: int = len(self.class_members[ClassName])
|
||||
actual_elements: int = len(struct_type.elements)
|
||||
if base > 0 and actual_elements == expected_fields:
|
||||
base = 0
|
||||
elif base == 0 and actual_elements == expected_fields + 1:
|
||||
# 跨模块类可能未被检测为 CVTable(如 Name 继承 AST@t.CVTable),
|
||||
# 但实际 struct 首元素是 vtable ptr → 需 base=1。
|
||||
# 但若类有继承(class_parent 有值),多出的 1 可能是继承字段而非 vtable,
|
||||
# 需检查 struct 首元素类型:i8*/i8** 为 vtable,其他为继承字段。
|
||||
_first_elem = struct_type.elements[0] if actual_elements > 0 else None
|
||||
_has_parent = self.class_parent.get(ClassName) is not None
|
||||
_is_vtable_ptr = (isinstance(_first_elem, ir.PointerType) and
|
||||
isinstance(_first_elem.pointee, ir.IntType) and _first_elem.pointee.width == 8)
|
||||
if not _has_parent or _is_vtable_ptr:
|
||||
base = 1
|
||||
if _ResolvedClass and _ResolvedClass in self.class_members:
|
||||
for i, (name, _) in enumerate(self.class_members[_ResolvedClass]):
|
||||
if name == field_name:
|
||||
return base + i
|
||||
# 继承链回退:当字段不在当前类的 class_members 中时(常见于跨模块导入
|
||||
# 父类未加载,字段被填充为 __inherited_N 占位名),沿 class_parent 链向上查找。
|
||||
# 子类 struct 布局为 [vtable?] + [基类字段...] + [子类字段...],
|
||||
# 基类字段在子类 struct 中的起始偏移即为 base(子类),
|
||||
# 因此祖先 class_members 中的索引 i 对应子类 struct 中的偏移 base + i。
|
||||
if ClassName and field_name:
|
||||
_parent: str | None = self.class_parent.get(ClassName)
|
||||
_visited: set = {ClassName} if ClassName else set()
|
||||
while _parent and _parent not in _visited:
|
||||
_visited.add(_parent)
|
||||
# 跳过 __inherited_N 占位条目,只在真实字段名中查找
|
||||
if _parent in self.class_members:
|
||||
_members: list = self.class_members[_parent]
|
||||
_has_placeholder: bool = any(n.startswith('__inherited_') for n, _ in _members)
|
||||
if not _has_placeholder:
|
||||
for i, (name, _) in enumerate(_members):
|
||||
if name == field_name:
|
||||
return base + i
|
||||
# 父类 class_members 未加载或含占位条目,尝试从 stub 加载真实字段
|
||||
if self._Trans and hasattr(self._Trans, 'ImportHandler'):
|
||||
sha1_map: dict[str, str] = getattr(self, 'ModuleSha1Map', {})
|
||||
for mod_name, mod_sha1 in sha1_map.items():
|
||||
stub_name: str = f"{mod_sha1}.stub.ll"
|
||||
self._Trans.ImportHandler._TryLoadClassMembersFromPyi(_parent, stub_name, self)
|
||||
if _parent in self.class_members and not any(n.startswith('__inherited_') for n, _ in self.class_members[_parent]):
|
||||
for i, (name, _) in enumerate(self.class_members[_parent]):
|
||||
if name == field_name:
|
||||
return base + i
|
||||
break
|
||||
_parent = self.class_parent.get(_parent)
|
||||
short_name: str | None = ClassName.split('.')[-1] if ClassName and '.' in ClassName else None
|
||||
if short_name and short_name in self.class_members:
|
||||
for i, (name, _) in enumerate(self.class_members[short_name]):
|
||||
if name == field_name:
|
||||
return base + i
|
||||
if ClassName and field_name:
|
||||
if ClassName not in self.class_members or field_name not in [n for n, _ in self.class_members.get(ClassName, [])]:
|
||||
if self._Trans and hasattr(self._Trans, 'ImportHandler'):
|
||||
sha1_map: dict[str, str] = getattr(self, 'ModuleSha1Map', {})
|
||||
for mod_name, mod_sha1 in sha1_map.items():
|
||||
stub_name: str = f"{mod_sha1}.stub.ll"
|
||||
self._Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, stub_name, self)
|
||||
if ClassName in self.class_members and len(self.class_members[ClassName]) > 0:
|
||||
for i, (name, _) in enumerate(self.class_members[ClassName]):
|
||||
if name == field_name:
|
||||
return base + i
|
||||
break
|
||||
if short_name:
|
||||
for mod_name, mod_sha1 in sha1_map.items():
|
||||
stub_name: str = f"{mod_sha1}.stub.ll"
|
||||
self._Trans.ImportHandler._TryLoadClassMembersFromPyi(short_name, stub_name, self)
|
||||
if short_name in self.class_members and len(self.class_members[short_name]) > 0:
|
||||
for i, (name, _) in enumerate(self.class_members[short_name]):
|
||||
if name == field_name:
|
||||
return base + i
|
||||
break
|
||||
if ClassName and field_name:
|
||||
for cn_key in self.class_members:
|
||||
if cn_key == ClassName or cn_key.endswith(f'.{ClassName}') or (short_name and (cn_key == short_name or cn_key.endswith(f'.{short_name}'))):
|
||||
for i, (name, _) in enumerate(self.class_members[cn_key]):
|
||||
if name == field_name:
|
||||
return base + i
|
||||
# REnum 变体搜索: ClassName 是 REnum(如 MetaType),成员注册在变体结构
|
||||
# (MetaType_Var, MetaType_Concrete, MetaType_App)中。变体与 REnum 主结构
|
||||
# 共享 max_variant_struct 布局,偏移一致(__tag 在偏移 0,字段从偏移 1 开始)
|
||||
if ClassName and field_name:
|
||||
variant_prefix: str = f"{ClassName}_"
|
||||
for cn_key in self.class_members:
|
||||
if cn_key.startswith(variant_prefix):
|
||||
for i, (name, _) in enumerate(self.class_members[cn_key]):
|
||||
if name == field_name:
|
||||
return i
|
||||
if short_name:
|
||||
variant_prefix = f"{short_name}_"
|
||||
for cn_key in self.class_members:
|
||||
if cn_key.startswith(variant_prefix):
|
||||
for i, (name, _) in enumerate(self.class_members[cn_key]):
|
||||
if name == field_name:
|
||||
return i
|
||||
if ClassName and ClassName in self.structs:
|
||||
struct_type: ir.IdentifiedStructType = self.structs[ClassName]
|
||||
if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None and len(struct_type.elements) > 0:
|
||||
for cn_key, members in self.class_members.items():
|
||||
if cn_key == short_name or (short_name and cn_key.endswith(f'.{short_name}')):
|
||||
for i, (name, _) in enumerate(members):
|
||||
if name == field_name and i < len(struct_type.elements):
|
||||
return i
|
||||
break
|
||||
else:
|
||||
if short_name:
|
||||
for cn_key, members in self.class_members.items():
|
||||
sn: str = cn_key.split('.')[-1] if '.' in cn_key else cn_key
|
||||
if sn == short_name:
|
||||
for i, (name, _) in enumerate(members):
|
||||
if name == field_name and i < len(struct_type.elements):
|
||||
return i
|
||||
break
|
||||
if ClassName and field_name and ClassName not in self.class_members:
|
||||
if self._Trans and hasattr(self._Trans, 'ImportHandler'):
|
||||
for temp_dir_candidate in [getattr(self, '_temp_dir', None)]:
|
||||
if temp_dir_candidate and os.path.isdir(temp_dir_candidate):
|
||||
for pyi_file in os.listdir(temp_dir_candidate):
|
||||
if pyi_file.endswith('.pyi'):
|
||||
stub_name: str = pyi_file.replace('.pyi', '.stub.ll')
|
||||
short_cn: str = short_name if short_name else ClassName
|
||||
self._Trans.ImportHandler._TryLoadClassMembersFromPyi(short_cn, stub_name, self)
|
||||
if short_cn in self.class_members and len(self.class_members[short_cn]) > 0:
|
||||
for i, (name, _) in enumerate(self.class_members[short_cn]):
|
||||
if name == field_name:
|
||||
return base + i
|
||||
break
|
||||
if ClassName and ClassName in self.structs and (ClassName not in self.class_members or len(self.class_members.get(ClassName, [])) == 0):
|
||||
struct_type: ir.IdentifiedStructType = self.structs[ClassName]
|
||||
if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None:
|
||||
if self._Trans and hasattr(self._Trans, 'ClassHandler'):
|
||||
class_handler: Any = self._Trans.ClassHandler
|
||||
if self._current_tree:
|
||||
for node in ast.iter_child_nodes(self._current_tree):
|
||||
if isinstance(node, ast.ClassDef) and (node.name == ClassName or node.name == short_name):
|
||||
if node.name not in self.class_members:
|
||||
self.class_members[node.name] = []
|
||||
if len(self.class_members[node.name]) == 0:
|
||||
class_handler._PreRegisterClassMembers(node, self)
|
||||
if ClassName in self.class_members:
|
||||
for i, (name, _) in enumerate(self.class_members[ClassName]):
|
||||
if name == field_name:
|
||||
return base + i
|
||||
if short_name and short_name in self.class_members:
|
||||
for i, (name, _) in enumerate(self.class_members[short_name]):
|
||||
if name == field_name:
|
||||
return base + i
|
||||
break
|
||||
# 最后回退:当继承链回退失败但 struct body 已加载时,
|
||||
# 从 struct elements 数和 class_members 数推断继承字段偏移。
|
||||
# 继承字段在 struct 开头(base 之后),此 fallback 仅适用于单继承字段的情况
|
||||
# (如 GSListNode[T] 的 Next 字段)。子类 struct 布局:
|
||||
# [vtable?] + [基类字段...] + [子类字段...]
|
||||
# 当 class_members 只含子类自身字段、基类 class_members 未加载时,
|
||||
# 继承字段数 = struct_elements - class_members_count,
|
||||
# 若该值 == 1,则所查字段(如 Next)的偏移 = base + 0。
|
||||
if ClassName and field_name:
|
||||
_st_final = self.structs.get(ClassName)
|
||||
if isinstance(_st_final, ir.IdentifiedStructType) and _st_final.elements is not None:
|
||||
_num_elements_final: int = len(_st_final.elements)
|
||||
_members_final: list = self.class_members.get(ClassName, [])
|
||||
_num_members_final: int = len(_members_final)
|
||||
if _num_elements_final > _num_members_final:
|
||||
_num_inherited_final: int = _num_elements_final - _num_members_final
|
||||
if _num_inherited_final == 1:
|
||||
# 单继承字段,偏移 = base(vtable 之后第一个位置)
|
||||
return base + 0
|
||||
return None
|
||||
|
||||
def _resolve_class_for_var(self, var_name: str) -> str | None:
|
||||
for ClassName in self.class_methods:
|
||||
if var_name == ClassName or var_name.startswith(f"__with_{ClassName}_"):
|
||||
return ClassName
|
||||
if var_name in self.variables:
|
||||
var: ir.Value = self.variables[var_name]
|
||||
if isinstance(var.type, ir.PointerType):
|
||||
for ClassName, struct_type in self.structs.items():
|
||||
if var.type.pointee == struct_type:
|
||||
return ClassName
|
||||
if isinstance(var.type.pointee, ir.PointerType) and var.type.pointee.pointee == struct_type:
|
||||
return ClassName
|
||||
return None
|
||||
|
||||
def _infer_return_type(self, FuncName: str) -> ir.Type:
|
||||
if FuncName in self.functions:
|
||||
return self.functions[FuncName].type.pointee.return_type
|
||||
# 也尝试混淆后的名称
|
||||
mangled: str = self._mangle_func_name(FuncName)
|
||||
if mangled != FuncName and mangled in self.functions:
|
||||
return self.functions[mangled].type.pointee.return_type
|
||||
if FuncName in self.known_return_types:
|
||||
return self.known_return_types[FuncName]
|
||||
if mangled != FuncName and mangled in self.known_return_types:
|
||||
return self.known_return_types[mangled]
|
||||
for ClassName, methods in self.class_methods.items():
|
||||
for method in methods:
|
||||
if FuncName == method:
|
||||
return ir.VoidType()
|
||||
if self._import_handler_ref:
|
||||
try:
|
||||
# 先用原始名称查找,再用混淆名称查找
|
||||
stub_func_type: Any = self._import_handler_ref._LookupStubFuncType(FuncName, self)
|
||||
if stub_func_type is None and mangled != FuncName:
|
||||
stub_func_type = self._import_handler_ref._LookupStubFuncType(mangled, self)
|
||||
if stub_func_type and hasattr(stub_func_type, 'return_type'):
|
||||
return stub_func_type.return_type
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"查找桩函数返回类型失败: {_e}", "Exception")
|
||||
return ir.IntType(32)
|
||||
|
||||
def _get_or_declare_func(self, name: str, func_type: ir.FunctionType) -> ir.Function:
|
||||
for fname, fobj in self.functions.items():
|
||||
if fname == name:
|
||||
return fobj
|
||||
if re.match(r'^[0-9a-f]{16,}\.' + re.escape(name) + r'$', fname):
|
||||
return fobj
|
||||
func_decl: ir.Function = ir.Function(self.module, func_type, name=name)
|
||||
self.functions[name] = func_decl
|
||||
return func_decl
|
||||
|
||||
def get_or_declare_c_func(self, name: str, fallback_type: ir.FunctionType | None = None) -> ir.Function | None:
|
||||
if name in self.functions:
|
||||
return self.functions[name]
|
||||
for fname, fobj in self.functions.items():
|
||||
if re.match(r'^[0-9a-f]{16,}\.' + re.escape(name) + r'$', fname):
|
||||
return fobj
|
||||
stub_func_type: ir.FunctionType | None = None
|
||||
if self._import_handler_ref:
|
||||
try:
|
||||
stub_func_type = self._import_handler_ref._LookupStubFuncType(name, self)
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"查找桩函数类型失败: {_e}", "Exception")
|
||||
if stub_func_type:
|
||||
func_decl: ir.Function = ir.Function(self.module, stub_func_type, name=name)
|
||||
self.functions[name] = func_decl
|
||||
return func_decl
|
||||
if fallback_type is not None:
|
||||
func_decl: ir.Function = ir.Function(self.module, fallback_type, name=name)
|
||||
self.functions[name] = func_decl
|
||||
return func_decl
|
||||
return None
|
||||
286
lib/core/LLVMCG/MemoryOps.py
Normal file
286
lib/core/LLVMCG/MemoryOps.py
Normal file
@@ -0,0 +1,286 @@
|
||||
from __future__ import annotations
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class MemoryOpsMixin:
|
||||
|
||||
def _register_local_heap_ptr(self, val: ir.Value, ClassName: str | None = None, VarName: str | None = None) -> None:
|
||||
if isinstance(val.type, ir.PointerType):
|
||||
pointee: ir.Type = val.type.pointee
|
||||
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
self._local_heap_ptrs.append((val, 'struct', ClassName))
|
||||
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
self._local_heap_ptrs.append((val, 'i8', ClassName))
|
||||
if VarName:
|
||||
self._var_to_heap_ptr[VarName] = val
|
||||
|
||||
def _unregister_local_heap_ptr(self, val: ir.Value) -> None:
|
||||
self._local_heap_ptrs = [(v, t, cn) for v, t, cn in self._local_heap_ptrs if v is not val]
|
||||
|
||||
def _emit_local_heap_frees(self) -> None:
|
||||
if not self._local_heap_ptrs or not self.builder:
|
||||
return
|
||||
deleted_objects: set[ir.Value] = set()
|
||||
for ptr, ptr_type, ClassName in self._local_heap_ptrs:
|
||||
if ptr_type == 'i8':
|
||||
Loaded_ptr: ir.Value = self.builder.load(ptr, name="load_ptr")
|
||||
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||||
is_null: ir.Value = self.builder.icmp_unsigned('==', Loaded_ptr, null_ptr, name="is_null")
|
||||
not_null_block: ir.Block = self.builder.append_basic_block(name="not_null")
|
||||
next_block: ir.Block = self.builder.append_basic_block(name="next")
|
||||
self.builder.cbranch(is_null, next_block, not_null_block)
|
||||
self.builder.position_at_end(not_null_block)
|
||||
if ClassName and self._has_function(f'{ClassName}.__del__'):
|
||||
cast_ptr: ir.Value
|
||||
if isinstance(ptr.type, ir.PointerType) and isinstance(ptr.type.pointee, ir.IntType) and ptr.type.pointee.width == 8:
|
||||
cast_ptr = self.builder.bitcast(ptr, ir.PointerType(self.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
else:
|
||||
cast_ptr = ptr
|
||||
if cast_ptr not in deleted_objects:
|
||||
self.builder.call(self._get_function(f'{ClassName}.__del__'), [cast_ptr], name=f"call_{ClassName}.__del__")
|
||||
deleted_objects.add(cast_ptr)
|
||||
raw: ir.Value
|
||||
if ptr_type == 'struct':
|
||||
raw = self.builder.bitcast(ptr, ir.PointerType(ir.IntType(8)), name="local_free_cast")
|
||||
elif ptr_type == 'i8':
|
||||
raw = ptr
|
||||
else:
|
||||
continue
|
||||
free_type: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])
|
||||
free_func: ir.Function = self._get_or_declare_func('free', free_type)
|
||||
self.builder.call(free_func, [raw])
|
||||
if ptr_type == 'i8':
|
||||
self.builder.branch(next_block)
|
||||
self.builder.position_at_end(next_block)
|
||||
self._local_heap_ptrs = []
|
||||
|
||||
def _RegisterTempPtr(self, val: ir.Value) -> None:
|
||||
if isinstance(val.type, ir.PointerType):
|
||||
pointee: ir.Type = val.type.pointee
|
||||
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
for CN, ST in self.structs.items():
|
||||
if pointee == ST:
|
||||
self._temp_struct_ptrs.append(val)
|
||||
return
|
||||
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
self._temp_struct_ptrs.append(val)
|
||||
|
||||
def _UnregisterTempPtr(self, val: ir.Value) -> None:
|
||||
self._temp_struct_ptrs = [t for t in self._temp_struct_ptrs if t is not val]
|
||||
|
||||
def _EmitTempFrees(self) -> None:
|
||||
if not self._temp_struct_ptrs or not self.builder:
|
||||
return
|
||||
for ptr in self._temp_struct_ptrs:
|
||||
raw: ir.Value
|
||||
if isinstance(ptr.type, ir.PointerType) and isinstance(ptr.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
raw = self.builder.bitcast(ptr, ir.PointerType(ir.IntType(8)), name="free_cast")
|
||||
elif isinstance(ptr.type, ir.PointerType) and isinstance(ptr.type.pointee, ir.IntType) and ptr.type.pointee.width == 8:
|
||||
raw = ptr
|
||||
else:
|
||||
continue
|
||||
free_type: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])
|
||||
free_func: ir.Function = self._get_or_declare_func('free', free_type)
|
||||
self.builder.call(free_func, [raw])
|
||||
self._temp_struct_ptrs = []
|
||||
|
||||
def _ZeroConst(self, typ: ir.Type) -> ir.Constant:
|
||||
if isinstance(typ, ir.PointerType):
|
||||
return ir.Constant(typ, None)
|
||||
if isinstance(typ, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
return ir.Constant(typ, None)
|
||||
if isinstance(typ, ir.ArrayType):
|
||||
return ir.Constant(typ, None)
|
||||
return ir.Constant(typ, 0)
|
||||
|
||||
def _alloca(self, typ: ir.Type, name: str = '', align: int | None = None, size: ir.Value | None = None) -> ir.AllocaInstr:
|
||||
if align is None:
|
||||
align = self._get_align(typ)
|
||||
instr: ir.AllocaInstr
|
||||
if size is not None:
|
||||
instr = self.builder.alloca(typ, size=size, name=name)
|
||||
else:
|
||||
instr = self.builder.alloca(typ, name=name)
|
||||
if align:
|
||||
instr.align = align
|
||||
return instr
|
||||
|
||||
def _allocaEntry(self, typ: ir.Type, name: str = '', align: int | None = None) -> ir.AllocaInstr:
|
||||
if align is None:
|
||||
align = self._get_align(typ)
|
||||
saved_block: ir.Block = self.builder.block
|
||||
entry_block: ir.Block = self.func.entry_basic_block
|
||||
instr: ir.AllocaInstr
|
||||
if entry_block.instructions:
|
||||
first_instr: ir.Instruction = entry_block.instructions[0]
|
||||
self.builder.position_before(first_instr)
|
||||
instr = self.builder.alloca(typ, name=name)
|
||||
if align:
|
||||
instr.align = align
|
||||
self.builder.position_at_end(saved_block)
|
||||
else:
|
||||
self.builder.position_at_start(entry_block)
|
||||
instr = self.builder.alloca(typ, name=name)
|
||||
if align:
|
||||
instr.align = align
|
||||
self.builder.position_at_end(saved_block)
|
||||
return instr
|
||||
|
||||
def _load(self, ptr: ir.Value, name: str = '', align: int | None = None) -> ir.LoadInstr:
|
||||
if align is None:
|
||||
if isinstance(ptr.type, ir.PointerType):
|
||||
align = self._get_align(ptr.type.pointee)
|
||||
else:
|
||||
align = 0
|
||||
if isinstance(ptr.type, ir.PointerType):
|
||||
pointee_type: ir.Type = ptr.type.pointee
|
||||
if isinstance(pointee_type, ir.IdentifiedStructType) and pointee_type.name in self.typedef_int_widths:
|
||||
width: int = self.typedef_int_widths[pointee_type.name]
|
||||
if width > 0:
|
||||
actual_type: ir.IntType = ir.IntType(width)
|
||||
bitcast_ptr: ir.Value = self.builder.bitcast(ptr, ir.PointerType(actual_type), name="typedef_bitcast_Load")
|
||||
return self.builder.load(bitcast_ptr, name=name, align=align)
|
||||
return self.builder.load(ptr, name=name, align=align)
|
||||
|
||||
def _Load_var(self, name: str) -> ir.Value | None:
|
||||
if name in self._direct_values:
|
||||
return self._direct_values[name]
|
||||
if name in self.variables and self.variables[name] is not None:
|
||||
VarPtr: ir.Value = self.variables[name]
|
||||
if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
|
||||
return VarPtr
|
||||
if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
|
||||
return VarPtr
|
||||
return self._load(VarPtr, name=name)
|
||||
if name in self.global_vars and name in self.module.globals:
|
||||
GVar: ir.GlobalVariable = self.module.globals[name]
|
||||
self.variables[name] = GVar
|
||||
if isinstance(GVar, ir.Function):
|
||||
return GVar
|
||||
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
|
||||
return GVar
|
||||
return self._load(GVar, name=name)
|
||||
if name in self.module.globals:
|
||||
GVar = self.module.globals[name]
|
||||
self.variables[name] = GVar
|
||||
if isinstance(GVar, ir.Function):
|
||||
return GVar
|
||||
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
|
||||
return GVar
|
||||
return self._load(GVar, name=name)
|
||||
return None
|
||||
|
||||
def _coerce_value(self, val: ir.Value, target_type: ir.Type) -> ir.Value | None:
|
||||
if val.type == target_type:
|
||||
return val
|
||||
if isinstance(target_type, ir.IdentifiedStructType) and target_type.name in self.typedef_int_widths:
|
||||
if isinstance(val.type, ir.IntType):
|
||||
return val
|
||||
if isinstance(target_type, ir.IntType) and isinstance(val.type, ir.IntType):
|
||||
if target_type.width < val.type.width:
|
||||
return self.builder.trunc(val, target_type, name="trunc_store")
|
||||
elif val.type.width == 1:
|
||||
# i1 是布尔值(来自 icmp/fcmp/__contains__ 归一化),无符号语义,
|
||||
# 必须用 zext 而非 sext,否则 i1 的 1 会被符号扩展为 -1
|
||||
return self.builder.zext(val, target_type, name="zext_bool_store")
|
||||
else:
|
||||
return self.builder.sext(val, target_type, name="sext_store")
|
||||
if isinstance(target_type, ir.PointerType) and isinstance(val.type, ir.PointerType):
|
||||
if isinstance(val, ir.Constant) and val.constant is None:
|
||||
return ir.Constant(target_type, None)
|
||||
return self.builder.bitcast(val, target_type, name="ptr_bitcast_store")
|
||||
if isinstance(target_type, ir.PointerType) and isinstance(val.type, ir.IntType):
|
||||
if val.type.width < 64:
|
||||
val = self.builder.zext(val, ir.IntType(64), name="zext_ptr_store")
|
||||
return self.builder.inttoptr(val, target_type, name="int_to_ptr_store")
|
||||
if isinstance(target_type, ir.IntType) and isinstance(val.type, ir.PointerType):
|
||||
if isinstance(val.type.pointee, ir.IntType) and val.type.pointee.width == target_type.width:
|
||||
return self.builder.load(val, name="load_ptr_as_int_store")
|
||||
if target_type.width <= 8 and isinstance(val.type.pointee, ir.IntType):
|
||||
Loaded: ir.Value = self.builder.load(val, name="load_ptr_byte_store")
|
||||
if Loaded.type != target_type:
|
||||
if isinstance(Loaded.type, ir.IntType) and isinstance(target_type, ir.IntType):
|
||||
if target_type.width < Loaded.type.width:
|
||||
return self.builder.trunc(Loaded, target_type, name="trunc_ptr_byte_store")
|
||||
return self.builder.zext(Loaded, target_type, name="zext_ptr_byte_store")
|
||||
return Loaded
|
||||
return self.builder.ptrtoint(val, target_type, name="ptr_to_int_store")
|
||||
if isinstance(target_type, ir.FloatType) and isinstance(val.type, ir.DoubleType):
|
||||
return self.builder.fptrunc(val, target_type, name="fptrunc_store")
|
||||
if isinstance(target_type, ir.DoubleType) and isinstance(val.type, ir.FloatType):
|
||||
return self.builder.fpext(val, target_type, name="fpext_store")
|
||||
if isinstance(target_type, ir.IntType) and isinstance(val.type, (ir.FloatType, ir.DoubleType)):
|
||||
return self.builder.fptosi(val, target_type, name="fptosi_store")
|
||||
if isinstance(target_type, (ir.FloatType, ir.DoubleType)) and isinstance(val.type, ir.IntType):
|
||||
return self.builder.sitofp(val, target_type, name="sitofp_store")
|
||||
if isinstance(target_type, ir.ArrayType) and isinstance(val.type, ir.ArrayType):
|
||||
if target_type.count == val.type.count and target_type.element == val.type.element:
|
||||
return val
|
||||
if (isinstance(target_type.element, ir.IntType) and target_type.element.width == 8
|
||||
and isinstance(val.type.element, ir.IntType) and val.type.element.width == 8):
|
||||
if target_type.count > val.type.count:
|
||||
padded: list[ir.Constant] = list(val.constant) if hasattr(val, 'constant') else []
|
||||
if padded and len(padded) == val.type.count:
|
||||
padded.extend([ir.Constant(ir.IntType(8), 0)] * (target_type.count - val.type.count))
|
||||
return ir.Constant(target_type, padded)
|
||||
elif target_type.count < val.type.count:
|
||||
trimmed: list[ir.Constant] = list(val.constant) if hasattr(val, 'constant') else []
|
||||
if trimmed and len(trimmed) == val.type.count:
|
||||
return ir.Constant(target_type, trimmed[:target_type.count])
|
||||
if isinstance(val.type, ir.PointerType) and not isinstance(target_type, ir.PointerType):
|
||||
if val.type.pointee == target_type:
|
||||
return self.builder.load(val, name="Load_struct_for_store")
|
||||
if isinstance(val.type.pointee, ir.IdentifiedStructType) and isinstance(target_type, ir.IdentifiedStructType):
|
||||
if val.type.pointee.name == target_type.name:
|
||||
Loaded: ir.Value = self.builder.load(val, name="Load_struct_for_store")
|
||||
if Loaded.type == target_type:
|
||||
return Loaded
|
||||
return None
|
||||
|
||||
def _store(self, val: ir.Value, ptr: ir.Value, align: int | None = None) -> ir.StoreInstr:
|
||||
if align is None:
|
||||
if isinstance(ptr.type, ir.PointerType):
|
||||
align = self._get_align(ptr.type.pointee)
|
||||
else:
|
||||
align = 0
|
||||
if isinstance(ptr.type, ir.PointerType):
|
||||
target_type: ir.Type = ptr.type.pointee
|
||||
if isinstance(target_type, ir.IdentifiedStructType) and target_type.name in self.typedef_int_widths:
|
||||
if isinstance(val.type, ir.IntType):
|
||||
width: int = self.typedef_int_widths[target_type.name]
|
||||
if width > 0:
|
||||
actual_type: ir.IntType = ir.IntType(width)
|
||||
bitcast_ptr: ir.Value = self.builder.bitcast(ptr, ir.PointerType(actual_type), name="typedef_bitcast")
|
||||
if val.type.width != actual_type.width:
|
||||
if val.type.width > actual_type.width:
|
||||
val = self.builder.trunc(val, actual_type, name="trunc_typedef")
|
||||
else:
|
||||
val = self.builder.zext(val, actual_type, name="zext_typedef")
|
||||
return self.builder.store(val, bitcast_ptr, align=align)
|
||||
if val.type != target_type:
|
||||
if isinstance(val, ir.Constant) and val.constant is None:
|
||||
if isinstance(target_type, ir.PointerType):
|
||||
val = ir.Constant(target_type, None)
|
||||
elif isinstance(target_type, ir.IdentifiedStructType):
|
||||
val = ir.Constant(ir.PointerType(target_type), None)
|
||||
ptr = self.builder.bitcast(ptr, ir.PointerType(ir.PointerType(target_type)), name="null_struct_ptr_cast")
|
||||
else:
|
||||
coerced: ir.Value | None = self._coerce_value(val, target_type)
|
||||
if coerced is not None:
|
||||
val = coerced
|
||||
else:
|
||||
src_info: str = self._get_node_info()
|
||||
raise TypeError(f"cannot store {val.type} to {ptr.type}: mismatching types{src_info}")
|
||||
return self.builder.store(val, ptr, align=align)
|
||||
|
||||
def _get_var_ptr(self, name: str) -> ir.Value | None:
|
||||
if name in self._reg_values:
|
||||
val: ir.Value = self._reg_values[name]
|
||||
var: ir.AllocaInstr = self._alloca(val.type, name=name)
|
||||
self._store(val, var)
|
||||
self.variables[name] = var
|
||||
del self._reg_values[name]
|
||||
return var
|
||||
if name in self.variables and self.variables[name] is not None:
|
||||
return self.variables[name]
|
||||
return None
|
||||
587
lib/core/LLVMCG/StructGen.py
Normal file
587
lib/core/LLVMCG/StructGen.py
Normal file
@@ -0,0 +1,587 @@
|
||||
from __future__ import annotations
|
||||
from typing import Any
|
||||
import re
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
from llvmlite.ir.values import _Undefined
|
||||
from lib.includes import t as _t
|
||||
|
||||
|
||||
class StructGenMixin:
|
||||
|
||||
def _get_align(self, llvm_type: ir.Type) -> int:
|
||||
if isinstance(llvm_type, ir.IntType):
|
||||
return max(1, llvm_type.width // 8)
|
||||
if isinstance(llvm_type, ir.FloatType):
|
||||
return 4
|
||||
if isinstance(llvm_type, ir.DoubleType):
|
||||
return 8
|
||||
if isinstance(llvm_type, ir.PointerType):
|
||||
return self.ptr_size
|
||||
if isinstance(llvm_type, ir.ArrayType):
|
||||
return self._get_align(llvm_type.element)
|
||||
if isinstance(llvm_type, ir.LiteralStructType):
|
||||
return max((self._get_align(f) for f in llvm_type.elements), default=1)
|
||||
if isinstance(llvm_type, ir.IdentifiedStructType):
|
||||
if llvm_type.elements is None or len(llvm_type.elements) == 0:
|
||||
return self.ptr_size # opaque struct, assume pointer alignment
|
||||
return max((self._get_align(f) for f in llvm_type.elements), default=1)
|
||||
if isinstance(llvm_type, ir.VoidType):
|
||||
return 0
|
||||
return 4
|
||||
|
||||
def _resolve_opaque_struct(self, llvm_type: ir.Type) -> ir.Type:
|
||||
"""尝试从 Gen.structs 中查找已解析的同名 struct,解决跨模块 struct 类型对象不一致的问题"""
|
||||
if not isinstance(llvm_type, ir.IdentifiedStructType):
|
||||
return llvm_type
|
||||
if llvm_type.elements is not None and len(llvm_type.elements) > 0:
|
||||
return llvm_type
|
||||
# opaque struct,尝试通过名称在 Gen.structs 中查找已解析的版本
|
||||
st_name: str
|
||||
try:
|
||||
st_name = llvm_type.name
|
||||
except Exception:
|
||||
return llvm_type
|
||||
if not st_name:
|
||||
return llvm_type
|
||||
# 提取短名称
|
||||
short_name: str = st_name
|
||||
if '.' in st_name:
|
||||
short_name = st_name.split('.', 1)[1]
|
||||
# 尝试短名称查找
|
||||
if short_name in self.structs:
|
||||
resolved: ir.IdentifiedStructType = self.structs[short_name]
|
||||
if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0:
|
||||
return resolved
|
||||
# 尝试全名查找
|
||||
if st_name in self.structs:
|
||||
resolved: ir.IdentifiedStructType = self.structs[st_name]
|
||||
if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0:
|
||||
return resolved
|
||||
# 尝试通过导入处理器从 stub 文件加载 struct 定义
|
||||
import_handler: Any = self._import_handler_ref
|
||||
if import_handler is not None:
|
||||
try:
|
||||
import_handler._TryLoadStructFromStub(short_name, self)
|
||||
except Exception:
|
||||
pass
|
||||
# 加载后再次查找
|
||||
if short_name in self.structs:
|
||||
resolved = self.structs[short_name]
|
||||
if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0:
|
||||
return resolved
|
||||
if st_name in self.structs:
|
||||
resolved = self.structs[st_name]
|
||||
if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0:
|
||||
return resolved
|
||||
return llvm_type
|
||||
|
||||
def _get_struct_size(self, llvm_type: ir.Type) -> int:
|
||||
if isinstance(llvm_type, ir.IntType):
|
||||
return max(1, llvm_type.width // 8)
|
||||
if isinstance(llvm_type, ir.FloatType):
|
||||
return 4
|
||||
if isinstance(llvm_type, ir.DoubleType):
|
||||
return 8
|
||||
if isinstance(llvm_type, ir.PointerType):
|
||||
return self.ptr_size
|
||||
if isinstance(llvm_type, ir.ArrayType):
|
||||
return self._get_struct_size(llvm_type.element) * llvm_type.count
|
||||
if isinstance(llvm_type, ir.LiteralStructType):
|
||||
total: int = 0
|
||||
max_align: int = 1
|
||||
for f in llvm_type.fields:
|
||||
fa: int = self._get_align(f)
|
||||
fs: int = self._get_struct_size(f)
|
||||
max_align = max(max_align, fa)
|
||||
if fa > 1:
|
||||
total = (total + fa - 1) // fa * fa
|
||||
total += fs
|
||||
if max_align > 1:
|
||||
total = (total + max_align - 1) // max_align * max_align
|
||||
return total
|
||||
if isinstance(llvm_type, ir.IdentifiedStructType):
|
||||
# 尝试解析 opaque struct 为已注册的版本
|
||||
llvm_type = self._resolve_opaque_struct(llvm_type)
|
||||
if llvm_type.elements is None or len(llvm_type.elements) == 0:
|
||||
return self.ptr_size # opaque struct, assume pointer size
|
||||
total: int = 0
|
||||
max_align: int = 1
|
||||
for f in llvm_type.elements:
|
||||
fa: int = self._get_align(f)
|
||||
fs: int = self._get_struct_size(f)
|
||||
max_align = max(max_align, fa)
|
||||
if fa > 1:
|
||||
total = (total + fa - 1) // fa * fa
|
||||
total += fs
|
||||
if max_align > 1:
|
||||
total = (total + max_align - 1) // max_align * max_align
|
||||
return total
|
||||
return 4
|
||||
|
||||
@staticmethod
|
||||
def _strip_unnecessary_quotes(ir_str: str) -> str:
|
||||
def _unquote(m: re.Match) -> str:
|
||||
prefix: str = m.group(1)
|
||||
name: str = m.group(2)
|
||||
if '.' in name:
|
||||
return m.group(0)
|
||||
if re.match(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$', name):
|
||||
return prefix + name
|
||||
return m.group(0)
|
||||
return re.sub(r'([@%])"([^"]+)"', _unquote, ir_str)
|
||||
|
||||
def finalize(self) -> str:
|
||||
self._set_Vtable_initializers()
|
||||
self._fix_global_var_init()
|
||||
ir_text: str
|
||||
try:
|
||||
ir_text = str(self.module)
|
||||
except TypeError as e:
|
||||
for func in self.module.functions:
|
||||
for block in func.blocks:
|
||||
for instr in block.instructions:
|
||||
try:
|
||||
str(instr)
|
||||
except TypeError as te:
|
||||
pass
|
||||
raise
|
||||
ir_text = self._strip_unnecessary_quotes(ir_text)
|
||||
struct_defs: list[str] = []
|
||||
struct_names: set[str] = set()
|
||||
for ClassName, struct_type in self.structs.items():
|
||||
if isinstance(struct_type, ir.IdentifiedStructType):
|
||||
sname: str = struct_type.name
|
||||
sname_ir: str
|
||||
if sname[0].isdigit() or '.' in sname or not sname.replace('_', '').replace('.', '').isalnum():
|
||||
sname_ir = f'%"{sname}"'
|
||||
else:
|
||||
sname_ir = f'%{sname}'
|
||||
if struct_type.elements is None or len(struct_type.elements) == 0:
|
||||
if ClassName not in self.typedef_int_widths:
|
||||
struct_names.add(sname)
|
||||
struct_defs.append(f'{sname_ir} = type opaque')
|
||||
continue
|
||||
elems: str = ', '.join(str(e) for e in struct_type.elements)
|
||||
if struct_type.packed:
|
||||
struct_defs.append(f'{sname_ir} = type <{{ {elems} }}>')
|
||||
else:
|
||||
struct_defs.append(f'{sname_ir} = type {{ {elems} }}')
|
||||
struct_names.add(sname)
|
||||
if struct_defs:
|
||||
lines: list[str] = ir_text.split('\n')
|
||||
filtered: list[str] = []
|
||||
for line in lines:
|
||||
stripped: str = line.strip()
|
||||
skip: bool = False
|
||||
for name in struct_names:
|
||||
patterns: list[str]
|
||||
if name[0].isdigit() or '.' in name or not name.replace('_', '').replace('.', '').isalnum():
|
||||
patterns = [f'%"{name}" = type', f'%"{name}"=type', f'%{name} = type', f'%{name}=type']
|
||||
else:
|
||||
patterns = [f'%{name} = type', f'%{name}= type', f'%{name}=type']
|
||||
for p in patterns:
|
||||
if stripped.startswith(p):
|
||||
skip = True
|
||||
break
|
||||
if skip:
|
||||
break
|
||||
if not skip:
|
||||
filtered.append(line)
|
||||
ir_text = '\n'.join(filtered)
|
||||
header_end: int = ir_text.find('\ndefine')
|
||||
if header_end == -1:
|
||||
header_end = ir_text.find('\ndeclare')
|
||||
if header_end == -1:
|
||||
header_end = ir_text.find('\n@')
|
||||
if header_end == -1:
|
||||
header_end = len(ir_text)
|
||||
insert_pos: int = ir_text.rfind('\n', 0, header_end)
|
||||
if insert_pos == -1:
|
||||
insert_pos = header_end
|
||||
struct_block: str = '\n'.join(struct_defs) + '\n'
|
||||
ir_text = ir_text[:insert_pos + 1] + struct_block + ir_text[insert_pos + 1:]
|
||||
for name in struct_names:
|
||||
if name[0].isdigit() or '.' in name:
|
||||
ir_text = re.sub(
|
||||
r'%' + re.escape(name) + r'(?=[^a-zA-Z0-9_$\.]|$)',
|
||||
r'%"' + name + r'"',
|
||||
ir_text
|
||||
)
|
||||
|
||||
return ir_text
|
||||
|
||||
def _generate_structs(self) -> None:
|
||||
all_classes: set[str] = set(self.class_methods.keys()) | set(self.class_members.keys())
|
||||
|
||||
preserved_structs: dict[str, ir.IdentifiedStructType] = {}
|
||||
for name, st in self.structs.items():
|
||||
if name not in all_classes:
|
||||
preserved_structs[name] = st
|
||||
elif isinstance(st, ir.IdentifiedStructType):
|
||||
preserved_structs[name] = st
|
||||
|
||||
self.structs.clear()
|
||||
|
||||
for name, st in preserved_structs.items():
|
||||
self.structs[name] = st
|
||||
|
||||
# Step 1: 先为所有类创建空的 struct,确保后面可以正确引用
|
||||
all_classes = set(self.class_methods.keys()) | set(self.class_members.keys())
|
||||
for ClassName in all_classes:
|
||||
is_packed: bool = ClassName in self.class_packed
|
||||
if self.SymbolTable:
|
||||
Entry = self.SymbolTable.lookup(ClassName)
|
||||
if Entry and Entry.IsExceptionClass:
|
||||
continue
|
||||
# 注意:类名可能与 CEnum 成员名冲突(如 ASTKind.Module 枚举成员与 Module 类同名)
|
||||
# 如果 ClassName 在 class_methods 中,表明是 _EmitClassLlvm 显式处理的常规类,
|
||||
# 不应被 IsEnum/IsTypedef 检查跳过
|
||||
if Entry and Entry.IsEnum and ClassName not in self.class_methods:
|
||||
if not Entry.IsRenum:
|
||||
continue
|
||||
if Entry and Entry.IsTypedef and ClassName not in self.class_methods:
|
||||
if Entry.BaseType and not isinstance(Entry.BaseType, (type(None),)):
|
||||
if not isinstance(Entry.BaseType, (_t._CTypedef,)):
|
||||
continue
|
||||
if ClassName in self.structs:
|
||||
if is_packed:
|
||||
self.structs[ClassName].packed = True
|
||||
continue
|
||||
mangled_name: str = self._mangle_name(ClassName)
|
||||
struct_type: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, mangled_name, packed=is_packed)
|
||||
self.structs[ClassName] = struct_type
|
||||
|
||||
# Step 2: 解析跨模块的成员类型
|
||||
for ClassName, annotations in self.class_member_annotations.items():
|
||||
if ClassName not in self.class_members:
|
||||
continue
|
||||
for i, (member_name, member_type) in enumerate(self.class_members[ClassName]):
|
||||
if member_name in annotations:
|
||||
annotation: Any = annotations[member_name]
|
||||
ResolvedType: ir.Type | None = None
|
||||
|
||||
if isinstance(annotation, ast.Attribute):
|
||||
ClassTypeName: str = annotation.attr
|
||||
if ClassTypeName in self.structs:
|
||||
ResolvedType = self.structs[ClassTypeName]
|
||||
elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
left: Any = annotation.left
|
||||
if isinstance(left, ast.Attribute):
|
||||
ClassTypeName: str = left.attr
|
||||
if ClassTypeName in self.structs:
|
||||
ResolvedType = self.structs[ClassTypeName]
|
||||
|
||||
if ResolvedType:
|
||||
self.class_members[ClassName][i] = (member_name, ResolvedType)
|
||||
|
||||
struct_name_map: dict[str, ir.IdentifiedStructType] = {}
|
||||
for struct_name, struct in self.structs.items():
|
||||
try:
|
||||
struct_name_map[struct.name] = struct
|
||||
except AssertionError:
|
||||
struct_name_map[struct_name] = struct
|
||||
orig: Any = getattr(struct, '_original_name', None)
|
||||
if orig:
|
||||
struct_name_map[orig] = struct
|
||||
|
||||
# Step 3: 更新成员类型,确保使用正确的 mangled struct 引用
|
||||
for ClassName in all_classes:
|
||||
if ClassName not in self.class_members:
|
||||
continue
|
||||
for i, (member_name, member_type) in enumerate(self.class_members[ClassName]):
|
||||
if isinstance(member_type, ir.PointerType):
|
||||
pointee: ir.Type = member_type.pointee
|
||||
if isinstance(pointee, ir.IdentifiedStructType):
|
||||
pname: str | None
|
||||
try:
|
||||
pname = pointee.name
|
||||
except AssertionError:
|
||||
pname = None
|
||||
struct: ir.IdentifiedStructType | None = struct_name_map.get(pname) if pname else None
|
||||
if struct is None:
|
||||
orig: Any = getattr(pointee, '_original_name', None)
|
||||
struct = struct_name_map.get(orig) if orig else None
|
||||
if struct is not None:
|
||||
self.class_members[ClassName][i] = (member_name, ir.PointerType(struct))
|
||||
else:
|
||||
raw_name: str = pname or ''
|
||||
if raw_name.startswith('struct.'):
|
||||
raw_name = raw_name[7:]
|
||||
new_struct: ir.IdentifiedStructType = self._get_or_create_struct(raw_name)
|
||||
self.class_members[ClassName][i] = (member_name, ir.PointerType(new_struct))
|
||||
elif isinstance(member_type, ir.IdentifiedStructType):
|
||||
mname: str | None
|
||||
try:
|
||||
mname = member_type.name
|
||||
except AssertionError:
|
||||
mname = None
|
||||
struct: ir.IdentifiedStructType | None = struct_name_map.get(mname) if mname else None
|
||||
if struct is None:
|
||||
orig: Any = getattr(member_type, '_original_name', None)
|
||||
struct = struct_name_map.get(orig) if orig else None
|
||||
if struct is not None:
|
||||
self.class_members[ClassName][i] = (member_name, struct)
|
||||
else:
|
||||
raw_name: str = mname or ''
|
||||
if raw_name.startswith('struct.'):
|
||||
raw_name = raw_name[7:]
|
||||
new_struct: ir.IdentifiedStructType = self._get_or_create_struct(raw_name)
|
||||
self.class_members[ClassName][i] = (member_name, new_struct)
|
||||
|
||||
# Step 4: 创建最终的 structs 并设置正确的成员类型
|
||||
for ClassName in all_classes:
|
||||
if self.SymbolTable:
|
||||
Entry = self.SymbolTable.lookup(ClassName)
|
||||
if Entry and Entry.IsExceptionClass:
|
||||
continue
|
||||
# 注意:类名可能与 CEnum 成员名冲突(如 ASTKind.Constant 枚举成员与 Constant 类同名)
|
||||
# 如果 ClassName 在 class_methods 中,表明是 _EmitClassLlvm 显式处理的常规类,
|
||||
# 不应被 IsEnum 检查跳过(与 Step 1 的守卫保持一致)
|
||||
if Entry and Entry.IsEnum and ClassName not in self.class_methods:
|
||||
if not Entry.IsRenum:
|
||||
continue
|
||||
existing_st: ir.IdentifiedStructType | None = self.structs.get(ClassName)
|
||||
if isinstance(existing_st, ir.IdentifiedStructType) and existing_st.elements is not None and len(existing_st.elements) > 0:
|
||||
# 治本修复:检查 struct body 是否不完整(元素数少于 class_members + vtable 预期)。
|
||||
# 常见于跨模块继承:子类 struct 在父类 class_members 加载前从 stub 生成,
|
||||
# stub 中的定义可能不完整或类型不正确(如 GSList* 代替 AST*、i8* 代替 i32)。
|
||||
# 此处检测到不完整后清除 _elements 和 stub 缓存,让后续代码重新从 stub 加载。
|
||||
_has_vtable_precheck: bool = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes
|
||||
if not _has_vtable_precheck:
|
||||
_p_pre: str | None = self.class_parent.get(ClassName)
|
||||
while _p_pre:
|
||||
if _p_pre in self.class_vtable or _p_pre in self._cross_module_vtable_classes:
|
||||
_has_vtable_precheck = True
|
||||
break
|
||||
_p_pre = self.class_parent.get(_p_pre)
|
||||
_expected_count_pre: int = len(self.class_members.get(ClassName, [])) + (1 if _has_vtable_precheck else 0)
|
||||
# has_vtable 时,首字段必须是 i8*(vtable 指针)。
|
||||
# 若首字段非指针(如 i8 占位符),struct body 不完整,需清除重新加载。
|
||||
_vtable_first_ok: bool = True
|
||||
if _has_vtable_precheck and len(existing_st.elements) > 0:
|
||||
_vtable_first_ok = isinstance(existing_st.elements[0], ir.PointerType)
|
||||
if len(existing_st.elements) >= _expected_count_pre and _vtable_first_ok:
|
||||
if ClassName in self.class_packed and not existing_st.packed:
|
||||
existing_st.packed = True
|
||||
continue
|
||||
# struct body 不完整,清除 _elements 和 stub 缓存以便重新加载
|
||||
existing_st._elements = None
|
||||
_import_handler_pre: Any = self._import_handler_ref
|
||||
if _import_handler_pre is not None:
|
||||
_cache_key_pre: tuple = (id(self), ClassName)
|
||||
if _cache_key_pre in _import_handler_pre._struct_Load_cache:
|
||||
del _import_handler_pre._struct_Load_cache[_cache_key_pre]
|
||||
has_vtable: bool = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes
|
||||
if not has_vtable:
|
||||
p: str | None = self.class_parent.get(ClassName)
|
||||
while p:
|
||||
if p in self.class_vtable or p in self._cross_module_vtable_classes:
|
||||
has_vtable = True
|
||||
self.class_vtable.add(ClassName)
|
||||
break
|
||||
p = self.class_parent.get(p)
|
||||
has_bitfield: bool = ClassName in self.class_member_bitfields and any(
|
||||
self.class_member_bitfields[ClassName].get(name, 0) > 0
|
||||
for name, _ in self.class_members.get(ClassName, [])
|
||||
)
|
||||
all_members: list[tuple[str, ir.Type]] = self.class_members.get(ClassName, [])
|
||||
# 跳过正在发射中且成员尚未填充的类(递归特化时避免过早设置空 body)
|
||||
if not all_members and not has_vtable and ClassName in self._classes_in_progress:
|
||||
continue
|
||||
# 字段收集期间触发的嵌套 _generate_structs:class_members 可能不完整,
|
||||
# set_body 只能调用一次,跳过等字段收集完成后再设置 body
|
||||
if ClassName in self._collecting_members_set:
|
||||
continue
|
||||
all_bitfield: bool = all(
|
||||
self.class_member_bitfields.get(ClassName, {}).get(name, 0) > 0
|
||||
for name, _ in all_members
|
||||
) if all_members else False
|
||||
|
||||
mangled_name: str = self._mangle_name(ClassName)
|
||||
|
||||
member_types: list[ir.Type]
|
||||
if has_bitfield and all_bitfield:
|
||||
total_bits: int = sum(self.class_member_bitfields.get(ClassName, {}).get(name, 0)
|
||||
for name, _ in all_members)
|
||||
storage_type: ir.IntType
|
||||
if total_bits <= 8:
|
||||
storage_type = ir.IntType(8)
|
||||
elif total_bits <= 16:
|
||||
storage_type = ir.IntType(16)
|
||||
elif total_bits <= 32:
|
||||
storage_type = ir.IntType(32)
|
||||
else:
|
||||
storage_type = ir.IntType(64)
|
||||
member_types = [storage_type]
|
||||
bitfield_offsets: dict[str, int] = {}
|
||||
current_bit_offset: int = 0
|
||||
for name, _ in all_members:
|
||||
bit_width: int = self.class_member_bitfields.get(ClassName, {}).get(name, 0)
|
||||
bitfield_offsets[name] = current_bit_offset
|
||||
current_bit_offset += bit_width
|
||||
self.class_member_bitoffsets[ClassName] = bitfield_offsets
|
||||
else:
|
||||
member_types = []
|
||||
if has_vtable:
|
||||
member_types.append(ir.PointerType(ir.IntType(8)))
|
||||
if ClassName in self.class_members:
|
||||
for _, member_type in self.class_members[ClassName]:
|
||||
if member_type is None:
|
||||
member_type = ir.IntType(32)
|
||||
member_types.append(member_type)
|
||||
else:
|
||||
if has_vtable:
|
||||
# has_vtable 但 class_members 为空(跨模块导入类):
|
||||
# 保持 member_types 为空([i8*] 占位会导致 stub 加载跳过,
|
||||
# 因为 set_body 后 is_opaque=False)。让 struct 保持 opaque,
|
||||
# 由 _TryLoadStructFromStub 设置完整 body。
|
||||
member_types = []
|
||||
else:
|
||||
member_types = [ir.IntType(8)]
|
||||
|
||||
# 获取之前创建的 struct 并设置成员
|
||||
struct_type: ir.IdentifiedStructType = self.structs[ClassName]
|
||||
if ClassName in self.class_packed:
|
||||
struct_type.packed = True
|
||||
# 只在未设置 body 时设置,避免重复定义错误
|
||||
if struct_type.elements is None:
|
||||
# 跨模块 struct 的 class_members 可能不完整(当前模块只解析了部分字段),
|
||||
# 优先从 stub.ll 加载完整定义。set_body 只能对 opaque struct 调用一次,
|
||||
# 若用不完整 class_members 设置 body,后续无法修正,会导致 GEP 越界。
|
||||
# 但本地定义的类(_classes_in_progress)不从 stub 加载,因为 stub 可能
|
||||
# 来自同名导入类,其 vtable 状态与本地定义不同(@t.NoVTable 冲突)
|
||||
import_handler: Any = self._import_handler_ref
|
||||
if import_handler is not None and ClassName not in self._classes_in_progress:
|
||||
try:
|
||||
import_handler._TryLoadStructFromStub(ClassName, self)
|
||||
except Exception:
|
||||
pass
|
||||
struct_type = self.structs.get(ClassName, struct_type)
|
||||
if struct_type.elements is None:
|
||||
# 防御性检查:member_types 为空时不调用 set_body。
|
||||
# set_body(*[]) 会设置 elements=() 使 is_opaque=False,
|
||||
# 后续无法再次 set_body(llvmlite 限制),导致跨模块类型永久损坏。
|
||||
# 根因:register_method 在 class_members[ClassName]=[] 时立即调用
|
||||
# _generate_structs,此时 member_types 为空。保持 opaque 状态,
|
||||
# 让后续 _TryLoadStructFromStub 能正确设置 body。
|
||||
if member_types:
|
||||
struct_type.set_body(*member_types)
|
||||
|
||||
def _create_Vtable_globals(self) -> None:
|
||||
for ClassName, methods in self.class_methods.items():
|
||||
if ClassName in self.Vtables:
|
||||
continue
|
||||
if not methods:
|
||||
continue
|
||||
if ClassName not in self.class_vtable and ClassName not in self._cross_module_vtable_classes:
|
||||
continue
|
||||
# 跳过正在发射中的类:它们的方法列表可能还不完整(如继承方法已添加但自有方法未添加),
|
||||
# 此时创建 vtable 会导致大小不匹配。这些类的 vtable 会在其 _EmitClassLlvm 完成后
|
||||
# 由 _create_vtable_for_class 显式创建,或在模块级 _create_Vtable_globals 调用中创建。
|
||||
if ClassName in self._classes_in_progress:
|
||||
continue
|
||||
# 跨模块虚表过滤:_precollect_vtable_state 会将所有 includes 的有方法类同时加入
|
||||
# _shared_class_vtable 和 _shared_cross_module_vtable,导致 class_vtable 与
|
||||
# _cross_module_vtable_classes 内容相同,无法用以区分本模块类与跨模块类。
|
||||
# _generate_structs 会为所有 class_methods 的类创建空 struct type,导致 self.structs
|
||||
# 也包含所有类。唯一可靠的过滤条件是 self.functions:_EmitClassLlvm 在本函数之前
|
||||
# 调用(LlvmGenerator.py L178-182),本模块定义的类方法已加入 self.functions;
|
||||
# import 声明的跨模块类方法也在 self.functions 中。若 self.functions 中没有任何
|
||||
# 以 "{ClassName}." 开头的键,说明本模块既未定义也未导入该类的方法,虚表会保持
|
||||
# 全 null,虚表分派时调用 null 指针引发段错误。此时应跳过虚表创建,让链接器
|
||||
# 从定义该类的模块解析虚表符号。
|
||||
has_local_method: bool = False
|
||||
prefix: str = f"{ClassName}."
|
||||
for func_name in self.functions:
|
||||
if func_name.startswith(prefix):
|
||||
has_local_method = True
|
||||
break
|
||||
if not has_local_method:
|
||||
continue
|
||||
VtableType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods))
|
||||
Vtable: ir.GlobalVariable = ir.GlobalVariable(self.module, VtableType, name=self._mangle_name(f"{ClassName}_Vtable"))
|
||||
Vtable.initializer = ir.Constant(VtableType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods))
|
||||
Vtable.linkage = 'internal'
|
||||
self.Vtables[ClassName] = Vtable
|
||||
|
||||
def _create_vtable_for_class(self, ClassName: str) -> None:
|
||||
"""为单个类创建 vtable(用于 _EmitClassLlvm 中当前类的方法已全部注册后)。"""
|
||||
methods: list = self.class_methods.get(ClassName, [])
|
||||
if not methods:
|
||||
return
|
||||
if ClassName not in self.class_vtable and ClassName not in self._cross_module_vtable_classes:
|
||||
return
|
||||
_vtable_name: str = self._mangle_name(f"{ClassName}_Vtable")
|
||||
# 如果虚表已在导入阶段创建(方法列表不完整,缺少继承方法),删除旧虚表
|
||||
if ClassName in self.Vtables:
|
||||
_old_vtable = self.Vtables[ClassName]
|
||||
_old_name = _old_vtable.name
|
||||
if _old_name in self.module.globals:
|
||||
del self.module.globals[_old_name]
|
||||
# llvmlite 的 NameScope._useset 追踪所有已使用的名字,
|
||||
# del module.globals[name] 不会从 _useset 移除,
|
||||
# 导致再次创建同名 GlobalVariable 时 scope.register() 报 DuplicatedNameError
|
||||
self.module.scope._useset.discard(_old_name)
|
||||
del self.Vtables[ClassName]
|
||||
# 防御性:如果全局变量已存在但不在 Vtables 字典中,也删除
|
||||
if _vtable_name in self.module.globals:
|
||||
del self.module.globals[_vtable_name]
|
||||
self.module.scope._useset.discard(_vtable_name)
|
||||
VtableType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods))
|
||||
Vtable: ir.GlobalVariable = ir.GlobalVariable(self.module, VtableType, name=_vtable_name)
|
||||
Vtable.initializer = ir.Constant(VtableType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods))
|
||||
Vtable.linkage = 'internal'
|
||||
self.Vtables[ClassName] = Vtable
|
||||
|
||||
def _fix_global_var_init(self) -> None:
|
||||
for gv_name, gv in list(self.module.globals.items()):
|
||||
if not isinstance(gv, ir.GlobalVariable):
|
||||
continue
|
||||
if gv.linkage in ('external', 'extern_weak'):
|
||||
continue
|
||||
needs_fix: bool = False
|
||||
if gv.initializer is None:
|
||||
needs_fix = True
|
||||
elif hasattr(gv.initializer, 'constant') and isinstance(gv.initializer.constant, _Undefined):
|
||||
needs_fix = True
|
||||
elif isinstance(gv.initializer, ir.Constant):
|
||||
if isinstance(gv.initializer.constant, list):
|
||||
if any(hasattr(c, 'constant') and isinstance(c.constant, _Undefined) for c in gv.initializer.constant):
|
||||
needs_fix = True
|
||||
if not needs_fix:
|
||||
continue
|
||||
gv.initializer = ir.Constant(gv.value_type, None)
|
||||
if gv_name.startswith('str_const_') or gv_name.endswith('_Vtable') or gv_name.endswith('_str'):
|
||||
gv.linkage = 'internal'
|
||||
|
||||
def _set_Vtable_initializers(self) -> None:
|
||||
for ClassName, methods in self.class_methods.items():
|
||||
if ClassName not in self.Vtables:
|
||||
continue
|
||||
if not methods:
|
||||
continue
|
||||
struct_type: ir.IdentifiedStructType | None = self.structs.get(ClassName)
|
||||
if struct_type is None:
|
||||
continue
|
||||
Vtable: ir.GlobalVariable = self.Vtables[ClassName]
|
||||
Vtable_entries: list[ir.Constant] = []
|
||||
for MethodName in methods:
|
||||
short_name: str = MethodName.split('.')[-1] if '.' in MethodName else MethodName
|
||||
full_MethodName: str = f"{ClassName}.{short_name}"
|
||||
func: ir.Function | None = None
|
||||
if full_MethodName in self.functions:
|
||||
func = self.functions[full_MethodName]
|
||||
if func is None:
|
||||
parent_cls: str | None = self.class_parent.get(ClassName)
|
||||
while parent_cls:
|
||||
parent_full: str = f"{parent_cls}.{short_name}"
|
||||
if parent_full in self.functions:
|
||||
func = self.functions[parent_full]
|
||||
break
|
||||
parent_cls = self.class_parent.get(parent_cls)
|
||||
if func is None:
|
||||
Vtable_entries.append(ir.Constant(ir.PointerType(ir.IntType(8)), None))
|
||||
continue
|
||||
Vtable_entries.append(func.bitcast(ir.PointerType(ir.IntType(8))))
|
||||
Vtable.initializer = ir.Constant(Vtable.type.pointee, Vtable_entries)
|
||||
767
lib/core/LLVMCG/TypeConvert.py
Normal file
767
lib/core/LLVMCG/TypeConvert.py
Normal file
@@ -0,0 +1,767 @@
|
||||
from __future__ import annotations
|
||||
from typing import Any
|
||||
import ast
|
||||
import re
|
||||
import logging
|
||||
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
|
||||
from lib.constants.config import mode as _config_mode
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.core.SymbolUtils import IsTModule
|
||||
|
||||
|
||||
class TypeConvertMixin:
|
||||
|
||||
# 限定符前缀映射表:(前缀字符串, 去除长度)
|
||||
# 这些限定符(const/volatile/static/extern/register/inline/export/CAuto 等)
|
||||
# 仅影响 C 语义,对 LLVM IR 类型本身无影响,统一去除后递归解析内部类型。
|
||||
_QUALIFIER_PREFIXES: tuple[tuple[str, int], ...] = (
|
||||
('const ', 6), ('volatile ', 9), ('const_', 6), ('volatile_', 9),
|
||||
('static ', 7), ('extern ', 7), ('register ', 9), ('inline ', 7),
|
||||
('export ', 7),
|
||||
('CStatic ', 8), ('CExtern ', 8), ('CRegister ', 10),
|
||||
('CInline ', 8), ('CAuto ', 6),
|
||||
)
|
||||
|
||||
def _ctype_to_llvm(self, type_info: _CTypeInfo | str | None) -> ir.Type:
|
||||
if type_info is None:
|
||||
return ir.IntType(32)
|
||||
|
||||
if isinstance(type_info, str):
|
||||
return self._type_str_to_llvm(type_info)
|
||||
|
||||
if not isinstance(type_info, _CTypeInfo):
|
||||
return ir.IntType(32)
|
||||
|
||||
if type_info.IsFuncPtr:
|
||||
ret_type: ir.Type = self._ctype_to_llvm(type_info.FuncPtrReturn) if type_info.FuncPtrReturn else ir.VoidType()
|
||||
param_types: list[ir.Type] = []
|
||||
if type_info.FuncPtrParams:
|
||||
for _name, param_info in type_info.FuncPtrParams:
|
||||
if isinstance(param_info, _CTypeInfo):
|
||||
param_types.append(self._ctype_to_llvm(param_info))
|
||||
else:
|
||||
param_types.append(ir.IntType(32))
|
||||
fn_type: ir.FunctionType = ir.FunctionType(ret_type, param_types)
|
||||
return ir.PointerType(fn_type)
|
||||
|
||||
if type_info.IsState and type_info.PtrCount == 0 and not type_info.IsTypedef:
|
||||
if type_info.BaseType is None or (isinstance(type_info.BaseType, type) and issubclass(type_info.BaseType, _t.CVoid)) or isinstance(type_info.BaseType, _t.CVoid):
|
||||
return ir.VoidType()
|
||||
|
||||
if type_info.IsTypedef and type_info.Name:
|
||||
resolved: ir.Type | None = self._resolve_typedef_ctype(type_info)
|
||||
if resolved is not None:
|
||||
return resolved
|
||||
|
||||
# REnum 类型:通过 Name 查找或创建结构体(BaseType 可能为 None)
|
||||
# 这对 BinOp `LLVMType | t.CPtr` 合并后的 CTypeInfo 至关重要
|
||||
if type_info.IsRenum and type_info.Name:
|
||||
if type_info.Name in self.structs:
|
||||
base: ir.Type = self.structs[type_info.Name]
|
||||
else:
|
||||
base = self._get_or_create_struct(type_info.Name)
|
||||
result: ir.Type = base
|
||||
for _ in range(type_info.PtrCount):
|
||||
result = ir.PointerType(result)
|
||||
return result
|
||||
|
||||
BaseType: ir.Type = self._base_ctype_to_llvm(type_info.BaseType, type_info)
|
||||
|
||||
result: ir.Type = BaseType
|
||||
for _ in range(type_info.PtrCount):
|
||||
if isinstance(result, ir.VoidType):
|
||||
result = ir.IntType(8).as_pointer()
|
||||
else:
|
||||
result = ir.PointerType(result)
|
||||
|
||||
for dim in reversed(type_info.ArrayDims):
|
||||
try:
|
||||
dim_val: int = int(dim)
|
||||
if dim_val > 0:
|
||||
result = ir.ArrayType(result, dim_val)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
return result
|
||||
|
||||
def _resolve_typedef_ctype(self, type_info: _CTypeInfo) -> ir.Type | None:
|
||||
name: str = type_info.Name
|
||||
if not name or not self.SymbolTable:
|
||||
return None
|
||||
|
||||
entry: Any = self.SymbolTable.lookup(name)
|
||||
if not entry or not isinstance(entry, _CTypeInfo):
|
||||
return None
|
||||
|
||||
if entry.BaseType and (not isinstance(entry.BaseType, _t._CTypedef) or entry.PtrCount > 0):
|
||||
resolved: Any = entry.Copy()
|
||||
resolved.IsTypedef = False
|
||||
if type_info.PtrCount > resolved.PtrCount:
|
||||
resolved.PtrCount = type_info.PtrCount
|
||||
return self._ctype_to_llvm(resolved)
|
||||
|
||||
if entry.OriginalType:
|
||||
if isinstance(entry.OriginalType, _CTypeInfo):
|
||||
resolved: Any = entry.OriginalType.Copy()
|
||||
resolved.IsTypedef = False
|
||||
if type_info.PtrCount > resolved.PtrCount:
|
||||
resolved.PtrCount = type_info.PtrCount
|
||||
return self._ctype_to_llvm(resolved)
|
||||
elif isinstance(entry.OriginalType, str):
|
||||
resolved: Any = _CTypeInfo.FromTypeName(entry.OriginalType)
|
||||
if resolved and resolved.BaseType:
|
||||
resolved.IsTypedef = False
|
||||
if type_info.PtrCount > resolved.PtrCount:
|
||||
resolved.PtrCount = type_info.PtrCount
|
||||
return self._ctype_to_llvm(resolved)
|
||||
|
||||
return None
|
||||
|
||||
def _base_ctype_to_llvm(self, BaseType: Any, type_info: _CTypeInfo | None = None) -> ir.Type:
|
||||
if BaseType is None:
|
||||
return ir.VoidType()
|
||||
|
||||
if isinstance(BaseType, (tuple, list)):
|
||||
elem_types: list[ir.Type] = [self._base_ctype_to_llvm(bt, type_info) for bt in BaseType]
|
||||
return ir.LiteralStructType(elem_types) if elem_types else ir.IntType(32)
|
||||
|
||||
if isinstance(BaseType, type) and issubclass(BaseType, _t.CType):
|
||||
BaseType = BaseType()
|
||||
|
||||
if isinstance(BaseType, _t.CVoid):
|
||||
return ir.VoidType()
|
||||
|
||||
if isinstance(BaseType, _t.CStruct):
|
||||
struct_name: str = getattr(BaseType, 'name', '') or (type_info.Name if type_info else '')
|
||||
if struct_name and struct_name in self.structs:
|
||||
return self.structs[struct_name]
|
||||
if struct_name:
|
||||
return self._get_or_create_struct(struct_name)
|
||||
return ir.LiteralStructType([])
|
||||
|
||||
if isinstance(BaseType, (_t.CEnum, _t.REnum)):
|
||||
enum_name: str = type_info.Name if type_info else ''
|
||||
if enum_name and enum_name in self.structs:
|
||||
return self.structs[enum_name]
|
||||
return ir.IntType(32)
|
||||
|
||||
if isinstance(BaseType, _t.CUnion):
|
||||
union_name: str = type_info.Name if type_info else ''
|
||||
if union_name and union_name in self.structs:
|
||||
return self.structs[union_name]
|
||||
if union_name:
|
||||
return self._get_or_create_struct(union_name)
|
||||
return ir.IntType(32)
|
||||
|
||||
if isinstance(BaseType, _t._CTypedef):
|
||||
typedef_name: str = getattr(BaseType, 'value', '') or (type_info.Name if type_info else '')
|
||||
if typedef_name and self.SymbolTable:
|
||||
entry: Any = self.SymbolTable.lookup(typedef_name)
|
||||
if entry and isinstance(entry, _CTypeInfo) and entry.BaseType:
|
||||
if not isinstance(entry.BaseType, _t._CTypedef) or entry.PtrCount > 0:
|
||||
return self._base_ctype_to_llvm(entry.BaseType, entry)
|
||||
return ir.IntType(32)
|
||||
|
||||
if isinstance(BaseType, _t.CDefine):
|
||||
# Use 64-bit type if the define value exceeds 32-bit range
|
||||
if type_info and isinstance(type_info.DefineValue, int):
|
||||
if type_info.DefineValue < 0 or type_info.DefineValue > 0xFFFFFFFF:
|
||||
return ir.IntType(64)
|
||||
return ir.IntType(32)
|
||||
|
||||
if isinstance(BaseType, _t.CPass):
|
||||
return ir.VoidType()
|
||||
|
||||
llvm_str: str = CTypeRegistry.CTypeToLLVM(type(BaseType))
|
||||
return self._llvm_str_to_ir(llvm_str)
|
||||
|
||||
def _get_source_sha1_from_type_str(self, type_str: str) -> str | None:
|
||||
"""从类型字符串中提取模块名,返回对应的源模块 SHA1。
|
||||
用于跨模块类型引用(如 memhub.MemBuddy),确保用源模块的 SHA1 创建 struct。
|
||||
"""
|
||||
if not type_str or '.' not in type_str:
|
||||
return None
|
||||
# 去除指针标记和空格
|
||||
clean: str = type_str.replace('*', '').strip()
|
||||
if '.' not in clean:
|
||||
return None
|
||||
# 提取模块名(最后一个 '.' 之前的部分)
|
||||
parts: list[str] = clean.rsplit('.', 1)
|
||||
if len(parts) < 2:
|
||||
return None
|
||||
module_name: str = parts[0]
|
||||
# 跳过 t/c 等内建模块
|
||||
if module_name in {'t', 'c'}:
|
||||
return None
|
||||
# 从 ModuleSha1Map 查找 SHA1(支持完整路径名和短名)
|
||||
sha1_map: dict[str, str] = getattr(self, 'ModuleSha1Map', {})
|
||||
source_sha1: str | None = sha1_map.get(module_name)
|
||||
if not source_sha1 and '.' in module_name:
|
||||
source_sha1 = sha1_map.get(module_name.split('.')[-1])
|
||||
return source_sha1
|
||||
|
||||
def _resolve_typedef(self, type_name: str) -> str:
|
||||
if type_name in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum', 'CPtr'}:
|
||||
return type_name
|
||||
if type_name == 'Callable':
|
||||
return 'Callable'
|
||||
visited: set[str] = set()
|
||||
current: str = type_name
|
||||
while current not in visited:
|
||||
visited.add(current)
|
||||
if self.SymbolTable:
|
||||
Entry: _CTypeInfo | None = self.SymbolTable.lookup(current)
|
||||
if isinstance(Entry, dict) and Entry.get('type') == 'typedef':
|
||||
OriginalType: str = Entry.get('OriginalType', '')
|
||||
if OriginalType:
|
||||
current = OriginalType
|
||||
continue
|
||||
elif Entry and Entry.IsTypedef:
|
||||
if Entry.OriginalType:
|
||||
if isinstance(Entry.OriginalType, _CTypeInfo):
|
||||
if Entry.OriginalType.IsFuncPtr:
|
||||
return 'Callable'
|
||||
return Entry.OriginalType.ToString() if Entry.OriginalType.BaseType else current
|
||||
elif isinstance(Entry.OriginalType, str):
|
||||
current = Entry.OriginalType
|
||||
continue
|
||||
if Entry.BaseType:
|
||||
if not isinstance(Entry.BaseType, (_t._CTypedef,)) or Entry.PtrCount > 0:
|
||||
resolved: str = self._resolve_ctype_to_str(Entry)
|
||||
if resolved and resolved != current:
|
||||
current = resolved
|
||||
continue
|
||||
bm: Any = BuiltinTypeMap.Get(current)
|
||||
if bm:
|
||||
base_cls: Any = bm[0]
|
||||
try:
|
||||
instance: Any = base_cls()
|
||||
cname: str = type(instance).__name__
|
||||
if cname:
|
||||
current = cname + ' *' * bm[1]
|
||||
continue
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
logging.warning(f"异常被忽略: {_e}")
|
||||
pass
|
||||
bm: Any = BuiltinTypeMap.Get(current)
|
||||
if bm and bm[1] > 0:
|
||||
base_cls: Any = bm[0]
|
||||
try:
|
||||
instance: Any = base_cls()
|
||||
cname: str = type(instance).__name__
|
||||
if cname:
|
||||
current = cname + ' *' * bm[1]
|
||||
continue
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
logging.warning(f"异常被忽略: {_e}")
|
||||
pass
|
||||
break
|
||||
return current
|
||||
|
||||
def _resolve_ctype_to_str(self, type_info: _CTypeInfo) -> str:
|
||||
parts: list[str] = []
|
||||
base: Any = type_info.BaseType
|
||||
if base is None or base is _t.CVoid or isinstance(base, _t.CVoid):
|
||||
parts.append('void')
|
||||
elif isinstance(base, _t._CTypedef) or base is _t._CTypedef:
|
||||
return ''
|
||||
elif isinstance(base, _t.CStruct) or base is _t.CStruct:
|
||||
parts.append(f'struct {getattr(base, "name", "")}')
|
||||
elif isinstance(base, _t.CEnum) or base is _t.CEnum:
|
||||
parts.append(f'enum {getattr(base, "name", "")}')
|
||||
else:
|
||||
cname: str = ''
|
||||
if isinstance(base, type) and issubclass(base, _t.CType):
|
||||
cname = base.__name__
|
||||
elif isinstance(base, _t.CType):
|
||||
cname = type(base).__name__
|
||||
if cname:
|
||||
parts.append(cname)
|
||||
else:
|
||||
return ''
|
||||
if type_info.PtrCount > 0:
|
||||
parts.append('*' * type_info.PtrCount)
|
||||
return ' '.join(parts)
|
||||
|
||||
def _type_str_to_llvm(self, type_str: str, IsPtr: bool = False) -> ir.Type:
|
||||
type_str = type_str.strip()
|
||||
cache_key: tuple[str, bool] = (type_str, IsPtr)
|
||||
cached: ir.Type | None = self._type_cache.get(cache_key)
|
||||
if cached is not None:
|
||||
return cached
|
||||
result: ir.Type = self._type_str_to_llvm_impl(type_str, IsPtr)
|
||||
if result is not None:
|
||||
if isinstance(result, (ir.IntType, ir.FloatType, ir.DoubleType, ir.VoidType)):
|
||||
self._type_cache[cache_key] = result
|
||||
elif isinstance(result, ir.PointerType) and isinstance(result.pointee, (ir.IntType, ir.FloatType, ir.DoubleType, ir.VoidType)):
|
||||
self._type_cache[cache_key] = result
|
||||
elif isinstance(result, ir.ArrayType) and not isinstance(result.element, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
self._type_cache[cache_key] = result
|
||||
return result
|
||||
|
||||
_CType2LLVM = _type_str_to_llvm
|
||||
|
||||
def _type_str_to_llvm_impl(self, type_str: str, IsPtr: bool = False) -> ir.Type:
|
||||
array_dims: list[int] = []
|
||||
dim_match: list[str] = re.findall(r'\[(\d+)\]', type_str)
|
||||
if dim_match:
|
||||
array_dims = [int(d) for d in dim_match]
|
||||
type_str = re.sub(r'\s*\[\d+\]', '', type_str).strip()
|
||||
result: ir.Type = self._type_str_to_llvm_base(type_str, IsPtr)
|
||||
for dim in reversed(array_dims):
|
||||
result = ir.ArrayType(result, dim)
|
||||
return result
|
||||
|
||||
def _type_str_to_llvm_base(self, type_str: str, IsPtr: bool = False) -> ir.Type:
|
||||
ptr_depth: int = 0
|
||||
while type_str.endswith('*'):
|
||||
ptr_depth += 1
|
||||
type_str = type_str[:-1].strip()
|
||||
if ptr_depth > 0:
|
||||
IsPtr = True
|
||||
if type_str in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}:
|
||||
result: ir.Type
|
||||
if IsPtr:
|
||||
result = ir.IntType(8).as_pointer()
|
||||
for _ in range(ptr_depth - 1):
|
||||
result = ir.PointerType(result)
|
||||
return result
|
||||
return ir.IntType(32)
|
||||
if type_str in {'const', 'volatile'}:
|
||||
return ir.IntType(8)
|
||||
if type_str == 'Callable':
|
||||
return ir.IntType(8).as_pointer()
|
||||
for _q_prefix, _q_offset in self._QUALIFIER_PREFIXES:
|
||||
if type_str.startswith(_q_prefix):
|
||||
return self._type_str_to_llvm(type_str[_q_offset:].strip(), IsPtr)
|
||||
resolved: str = self._resolve_typedef(type_str)
|
||||
if resolved != type_str:
|
||||
if '*' in resolved:
|
||||
IsPtr = False
|
||||
return self._type_str_to_llvm(resolved, IsPtr)
|
||||
if type_str.endswith('*'):
|
||||
BaseType: str = type_str[:-1].strip()
|
||||
base_llvm: ir.Type | None = self._basic_type_to_llvm(BaseType)
|
||||
if base_llvm is not None and isinstance(base_llvm, ir.VoidType):
|
||||
result: ir.Type = ir.IntType(8).as_pointer()
|
||||
for _ in range(ptr_depth):
|
||||
result = ir.PointerType(result)
|
||||
return result
|
||||
if base_llvm is not None and not isinstance(base_llvm, ir.VoidType):
|
||||
if isinstance(base_llvm, ir.PointerType):
|
||||
return base_llvm
|
||||
return ir.PointerType(base_llvm)
|
||||
if BaseType in self.structs:
|
||||
return ir.PointerType(self.structs[BaseType])
|
||||
if BaseType.startswith('struct '):
|
||||
stripped: str = BaseType[7:].strip()
|
||||
if stripped in self.structs:
|
||||
return ir.PointerType(self.structs[stripped])
|
||||
if '.' in BaseType:
|
||||
LastPart: str = BaseType.split('.')[-1]
|
||||
if LastPart in self.structs:
|
||||
return ir.PointerType(self.structs[LastPart])
|
||||
_src_sha1: str | None = self._get_source_sha1_from_type_str(BaseType)
|
||||
placeholder: ir.IdentifiedStructType = self._get_or_create_struct(LastPart, source_sha1=_src_sha1)
|
||||
return ir.PointerType(placeholder)
|
||||
if base_llvm is not None and isinstance(base_llvm, ir.VoidType):
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
if type_str.startswith('{') and type_str.endswith('}'):
|
||||
inner: str = type_str[1:-1].strip()
|
||||
elem_strs: list[str] = []
|
||||
depth: int = 0
|
||||
current: str = ''
|
||||
for ch in inner:
|
||||
if ch == ',' and depth == 0:
|
||||
elem_strs.append(current.strip())
|
||||
current = ''
|
||||
else:
|
||||
if ch == '{':
|
||||
depth += 1
|
||||
elif ch == '}':
|
||||
depth -= 1
|
||||
current += ch
|
||||
if current.strip():
|
||||
elem_strs.append(current.strip())
|
||||
elem_types: list[ir.Type] = []
|
||||
for es in elem_strs:
|
||||
et: ir.Type = self._type_str_to_llvm(es, '*' in es)
|
||||
if isinstance(et, ir.VoidType):
|
||||
et = ir.IntType(8).as_pointer()
|
||||
elem_types.append(et)
|
||||
if elem_types:
|
||||
return ir.LiteralStructType(elem_types)
|
||||
return ir.IntType(32)
|
||||
if type_str in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}:
|
||||
return ir.IntType(32)
|
||||
if type_str.startswith('%'):
|
||||
stripped: str = type_str[1:]
|
||||
if stripped in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}:
|
||||
return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32))
|
||||
basic_stripped: ir.Type | None = self._basic_type_to_llvm(stripped)
|
||||
if basic_stripped is not None:
|
||||
if IsPtr and not isinstance(basic_stripped, ir.VoidType):
|
||||
return ir.PointerType(basic_stripped)
|
||||
return basic_stripped
|
||||
if self.SymbolTable:
|
||||
_Entry: _CTypeInfo | None = self.SymbolTable.lookup(type_str)
|
||||
if _Entry and _Entry.IsTypedef:
|
||||
resolved_str: str = self._resolve_typedef(type_str)
|
||||
if resolved_str != type_str:
|
||||
return self._type_str_to_llvm(resolved_str, IsPtr)
|
||||
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, IsPtr)
|
||||
if _Entry and _Entry.IsRenum:
|
||||
if type_str in self.structs:
|
||||
if IsPtr:
|
||||
return ir.PointerType(self.structs[type_str])
|
||||
return self.structs[type_str]
|
||||
# REnum 结构体尚未创建时不能 fall through 到 IsEnum(会返回 i32),
|
||||
# 需要通过 _get_or_create_struct 创建 opaque 结构体(自引用安全)。
|
||||
_renum_sha1: str | None = self._get_source_sha1_from_type_str(type_str)
|
||||
opaque: ir.Type = self._get_or_create_struct(type_str, source_sha1=_renum_sha1)
|
||||
if IsPtr:
|
||||
return ir.PointerType(opaque)
|
||||
return opaque
|
||||
if _Entry and _Entry.IsStruct:
|
||||
# 结构体类型(来自 _InsertClassSymbol):必须返回结构体类型而非 i32,
|
||||
# 否则 (ast.Import | t.CPtr) 联合转换会得到 i32* 导致字段访问 GEP 偏移错误
|
||||
if type_str in self.structs:
|
||||
if IsPtr:
|
||||
return ir.PointerType(self.structs[type_str])
|
||||
return self.structs[type_str]
|
||||
# 结构体尚未创建时,通过 _get_or_create_struct 创建 opaque 结构体
|
||||
# (_TryLoadStructFromStub 会在后续阶段填充字段)
|
||||
_struct_sha1: str | None = self._get_source_sha1_from_type_str(type_str)
|
||||
opaque_struct: ir.IdentifiedStructType = self._get_or_create_struct(type_str, source_sha1=_struct_sha1)
|
||||
if IsPtr:
|
||||
return ir.PointerType(opaque_struct)
|
||||
return opaque_struct
|
||||
if _Entry and _Entry.IsEnum:
|
||||
return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32))
|
||||
if _Entry and _Entry.IsExceptionClass:
|
||||
return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32))
|
||||
if _Entry and _Entry.IsFunction:
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
if _Entry and _Entry.BaseType:
|
||||
if (isinstance(_Entry.BaseType, type) and issubclass(_Entry.BaseType, _t.CEnum)) or _Entry.BaseType is _t.CEnum:
|
||||
return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32))
|
||||
for ClassName in self.structs:
|
||||
if type_str == ClassName:
|
||||
if IsPtr:
|
||||
return ir.PointerType(self.structs[ClassName])
|
||||
return self.structs[ClassName]
|
||||
if '.' in type_str and not type_str.startswith('%'):
|
||||
LastPart: str = type_str.split('.')[-1]
|
||||
basic_last: ir.Type | None = self._basic_type_to_llvm(LastPart)
|
||||
if basic_last is not None:
|
||||
if IsPtr and not isinstance(basic_last, ir.VoidType):
|
||||
return ir.PointerType(basic_last)
|
||||
return basic_last
|
||||
if self.SymbolTable:
|
||||
_Entry: _CTypeInfo | None = self.SymbolTable.lookup(LastPart)
|
||||
if _Entry and _Entry.IsTypedef:
|
||||
resolved_str: str = self._resolve_typedef(LastPart)
|
||||
if resolved_str != LastPart:
|
||||
return self._type_str_to_llvm(resolved_str, IsPtr)
|
||||
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, IsPtr)
|
||||
if _Entry and _Entry.IsRenum:
|
||||
if LastPart in self.structs:
|
||||
if IsPtr:
|
||||
return ir.PointerType(self.structs[LastPart])
|
||||
return self.structs[LastPart]
|
||||
# REnum 结构体尚未创建时不能 fall through 到 IsEnum(会返回 i32)。
|
||||
_lp_sha1: str | None = self._get_source_sha1_from_type_str(type_str)
|
||||
opaque_lp: ir.Type = self._get_or_create_struct(LastPart, source_sha1=_lp_sha1)
|
||||
if IsPtr:
|
||||
return ir.PointerType(opaque_lp)
|
||||
return opaque_lp
|
||||
if _Entry and _Entry.IsEnum:
|
||||
return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32))
|
||||
if _Entry and _Entry.IsExceptionClass:
|
||||
return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32))
|
||||
if _Entry and _Entry.IsFunction:
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
if _Entry and _Entry.BaseType:
|
||||
if (isinstance(_Entry.BaseType, type) and issubclass(_Entry.BaseType, _t.CEnum)) or _Entry.BaseType is _t.CEnum:
|
||||
return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32))
|
||||
if LastPart in self.structs:
|
||||
if IsPtr:
|
||||
return ir.PointerType(self.structs[LastPart])
|
||||
return self.structs[LastPart]
|
||||
_lp_sha1_2: str | None = self._get_source_sha1_from_type_str(type_str)
|
||||
placeholder: ir.IdentifiedStructType = self._get_or_create_struct(LastPart, source_sha1=_lp_sha1_2)
|
||||
if IsPtr:
|
||||
return ir.PointerType(placeholder)
|
||||
return placeholder
|
||||
if type_str.startswith('struct '):
|
||||
stripped: str = type_str[7:].strip().replace(' *', '').replace('*', '')
|
||||
if stripped in self.structs:
|
||||
if IsPtr:
|
||||
return ir.PointerType(self.structs[stripped])
|
||||
return self.structs[stripped]
|
||||
basic_match: ir.Type | None = self._basic_type_to_llvm(stripped)
|
||||
if basic_match is not None:
|
||||
if IsPtr and not isinstance(basic_match, ir.VoidType):
|
||||
return ir.PointerType(basic_match)
|
||||
return basic_match
|
||||
_stripped_sha1: str | None = self._get_source_sha1_from_type_str(stripped)
|
||||
placeholder: ir.IdentifiedStructType = self._get_or_create_struct(stripped, source_sha1=_stripped_sha1)
|
||||
if IsPtr:
|
||||
return ir.PointerType(placeholder)
|
||||
return placeholder
|
||||
if type_str.startswith('%struct.'):
|
||||
stripped: str = type_str[8:].strip().replace(' *', '').replace('*', '')
|
||||
if stripped in self.structs:
|
||||
if IsPtr:
|
||||
return ir.PointerType(self.structs[stripped])
|
||||
return self.structs[stripped]
|
||||
basic_match: ir.Type | None = self._basic_type_to_llvm(stripped)
|
||||
if basic_match is not None:
|
||||
if IsPtr and not isinstance(basic_match, ir.VoidType):
|
||||
return ir.PointerType(basic_match)
|
||||
return basic_match
|
||||
_stripped_sha1_2: str | None = self._get_source_sha1_from_type_str(stripped)
|
||||
placeholder: ir.IdentifiedStructType = self._get_or_create_struct(stripped, source_sha1=_stripped_sha1_2)
|
||||
if IsPtr:
|
||||
return ir.PointerType(placeholder)
|
||||
return placeholder
|
||||
if type_str.startswith('union '):
|
||||
stripped: str = type_str[6:].strip()
|
||||
basic_match: ir.Type | None = self._basic_type_to_llvm(stripped)
|
||||
if basic_match is not None:
|
||||
if IsPtr and not isinstance(basic_match, ir.VoidType):
|
||||
return ir.PointerType(basic_match)
|
||||
return basic_match
|
||||
if type_str.endswith('*'):
|
||||
pointee: ir.Type = self._type_str_to_llvm(type_str[:-1].strip())
|
||||
if isinstance(pointee, ir.VoidType):
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
return ir.PointerType(pointee)
|
||||
result: ir.Type | None = self._basic_type_to_llvm(type_str)
|
||||
if result is None:
|
||||
# 未知类型:可能是跨模块结构体(如 'Import' 来自 ast 模块)。
|
||||
# 尝试通过 _get_or_create_struct 创建/查找结构体,
|
||||
# 该方法内部会检查 typedef/enum 等并返回正确类型。
|
||||
# 必须在 fallback 到 i32 之前执行,否则 (ast.Import | t.CPtr) 联合转换
|
||||
# 会得到 i32* 导致字段访问 GEP 偏移错误(AccessViolation 崩溃)。
|
||||
_cand_sha1: str | None = self._get_source_sha1_from_type_str(type_str)
|
||||
candidate: ir.Type = self._get_or_create_struct(type_str, source_sha1=_cand_sha1)
|
||||
if isinstance(candidate, ir.IdentifiedStructType):
|
||||
result = candidate
|
||||
else:
|
||||
result = ir.IntType(32)
|
||||
if IsPtr:
|
||||
if isinstance(result, ir.VoidType):
|
||||
result = ir.PointerType(ir.IntType(8))
|
||||
elif isinstance(result, ir.PointerType):
|
||||
pass
|
||||
else:
|
||||
result = ir.PointerType(result)
|
||||
for _ in range(ptr_depth - 1):
|
||||
result = ir.PointerType(result)
|
||||
return result
|
||||
|
||||
def _llvm_str_to_ir(self, llvm_str: str) -> ir.Type | None:
|
||||
_LLVM_IR_TYPES: dict[str, ir.Type] = {
|
||||
'void': ir.VoidType(), 'i1': ir.IntType(1), 'i8': ir.IntType(8),
|
||||
'i16': ir.IntType(16), 'i32': ir.IntType(32), 'i64': ir.IntType(64),
|
||||
'i128': ir.IntType(128), 'float': ir.FloatType(), 'double': ir.DoubleType(),
|
||||
'half': ir.IntType(16), 'fp128': ir.IntType(128),
|
||||
}
|
||||
return _LLVM_IR_TYPES.get(llvm_str)
|
||||
|
||||
def _basic_type_to_llvm(self, type_str: str) -> ir.Type | None:
|
||||
_LLVM_IR_TYPES: dict[str, ir.Type] = {
|
||||
'void': ir.VoidType(), 'i1': ir.IntType(1), 'i8': ir.IntType(8),
|
||||
'i16': ir.IntType(16), 'i32': ir.IntType(32), 'i64': ir.IntType(64),
|
||||
'i128': ir.IntType(128), 'f32': ir.FloatType(), 'f64': ir.DoubleType(),
|
||||
'half': ir.IntType(16), 'fp128': ir.IntType(128),
|
||||
}
|
||||
if type_str in _LLVM_IR_TYPES:
|
||||
return _LLVM_IR_TYPES[type_str]
|
||||
resolved: Any = CTypeRegistry.ResolveName(type_str)
|
||||
if resolved is not None:
|
||||
ctype_cls: Any
|
||||
ptr_level: int
|
||||
ctype_cls, ptr_level = resolved
|
||||
llvm_str: str = CTypeRegistry.CTypeToLLVM(ctype_cls)
|
||||
if llvm_str:
|
||||
# CTypeToLLVM 对 CPtr 等指针类型已返回含 * 的串(如 'i8*'),
|
||||
# 此时 ptr_level 已内含在 llvm_str 中,直接解析即可
|
||||
if '*' in llvm_str:
|
||||
return self._type_str_to_llvm(llvm_str)
|
||||
base: ir.Type | None = self._llvm_str_to_ir(llvm_str)
|
||||
if base is not None:
|
||||
for _ in range(ptr_level):
|
||||
if isinstance(base, ir.VoidType):
|
||||
base = ir.IntType(8).as_pointer()
|
||||
else:
|
||||
base = ir.PointerType(base)
|
||||
return base
|
||||
if type_str == '*':
|
||||
return ir.IntType(8)
|
||||
if type_str in ('const_', 'const'):
|
||||
return ir.IntType(8)
|
||||
return None
|
||||
|
||||
def _is_type_unsigned(self, type_str: str) -> bool:
|
||||
s: str = type_str.strip()
|
||||
if s.endswith('*'):
|
||||
return True
|
||||
if s.startswith('unsigned'):
|
||||
return True
|
||||
resolved: Any = CTypeRegistry.ResolveName(s)
|
||||
if resolved is not None:
|
||||
ctype_cls: Any
|
||||
_: int
|
||||
ctype_cls, _ = resolved
|
||||
try:
|
||||
inst: Any = ctype_cls()
|
||||
if getattr(inst, 'IsSigned', None) is False:
|
||||
return True
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"判断类型符号性失败: {_e}", "Exception")
|
||||
return False
|
||||
|
||||
def _record_var_signedness(self, name: str, type_str_or_bool: str | bool) -> None:
|
||||
if isinstance(type_str_or_bool, bool):
|
||||
self.var_signedness[name] = type_str_or_bool
|
||||
else:
|
||||
self.var_signedness[name] = self._is_type_unsigned(type_str_or_bool)
|
||||
|
||||
def _is_var_unsigned(self, name: str) -> bool:
|
||||
return self.var_signedness.get(name, False)
|
||||
|
||||
def _check_node_unsigned(self, node: ast.AST) -> bool:
|
||||
if isinstance(node, ast.Name):
|
||||
return self._is_var_unsigned(node.id)
|
||||
if isinstance(node, ast.BinOp):
|
||||
return self._check_node_unsigned(node.left) or self._check_node_unsigned(node.right)
|
||||
if isinstance(node, ast.UnaryOp):
|
||||
return self._check_node_unsigned(node.operand)
|
||||
if isinstance(node, ast.Call):
|
||||
return self._check_call_unsigned(node)
|
||||
if isinstance(node, ast.Subscript):
|
||||
return self._check_node_unsigned(node.value)
|
||||
if isinstance(node, ast.Attribute):
|
||||
# 检查是否为结构体字段,并查询其符号性
|
||||
field_signed: bool | None = self._check_attribute_signedness(node)
|
||||
if field_signed is not None:
|
||||
return not field_signed # IsSigned=False 表示无符号 → 返回 True
|
||||
return self._check_node_unsigned(node.value)
|
||||
return False
|
||||
|
||||
def _check_call_unsigned(self, node: ast.Call) -> bool:
|
||||
"""推断函数调用返回值的无符号性。
|
||||
|
||||
修复:原代码对所有 Call 节点返回 False,导致函数调用返回值
|
||||
直接参与 >>/% 等运算时丢失无符号性,退化成 ashr/srem。
|
||||
|
||||
规则(用户确认):
|
||||
- a = b 赋值时,若 a 无显式类型注解,则自动推导为 b 的类型(含符号性)
|
||||
- 若 a 有显式有符号类型,b 无符号,则相当于将 b 强转为 a 的有符号类型
|
||||
- 此处仅推断 b(调用本身)的符号性,赋值时的强转由赋值逻辑处理
|
||||
"""
|
||||
func_node: ast.AST = node.func
|
||||
func_name: str = ''
|
||||
|
||||
if isinstance(func_node, ast.Name):
|
||||
# 直接调用: rdrand64()
|
||||
func_name = func_node.id
|
||||
elif isinstance(func_node, ast.Attribute):
|
||||
# t.CUInt64T(x) 等类型转换调用
|
||||
if hasattr(func_node.value, 'id') and IsTModule(func_node.value.id, self.SymbolTable):
|
||||
if self._is_type_unsigned(func_node.attr):
|
||||
return True
|
||||
# module.func() 形式的调用
|
||||
try:
|
||||
func_name = f"{func_node.value.id}.{func_node.attr}"
|
||||
except AttributeError:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
if not func_name or not self.SymbolTable:
|
||||
return False
|
||||
|
||||
try:
|
||||
sym_info: Any = self.SymbolTable.lookup(func_name)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
if sym_info and isinstance(sym_info, _CTypeInfo):
|
||||
if sym_info.IsFunction or sym_info.IsFuncPtr:
|
||||
ret_info: Any = sym_info.FuncPtrReturn
|
||||
if ret_info and isinstance(ret_info, _CTypeInfo):
|
||||
# 指针类型视为无符号
|
||||
if ret_info.PtrCount > 0:
|
||||
return True
|
||||
# 检查返回类型的 IsUInt 属性(IsSigned is False)
|
||||
if ret_info.IsUInt:
|
||||
return True
|
||||
elif sym_info.IsTypedef:
|
||||
# 修复:typedef 强转调用(如 ULONGLONG(0x11))需要解析底层类型的无符号性
|
||||
# IsUInt 对组合类型(CType | CType 产生的 list)会失败,需多策略回退
|
||||
if sym_info.IsUInt:
|
||||
return True
|
||||
# 策略1:直接检查 BaseType(可能是组合类型,如 ULONGLONG = CUnsignedLong | CLong)
|
||||
bt: Any = sym_info.BaseType
|
||||
if isinstance(bt, (tuple, list)):
|
||||
for elem in bt:
|
||||
if isinstance(elem, _t.CType) and getattr(elem, 'IsSigned', None) is False:
|
||||
return True
|
||||
elif isinstance(bt, _t.CType) and getattr(bt, 'IsSigned', None) is False:
|
||||
return True
|
||||
# 策略2:通过 OriginalType 解析
|
||||
if sym_info.OriginalType:
|
||||
ot: Any = sym_info.OriginalType
|
||||
if isinstance(ot, str):
|
||||
if self._is_type_unsigned(ot):
|
||||
return True
|
||||
elif isinstance(ot, _CTypeInfo):
|
||||
if ot.IsUInt:
|
||||
return True
|
||||
elif isinstance(ot, (tuple, list)):
|
||||
for elem in ot:
|
||||
if isinstance(elem, _t.CType) and getattr(elem, 'IsSigned', None) is False:
|
||||
return True
|
||||
# 策略3:通过 _resolve_typedef 解析为字符串后判断
|
||||
resolved_str: str = self._resolve_typedef(func_name)
|
||||
if resolved_str and self._is_type_unsigned(resolved_str):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _check_attribute_signedness(self, node: ast.Attribute) -> bool | None:
|
||||
"""检查 Attribute 节点是否引用具有已知符号性的结构体字段。
|
||||
|
||||
Returns:
|
||||
True: 字段是有符号类型
|
||||
False: 字段是无符号类型
|
||||
None: 无法确定(非结构体字段或符号性未知)
|
||||
"""
|
||||
if not isinstance(node.value, ast.Name):
|
||||
return None
|
||||
var_name: str = node.value.id
|
||||
field_name: str = node.attr
|
||||
class_name: str | None = self._resolve_class_for_var(var_name)
|
||||
if not class_name:
|
||||
return None
|
||||
signed_dict: dict[str, bool] = self.class_member_signeds.get(class_name, {})
|
||||
if field_name in signed_dict:
|
||||
return signed_dict[field_name]
|
||||
return None
|
||||
94
lib/core/LLVMCG/VaArg.py
Normal file
94
lib/core/LLVMCG/VaArg.py
Normal file
@@ -0,0 +1,94 @@
|
||||
from __future__ import annotations
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.LLVMCG.BaseGen import VaArgInstruction
|
||||
|
||||
|
||||
class VaArgMixin:
|
||||
|
||||
def _get_va_start_intrinsic(self) -> ir.Function:
|
||||
if 'llvm.va_start' in self.functions:
|
||||
return self.functions['llvm.va_start']
|
||||
ftype: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.IntType(8).as_pointer()])
|
||||
func: ir.Function = ir.Function(self.module, ftype, name='llvm.va_start')
|
||||
self.functions['llvm.va_start'] = func
|
||||
return func
|
||||
|
||||
def _get_va_end_intrinsic(self) -> ir.Function:
|
||||
if 'llvm.va_end' in self.functions:
|
||||
return self.functions['llvm.va_end']
|
||||
ftype: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.IntType(8).as_pointer()])
|
||||
func: ir.Function = ir.Function(self.module, ftype, name='llvm.va_end')
|
||||
self.functions['llvm.va_end'] = func
|
||||
return func
|
||||
|
||||
def emit_va_start(self, va_list_ptr: ir.Value) -> None:
|
||||
if not self.builder:
|
||||
return None
|
||||
func: ir.Function = self._get_va_start_intrinsic()
|
||||
i8ptr_type: ir.PointerType = ir.IntType(8).as_pointer()
|
||||
if va_list_ptr.type == i8ptr_type:
|
||||
self.builder.call(func, [va_list_ptr])
|
||||
else:
|
||||
ptr: ir.Value = self.builder.bitcast(va_list_ptr, i8ptr_type, name="va_list_i8ptr")
|
||||
self.builder.call(func, [ptr])
|
||||
return None
|
||||
|
||||
def _emit_stack_align(self, alignment: int = 16) -> None:
|
||||
if not self.builder:
|
||||
return None
|
||||
void: ir.VoidType = ir.VoidType()
|
||||
asm_type: ir.FunctionType = ir.FunctionType(void, [])
|
||||
mask: int = -alignment
|
||||
asm_str: str = f"andq $${mask}, %rsp"
|
||||
asm_func: ir.InlineAsm = ir.InlineAsm(asm_type, asm_str, "~{dirflag},~{fpsr},~{flags},~{rsp}", side_effect=True)
|
||||
self.builder.call(asm_func, [], name="align_stack")
|
||||
return None
|
||||
|
||||
def emit_va_end(self, va_list_ptr: ir.Value) -> None:
|
||||
if not self.builder:
|
||||
return None
|
||||
func: ir.Function = self._get_va_end_intrinsic()
|
||||
i8ptr_type: ir.PointerType = ir.IntType(8).as_pointer()
|
||||
if va_list_ptr.type == i8ptr_type:
|
||||
self.builder.call(func, [va_list_ptr])
|
||||
else:
|
||||
ptr: ir.Value = self.builder.bitcast(va_list_ptr, i8ptr_type, name="va_list_i8ptr")
|
||||
self.builder.call(func, [ptr])
|
||||
return None
|
||||
|
||||
def emit_va_arg(self, va_list_ptr: ir.Value, arg_type: ir.Type) -> ir.Value:
|
||||
if not self.builder:
|
||||
return self._ZeroConst(arg_type)
|
||||
if not hasattr(self, '_va_arg_counter'):
|
||||
self._va_arg_counter: int = 0
|
||||
self._va_arg_counter += 1
|
||||
is_x86_64: bool = self._platform_info['is_x86_64']
|
||||
if is_x86_64:
|
||||
va_arg_type: ir.Type
|
||||
if isinstance(arg_type, ir.PointerType):
|
||||
va_arg_type = ir.IntType(64)
|
||||
elif isinstance(arg_type, (ir.FloatType, ir.DoubleType)):
|
||||
va_arg_type = ir.DoubleType()
|
||||
elif isinstance(arg_type, ir.IntType) and arg_type.width < 64:
|
||||
va_arg_type = ir.IntType(64)
|
||||
else:
|
||||
va_arg_type = arg_type
|
||||
instr: ir.Instruction = VaArgInstruction(self.builder.block, va_arg_type, 'va_arg', (va_list_ptr,), name=f'va_arg_raw_{self._va_arg_counter}')
|
||||
self.builder._insert(instr)
|
||||
result: ir.Value
|
||||
if va_arg_type != arg_type:
|
||||
if isinstance(arg_type, ir.PointerType):
|
||||
result = self.builder.inttoptr(instr, arg_type, name=f'va_arg_ptr_{self._va_arg_counter}')
|
||||
elif isinstance(arg_type, ir.FloatType):
|
||||
result = self.builder.fptrunc(instr, arg_type, name=f'va_arg_fptrunc_{self._va_arg_counter}')
|
||||
else:
|
||||
result = self.builder.trunc(instr, arg_type, name=f'va_arg_trunc_{self._va_arg_counter}')
|
||||
else:
|
||||
result = instr
|
||||
return result
|
||||
else:
|
||||
if isinstance(arg_type, ir.IntType) and arg_type.width < 64:
|
||||
arg_type = ir.IntType(64)
|
||||
instr: ir.Instruction = VaArgInstruction(self.builder.block, arg_type, 'va_arg', (va_list_ptr,), name=f'va_arg_raw_{self._va_arg_counter}')
|
||||
self.builder._insert(instr)
|
||||
return instr
|
||||
34
lib/core/LLVMCG/__init__.py
Normal file
34
lib/core/LLVMCG/__init__.py
Normal file
@@ -0,0 +1,34 @@
|
||||
"""
|
||||
LLVMCG 包 - LLVM 代码生成器模块
|
||||
|
||||
将 LlvmCodeGenerator.py 拆分为多个 Mixin 模块:
|
||||
- BaseGen: 基础设施(__init__、平台解析、名称修饰、函数查找)
|
||||
- TypeConvert: 类型转换(CType -> LLVM IR 类型)
|
||||
- StructGen: 结构体生成(struct/vtable 定义与初始化)
|
||||
- MemoryOps: 内存操作(alloca/Load/store/coerce)
|
||||
- ExprGen: 表达式生成(常量、二元运算、返回、printf)
|
||||
- FuncGen: 函数处理(参数调整、成员偏移、函数声明)
|
||||
- VaArg: 变长参数处理(va_start/va_end/va_arg)
|
||||
"""
|
||||
|
||||
from lib.core.LLVMCG.BaseGen import (
|
||||
BaseGenMixin,
|
||||
VaArgInstruction,
|
||||
)
|
||||
from lib.core.LLVMCG.TypeConvert import TypeConvertMixin
|
||||
from lib.core.LLVMCG.StructGen import StructGenMixin
|
||||
from lib.core.LLVMCG.MemoryOps import MemoryOpsMixin
|
||||
from lib.core.LLVMCG.ExprGen import ExprGenMixin
|
||||
from lib.core.LLVMCG.FuncGen import FuncGenMixin
|
||||
from lib.core.LLVMCG.VaArg import VaArgMixin
|
||||
|
||||
__all__ = [
|
||||
'BaseGenMixin',
|
||||
'TypeConvertMixin',
|
||||
'StructGenMixin',
|
||||
'MemoryOpsMixin',
|
||||
'ExprGenMixin',
|
||||
'FuncGenMixin',
|
||||
'VaArgMixin',
|
||||
'VaArgInstruction',
|
||||
]
|
||||
Reference in New Issue
Block a user