修复了大量存在的问题,增加了假鸭子类型等等机制

This commit is contained in:
2026-06-25 14:49:46 +08:00
parent 19f2787db0
commit d88d11b646
827 changed files with 32617 additions and 18316 deletions

View File

@@ -1,416 +1,491 @@
from __future__ import annotations
import re
import ast
import os
import hashlib
import llvmlite.ir as ir
from llvmlite.ir.values import _Undefined
class VaArgInstruction(ir.Instruction):
def descr(self, buf):
ptr = self.operands[0]
buf.append("va_arg {0} {1}, {2}\n".format(
ptr.type, ptr.get_reference(), self.type))
class BaseGenMixin:
@staticmethod
def _parse_triple(triple):
"""解析目标三元组,返回平台信息字典"""
info = {
'is_windows': False, 'is_linux': False, 'is_macos': False,
'is_x86_64': False, 'is_arm64': False, 'is_32bit': False,
'ptr_size': 8, 'long_size': 8, 'wchar_t_size': 32,
}
if not triple:
return info
triple_lower = triple.lower()
# 检测操作系统
if 'windows' in triple_lower or 'win32' in triple_lower or 'mingw' in triple_lower or 'msvc' in triple_lower or 'cygwin' in triple_lower:
info['is_windows'] = True
# Windows LLP64: long = 32 位, wchar_t = 16 位
info['long_size'] = 32
info['wchar_t_size'] = 16
elif 'linux' in triple_lower:
info['is_linux'] = True
elif 'darwin' in triple_lower or 'macos' in triple_lower or 'apple' in triple_lower:
info['is_macos'] = True
# 检测架构
if 'x86_64' in triple_lower or 'amd64' in triple_lower or 'x64' in triple_lower:
info['is_x86_64'] = True
elif 'aarch64' in triple_lower or 'arm64' in triple_lower:
info['is_arm64'] = True
elif 'i386' in triple_lower or 'i686' in triple_lower or 'arm' in triple_lower:
info['is_32bit'] = True
info['ptr_size'] = 4
info['long_size'] = 32
if info['is_windows']:
info['wchar_t_size'] = 16
else:
info['wchar_t_size'] = 32
return info
def __init__(self, triple=None, datalayout=None):
self.module = ir.Module(name="transpyc_module")
if triple:
self.module.triple = triple
else:
self.module.triple = "x86_64-none-elf"
if datalayout:
self.module.data_layout = datalayout
else:
self.module.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
# 解析目标平台信息
self._platform_info = self._parse_triple(self.module.triple)
self.ptr_size = self._platform_info['ptr_size']
# 根据目标平台配置 t 模块中的平台相关类型大小
import t as _t
_t.configure_platform(self.module.triple)
self.builder = None
self.func = None
self.functions = {}
self.variables = {}
self._direct_values = {}
self._reg_values = {}
self.var_signedness = {}
self._unsigned_results = {}
self.string_const_counter = 0
self.Vtables = {}
self.class_methods = {}
self.class_members = {}
self.class_member_defaults = {}
self.class_member_signeds = {}
self.class_member_bitfields = {}
self.class_member_byteorders = {}
self.class_member_element_class = {}
self.class_member_bitoffsets = {}
self.structs = {}
self.typedef_int_widths = {} # typedef名称 -> 底层整数位宽 (如 'UINT' -> 32, 'BYTE' -> 8)
self._cross_module_vtable_classes = set()
self.class_vtable = set()
self.class_parent = {}
# Store member annotations for deferred type resolution (cross-module class references)
self.class_member_annotations = {}
self.loop_break_targets = []
self.loop_continue_targets = []
self.eh_jmp_buf_stack = []
self.eh_except_block_stack = []
self.eh_finally_stack = []
self.global_vars = set()
self.nonlocal_params = {}
self._variable_scope_stack = [] # Stack of outer scope variables for nested function nonlocal lookup
self.var_struct_class = {}
self.global_struct_class = {}
self.var_type_info = {}
self.var_const_flags = {}
self._current_source_file = None
self._current_source_lines = []
self._ns_cache = {}
self._type_cache = {}
self._typedef_cache = {}
self._func_sig_cache = {}
self.var_type_assignments = {}
self._temp_struct_ptrs = []
self._stop_iter_flag_param = None
self._local_heap_ptrs = []
self._var_to_heap_ptr = {}
self.known_return_types = {}
self._current_lineno = 0
self._current_node_info = ""
self.module_sha1 = None
self.ModuleSha1Map = {}
self._temp_dir = None
self._export_funcs = set()
self._export_extern_funcs = set()
self._current_module_func_names = set()
self.class_packed = set()
self._define_constants = {}
pi = self._platform_info
# 根据目标平台设置宏(声明式,从三元组推导)
if pi['is_windows']:
self._define_constants['_WIN32'] = 1
if not pi['is_32bit']:
self._define_constants['_WIN64'] = 1
self._define_constants['WIN64'] = 1
self._define_constants['WIN32'] = 1
if pi['is_linux']:
self._define_constants['__linux__'] = 1
if pi['is_macos']:
self._define_constants['__APPLE__'] = 1
self._define_constants['__MACH__'] = 1
if pi['is_x86_64']:
self._define_constants['__x86_64__'] = 1
self._define_constants['__x86_64'] = 1
self._define_constants['_M_X64'] = 1
elif pi['is_arm64']:
self._define_constants['__aarch64__'] = 1
self._define_constants['_M_ARM64'] = 1
if not pi['is_32bit'] and pi['is_linux']:
self._define_constants['__LP64__'] = 1
elif pi['is_32bit']:
self._define_constants['_ILP32'] = 1
self._define_constants['SIZEOF_VOID_P'] = pi['ptr_size']
self._define_constants['__SIZEOF_POINTER__'] = pi['ptr_size']
def find_struct_by_pointee(self, pointee):
"""根据 pointee 类型查找匹配的结构体,返回 (class_name, struct_type) 或 None"""
for class_name, struct_type in self.structs.items():
if pointee == struct_type:
return (class_name, struct_type)
return None
def _get_or_create_struct(self, name, source_sha1=None, packed=False):
clean_name = name.replace(' *', '').replace('*', '').replace(' ', '_').replace('const', 'const_').replace('volatile', 'volatile_')
if clean_name in self.structs:
existing = self.structs[clean_name]
if packed and isinstance(existing, ir.IdentifiedStructType) and not existing.packed:
existing.packed = True
return existing
if clean_name in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum', 'Void', 'void'}:
return ir.IntType(8)
if hasattr(self, 'SymbolTable') and self.SymbolTable and self.SymbolTable.has(clean_name):
Entry = self.SymbolTable[clean_name]
if Entry.IsTypedef:
resolved_str = self._resolve_typedef(clean_name)
if resolved_str != clean_name:
return self._type_str_to_llvm(resolved_str)
if Entry.BaseType:
from lib.includes import t as _t
if not isinstance(Entry.BaseType, (_t._CTypedef,)) or Entry.PtrCount > 0:
resolved = self._resolve_ctype_to_str(Entry)
if resolved:
return self._type_str_to_llvm(resolved)
if Entry.IsRenum:
if clean_name in self.structs:
return self.structs[clean_name]
if Entry.IsEnum:
return ir.IntType(32)
if Entry.IsExceptionClass:
return ir.IntType(32)
if Entry.IsFunction:
return ir.PointerType(ir.IntType(8))
if Entry.IsVariable:
return ir.PointerType(ir.IntType(8))
if Entry.BaseType:
from lib.includes import t as _t
if isinstance(Entry.BaseType, type) and issubclass(Entry.BaseType, _t.CEnum):
return ir.IntType(32)
if Entry.BaseType is _t.CEnum:
return ir.IntType(32)
if source_sha1:
ns_name = f"{source_sha1}.{clean_name}"
elif hasattr(self, '_struct_sha1_map') and clean_name in self._struct_sha1_map:
ns_name = f"{self._struct_sha1_map[clean_name]}.{clean_name}"
else:
ns_name = self._mangle_name(clean_name)
st = ir.IdentifiedStructType(self.module, name=ns_name, packed=packed)
self.structs[clean_name] = st
# 尝试解析 typedef 的底层整数位宽
width = self._resolve_typedef_int_width(clean_name)
if width is not None:
self.typedef_int_widths[clean_name] = width
return st
def _resolve_typedef_int_width(self, name: str):
"""解析 typedef 名称的底层整数位宽
通过 CTypeRegistry 和 BuiltinTypeMap 动态解析,
替代硬编码的 TYPEDEF_NAMES 映射表。
返回 int 位宽或 None无法解析
"""
from lib.includes.t import CTypeRegistry
from lib.core.Handles.HandlesBase import BuiltinTypeMap
# 1. 先查 BuiltinTypeMap覆盖 BYTEPTR 等指针别名)
bm = BuiltinTypeMap.Get(name)
if bm:
ctype_cls, ptr_count = bm
if ptr_count > 0:
return None # 指针类型,不是整数 typedef
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit():
return int(llvm_str[1:])
# 2. 再查 SymbolTable用户定义的 typedef
if hasattr(self, 'SymbolTable') and self.SymbolTable and self.SymbolTable.has(name):
Entry = self.SymbolTable[name]
if Entry.IsTypedef:
if Entry.BaseType:
from lib.includes import t as _t
if not isinstance(Entry.BaseType, (_t._CTypedef,)) and Entry.PtrCount == 0:
llvm_str = CTypeRegistry.CTypeToLLVM(type(Entry.BaseType) if isinstance(Entry.BaseType, _t.CType) else Entry.BaseType)
if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit():
return int(llvm_str[1:])
if Entry.OriginalType:
from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo
if isinstance(Entry.OriginalType, _CTypeInfo) and Entry.OriginalType.BaseType:
if not isinstance(Entry.OriginalType.BaseType, (_t._CTypedef,)) and Entry.OriginalType.PtrCount == 0:
llvm_str = CTypeRegistry.CTypeToLLVM(type(Entry.OriginalType.BaseType) if isinstance(Entry.OriginalType.BaseType, _t.CType) else Entry.OriginalType.BaseType)
if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit():
return int(llvm_str[1:])
# 3. 尝试 CTypeRegistry 直接按名称查找
ctype_cls = CTypeRegistry.GetClassByName(name)
if ctype_cls:
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit():
return int(llvm_str[1:])
# 4. 特殊名称(非整数类型,但需要标记为 typedef 以跳过 opaque 定义)
_SPECIAL_TYPEDEFS = {
'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion',
'CStruct', 'enum', 'REnum', 'renum',
'list', 'dict', 'tuple', 'set', 'str', 'bytes', 'array', 'type',
}
if name in _SPECIAL_TYPEDEFS:
return 0 # 标记为 typedef但位宽为 0非整数
return None
def _set_node_info(self, node, extra_info=""):
if hasattr(node, 'lineno'):
self._current_lineno = node.lineno
else:
self._current_lineno = 0
if hasattr(node, 'col_offset'):
self._current_node_info = f"line {self._current_lineno}, col {node.col_offset}"
else:
self._current_node_info = f"line {self._current_lineno}"
if extra_info:
self._current_node_info += f" ({extra_info})"
def _set_source_info(self, filepath):
self._current_source_file = filepath
try:
with open(filepath, 'r', encoding='utf-8') as f:
self._current_source_lines = f.readlines()
except Exception: # 文件读取失败时回退为空行列表
self._current_source_lines = []
def _ns_hash(self):
if 'workspace' in self._ns_cache:
return self._ns_cache['workspace']
cwd = os.getcwd().replace('\\', '/').lower()
digest = hashlib.sha1(cwd.encode('utf-8')).hexdigest()[:12]
self._ns_cache['workspace'] = digest
return digest
def _skip_mangle(self, name):
skip_prefixes = ('llvm.', 'str_const_', 'printf', 'memset_pattern')
if any(name.startswith(p) for p in skip_prefixes):
return True
if '.' in name:
parts = name.split('.', 1)
if len(parts[0]) >= 8 and all(c in '0123456789abcdef' for c in parts[0]):
return True
return False
def _mangle_name(self, name):
if self._skip_mangle(name):
return name
if name in self._export_funcs:
return name
if self.module_sha1:
return f"{self.module_sha1}.{name}"
return name
def _find_function(self, name):
if name in self.functions:
return self.functions[name]
g = self.module.globals.get(name)
if g and isinstance(g, ir.Function):
self.functions[name] = g
return g
mangled = self._mangle_func_name(name)
if mangled != name:
if mangled in self.functions:
self.functions[name] = self.functions[mangled]
return self.functions[mangled]
g = self.module.globals.get(mangled)
if g and isinstance(g, ir.Function):
self.functions[mangled] = g
self.functions[name] = g
return g
for sha1 in self.ModuleSha1Map.values():
prefixed = f"{sha1}.{name}"
if prefixed in self.functions:
self.functions[name] = self.functions[prefixed]
return self.functions[prefixed]
g = self.module.globals.get(prefixed)
if g and isinstance(g, ir.Function):
self.functions[prefixed] = g
self.functions[name] = g
return g
return None
def _has_function(self, name):
return self._find_function(name) is not None
def _get_or_declare_function(self, mangled_name, func_type):
for g in self.module.globals:
if isinstance(g, ir.Function) and g.name == mangled_name:
return g
return ir.Function(self.module, func_type, name=mangled_name)
def _get_function(self, name):
func = self._find_function(name)
return func
def _mangle_func_name(self, name, module_name=None):
if name in self._export_funcs:
return name
if name in self._export_extern_funcs and name not in self._current_module_func_names:
return name
# main 函数作为程序入口点,永远不混淆
if name == 'main':
return name
# Try class_sha1_map first for class methods (e.g., 'md5.__init__' -> class 'md5')
class_sha1_map = getattr(self, 'class_sha1_map', {})
if class_sha1_map:
if '.' in name:
base_class = name.split('.')[0]
if base_class in class_sha1_map:
sha1 = class_sha1_map[base_class]
return f"{sha1}.{name}"
elif name in class_sha1_map:
sha1 = class_sha1_map[name]
return f"{sha1}.{name}"
# If module_name is already a SHA1 hash (16 hex chars), use it directly
if module_name and len(module_name) == 16 and all(c in '0123456789abcdef' for c in module_name):
return f"{module_name}.{name}"
if module_name and module_name in self.ModuleSha1Map:
sha1 = self.ModuleSha1Map[module_name]
return f"{sha1}.{name}"
# Try parent package name (e.g., 'hashlib' -> 'hashlib.__init__')
if module_name:
init_name = f"{module_name}.__init__"
if init_name in self.ModuleSha1Map:
sha1 = self.ModuleSha1Map[init_name]
return f"{sha1}.{name}"
if self._skip_mangle(name):
return name
if self.module_sha1:
return f"{self.module_sha1}.{name}"
return name
def _get_source_line(self, lineno):
if 0 < lineno <= len(self._current_source_lines):
return self._current_source_lines[lineno - 1].rstrip('\r\n')
return None
def _get_node_info(self):
info = ""
if self._current_node_info:
info = f" [{self._current_node_info}]"
if self._current_source_file:
info += f" in {self._current_source_file}"
lineno = self._current_lineno
if lineno > 0:
info += f", line {lineno}:"
source_line = self._get_source_line(lineno)
if source_line:
info += f"\n{source_line}"
return info
from __future__ import annotations
from typing import Any
import re
import ast
import os
import hashlib
import llvmlite.ir as ir
from llvmlite.ir.values import _Undefined
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
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.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] = {}
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: set[str] = set()
self._current_module_func_names: set[str] = set()
self.class_packed: set[str] = set()
self._define_constants: dict[str, int] = {}
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
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:
return self.structs[short_name]
if clean_name in self.structs:
existing: ir.IdentifiedStructType = self.structs[clean_name]
if packed and isinstance(existing, ir.IdentifiedStructType) and not existing.packed:
existing.packed = True
return existing
if clean_name in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum', 'Void', 'void'}:
return ir.IntType(8)
if hasattr(self, 'SymbolTable') and self.SymbolTable:
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]
if Entry and Entry.IsEnum:
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 hasattr(self, '_struct_sha1_map') and clean_name in self._struct_sha1_map:
ns_name = f"{self._struct_sha1_map[clean_name]}.{clean_name}"
else:
ns_name = self._mangle_name(clean_name)
st: ir.IdentifiedStructType = 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 hasattr(self, 'SymbolTable') and 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:])
# 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 _ns_hash(self) -> str:
if 'workspace' in self._ns_cache:
return self._ns_cache['workspace']
cwd: str = os.getcwd().replace('\\', '/').lower()
digest: str = hashlib.sha1(cwd.encode('utf-8')).hexdigest()[:12]
self._ns_cache['workspace'] = digest
return digest
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:
for g in self.module.globals:
if isinstance(g, ir.Function) and g.name == mangled_name:
return g
return ir.Function(self.module, func_type, name=mangled_name)
def _get_function(self, name: 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:
return name
if name in self._export_extern_funcs and name not in self._current_module_func_names:
return name
# main 函数作为程序入口点,永远不混淆
if name == 'main':
return name
# Try class_sha1_map first for class methods (e.g., 'md5.__init__' -> class 'md5')
class_sha1_map: dict[str, str] = getattr(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 _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

View File

@@ -1,353 +1,365 @@
from __future__ import annotations
import llvmlite.ir as ir
class ExprGenMixin:
def emit_constant(self, value, type_name='int'):
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 = value.encode('utf-8') + b'\x00'
str_type = ir.ArrayType(ir.IntType(8), len(encoded))
str_const = ir.Constant(str_type, bytearray(encoded))
global_var = 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, left, right, is_unsigned=False):
# 处理指针和整数之间的类型转换
if isinstance(left.type, ir.PointerType) and isinstance(right.type, ir.IntType):
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):
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 = isinstance(left.type, (ir.FloatType, ir.DoubleType)) or \
isinstance(right.type, (ir.FloatType, ir.DoubleType))
if is_float:
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 = {
'+': 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 = {
'==': '==', '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)
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 = {
'==': '==', 'Eq': '==', '!=': '!=', 'NotEq': '!=',
'<': '<', 'Lt': '<', '<=': '<=', 'LtE': '<=',
'>': '>', 'Gt': '>', '>=': '>=', 'GtE': '>=',
}
logic_ops = {
'&&': 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 hasattr(self, '_last_var_name') and self._last_var_name:
is_unsigned = self._is_var_unsigned(self._last_var_name)
elif left.type.width == 64:
if hasattr(self, '_last_var_name') and self._last_var_name:
is_unsigned = self._is_var_unsigned(self._last_var_name)
shift_ops = {
'>>': 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 = {
'&': 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 = left.constant
rv = right.constant
if isinstance(lv, int) and isinstance(rv, int) and rv >= 0:
result = lv ** rv
return ir.Constant(left.type, result)
except Exception as _e:
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
import logging; logging.warning(f"异常被忽略: {_e}")
pass
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 = self._to_float(left, ftype)
rf = self._to_float(right, ftype)
powf = self.module.globals.get('llvm.pow.f64')
if not powf:
fnty = 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 = self.builder.call(powf, [lf, rf], name="pow")
both_int = isinstance(left.type, ir.IntType) and isinstance(right.type, ir.IntType)
right_is_pos_int_const = 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, ftype=None):
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=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 hasattr(self, '_variadic_info') and self._variadic_info and self._variadic_info.get('va_start_called'):
va_list_ptr = 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 = 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.IdentifiedStructType):
if ret_type.elements:
zero_val = 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 = self.func.ftype.return_type
if ret_type != value.type:
if isinstance(ret_type, ir.PointerType) and isinstance(value.type, ir.PointerType):
if value.type.pointee == ret_type:
value = self._load(value, name="ret_Load")
else:
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 = 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:
# 有符号值用 sext无符号值用 zext
is_unsigned = 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.FloatType, ir.DoubleType)) and isinstance(value.type, (ir.FloatType, ir.DoubleType)):
if ret_type != value.type:
value = self.builder.fpext(value, ret_type, name="ret_fpext")
self.builder.ret(value)
def _emit_printf(self, args, unsigned_flags=None, sep=" ", end="\n"):
if not args:
return None
if unsigned_flags is None:
unsigned_flags = []
format_str = ""
cast_args = []
for i, arg in enumerate(args):
is_u = i < len(unsigned_flags) and unsigned_flags[i]
if isinstance(arg.type, ir.IntType):
if arg.type.width == 8:
format_str += "%c"
ext = 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 = self.builder.ptrtoint(arg, ir.IntType(64), name="ptr2int")
trunc_val = 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.IntType(8), len(format_str.encode('utf-8')) + 1)
string_const = ir.Constant(string_type, bytearray(format_str + '\x00', 'utf-8'))
global_var = 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 = self.builder.bitcast(global_var, ir.PointerType(ir.IntType(8)))
call_args = [format_ptr] + cast_args
printf_func = 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")
def emit_sizeof(self, type_name):
for class_name, struct_type in self.structs.items():
if type_name == class_name:
size = self._get_struct_size(struct_type)
if size > 0:
return ir.Constant(ir.IntType(64), size)
return ir.Constant(ir.IntType(64), 4)
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 hasattr(self, '_last_var_name') and self._last_var_name:
is_unsigned = self._is_var_unsigned(self._last_var_name)
elif left.type.width == 64:
if hasattr(self, '_last_var_name') and 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 hasattr(self, '_variadic_info') and 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.IdentifiedStructType):
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):
if value.type.pointee == ret_type:
value = self._load(value, name="ret_Load")
else:
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:
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.FloatType, ir.DoubleType)) and isinstance(value.type, (ir.FloatType, ir.DoubleType)):
if ret_type != value.type:
value = self.builder.fpext(value, ret_type, name="ret_fpext")
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 == 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")
def emit_sizeof(self, type_name: str) -> ir.Constant:
for class_name, struct_type in self.structs.items():
if type_name == class_name:
size: int = self._get_struct_size(struct_type)
if size > 0:
return ir.Constant(ir.IntType(64), size)
return ir.Constant(ir.IntType(64), 4)

View File

@@ -1,390 +1,437 @@
from __future__ import annotations
import ast
import os
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import CTypeInfo
class FuncGenMixin:
def setup_from_symbol_table(self, SymbolTable):
self.SymbolTable = 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 = info.get('type', '')
if TypeKind == 'struct':
ClassName = name
self.class_methods[ClassName] = []
self.class_members[ClassName] = []
members = info.get('members', {})
if members:
for MemberName, MemberInfo in members.items():
if isinstance(MemberInfo, dict):
MemberType = 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 = 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, MethodName):
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()
if MethodName not in self.class_methods[ClassName]:
self.class_methods[ClassName].append(MethodName)
def _adjust_args(self, args, func):
adjusted = []
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):
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 = self._alloca(ir.ArrayType(ir.IntType(8), 2), name=f"char2str_arg_{i}")
zero = ir.Constant(ir.IntType(32), 0)
char_ptr = self.builder.gep(tmp, [zero, zero], name=f"char2str_ptr_{i}")
self._store(arg, char_ptr)
null_ptr = 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 = 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.IntType(32), 0)
elem_ptr = 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.IntType(32), 0)
elem_ptr = 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 = self._alloca(param.type, name=f"temp_arg_{i}")
Loaded = self.builder.bitcast(arg, ir.PointerType(param.type), name=f"cast_arg_{i}")
Loaded_val = 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 = self._alloca(param.type, name=f"temp_arg_{i}")
cast_ptr = self.builder.bitcast(arg, ir.PointerType(param.type), name=f"cast_arg_{i}")
Loaded_val = 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 = 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 = 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 = 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 = self._alloca(arg.type, name=f"temp_arg_{i}")
self._store(arg, tmp)
adjusted.append(tmp)
else:
adjusted.append(arg)
else:
adjusted.append(arg)
while len(adjusted) < len(func.args):
missing_idx = len(adjusted)
param = func.args[missing_idx]
param_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 = args[i]
adjusted.append(arg)
return adjusted
def _get_member_offset(self, field_name, ClassName=None):
has_vtable = ClassName and (ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes)
base = 1 if has_vtable else 0
if ClassName and ClassName in self.structs:
struct_type = 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 = len(self.class_members[ClassName])
actual_elements = len(struct_type.elements)
if base > 0 and actual_elements == expected_fields:
base = 0
if ClassName and ClassName in self.class_members:
for i, (name, _) in enumerate(self.class_members[ClassName]):
if name == field_name:
return base + i
short_name = 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 hasattr(self, '_Trans') and self._Trans and hasattr(self._Trans, 'ImportHandler'):
sha1_map = getattr(self, 'ModuleSha1Map', {})
for mod_name, mod_sha1 in sha1_map.items():
stub_name = 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 = 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
if ClassName and ClassName in self.structs:
struct_type = 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 = 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 hasattr(self, '_Trans') and 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 = pyi_file.replace('.pyi', '.stub.ll')
short_cn = 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 = self.structs[ClassName]
if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None:
if hasattr(self, '_Trans') and self._Trans and hasattr(self._Trans, 'ClassHandler'):
class_handler = self._Trans.ClassHandler
if hasattr(self, '_current_tree') and 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
return None
def _resolve_class_for_var(self, var_name):
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 = 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 _GetOrCreateFunc(self, FuncName, ArgTypes):
mangled_name = self._mangle_func_name(FuncName)
if mangled_name in self.functions:
return self.functions[mangled_name]
FuncType = self._InferFuncTypeForCall(FuncName, ArgTypes)
try:
func = ir.Function(self.module, FuncType, name=mangled_name)
except Exception: # 函数名冲突时添加前缀重试
func = ir.Function(self.module, FuncType, name=f"_{mangled_name}")
self.functions[mangled_name] = func
return func
def _resolve_method_class(self, MethodName):
for ClassName, methods in self.class_methods.items():
if MethodName in methods:
return ClassName
full_name = f"{ClassName}.{MethodName}"
if full_name in methods:
return ClassName
return None
def _infer_return_type(self, FuncName):
if FuncName in self.functions:
return self.functions[FuncName].type.pointee.return_type
if FuncName in self.known_return_types:
return self.known_return_types[FuncName]
for ClassName, methods in self.class_methods.items():
for method in methods:
if FuncName == method:
return ir.VoidType()
return ir.IntType(32)
def _InferFuncTypeForCall(self, FuncName, ArgTypes):
return_type = self._infer_return_type(FuncName)
if not ArgTypes:
for ClassName, methods in self.class_methods.items():
if FuncName in methods:
if ClassName in self.structs:
ArgTypes = [ir.PointerType(self.structs[ClassName])]
else:
ArgTypes = [ir.PointerType(ir.LiteralStructType([ir.PointerType(ir.IntType(8)), ir.IntType(32)]))]
break
else:
ArgTypes = [ir.IntType(32)]
return ir.FunctionType(return_type, ArgTypes)
def _get_or_declare_func(self, name, func_type):
import re
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(self.module, func_type, name=name)
self.functions[name] = func_decl
return func_decl
def get_or_declare_c_func(self, name, fallback_type=None):
if name in self.functions:
return self.functions[name]
import re
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 = None
if hasattr(self, '_import_handler_ref') and self._import_handler_ref:
try:
stub_func_type = self._import_handler_ref._LookupStubFuncType(name, self)
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"查找桩函数类型失败: {_e}", "Exception")
if stub_func_type:
func_decl = 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(self.module, fallback_type, name=name)
self.functions[name] = func_decl
return func_decl
return None
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()
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)
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:
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
if ClassName and ClassName in self.class_members:
for i, (name, _) in enumerate(self.class_members[ClassName]):
if name == field_name:
return base + i
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 hasattr(self, '_Trans') and 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
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 hasattr(self, '_Trans') and 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 hasattr(self, '_Trans') and self._Trans and hasattr(self._Trans, 'ClassHandler'):
class_handler: Any = self._Trans.ClassHandler
if hasattr(self, '_current_tree') and 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
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 _GetOrCreateFunc(self, FuncName: str, ArgTypes: list[ir.Type]) -> ir.Function:
mangled_name: str = self._mangle_func_name(FuncName)
if mangled_name in self.functions:
return self.functions[mangled_name]
FuncType: ir.FunctionType = self._InferFuncTypeForCall(FuncName, ArgTypes)
try:
func: ir.Function = ir.Function(self.module, FuncType, name=mangled_name)
except Exception: # 函数名冲突时添加前缀重试
func = ir.Function(self.module, FuncType, name=f"_{mangled_name}")
self.functions[mangled_name] = func
return func
def _resolve_method_class(self, MethodName: str) -> str | None:
for ClassName, methods in self.class_methods.items():
if MethodName in methods:
return ClassName
full_name: str = f"{ClassName}.{MethodName}"
if full_name in methods:
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 hasattr(self, '_import_handler_ref') and 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 _InferFuncTypeForCall(self, FuncName: str, ArgTypes: list[ir.Type]) -> ir.FunctionType:
return_type: ir.Type = self._infer_return_type(FuncName)
if not ArgTypes:
for ClassName, methods in self.class_methods.items():
if FuncName in methods:
if ClassName in self.structs:
ArgTypes = [ir.PointerType(self.structs[ClassName])]
else:
ArgTypes = [ir.PointerType(ir.LiteralStructType([ir.PointerType(ir.IntType(8)), ir.IntType(32)]))]
break
else:
ArgTypes = [ir.IntType(32)]
return ir.FunctionType(return_type, ArgTypes)
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 hasattr(self, '_import_handler_ref') and 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

View File

@@ -1,312 +1,305 @@
from __future__ import annotations
import llvmlite.ir as ir
class MemoryOpsMixin:
def _register_local_heap_ptr(self, val, ClassName=None, VarName=None):
if isinstance(val.type, ir.PointerType):
pointee = 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):
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):
if not self._local_heap_ptrs or not self.builder:
return
# 创建一个集合来跟踪已经删除的对象
deleted_objects = set()
for ptr, ptr_type, ClassName in self._local_heap_ptrs:
# 先检查指针是否为 null
if ptr_type == 'i8':
# 对于 i8* 类型的指针,加载其值并检查是否为 null
Loaded_ptr = self.builder.load(ptr, name="load_ptr")
null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None)
is_null = self.builder.icmp_unsigned('==', Loaded_ptr, null_ptr, name="is_null")
# 创建一个基本块来处理非 null 的情况
not_null_block = self.builder.append_basic_block(name="not_null")
# 创建一个基本块来处理下一个对象
next_block = self.builder.append_basic_block(name="next")
# 如果指针为 null跳转到下一个对象
self.builder.cbranch(is_null, next_block, not_null_block)
# 切换到非 null 的基本块
self.builder.position_at_end(not_null_block)
# 然后调用 __del__ 方法
if ClassName and self._has_function(f'{ClassName}.__del__'):
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)
# 最后释放内存
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.VoidType(), [ir.PointerType(ir.IntType(8))])
free_func = self._get_or_declare_func('free', free_type)
self.builder.call(free_func, [raw])
# 如果是 i8* 类型的指针,跳转到下一个对象
if ptr_type == 'i8':
self.builder.branch(next_block)
# 切换到下一个对象的基本块
self.builder.position_at_end(next_block)
self._local_heap_ptrs = []
def _RegisterTempPtr(self, val):
if isinstance(val.type, ir.PointerType):
pointee = 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):
self._temp_struct_ptrs = [t for t in self._temp_struct_ptrs if t is not val]
def _EmitTempFrees(self):
if not self._temp_struct_ptrs or not self.builder:
return
for ptr in self._temp_struct_ptrs:
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.VoidType(), [ir.PointerType(ir.IntType(8))])
free_func = self._get_or_declare_func('free', free_type)
self.builder.call(free_func, [raw])
self._temp_struct_ptrs = []
def _ZeroConst(self, typ):
if isinstance(typ, ir.PointerType):
return ir.Constant(typ, None)
return ir.Constant(typ, 0)
def _alloca(self, typ, name='', align=None, size=None):
if align is None:
align = self._get_align(typ)
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, name='', align=None):
if align is None:
align = self._get_align(typ)
saved_block = self.builder.block
entry_block = self.func.entry_basic_block
if entry_block.instructions:
first_instr = 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, name='', align=None):
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 = ptr.type.pointee
if isinstance(pointee_type, ir.IdentifiedStructType) and pointee_type.name in self.typedef_int_widths:
width = self.typedef_int_widths[pointee_type.name]
if width > 0:
actual_type = ir.IntType(width)
bitcast_ptr = 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):
if name in self._direct_values:
return self._direct_values[name]
if name in self.variables and self.variables[name] is not None:
VarPtr = 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 = 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 _store_var(self, name, value):
if name in self._direct_values:
old_val = self._direct_values.pop(name)
if name not in self.variables or self.variables[name] is None:
var = self.builder.alloca(old_val.type, name=name)
self._store(old_val, var)
self.variables[name] = var
if name in self.variables and self.variables[name] is not None:
self._store(value, self.variables[name])
else:
var = self.builder.alloca(value.type, name=name)
self._store(value, var)
self.variables[name] = var
def _ensure_alloca(self, name, llvm_type):
if name in self._direct_values:
val = self._direct_values.pop(name)
var = self.builder.alloca(llvm_type, name=name)
self._store(val, var)
self.variables[name] = var
return var
if name in self.variables and self.variables[name] is not None:
return self.variables[name]
var = self.builder.alloca(llvm_type, name=name)
self.variables[name] = var
return var
def _coerce_value(self, val, target_type):
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")
else:
# 使用 sext符号扩展以正确处理负数
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 = 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(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(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 = self.builder.load(val, name="Load_struct_for_store")
if Loaded.type == target_type:
return Loaded
return None
def _store(self, val, ptr, align=None):
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 = 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 = self.typedef_int_widths[target_type.name]
if width > 0:
actual_type = ir.IntType(width)
bitcast_ptr = 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 = self._coerce_value(val, target_type)
if coerced is not None:
val = coerced
else:
src_info = 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):
if name in self._reg_values:
val = self._reg_values[name]
var = 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
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)
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 _store_var(self, name: str, value: ir.Value) -> None:
if name in self._direct_values:
old_val: ir.Value = self._direct_values.pop(name)
if name not in self.variables or self.variables[name] is None:
var: ir.AllocaInstr = self.builder.alloca(old_val.type, name=name)
self._store(old_val, var)
self.variables[name] = var
if name in self.variables and self.variables[name] is not None:
self._store(value, self.variables[name])
else:
var: ir.AllocaInstr = self.builder.alloca(value.type, name=name)
self._store(value, var)
self.variables[name] = var
def _ensure_alloca(self, name: str, llvm_type: ir.Type) -> ir.AllocaInstr:
if name in self._direct_values:
val: ir.Value = self._direct_values.pop(name)
var: ir.AllocaInstr = self.builder.alloca(llvm_type, name=name)
self._store(val, var)
self.variables[name] = var
return var
if name in self.variables and self.variables[name] is not None:
return self.variables[name]
var: ir.AllocaInstr = self.builder.alloca(llvm_type, name=name)
self.variables[name] = var
return var
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")
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

View File

@@ -1,13 +1,15 @@
from __future__ import annotations
from typing import Any, Callable
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):
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):
@@ -28,7 +30,53 @@ class StructGenMixin:
return 0
return 4
def _get_struct_size(self, llvm_type):
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 = getattr(self, '_import_handler_ref', None)
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):
@@ -40,11 +88,11 @@ class StructGenMixin:
if isinstance(llvm_type, ir.ArrayType):
return self._get_struct_size(llvm_type.element) * llvm_type.count
if isinstance(llvm_type, ir.LiteralStructType):
total = 0
max_align = 1
total: int = 0
max_align: int = 1
for f in llvm_type.fields:
fa = self._get_align(f)
fs = self._get_struct_size(f)
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
@@ -53,13 +101,15 @@ class StructGenMixin:
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 = 0
max_align = 1
total: int = 0
max_align: int = 1
for f in llvm_type.elements:
fa = self._get_align(f)
fs = self._get_struct_size(f)
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
@@ -70,10 +120,10 @@ class StructGenMixin:
return 4
@staticmethod
def _strip_unnecessary_quotes(ir_str):
def _unquote(m):
prefix = m.group(1)
name = m.group(2)
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):
@@ -81,9 +131,10 @@ class StructGenMixin:
return m.group(0)
return re.sub(r'([@%])"([^"]+)"', _unquote, ir_str)
def finalize(self):
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:
@@ -96,11 +147,12 @@ class StructGenMixin:
pass
raise
ir_text = self._strip_unnecessary_quotes(ir_text)
struct_defs = []
struct_names = set()
struct_defs: list[str] = []
struct_names: set[str] = set()
for ClassName, struct_type in self.structs.items():
if isinstance(struct_type, ir.IdentifiedStructType):
sname = struct_type.name
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:
@@ -110,19 +162,20 @@ class StructGenMixin:
struct_names.add(sname)
struct_defs.append(f'{sname_ir} = type opaque')
continue
elems = ', '.join(str(e) for e in struct_type.elements)
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 = ir_text.split('\n')
filtered = []
lines: list[str] = ir_text.split('\n')
filtered: list[str] = []
for line in lines:
stripped = line.strip()
skip = False
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:
@@ -136,17 +189,17 @@ class StructGenMixin:
if not skip:
filtered.append(line)
ir_text = '\n'.join(filtered)
header_end = ir_text.find('\ndefine')
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 = ir_text.rfind('\n', 0, header_end)
insert_pos: int = ir_text.rfind('\n', 0, header_end)
if insert_pos == -1:
insert_pos = header_end
struct_block = '\n'.join(struct_defs) + '\n'
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:
@@ -158,13 +211,13 @@ class StructGenMixin:
return ir_text
def _collect_classes_and_methods(self, ast_nodes, parent=None):
current_class = None
def _collect_classes_and_methods(self, ast_nodes: list[ast.AST], parent: ast.AST | None = None) -> None:
current_class: str | None = None
for node in ast_nodes:
if isinstance(node, str):
continue
node.parent = parent
node_type = type(node).__name__
node_type: str = type(node).__name__
if node_type == 'Struct':
if hasattr(node, 'name'):
current_class = node.name
@@ -173,11 +226,11 @@ class StructGenMixin:
if hasattr(node, 'decls') and node.decls:
for decl in node.decls:
if type(decl).__name__ == 'Decl' and hasattr(decl, 'name'):
member_type = self._get_type(decl.type) if hasattr(decl, 'type') else ir.IntType(32)
member_type: ir.Type = self._get_type(decl.type) if hasattr(decl, 'type') else ir.IntType(32)
self.class_members[current_class].append((decl.name, member_type))
elif node_type == 'FuncDef':
if current_class and current_class in self.class_methods:
MethodName = node.decl.name if hasattr(node.decl, 'name') else 'unknown_method'
MethodName: str = node.decl.name if hasattr(node.decl, 'name') else 'unknown_method'
if not MethodName.startswith(f"{current_class}."):
MethodName = f"{current_class}.{MethodName}"
self.class_methods[current_class].append(MethodName)
@@ -186,10 +239,10 @@ class StructGenMixin:
elif hasattr(node, 'BlockItems') and node.BlockItems:
self._collect_classes_and_methods(node.BlockItems, parent=node)
def _generate_structs(self):
all_classes = set(self.class_methods.keys()) | set(self.class_members.keys())
def _generate_structs(self) -> None:
all_classes: set[str] = set(self.class_methods.keys()) | set(self.class_members.keys())
preserved_structs = {}
preserved_structs: dict[str, ir.IdentifiedStructType] = {}
for name, st in self.structs.items():
if name not in all_classes:
preserved_structs[name] = st
@@ -204,25 +257,24 @@ class StructGenMixin:
# Step 1: 先为所有类创建空的 struct确保后面可以正确引用
all_classes = set(self.class_methods.keys()) | set(self.class_members.keys())
for ClassName in all_classes:
is_packed = ClassName in self.class_packed
if hasattr(self, 'SymbolTable') and self.SymbolTable and self.SymbolTable.has(ClassName):
Entry = self.SymbolTable[ClassName]
if Entry.IsExceptionClass:
is_packed: bool = ClassName in self.class_packed
if hasattr(self, 'SymbolTable') and self.SymbolTable:
Entry = self.SymbolTable.lookup(ClassName)
if Entry and Entry.IsExceptionClass:
continue
if Entry.IsEnum:
if Entry and Entry.IsEnum:
if not Entry.IsRenum:
continue
if Entry.IsTypedef:
if Entry and Entry.IsTypedef:
if Entry.BaseType and not isinstance(Entry.BaseType, (type(None),)):
import lib.includes.t as _t
if not isinstance(Entry.BaseType, (_t._CTypedef,)):
continue
if ClassName in self.structs:
if is_packed:
self.structs[ClassName].packed = True
continue
mangled_name = self._mangle_name(ClassName)
struct_type = ir.IdentifiedStructType(self.module, mangled_name, packed=is_packed)
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: 解析跨模块的成员类型
@@ -231,30 +283,30 @@ class StructGenMixin:
continue
for i, (member_name, member_type) in enumerate(self.class_members[ClassName]):
if member_name in annotations:
annotation = annotations[member_name]
ResolvedType = None
annotation: Any = annotations[member_name]
ResolvedType: ir.Type | None = None
if isinstance(annotation, ast.Attribute):
ClassTypeName = annotation.attr
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 = annotation.left
left: Any = annotation.left
if isinstance(left, ast.Attribute):
ClassTypeName = left.attr
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 = {}
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 = getattr(struct, '_original_name', None)
orig: Any = getattr(struct, '_original_name', None)
if orig:
struct_name_map[orig] = struct
@@ -264,81 +316,85 @@ class StructGenMixin:
continue
for i, (member_name, member_type) in enumerate(self.class_members[ClassName]):
if isinstance(member_type, ir.PointerType):
pointee = member_type.pointee
pointee: ir.Type = member_type.pointee
if isinstance(pointee, ir.IdentifiedStructType):
pname: str | None
try:
pname = pointee.name
except AssertionError:
pname = None
struct = struct_name_map.get(pname) if pname else None
struct: ir.IdentifiedStructType | None = struct_name_map.get(pname) if pname else None
if struct is None:
orig = getattr(pointee, '_original_name', 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 = pname or ''
raw_name: str = pname or ''
if raw_name.startswith('struct.'):
raw_name = raw_name[7:]
new_struct = self._get_or_create_struct(raw_name)
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 = struct_name_map.get(mname) if mname else None
struct: ir.IdentifiedStructType | None = struct_name_map.get(mname) if mname else None
if struct is None:
orig = getattr(member_type, '_original_name', 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 = mname or ''
raw_name: str = mname or ''
if raw_name.startswith('struct.'):
raw_name = raw_name[7:]
new_struct = self._get_or_create_struct(raw_name)
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 hasattr(self, 'SymbolTable') and self.SymbolTable and self.SymbolTable.has(ClassName):
Entry = self.SymbolTable[ClassName]
if Entry.IsExceptionClass:
if hasattr(self, 'SymbolTable') and self.SymbolTable:
Entry = self.SymbolTable.lookup(ClassName)
if Entry and Entry.IsExceptionClass:
continue
if Entry.IsEnum:
if Entry and Entry.IsEnum:
if not Entry.IsRenum:
continue
existing_st = self.structs.get(ClassName)
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 已有元素,也需要修正 packed 属性
if ClassName in self.class_packed and not existing_st.packed:
existing_st.packed = True
continue
has_vtable = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes
has_vtable: bool = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes
if not has_vtable:
p = self.class_parent.get(ClassName)
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 = ClassName in self.class_member_bitfields and any(
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 = self.class_members.get(ClassName, [])
all_bitfield = all(
all_members: list[tuple[str, ir.Type]] = self.class_members.get(ClassName, [])
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 = self._mangle_name(ClassName)
mangled_name: str = self._mangle_name(ClassName)
member_types: list[ir.Type]
if has_bitfield and all_bitfield:
total_bits = sum(self.class_member_bitfields.get(ClassName, {}).get(name, 0)
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:
@@ -348,10 +404,10 @@ class StructGenMixin:
else:
storage_type = ir.IntType(64)
member_types = [storage_type]
bitfield_offsets = {}
current_bit_offset = 0
bitfield_offsets: dict[str, int] = {}
current_bit_offset: int = 0
for name, _ in all_members:
bit_width = self.class_member_bitfields.get(ClassName, {}).get(name, 0)
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
@@ -368,14 +424,14 @@ class StructGenMixin:
member_types = [ir.IntType(8)]
# 获取之前创建的 struct 并设置成员
struct_type = self.structs[ClassName]
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_type.set_body(*member_types)
def _create_Vtable_globals(self):
def _create_Vtable_globals(self) -> None:
for ClassName, methods in self.class_methods.items():
if ClassName in self.Vtables:
continue
@@ -383,19 +439,19 @@ class StructGenMixin:
continue
if ClassName not in self.class_vtable and ClassName not in self._cross_module_vtable_classes:
continue
VtableType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods))
Vtable = ir.GlobalVariable(self.module, VtableType, name=self._mangle_name(f"{ClassName}_Vtable"))
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 _fix_global_var_init(self):
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 = False
needs_fix: bool = False
if gv.initializer is None:
needs_fix = True
elif hasattr(gv.initializer, 'constant') and isinstance(gv.initializer.constant, _Undefined):
@@ -410,48 +466,27 @@ class StructGenMixin:
if gv_name.startswith('str_const_') or gv_name.endswith('_Vtable') or gv_name.endswith('_str'):
gv.linkage = 'internal'
def _zero_value_for_type(self, var_type):
if isinstance(var_type, ir.IntType):
return ir.Constant(var_type, 0)
elif isinstance(var_type, (ir.FloatType, ir.DoubleType)):
return ir.Constant(var_type, 0.0)
elif isinstance(var_type, ir.PointerType):
return ir.Constant(var_type, None)
elif isinstance(var_type, ir.ArrayType):
elem_zv = self._zero_value_for_type(var_type.element)
if elem_zv is None:
return None
return ir.Constant(var_type, [elem_zv] * var_type.count)
elif isinstance(var_type, ir.BaseStructType):
if var_type.elements is not None and len(var_type.elements) > 0:
elem_zvs = [self._zero_value_for_type(m) for m in var_type.elements]
if any(zv is None for zv in elem_zvs):
return None
return ir.Constant(var_type, elem_zvs)
return None
return None
def _set_Vtable_initializers(self):
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 = self.structs.get(ClassName)
struct_type: ir.IdentifiedStructType | None = self.structs.get(ClassName)
if not struct_type:
continue
Vtable = self.Vtables[ClassName]
Vtable_entries = []
Vtable: ir.GlobalVariable = self.Vtables[ClassName]
Vtable_entries: list[ir.Constant] = []
for MethodName in methods:
short_name = MethodName.split('.')[-1] if '.' in MethodName else MethodName
full_MethodName = f"{ClassName}.{short_name}"
func = None
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 = self.class_parent.get(ClassName)
parent_cls: str | None = self.class_parent.get(ClassName)
while parent_cls:
parent_full = f"{parent_cls}.{short_name}"
parent_full: str = f"{parent_cls}.{short_name}"
if parent_full in self.functions:
func = self.functions[parent_full]
break
@@ -460,4 +495,4 @@ class StructGenMixin:
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)
Vtable.initializer = ir.Constant(Vtable.type.pointee, Vtable_entries)

File diff suppressed because it is too large Load Diff

View File

@@ -1,94 +1,94 @@
from __future__ import annotations
import sys
import llvmlite.ir as ir
from lib.core.LLVMCG.BaseGen import VaArgInstruction
class VaArgMixin:
def _get_va_start_intrinsic(self):
if 'llvm.va_start' in self.functions:
return self.functions['llvm.va_start']
ftype = ir.FunctionType(ir.VoidType(), [ir.IntType(8).as_pointer()])
func = ir.Function(self.module, ftype, name='llvm.va_start')
self.functions['llvm.va_start'] = func
return func
def _get_va_end_intrinsic(self):
if 'llvm.va_end' in self.functions:
return self.functions['llvm.va_end']
ftype = ir.FunctionType(ir.VoidType(), [ir.IntType(8).as_pointer()])
func = 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):
if not self.builder:
return None
func = self._get_va_start_intrinsic()
i8ptr_type = ir.IntType(8).as_pointer()
if va_list_ptr.type == i8ptr_type:
self.builder.call(func, [va_list_ptr])
else:
ptr = 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=16):
if not self.builder:
return None
void = ir.VoidType()
asm_type = ir.FunctionType(void, [])
mask = -alignment
asm_str = f"andq ${mask}, %rsp"
asm_func = 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):
if not self.builder:
return None
func = self._get_va_end_intrinsic()
i8ptr_type = ir.IntType(8).as_pointer()
if va_list_ptr.type == i8ptr_type:
self.builder.call(func, [va_list_ptr])
else:
ptr = 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, arg_type):
if not self.builder:
return self._ZeroConst(arg_type)
if not hasattr(self, '_va_arg_counter'):
self._va_arg_counter = 0
self._va_arg_counter += 1
import sys
is_x86_64 = sys.platform in ('win32', 'win64', 'windows', 'linux', 'linux2', 'darwin')
if is_x86_64:
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 = 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)
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 = 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
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