from __future__ import annotations from typing import TYPE_CHECKING, Any if TYPE_CHECKING: from lib.core.translator import Translator import ast import sys import llvmlite.ir as ir from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta from lib.core.VLogger import get_logger as _vlog from lib.core.ConstEvaluator import ConstEvaluator, EvalContext from lib.constants.config import mode as _config_mode from lib.includes import t from lib.includes.t import CTypeRegistry from lib.core.SymbolUtils import IsTModule, ParseListAnnotation, AnnotationContainsName class AssignHandle(BaseHandle): def __init__(self, translator: "Translator") -> None: super().__init__(translator) self._CurrentCpythonObjectClass: str | None = None @staticmethod def _contains_identified_struct(var_type: ir.Type) -> bool: if isinstance(var_type, ir.IdentifiedStructType): return True if isinstance(var_type, ir.ArrayType): return AssignHandle._contains_identified_struct(var_type.element) if isinstance(var_type, ir.PointerType): return AssignHandle._contains_identified_struct(var_type.pointee) if isinstance(var_type, ir.BaseStructType): if var_type.elements: return any(AssignHandle._contains_identified_struct(e) for e in var_type.elements) return False def HandleExprLlvm(self, Node: ast.expr, VarType: ir.Type | None = None) -> ir.Value | None: return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType) def _HandleAssignLlvm(self, Node: ast.Assign) -> None: Gen: "Translator.LlvmGen" = self.Trans.LlvmGen Gen._set_node_info(Node, "Assign") if len(Node.targets) == 1: Target: ast.expr = Node.targets[0] if isinstance(Target, ast.Name): VarName: str = Target.id if VarName in Gen.var_const_flags: src_info: str = Gen._get_node_info() _vlog().error(f"不能对 const 变量 '{VarName}' 赋值{src_info}") sys.exit(1) if isinstance(Node.value, ast.Attribute) and isinstance(Node.value.value, ast.Name) and IsTModule(Node.value.value.id, self.Trans.SymbolTable): AttrName: str = Node.value.attr Gen.var_type_info[VarName] = {'type': 't_type', 'name': AttrName} Gen.var_type_assignments.setdefault(VarName, []).append({'type': 't_type', 'name': AttrName}) c_type_name: str = '' resolved: tuple[type, int] | None = CTypeRegistry.ResolveName(AttrName) if resolved is not None: ctype_cls: type = resolved[0] ptr_level: int = resolved[1] c_type_name = CTypeRegistry.CTypeToName(ctype_cls) if ptr_level > 0 and c_type_name: c_type_name = c_type_name + ' *' if not c_type_name: if AttrName == 'CPtr': c_type_name = 'void *' is_unsigned: bool = Gen._is_type_unsigned(c_type_name) if c_type_name else False fmt_str: str = "%u\n" if is_unsigned else "%d\n" fmt_ptr: ir.Value = Gen._create_string_global(fmt_str) fmt_var_name: str = f"__{VarName}_fmt" if fmt_var_name not in Gen.variables: fmt_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=fmt_var_name) Gen.variables[fmt_var_name] = fmt_alloca Gen.builder.store(fmt_ptr, Gen.variables[fmt_var_name]) kind_var_name: str = f"__{VarName}_kind" if kind_var_name not in Gen.variables: kind_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=kind_var_name) Gen.variables[kind_var_name] = kind_alloca Gen.builder.store(ir.Constant(ir.IntType(32), 0), Gen.variables[kind_var_name]) if VarName not in Gen.variables: dummy_var: ir.AllocaInstr = Gen._alloca(ir.IntType(8), name=VarName) Gen.variables[VarName] = dummy_var return if isinstance(Node.value, ast.Name) and Node.value.id in Gen.structs: ClassName: str = Node.value.id Gen.var_type_info[VarName] = {'type': 'class_cast', 'name': ClassName} Gen.var_type_assignments.setdefault(VarName, []).append({'type': 'class_cast', 'name': ClassName}) fmt_str: str = "%p\n" fmt_ptr: ir.Value = Gen._create_string_global(fmt_str) fmt_var_name: str = f"__{VarName}_fmt" if fmt_var_name not in Gen.variables: fmt_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=fmt_var_name) Gen.variables[fmt_var_name] = fmt_alloca Gen.builder.store(fmt_ptr, Gen.variables[fmt_var_name]) kind_var_name: str = f"__{VarName}_kind" if kind_var_name not in Gen.variables: kind_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=kind_var_name) Gen.variables[kind_var_name] = kind_alloca Gen.builder.store(ir.Constant(ir.IntType(32), 1), Gen.variables[kind_var_name]) if VarName not in Gen.variables: dummy_var: ir.AllocaInstr = Gen._alloca(ir.IntType(8), name=VarName) Gen.variables[VarName] = dummy_var return if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name) and Node.value.func.id == 'va_list': va_list_ptr: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(8).as_pointer(), name="va_list") Gen.variables[VarName] = va_list_ptr return IsStructCtor: bool = (isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name) and Node.value.func.id in Gen.structs) if IsStructCtor: ClassName: str = Node.value.func.id StructType: ir.Type = Gen.structs[ClassName] IsUnion: bool = False TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(ClassName) if TypeInfo and TypeInfo.IsUnion: IsUnion = True if IsUnion: Value: ir.Value | None = self.HandleExprLlvm(Node.value) if Value: var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName) Gen._store(Value, var) Gen.variables[VarName] = var return ExistingPtr: ir.Value | None = None if VarName in Gen.variables and Gen.variables[VarName] is not None: VarPtr: ir.Value = Gen.variables[VarName] if isinstance(VarPtr.type.pointee, ir.PointerType): ExistingPtr = VarPtr elif VarName in Gen._reg_values: OldVal: ir.Value = Gen._reg_values[VarName] if isinstance(OldVal.type, ir.PointerType): var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName) Gen._store(OldVal, var) Gen.variables[VarName] = var del Gen._reg_values[VarName] ExistingPtr = var elif VarName in Gen._direct_values: OldVal: ir.Value = Gen._direct_values.pop(VarName) if isinstance(OldVal.type, ir.PointerType): var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName) Gen._store(OldVal, var) Gen.variables[VarName] = var ExistingPtr = var if ExistingPtr: pointee: ir.Type = ExistingPtr.type.pointee # 仅当 alloca 直接存储结构体值(pointee 不是指针)时才 in-place 初始化。 # 当 pointee 是 PointerType 时,alloca 存储的是堆对象指针: # - 若 AnnAssign 分支未执行,alloca 内容是未初始化的栈垃圾 # (可能恰好等于 pool 地址),_InitStructAtPtr 会向垃圾地址写字段 → 内存损坏 # - 即使指针有效,node = Class(...) 的语义也是创建新对象并更新指针, # 而非在旧对象位置 in-place 重初始化 # 此时必须 fall through 到通用路径 HandleExprLlvm → _HandleClassNewLlvm # 以正确调用 __new__/__before_init__/__init__ 构造新对象。 if not isinstance(pointee, ir.PointerType) and pointee == StructType: self._InitStructAtPtr(Node.value, ClassName, ExistingPtr) return if isinstance(Node.value, ast.Attribute): enum_type_name: str | None = self._CheckEnumMemberAssignment(Node.value) if enum_type_name: Gen.var_type_info[VarName] = {'type': 'enum', 'name': enum_type_name} var_type_for_list: ir.Type | None = None if isinstance(Node.value, ast.List) and VarName in Gen.var_type_info: type_info: dict[str, str] = Gen.var_type_info[VarName] if type_info.get('type') == 'CArray': var_type_for_list = type_info.get('full_type') Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=var_type_for_list) # 闭包变量追踪:当赋值右侧是返回闭包的函数调用时,记录变量为闭包类型 if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): CalledName: str = Node.value.func.id if CalledName in Gen._closure_return_types: Gen._closure_var_types[VarName] = Gen._closure_return_types[CalledName] if not Value: return if isinstance(Value.type, ir.VoidType): return Gen._UnregisterTempPtr(Value) # 大端局部变量:赋值时 bswap Value = Gen._apply_bswap_if_big(Value, Gen.local_var_byteorders.get(VarName, ""), f"bswap_assign_{VarName}") if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): found_class: str | None = None found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(Value.type.pointee) if found: CN: str = found[0] ST: ir.Type = found[1] found_class = CN Gen.var_struct_class[VarName] = CN Gen._var_to_heap_ptr[VarName] = Value if found_class is None and isinstance(Value.type.pointee, ir.IdentifiedStructType): pointee_name: str = Value.type.pointee.name pointee_short: str = Gen._extract_short_name(pointee_name) best_elem_count: int = 0 for CN, ST in Gen.structs.items(): if isinstance(ST, ir.IdentifiedStructType): st_short: str = Gen._extract_short_name(ST.name) if st_short == pointee_short: elem_count: int = len(ST.elements) if ST.elements else 0 if elem_count > best_elem_count: found_class = CN best_elem_count = elem_count if found_class: Gen.var_struct_class[VarName] = found_class Gen._var_to_heap_ptr[VarName] = Value # 泛型类特化触发:返回类型是泛型类特化(如 list[str])但结构体尚未创建, # 或虽然找到了结构体但它是 opaque(来自 stub 声明,尚未发射方法体) _fd_struct_opaque: bool = False if found_class and found_class in Gen.structs: _fd_st: ir.IdentifiedStructType = Gen.structs[found_class] if isinstance(_fd_st, ir.IdentifiedStructType) and (_fd_st.elements is None or len(_fd_st.elements) == 0): _fd_struct_opaque = True if (found_class is None or _fd_struct_opaque) and isinstance(Value.type.pointee, ir.IdentifiedStructType): pn: str = Value.type.pointee.name short_pn: str = pn if '.' in pn: pn_parts: list[str] = pn.split('.', 1) if len(pn_parts[0]) >= 8 and all(c in '0123456789abcdef' for c in pn_parts[0]): short_pn = pn_parts[1] if '[' in short_pn and short_pn.endswith(']'): gc_base: str = short_pn.split('[')[0] gc_args_raw: str = short_pn[len(gc_base):] gc_type_args: list[str] = [] for gc_arg_part in gc_args_raw.split(']['): gc_arg_part = gc_arg_part.strip('[]') if gc_arg_part: gc_type_args.append(gc_arg_part) if (gc_type_args and hasattr(self.Trans.ClassHandler, '_generic_class_templates') and gc_base in self.Trans.ClassHandler._generic_class_templates): gc_type_names: list[str] = [] for gc_ta in gc_type_args: gc_tn: str = gc_ta if gc_ta == 'int': gc_tn = 'CInt' elif gc_ta == 'double': gc_tn = 'CDouble' elif gc_ta == 'float': gc_tn = 'CFloat' elif gc_ta == 'char': gc_tn = 'CChar' elif gc_ta == 'bool': gc_tn = 'CBool' gc_type_names.append(gc_tn) gc_spec: str | None = self.Trans.ClassHandler._specialize_generic_class( gc_base, gc_type_args, Gen, type_names=gc_type_names) if gc_spec and gc_spec in Gen.structs: found_class = gc_spec Gen.var_struct_class[VarName] = gc_spec Gen._var_to_heap_ptr[VarName] = Value else: if VarName in ('mctx', 's1ctx', 's2ctx', 's5ctx'): pass if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): if VarName in Gen.variables and Gen.variables[VarName] is not None: Gen._store(Value, Gen.variables[VarName]) else: var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName) Gen._store(Value, var) Gen.variables[VarName] = var if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): call_func_name: str = Node.value.func.id if call_func_name in Gen.var_type_info: type_info: dict[str, str] = Gen.var_type_info[call_func_name] if type_info['type'] in ('t_type', 'class_cast'): src_fmt_var: str = f"__{call_func_name}_fmt" dst_fmt_var: str = f"__{VarName}_fmt" if src_fmt_var in Gen.variables: if dst_fmt_var not in Gen.variables: dst_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var) Gen.variables[dst_fmt_var] = dst_alloca src_fmt_ptr: ir.Value = Gen._load(Gen.variables[src_fmt_var], name=f"Load_{call_func_name}_fmt_for_{VarName}") Gen.builder.store(src_fmt_ptr, Gen.variables[dst_fmt_var]) src_kind_var: str = f"__{call_func_name}_kind" dst_kind_var: str = f"__{VarName}_kind" if src_kind_var in Gen.variables: if dst_kind_var not in Gen.variables: dst_kind_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=dst_kind_var) Gen.variables[dst_kind_var] = dst_kind_alloca src_kind_val: ir.Value = Gen._load(Gen.variables[src_kind_var], name=f"Load_{call_func_name}_kind_for_{VarName}") Gen.builder.store(src_kind_val, Gen.variables[dst_kind_var]) Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name} return if VarName in Gen.global_vars: if VarName in Gen.module.globals: GVar: ir.GlobalVariable = Gen.module.globals[VarName] Gen._store(Value, GVar) Gen.variables[VarName] = GVar if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(Value.type.pointee) if found: CN: str = found[0] ST: ir.Type = found[1] Gen.var_struct_class[VarName] = CN elif VarName in Gen.variables and Gen.variables[VarName] is not None: Gen._store(Value, Gen.variables[VarName]) return if VarName in Gen._reg_values: OldVal: ir.Value = Gen._reg_values[VarName] var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName) Gen._store(OldVal, var) Gen.variables[VarName] = var del Gen._reg_values[VarName] if VarName in Gen._direct_values: OldVal: ir.Value = Gen._direct_values.pop(VarName) var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName) Gen._store(OldVal, var) Gen.variables[VarName] = var if VarName in Gen.variables and Gen.variables[VarName] is not None: VarPtr: ir.Value = Gen.variables[VarName] TargetType: ir.Type | None = VarPtr.type.pointee if isinstance(VarPtr.type, ir.PointerType) else None types_differ: bool try: types_differ = TargetType and Value.type != TargetType except AssertionError: types_differ = False if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.PointerType): LoadedValue: ir.Value = Gen._load(Value, name=f"Load_{VarName}") Loaded_differ: bool try: Loaded_differ = TargetType and LoadedValue.type != TargetType except AssertionError: Loaded_differ = False if Loaded_differ: try: Coerced: ir.Value | None = Gen._coerce_value(LoadedValue, TargetType) if Coerced is not None: LoadedValue = Coerced except AssertionError: pass Gen._store(LoadedValue, VarPtr) elif types_differ: try: Coerced: ir.Value | None = Gen._coerce_value(Value, TargetType) if Coerced is not None: Gen._store(Coerced, VarPtr) else: Gen._store(Value, VarPtr) except AssertionError: Gen._store(Value, VarPtr) else: Gen._store(Value, VarPtr) if VarName not in Gen.variables: # 检查是否为模块级全局变量 # main 函数代表模块级作用域,直接修改全局变量 # 其他函数中,未声明 global 且未先读取的赋值创建局部变量(Python 作用域语义) # 先读取过的变量已通过 HandleExprLlvm 加入 Gen.variables,会走 L289 分支存储到全局 CurrentFuncName: str = getattr(Gen.func, 'name', '') if Gen.func else '' IsMainScope: bool = CurrentFuncName == 'main' or CurrentFuncName.endswith('.main') if VarName in Gen.module.globals and (VarName in Gen.global_vars or IsMainScope): GVar: ir.GlobalVariable = Gen.module.globals[VarName] Gen._store(Value, GVar) Gen.variables[VarName] = GVar elif isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.PointerType): LoadedValue: ir.Value = Gen._load(Value, name=f"Load_{VarName}") var: ir.AllocaInstr = Gen._allocaEntry(LoadedValue.type, name=VarName) Gen._store(LoadedValue, var) Gen.variables[VarName] = var else: var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName) Gen._store(Value, var) Gen.variables[VarName] = var is_u: bool = Gen._check_node_unsigned(Node.value) Gen._record_var_signedness(VarName, 'unsigned int' if is_u else 'int') if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): call_func_name: str = Node.value.func.id if call_func_name in Gen.var_type_info: type_info: dict[str, str] = Gen.var_type_info[call_func_name] if type_info['type'] in ('t_type', 'class_cast'): src_fmt_var: str = f"__{call_func_name}_fmt" dst_fmt_var: str = f"__{VarName}_fmt" if src_fmt_var in Gen.variables: if dst_fmt_var not in Gen.variables: dst_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var) Gen.variables[dst_fmt_var] = dst_alloca src_fmt_ptr: ir.Value = Gen._load(Gen.variables[src_fmt_var], name=f"Load_{call_func_name}_fmt_for_{VarName}") Gen.builder.store(src_fmt_ptr, Gen.variables[dst_fmt_var]) src_kind_var: str = f"__{call_func_name}_kind" dst_kind_var: str = f"__{VarName}_kind" if src_kind_var in Gen.variables: if dst_kind_var not in Gen.variables: dst_kind_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=dst_kind_var) Gen.variables[dst_kind_var] = dst_kind_alloca src_kind_val: ir.Value = Gen._load(Gen.variables[src_kind_var], name=f"Load_{call_func_name}_kind_for_{VarName}") Gen.builder.store(src_kind_val, Gen.variables[dst_kind_var]) Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name} else: Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name} elif isinstance(Target, ast.Attribute): TargetType: ir.Type | None = None AttrName: str = Target.attr VarName: str | None = None if isinstance(Target.value, ast.Name): VarName = Target.value.id if VarName: ClassName: str | None = Gen.var_struct_class.get(VarName) if not ClassName and Gen.global_struct_class: ClassName = Gen.global_struct_class.get(VarName) if ClassName: Gen.var_struct_class[VarName] = ClassName if not ClassName: for CN in Gen.structs: if VarName == CN.lower() or VarName.startswith(CN): ClassName = CN break if ClassName and ClassName in Gen.class_members: for m_name, m_type in Gen.class_members[ClassName]: if m_name == AttrName: TargetType = m_type break Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=TargetType) if Value: self._HandleAttributeStoreLlvm(Target, Value) elif isinstance(Target, ast.Subscript): TargetType: ir.Type | None = None SubVarName: str | None = None if isinstance(Target.value, ast.Name): SubVarName = Target.value.id if SubVarName in Gen.var_struct_class: ClassName: str = Gen.var_struct_class[SubVarName] if ClassName in Gen.class_members: for m_name, m_type in Gen.class_members[ClassName]: if m_name == SubVarName: if isinstance(m_type, ir.PointerType): pointee: ir.Type = m_type.pointee if isinstance(pointee, ir.ArrayType): TargetType = pointee.element elif isinstance(m_type, ir.ArrayType): TargetType = m_type.element break if not TargetType and isinstance(Target.value, ast.Name): SubVarName = Target.value.id var_val: ir.Value | None = Gen.variables.get(SubVarName) if var_val is None and SubVarName in Gen._direct_values: var_val = Gen._direct_values[SubVarName] if var_val is not None: var_type: ir.Type = var_val.type if isinstance(var_type, ir.PointerType): pointee: ir.Type = var_type.pointee if isinstance(pointee, ir.ArrayType): TargetType = pointee.element elif isinstance(var_type, ir.ArrayType): TargetType = var_type.element Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=TargetType) if Value: self._HandleSubscriptStoreLlvm(Target, Value) elif isinstance(Target, ast.Tuple): if isinstance(Node.value, ast.Call): FuncName: str | None = None ModulePath: str | None = None if isinstance(Node.value.func, ast.Name): FuncName = Node.value.func.id elif isinstance(Node.value.func, ast.Attribute): FuncName = Node.value.func.attr ModulePath = self.Trans.ExprCallHandle._get_ModulePath(Node.value.func.value) CReturnTypes: list[ast.expr] = [] FuncDef: ast.FunctionDef | None = self.Trans.FunctionDefCache.get(FuncName) if FuncName else None if FuncDef: if FuncDef.returns and isinstance(FuncDef.returns, ast.Subscript): if isinstance(FuncDef.returns.value, ast.Name) and FuncDef.returns.value.id == 'tuple': slice_node: ast.expr = FuncDef.returns.slice if isinstance(slice_node, ast.Tuple): CReturnTypes = slice_node.elts else: CReturnTypes = [slice_node] if FuncDef.decorator_list: for decorator in FuncDef.decorator_list: if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute): if decorator.func.attr == 'CReturn': for arg in decorator.args: CReturnTypes.append(arg) if not CReturnTypes and FuncName: func: ir.Function | None = Gen.functions.get(FuncName) if func: func_ft: ir.FunctionType | None = getattr(func, 'ftype', None) if func_ft: ret_type: ir.Type = func_ft.return_type if isinstance(ret_type, ir.LiteralStructType): CReturnTypes = [None] * len(ret_type.elements) if not CReturnTypes: sym_key: str = FuncName if not self.Trans.SymbolTable.has(sym_key): if ModulePath: sym_key = f"{ModulePath}.{FuncName}" sym_info: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(sym_key) if sym_info and sym_info.IsFunction: ret_type_info: CTypeInfo | None = sym_info.FuncPtrReturn param_type_infos: list[tuple[str, CTypeInfo]] = [pt for _, pt in (sym_info.FuncPtrParams or [])] if ret_type_info: if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType: ret_type: ir.Type = ret_type_info.ToLLVM(Gen) else: ret_type = Gen._type_str_to_llvm(str(ret_type_info) if ret_type_info else 'i32', False) if isinstance(ret_type, ir.LiteralStructType): CReturnTypes = [None] * len(ret_type.elements) if FuncName not in Gen.functions: if isinstance(ret_type, ir.VoidType): ret_type = ir.IntType(32) llvm_param_types: list[ir.Type] = [] for pt in param_type_infos: if isinstance(pt, CTypeInfo) and pt.BaseType: lp: ir.Type = pt.ToLLVM(Gen) else: lp = Gen._type_str_to_llvm(str(pt) if pt else 'i32', '*' in str(pt) if isinstance(pt, str) else False) if isinstance(lp, ir.VoidType): lp = ir.IntType(8).as_pointer() llvm_param_types.append(lp) func_type: ir.FunctionType = ir.FunctionType(ret_type, llvm_param_types) MangledName: str = Gen._mangle_func_name(FuncName) func_decl: ir.Function = ir.Function(Gen.module, func_type, name=MangledName) Gen.functions[MangledName] = func_decl Gen.functions[FuncName] = func_decl if not CReturnTypes and FuncName: func: ir.Function | None = Gen.functions.get(FuncName) if func: func_ft: ir.FunctionType | None = getattr(func, 'ftype', None) if func_ft: ret_type: ir.Type = func_ft.return_type if isinstance(ret_type, ir.LiteralStructType): CReturnTypes = [None] * len(ret_type.elements) if CReturnTypes and len(Target.elts) == len(CReturnTypes): CallArgs: list[ir.Value | None] = [] for arg in Node.value.args: ArgVal: ir.Value | None = self.HandleExprLlvm(arg) if ArgVal: CallArgs.append(ArgVal) for kw in Node.value.keywords: pass func: ir.Function | None = Gen.functions.get(FuncName) func_ft: ir.FunctionType | None = getattr(func, 'ftype', None) if func else None func_params: list[ir.Type] = list(getattr(func_ft, 'args', []) or []) if func_ft else [] while len(CallArgs) < len(func_params): FuncDef: ast.FunctionDef | None = self.Trans.FunctionDefCache.get(FuncName) if FuncDef and len(CallArgs) < len(FuncDef.args.args): arg_def: list[ast.expr] = FuncDef.args.defaults arg_idx: int = len(CallArgs) total_args: int = len(FuncDef.args.args) default_start: int = total_args - len(arg_def) if arg_idx >= default_start: def_idx: int = arg_idx - default_start if def_idx < len(arg_def): DefVal: ir.Value | None = self.HandleExprLlvm(arg_def[def_idx]) if DefVal: expected_type: ir.Type = func_params[arg_idx] if DefVal.type != expected_type: if isinstance(expected_type, ir.IntType) and isinstance(DefVal.type, ir.IntType): if DefVal.type.width < expected_type.width: DefVal = Gen.builder.zext(DefVal, expected_type, name=f"zext_default_{arg_idx}") elif DefVal.type.width > expected_type.width: DefVal = Gen.builder.trunc(DefVal, expected_type, name=f"trunc_default_{arg_idx}") CallArgs.append(DefVal) continue if len(CallArgs) < len(func_params): CallArgs.append(ir.Constant(func_params[len(CallArgs)], 0)) else: break adjusted: list[ir.Value] = Gen._adjust_args(CallArgs, func) call_result: ir.Value = Gen.builder.call(func, adjusted, name=f"call_{FuncName}") func_ft: ir.FunctionType | None = getattr(func, 'ftype', None) ret_type: ir.Type | None = getattr(func_ft, 'return_type', None) if func_ft else None for j, elt in enumerate(Target.elts): if isinstance(elt, ast.Name): VarName: str = elt.id field_val: ir.Value = Gen.builder.extract_value(call_result, j, name=f"extract_{FuncName}_{j}") VarType: ir.Type if CReturnTypes[j] is not None: ReturnTypeInfo: CTypeInfo | None = CTypeInfo.FromNode(CReturnTypes[j], self.Trans.SymbolTable) if ReturnTypeInfo is None: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CInt() VarType = Gen._ctype_to_llvm(ReturnTypeInfo) elif ret_type and isinstance(ret_type, ir.LiteralStructType) and j < len(ret_type.elements): VarType = ret_type.elements[j] else: VarType = field_val.type if isinstance(VarType, ir.VoidType): VarType = ir.IntType(32) var: ir.AllocaInstr = Gen._alloca(VarType, name=VarName) Gen.variables[VarName] = var if CReturnTypes[j] is not None: Gen._record_var_signedness(VarName, ReturnTypeStr) elif ret_type and isinstance(ret_type, ir.LiteralStructType) and j < len(ret_type.elements): elem_type: ir.Type = ret_type.elements[j] if isinstance(elem_type, ir.IntType): if elem_type.width == 16: Gen._record_var_signedness(VarName, 'unsigned short') elif elem_type.width == 32: Gen._record_var_signedness(VarName, 'unsigned int') elif elem_type.width == 64: Gen._record_var_signedness(VarName, 'unsigned long long') Gen._store(field_val, var) return def _InitStructAtPtr(self, call_node: ast.Call, ClassName: str, VarPtr: ir.Value) -> None: Gen: "Translator.LlvmGen" = self.Trans.LlvmGen if ClassName not in Gen.structs: return StructType: ir.Type = Gen.structs[ClassName] StructPtrType: ir.PointerType = ir.PointerType(StructType) RawPtr: ir.Value = Gen._load(VarPtr, name=getattr(VarPtr, 'name', 'ptr')) StructPtr: ir.Value = Gen.builder.bitcast(RawPtr, StructPtrType, name=ClassName) members: list[tuple[str, ir.Type]] = Gen.class_members.get(ClassName, []) defaults: dict[str, ir.Value] = Gen.class_member_defaults.get(ClassName, {}) member_values: dict[str, ir.Value] = {} for member_name, member_type in members: if member_name in defaults: member_values[member_name] = defaults[member_name] if call_node.args: for i, arg in enumerate(call_node.args): if i < len(members): member_name: str = members[i][0] val: ir.Value | None = self.HandleExprLlvm(arg) if val: member_values[member_name] = val if call_node.keywords: for kw in call_node.keywords: val: ir.Value | None = self.HandleExprLlvm(kw.value) if val: member_values[kw.arg] = val has_vtable: bool = ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes base: int = 1 if has_vtable else 0 for i, (member_name, member_type) in enumerate(members): if isinstance(member_type, ir.VoidType): continue if member_name in member_values: ElemPtr: ir.Value = Gen.builder.gep(StructPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), base + i)], name=f"{ClassName}_{member_name}") try: Gen._store(member_values[member_name], ElemPtr) except Exception as _e: if _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") InitFuncName: str = f'{ClassName}.__init__' if Gen._has_function(InitFuncName): Args: list[ir.Value | None] = [self.HandleExprLlvm(arg) for arg in call_node.args] Args = [a for a in Args if a] Gen.builder.call(Gen._get_function(InitFuncName), [StructPtr] + Args, name=f"call_{InitFuncName}") def _HandleAttributeStoreLlvm(self, Target: ast.Attribute, Value: ir.Value) -> None: Gen: "Translator.LlvmGen" = self.Trans.LlvmGen AttrName: str = Target.attr if isinstance(Target.value, ast.Name) and Target.value.id == 'self': ClassName: str | None = self.Trans._CurrentCpythonObjectClass if ClassName and ClassName in Gen.structs: PropKey: str = f'{ClassName}.{AttrName}' PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey) if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList: SelfVar: ir.Value | None = Gen._get_var_ptr('self') if SelfVar: SelfPtr: ir.Value = Gen._load(SelfVar, name="self") SetterFunc: ir.Function | None = Gen._get_function(PropKey + '$set') if SetterFunc and SelfPtr: Gen.builder.call(SetterFunc, [SelfPtr, Value], name=f"prop_set_{PropKey}") return SelfVar: ir.Value | None = Gen._get_var_ptr('self') if not SelfVar: return if SelfVar: SelfPtr: ir.Value = Gen._load(SelfVar, name="self") is_vtable_method: bool = False method_idx: int = 0 if ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes: if ClassName in Gen.class_methods: for mi, mn in enumerate(Gen.class_methods[ClassName]): method_short: str = mn.split('.')[-1] if '.' in mn else mn if method_short == AttrName or mn == AttrName: is_vtable_method = True method_idx = mi break if is_vtable_method: VtableSlotPtr: ir.Value = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}") VtablePtr: ir.Value = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}") methods: list[str] = Gen.class_methods[ClassName] VtableArrayType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) ClassVtable: ir.GlobalVariable | None = Gen.Vtables.get(ClassName) if ClassVtable: ClassVtableAddr: ir.Value = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"class_vtable_addr_{ClassName}") IsSameVtable: ir.Value = Gen.builder.icmp_unsigned('==', VtablePtr, ClassVtableAddr, name=f"is_same_vtable_{ClassName}") CopyBlock: ir.Block = Gen.func.append_basic_block(name=f"vtable_copy_self_{AttrName}") SkipBlock: ir.Block = Gen.func.append_basic_block(name=f"vtable_skip_self_{AttrName}") Gen.builder.cbranch(IsSameVtable, CopyBlock, SkipBlock) Gen.builder.position_at_end(CopyBlock) Gen._vtable_copy_counter += 1 CopyName: str = f"{Gen._mangle_name(ClassName)}_vtable_copy_self_{Gen._vtable_copy_counter}" VtableCopyGlobal: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VtableArrayType, name=CopyName) VtableCopyGlobal.linkage = 'internal' VtableCopyGlobal.initializer = ir.Constant(VtableArrayType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods)) VtableCopyTyped: ir.Value = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_typed") SrcTyped: ir.Value = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"src_vtable_typed") VtableSize: int = len(methods) * Gen.ptr_size MemcpyFunc: ir.Function | None = Gen._find_function('llvm.memcpy.p0i8.p0i8.i64') if not MemcpyFunc: MemcpyType: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)]) MemcpyFunc = ir.Function(Gen.module, MemcpyType, name='llvm.memcpy.p0i8.p0i8.i64') Gen.functions['llvm.memcpy.p0i8.p0i8.i64'] = MemcpyFunc Gen.builder.call(MemcpyFunc, [VtableCopyTyped, SrcTyped, ir.Constant(ir.IntType(64), VtableSize), ir.Constant(ir.IntType(1), 0)]) VtableCopyGlobalAddr: ir.Value = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_addr") Gen._store(VtableCopyGlobalAddr, VtableSlotPtr) Gen.builder.branch(SkipBlock) Gen.builder.position_at_end(SkipBlock) VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}_after_copy") VtableTyped: ir.Value = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}") MethodPtrAddr: ir.Value = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_slot_{AttrName}") FuncPtrI8: ir.Value = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"func_ptr_i8_{AttrName}") Gen._store(FuncPtrI8, MethodPtrAddr) return offset: int = Gen._get_member_offset(AttrName, ClassName) struct_type: ir.Type = Gen.structs[ClassName] max_offset: int = len(struct_type.elements) if isinstance(struct_type, ir.IdentifiedStructType) else 0 if offset >= max_offset: VarName: str = f"self.{AttrName}" if VarName not in Gen.variables: NewVar: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=AttrName) Gen.variables[VarName] = NewVar Gen._store(Value, Gen.variables[VarName]) return MemberPtr: ir.Value = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) self._StoreWithCoerce(Value, MemberPtr) elif isinstance(Target.value, ast.Name): VarName: str = Target.value.id # FakeDuck: 检查是否有影子结构体 a__meta__ (str 变量的 per-instance 字段存储) # 直接通过 a.__field__ = value 访问影子结构体字段 (语法糖) _fd_meta_name: str = f"{VarName}__meta__" if _fd_meta_name in Gen.variables and '_str' in Gen.structs: _fd_offset = Gen._get_member_offset(AttrName, '_str') if _fd_offset is not None: _fd_meta_ptr: ir.Value = Gen.variables[_fd_meta_name] _fd_field_ptr: ir.Value = Gen.builder.gep(_fd_meta_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _fd_offset)], name=f"{VarName}_{AttrName}_ptr") self._StoreWithCoerce(Value, _fd_field_ptr) return ClassName: str | None = Gen.var_struct_class.get(VarName) if not ClassName and Gen.global_struct_class: ClassName = Gen.global_struct_class.get(VarName) if ClassName: Gen.var_struct_class[VarName] = ClassName if not ClassName: for CN in Gen.structs: if VarName == CN.lower() or VarName.startswith(CN): ClassName = CN break if not ClassName and VarName in Gen.module.globals: GVar: ir.GlobalVariable = Gen.module.globals[VarName] if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(GVar.type.pointee) if found: ClassName = found[0] Gen.var_struct_class[VarName] = ClassName if Gen.global_struct_class: Gen.global_struct_class[VarName] = ClassName if not ClassName and VarName in Gen.variables: VarPtr: ir.Value = Gen.variables[VarName] if isinstance(VarPtr.type, ir.PointerType): pointee: ir.Type = VarPtr.type.pointee if isinstance(pointee, ir.PointerType): pointee = pointee.pointee found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(pointee) if found: CN: str = found[0] ST: ir.Type = found[1] ClassName = CN elif isinstance(pointee, ir.IdentifiedStructType): # sha1 冲突 fallback:find_struct_by_pointee 因 sha1 前缀不匹配失败时, # 用短名(去掉 sha1 前缀)匹配,优先选字段最多的完整版本 pointee_short: str = Gen._extract_short_name(pointee.name) best_elem_count: int = 0 for CN, ST in Gen.structs.items(): if isinstance(ST, ir.IdentifiedStructType): st_short: str = Gen._extract_short_name(ST.name) if st_short == pointee_short: elem_count: int = len(ST.elements) if ST.elements else 0 if elem_count > best_elem_count: ClassName = CN best_elem_count = elem_count IsUnion: bool = False if ClassName: TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(ClassName) if TypeInfo and TypeInfo.IsUnion: IsUnion = True if ClassName and ClassName in Gen.structs: PropKey: str = f'{ClassName}.{AttrName}' PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey) if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList: ObjVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value) SetterFunc: ir.Function | None = Gen._get_function(PropKey + '$set') if SetterFunc and ObjVal: if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): ObjVal = Gen._load(ObjVal, name=f"Load_{ClassName}") Gen.builder.call(SetterFunc, [ObjVal, Value], name=f"prop_set_{PropKey}") return ObjVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value) if ObjVal: if BaseHandle._is_char_pointer(ObjVal): ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): ObjVal = Gen._load(ObjVal, name=f"Load_{ClassName}") # 跨模块 opaque 类型:ObjVal.type.pointee 与 Gen.structs[ClassName] 可能是 # 不同的 IdentifiedStructType 对象(虽然 name 相同),== 返回 False。 # 使用 name 匹配作为 fallback,与链式赋值路径(第 926-927 行)一致。 # sha1 冲突时还需短名匹配(如 6bc91356c652f8ca.Function vs 8ad0c0a2934ca5b4.Function) _ObjPointee = ObjVal.type.pointee if isinstance(ObjVal.type, ir.PointerType) else None _TargetStruct = Gen.structs.get(ClassName) _MatchesStruct = (_ObjPointee is not None and _TargetStruct is not None and (_ObjPointee == _TargetStruct or (isinstance(_ObjPointee, ir.IdentifiedStructType) and isinstance(_TargetStruct, ir.IdentifiedStructType) and (_ObjPointee.name == _TargetStruct.name or Gen._extract_short_name(_ObjPointee.name) == Gen._extract_short_name(_TargetStruct.name))))) # opaque 泛型结构体 → 特化版本 bitcast # 当 ObjVal 的 pointee 是 opaque 基础泛型结构体(如 GSList,来自跨模块 stub), # 而 ClassName 是特化版本(如 GSList[BasicBlock])时,两者 short name 不同 # (GSList vs GSList[BasicBlock]),_MatchesStruct 失败。 # 验证特化 short name 以 基础名+'[' 开头,bitcast 到特化版本使后续 GEP 能正确访问字段。 if (not _MatchesStruct and isinstance(ObjVal.type, ir.PointerType) and isinstance(_ObjPointee, ir.IdentifiedStructType) and isinstance(_TargetStruct, ir.IdentifiedStructType) and '[' in ClassName): _BaseShort: str = Gen._extract_short_name(_ObjPointee.name) _SpecShort: str = Gen._extract_short_name(_TargetStruct.name) if _BaseShort and _SpecShort.startswith(_BaseShort + '['): ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(_TargetStruct), name=f"cast_spec_{ClassName}") _MatchesStruct = True if isinstance(ObjVal.type, ir.PointerType) and _MatchesStruct: if IsUnion: NestedStructName: str = f"{ClassName}_{AttrName}" if NestedStructName in Gen.structs: NestedStructType: ir.Type = Gen.structs[NestedStructName] ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}") offset: int | None = Gen._get_member_offset(AttrName, NestedStructName) if offset is not None and offset < len(NestedStructType.elements): MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) self._StoreWithCoerce(Value, MemberPtr) return bitfield_offsets: dict[str, int] = Gen.class_member_bitoffsets.get(ClassName, {}) if AttrName in bitfield_offsets: self._store_bitfield_member(ObjVal, ClassName, AttrName, Value) return bitfields: dict[str, int] = Gen.class_member_bitfields.get(ClassName, {}) if AttrName in bitfields and bitfields[AttrName] > 0: if ClassName not in Gen.class_member_bitoffsets: Gen.class_member_bitoffsets[ClassName] = {} if AttrName not in Gen.class_member_bitoffsets[ClassName]: bo: int = 0 for bf_name, bf_width in bitfields.items(): if bf_name == AttrName: break bo += bf_width Gen.class_member_bitoffsets[ClassName][AttrName] = bo self._store_bitfield_member(ObjVal, ClassName, AttrName, Value) return is_vtable_method: bool = False method_idx: int = 0 if ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes: if ClassName in Gen.class_methods: for mi, mn in enumerate(Gen.class_methods[ClassName]): method_short: str = mn.split('.')[-1] if '.' in mn else mn if method_short == AttrName or mn == AttrName: is_vtable_method = True method_idx = mi break if is_vtable_method: VtableSlotPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}") VtablePtr: ir.Value = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}") methods: list[str] = Gen.class_methods[ClassName] VtableArrayType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) ClassVtable: ir.GlobalVariable | None = Gen.Vtables.get(ClassName) if ClassVtable: ClassVtableAddr: ir.Value = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"class_vtable_addr_{ClassName}") IsSameVtable: ir.Value = Gen.builder.icmp_unsigned('==', VtablePtr, ClassVtableAddr, name=f"is_same_vtable_{ClassName}") CopyBlock: ir.Block = Gen.func.append_basic_block(name=f"vtable_copy_{AttrName}") SkipBlock: ir.Block = Gen.func.append_basic_block(name=f"vtable_skip_{AttrName}") Gen.builder.cbranch(IsSameVtable, CopyBlock, SkipBlock) Gen.builder.position_at_end(CopyBlock) Gen._vtable_copy_counter += 1 CopyName: str = f"{Gen._mangle_name(ClassName)}_vtable_copy_{Gen._vtable_copy_counter}" VtableCopyGlobal: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VtableArrayType, name=CopyName) VtableCopyGlobal.linkage = 'internal' VtableCopyGlobal.initializer = ir.Constant(VtableArrayType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods)) VtableCopyTyped: ir.Value = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_typed") SrcTyped: ir.Value = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"src_vtable_typed") VtableSize: int = len(methods) * Gen.ptr_size MemcpyFunc: ir.Function | None = Gen._find_function('llvm.memcpy.p0i8.p0i8.i64') if not MemcpyFunc: MemcpyType: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)]) MemcpyFunc = ir.Function(Gen.module, MemcpyType, name='llvm.memcpy.p0i8.p0i8.i64') Gen.functions['llvm.memcpy.p0i8.p0i8.i64'] = MemcpyFunc Gen.builder.call(MemcpyFunc, [VtableCopyTyped, SrcTyped, ir.Constant(ir.IntType(64), VtableSize), ir.Constant(ir.IntType(1), 0)]) VtableCopyGlobalAddr: ir.Value = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_addr") Gen._store(VtableCopyGlobalAddr, VtableSlotPtr) Gen.builder.branch(SkipBlock) Gen.builder.position_at_end(SkipBlock) VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}_after_copy") VtableTyped: ir.Value = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}") MethodPtrAddr: ir.Value = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_slot_{AttrName}") FuncPtrI8: ir.Value = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"func_ptr_i8_{AttrName}") Gen._store(FuncPtrI8, MethodPtrAddr) return offset: int | None = Gen._get_member_offset(AttrName, ClassName) StructType: ir.Type | None = Gen.structs.get(ClassName) if isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0): self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) StructType = Gen.structs.get(ClassName) if isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0): return # 重新计算 offset:_TryLoadStructFromStub 刚加载了 struct body, # 之前 offset 可能因 struct opaque / class_members 不完整而返回 None offset = Gen._get_member_offset(AttrName, ClassName) # sha1 冲突修复:Gen.structs[ClassName] 可能是字段不全的版本(如 2 字段 Function # 来自 MetaType.py scope,而正确版本是 8 字段 Function 来自 __function.py)。 # _get_member_offset 通过 class_sha1_map 已返回正确的 offset(如 5), # 但 StructType 可能只有 2 个 elements,导致 offset < len(elements) 失败。 # 在所有 structs 中查找同短名且字段最多的版本。 if offset is not None and isinstance(StructType, ir.IdentifiedStructType) and StructType.elements is not None and offset >= len(StructType.elements): _short: str = Gen._extract_short_name(StructType.name) _best: int = len(StructType.elements) for _cn, _st in Gen.structs.items(): if isinstance(_st, ir.IdentifiedStructType) and _st.elements is not None: if Gen._extract_short_name(_st.name) == _short and len(_st.elements) > _best: StructType = _st _best = len(_st.elements) # bitcast:当 ObjVal 的 pointee 是 opaque 或与 StructType 不是同一个类型对象 # (sha1 前缀不同但短名相同)时,需要 bitcast 到 StructType 才能正确 GEP if StructType is not None and StructType.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and (ObjVal.type.pointee.elements is None or ObjVal.type.pointee != StructType): ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(StructType), name=f"cast_{ClassName}") if offset is not None and StructType is not None and StructType.elements is not None and offset < len(StructType.elements): MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) else: return byte_order: str = Gen.class_member_byteorders.get(ClassName, {}).get(AttrName, "") if byte_order == 'big': if StructType is None or StructType.elements is None or len(StructType.elements) == 0: return member_type: ir.Type = StructType.elements[offset] if isinstance(member_type, ir.IntType): Value = Gen._apply_bswap_if_big(Value, byte_order, f"bswap_store_{AttrName}") self._StoreWithCoerce(Value, MemberPtr) if not ClassName: imported_modules: list[str] | None = getattr(self.Trans, '_ImportedModules', None) resolved_mod: str = self.Trans.SymbolTable.resolve_alias(VarName) if imported_modules and (VarName in imported_modules or resolved_mod in imported_modules): PossibleKeys: list[str] = [f"{VarName}.{AttrName}", AttrName] for mod_name in imported_modules: if mod_name.endswith(f".{VarName}") or mod_name == VarName: key: str = f"{mod_name}.{AttrName}" if key not in PossibleKeys: PossibleKeys.append(key) for key in PossibleKeys: if key in Gen.module.globals: GVar: ir.GlobalVariable = Gen.module.globals[key] if isinstance(GVar, ir.Function): return if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): return self._StoreWithCoerce(Value, GVar) return ModuleSha1Map: dict[str, str] = Gen.ModuleSha1Map sha1_candidates: list[str] = [VarName, resolved_mod] for mod_name in imported_modules: if mod_name.endswith(f".{VarName}") or mod_name == VarName: if mod_name not in sha1_candidates: sha1_candidates.append(mod_name) for cand in sha1_candidates: sha1: str | None = ModuleSha1Map.get(cand) if sha1: prefixed: str = f"{sha1}.{AttrName}" if prefixed in Gen.module.globals: GVar2: ir.GlobalVariable = Gen.module.globals[prefixed] if isinstance(GVar2, ir.Function): return if isinstance(GVar2.type, ir.PointerType) and isinstance(GVar2.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): return self._StoreWithCoerce(Value, GVar2) return elif isinstance(Target.value, ast.Attribute): ObjVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value) if ObjVal and isinstance(ObjVal.type, ir.PointerType): pointee: ir.Type = ObjVal.type.pointee if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is None: for CN, ST in Gen.structs.items(): if isinstance(ST, ir.IdentifiedStructType) and ST.name == pointee.name and ST.elements is not None: pointee = ST ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}") break found_match: bool = False for CN, ST in Gen.structs.items(): if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name): found_match = True if ST.elements is None: self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen) ST = Gen.structs.get(CN, ST) if ST.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None: ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}") bitfield_offsets: dict[str, int] = Gen.class_member_bitoffsets.get(CN, {}) if AttrName in bitfield_offsets: self._store_bitfield_member(ObjVal, CN, AttrName, Value) return offset: int = Gen._get_member_offset(AttrName, CN) if offset is not None and ST.elements is not None and offset < len(ST.elements): MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) self._StoreWithCoerce(Value, MemberPtr) break if not found_match: if isinstance(pointee, ir.IdentifiedStructType): matched_cn: str | None = None for CN in Gen.class_members: members: list[tuple[str, ir.Type]] = Gen.class_members[CN] for mname, mtype in members: if mname == AttrName: matched_cn = CN break if matched_cn: break if matched_cn and matched_cn in Gen.structs: ST: ir.Type = Gen.structs[matched_cn] if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): self.Trans.ImportHandler._TryLoadStructFromStub(matched_cn, Gen) ST = Gen.structs.get(matched_cn, ST) if ST.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None: ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{matched_cn}") offset: int = Gen._get_member_offset(AttrName, matched_cn) if offset is not None and ST.elements is not None and offset < len(ST.elements): MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) self._StoreWithCoerce(Value, MemberPtr) return elif isinstance(Target.value, ast.Call): # Check if this is c.Deref(...) — we need the pointer, not the Loaded value ObjVal: ir.Value | None = None is_cderef: bool = (isinstance(Target.value.func, ast.Attribute) and isinstance(Target.value.func.value, ast.Name) and Target.value.func.value.id == 'c' and Target.value.func.attr == 'Deref' and Target.value.args) if is_cderef: # Get the pointer from c.Deref argument, don't Load the value deref_arg: ast.expr = Target.value.args[0] inner_val: ir.Value | None = self.HandleExprLlvm(deref_arg) if inner_val and isinstance(inner_val.type, ir.PointerType): if isinstance(inner_val.type.pointee, ir.PointerType): ObjVal = Gen._load(inner_val, name="deref_load_ptr") else: ObjVal = inner_val if ObjVal is None: ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value) if ObjVal and isinstance(ObjVal.type, ir.PointerType): pointee: ir.Type = ObjVal.type.pointee if isinstance(pointee, ir.PointerType): ObjVal = Gen._load(ObjVal, name="load_ptr_for_attr") pointee = ObjVal.type.pointee for CN, ST in Gen.structs.items(): if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name): if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen) ST = Gen.structs.get(CN, ST) if ST.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None: ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}") bitfield_offsets: dict[str, int] = Gen.class_member_bitoffsets.get(CN, {}) if AttrName in bitfield_offsets: self._store_bitfield_member(ObjVal, CN, AttrName, Value) return offset: int = Gen._get_member_offset(AttrName, CN) if offset is not None and ST.elements is not None and offset < len(ST.elements): MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) self._StoreWithCoerce(Value, MemberPtr) break elif isinstance(Target.value, ast.Subscript): SubPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Target.value) if SubPtr and isinstance(SubPtr.type, ir.PointerType): pointee: ir.Type = SubPtr.type.pointee if isinstance(Target.value.value, ast.Attribute): AttrNameSub: str = Target.value.value.attr if AttrNameSub == 'items' and 'Item' in Gen.structs: ObjValCast: ir.Value = Gen.builder.bitcast(SubPtr, ir.PointerType(Gen.structs['Item']), name=f"cast_Item") offset: int = Gen._get_member_offset(AttrName, 'Item') MemberPtr: ir.Value = Gen.builder.gep(ObjValCast, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) self._StoreWithCoerce(Value, MemberPtr) return if BaseHandle._is_char_pointer(SubPtr): for CN, ST in Gen.structs.items(): ObjValCast: ir.Value = Gen.builder.bitcast(SubPtr, ir.PointerType(ST), name=f"cast_{CN}") offset: int = Gen._get_member_offset(AttrName, CN) MemberPtr: ir.Value = Gen.builder.gep(ObjValCast, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) self._StoreWithCoerce(Value, MemberPtr) break elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(pointee) if found: CN: str = found[0] ST: ir.Type = found[1] if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen) ST = Gen.structs.get(CN, ST) if ST.elements is not None and isinstance(SubPtr.type, ir.PointerType) and isinstance(SubPtr.type.pointee, ir.IdentifiedStructType) and SubPtr.type.pointee.elements is None: SubPtr = Gen.builder.bitcast(SubPtr, ir.PointerType(ST), name=f"cast_{CN}") offset: int = Gen._get_member_offset(AttrName, CN) if offset is not None and ST.elements is not None and offset < len(ST.elements): MemberPtr: ir.Value = Gen.builder.gep(SubPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) self._StoreWithCoerce(Value, MemberPtr) elif isinstance(pointee, ir.PointerType): LoadedPtr: ir.Value = Gen._load(SubPtr, name=f"Load_{AttrName}_ptr") if isinstance(LoadedPtr.type, ir.PointerType) and isinstance(LoadedPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(LoadedPtr.type.pointee) if found: CN: str = found[0] ST: ir.Type = found[1] offset: int = Gen._get_member_offset(AttrName, CN) MemberPtr: ir.Value = Gen.builder.gep(LoadedPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) self._StoreWithCoerce(Value, MemberPtr) def _StoreArrElemWithCoerceBswap(self, Value: ir.Value, Ptr: ir.Value, arr_byte_order: str) -> None: """对数组元素存储应用 bswap 后再 coerce 存储""" Gen: "Translator.LlvmGen" = self.Trans.LlvmGen Value = Gen._apply_bswap_if_big(Value, arr_byte_order, "bswap_arr_store") self._StoreWithCoerce(Value, Ptr) def _HandleSubscriptStoreLlvm(self, Target: ast.Subscript, Value: ir.Value) -> None: Gen: "Translator.LlvmGen" = self.Trans.LlvmGen # 查询数组元素字节序 arr_byte_order: str = '' if isinstance(Target.value, ast.Name) and Target.value.id in Gen.local_var_byteorders: arr_byte_order = Gen.local_var_byteorders[Target.value.id] if isinstance(Target.value, ast.Name): SubVarName: str = Target.value.id if SubVarName in Gen.var_const_flags: src_info: str = Gen._get_node_info() self.Trans.LogError(f"不能对 const 变量 '{SubVarName}' 的元素赋值{src_info}") ClassName: str | None = self.Trans.ExprHandler._get_var_class(Target.value, Gen) if ClassName and Gen._has_function(f'{ClassName}.__setitem__'): obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value) idx_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.slice) if obj_val and idx_val: # 处理 obj_val 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8 if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8: obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}") if BaseHandle._is_char_pointer(obj_val): obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") setitem_args: list[ir.Value] = [obj_val, idx_val, Value] setitem_func_name: str = f'{ClassName}.__setitem__' setitem_args = Gen._apply_auto_addr(setitem_func_name, setitem_args) setitem_func: ir.Function = Gen._get_function(setitem_func_name) setitem_args = Gen._adjust_args(setitem_args, setitem_func) Gen.builder.call(setitem_func, setitem_args, name=f"call_{setitem_func_name}") return ValueVal: ir.Value | None = self.HandleExprLlvm(Target.value) IndexVal: ir.Value | None = self.HandleExprLlvm(Target.slice) if not ValueVal or not IndexVal: return # 当变量本身是二级指针(如 elem_ptr: T | t.CPtr = AST**), # 且存储的值也是指针时,elem_ptr[i] = item 应直接存储指针(8 字节), # 而非解引用后复制结构体(如 48 字节的 AST),避免对象切片 if isinstance(Target.value, ast.Name): VarName: str = Target.value.id if VarName in Gen.variables and Gen.variables[VarName] is not None: VarAlloca: ir.Value = Gen.variables[VarName] if isinstance(VarAlloca.type, ir.PointerType) and isinstance(VarAlloca.type.pointee, ir.PointerType): if (isinstance(ValueVal.type, ir.PointerType) and isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType))): if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index_store") # ValueVal 是 AST*(加载自 elem_ptr 的基指针), # 但 GEP 默认将其视为 AST 结构体数组。需要先 bitcast 为 # AST**(指向 AST* 的指针),让 GEP 正确索引 AST* 指针数组, # 而非 AST 结构体数组。然后用 builder.store 直接存储指针, # 避免 _store 的类型强制转换将指针解引用为结构体。 PtrToStruct: ir.Type = Value.type.pointee BaseAsPP: ir.Value = Gen.builder.bitcast(ValueVal, ir.PointerType(ir.PointerType(PtrToStruct)), name="cast_base_pp") ElemPtr: ir.Value = Gen.builder.gep(BaseAsPP, [IndexVal], name="subscript") Gen.builder.store(Value, ElemPtr) return if BaseHandle._is_char_pointer(IndexVal): Loaded_byte: ir.Value = Gen._load(IndexVal, name="Load_char_idx_store") IndexVal = Gen.builder.zext(Loaded_byte, ir.IntType(32), name="char_to_int_idx_store") if isinstance(ValueVal.type, ir.IntType): var_ptr: ir.Value | None = self._get_int_ptr(Target.value) if var_ptr: i8_ptr: ir.Value = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr_store") if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index_store") ptr: ir.Value = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr_store") self._StoreWithCoerce(Value, ptr) return if isinstance(ValueVal.type, ir.PointerType) and isinstance(ValueVal.type.pointee, ir.PointerType): if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index_store") ElemPtr: ir.Value = Gen.builder.gep(ValueVal, [IndexVal], name="subscript") self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) return if isinstance(ValueVal.type, ir.PointerType): pointee: ir.Type = ValueVal.type.pointee if isinstance(pointee, ir.ArrayType): zero: ir.Constant = ir.Constant(ir.IntType(32), 0) if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: if IndexVal.type.width < 32: IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") else: IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") ElemPtr: ir.Value = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript") elif (isinstance(pointee, ir.IntType) and pointee.width == 8 and isinstance(Target.value, ast.Name) and (Gen.var_ptr_element.get(Target.value.id, False) or Gen.global_var_ptr_element.get(Target.value.id, False))): # 指针到 str/bytes 的变量 (BinOp 注解如 str | t.CPtr) # elem_ptr 是 i8* 但实际指向 i8* (字符串指针), elem_ptr[0] = item 应存储 8 字节 CastedPtrPtr: ir.Value = Gen.builder.bitcast(ValueVal, ir.PointerType(ir.PointerType(ir.IntType(8))), name="cast_pp_str_store") if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_pp_str_index_store") ElemPtr = Gen.builder.gep(CastedPtrPtr, [IndexVal], name="subscript") self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) return else: ElemPtr: ir.Value = Gen.builder.gep(ValueVal, [IndexVal], name="subscript") self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) elif isinstance(ValueVal.type, ir.ArrayType): zero: ir.Constant = ir.Constant(ir.IntType(32), 0) if isinstance(Target.value, ast.Name): VarName: str = Target.value.id if VarName in Gen.variables and Gen.variables[VarName] is not None: VarPtr: ir.Value = Gen.variables[VarName] if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType): if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: if IndexVal.type.width < 32: IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") else: IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") ElemPtr: ir.Value = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript") self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) return if isinstance(Target.value, ast.Subscript): InnerPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Target.value) if InnerPtr: if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: if IndexVal.type.width < 32: IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") else: IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") ElemPtr: ir.Value = Gen.builder.gep(InnerPtr, [zero, IndexVal], name="subscript") self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) return if isinstance(Target.value, ast.Attribute): AttrPtr: ir.Value | None = self.Trans.ExprAttrHandle._get_attr_ptr(Target.value) if AttrPtr and isinstance(AttrPtr.type, ir.PointerType) and isinstance(AttrPtr.type.pointee, ir.ArrayType): if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: if IndexVal.type.width < 32: IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") else: IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") ElemPtr: ir.Value = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript") self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) return arr_alloc: ir.AllocaInstr = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp") Gen._store(ValueVal, arr_alloc) ElemPtr: ir.Value = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript") self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) ModifiedArr: ir.Value = Gen._load(arr_alloc, name="modified_arr") if isinstance(Target.value, ast.Subscript): OuterPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Target.value) if OuterPtr: Gen._store(ModifiedArr, OuterPtr) elif isinstance(Target.value, ast.Attribute): OuterPtr: ir.Value | None = self.Trans.ExprAttrHandle._get_attr_ptr(Target.value) if OuterPtr: Gen._store(ModifiedArr, OuterPtr) def _StoreWithCoerce(self, Value: ir.Value, Ptr: ir.Value) -> None: Gen: "Translator.LlvmGen" = self.Trans.LlvmGen if isinstance(Ptr.type, ir.PointerType): TargetType: ir.Type = Ptr.type.pointee if Value.type != TargetType: if isinstance(TargetType, ir.ArrayType) and isinstance(Value.type, ir.PointerType): ElemType: ir.Type = TargetType.element ElemSize: int = Gen._get_struct_size(ElemType) for i in range(TargetType.count): DstElem: ir.Value = Gen.builder.gep(Ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i)], name=f"arr_dst_{i}") SrcPtr: ir.Value if ElemSize == 1: SrcPtr = Gen.builder.gep(Value, [ir.Constant(ir.IntType(32), i)], name=f"arr_src_{i}") else: PtrInt: ir.Value = Gen.builder.ptrtoint(Value, ir.IntType(64)) Offset: ir.Constant = ir.Constant(ir.IntType(64), i * ElemSize) NewPtrInt: ir.Value = Gen.builder.add(PtrInt, Offset) SrcPtr = Gen.builder.inttoptr(NewPtrInt, ir.PointerType(ElemType), name=f"arr_src_{i}") SrcVal: ir.Value = Gen._load(SrcPtr, name=f"arr_elem_{i}") if SrcVal.type != ElemType: try: SrcVal = Gen.builder.bitcast(SrcVal, ElemType, name=f"arr_cast_{i}") except Exception: # 回退:bitcast 失败时跳过该元素 continue Gen._store(SrcVal, DstElem) return if isinstance(TargetType, ir.PointerType) and isinstance(Value, ir.Constant) and Value.constant is None: Value = ir.Constant(TargetType, None) elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.PointerType): try: Value = Gen.builder.bitcast(Value, TargetType, name="null_ptr_bitcast") except Exception: # 回退:bitcast 失败时设为 null 常量 Value = ir.Constant(TargetType, None) else: Coerced: ir.Value | None = Gen._coerce_value(Value, TargetType) if Coerced is not None: Value = Coerced Gen._store(Value, Ptr) def _get_int_ptr(self, target: ast.expr) -> ir.Value | None: Gen: "Translator.LlvmGen" = self.Trans.LlvmGen if isinstance(target, ast.Name): VarName: str = target.id if VarName in Gen.variables and Gen.variables[VarName] is not None: VarPtr: ir.Value = Gen.variables[VarName] if isinstance(VarPtr.type, ir.PointerType): pointee: ir.Type = VarPtr.type.pointee if isinstance(pointee, ir.ArrayType): return Gen.builder.gep(VarPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"arr_start_{VarName}") return None def _EmitGlobalAnnAssignLlvm(self, Node: ast.AnnAssign, Gen: "Translator.LlvmGen") -> None: if isinstance(Node.target, ast.Name): VarName: str = Node.target.id Info: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(VarName) if Info: if Info.IsTypedef: return parse_result = ParseListAnnotation(Node.annotation) if parse_result: elem_type_node: ast.expr = parse_result.elem_type_node ElemType, ElemTypeInfo = self.ResolveListElementType( elem_type_node, Gen, check_func_ptr=True, void_fallback_width=32, fallback_to_cint=True, ) if parse_result.is_pointer: # 单参数 list[type] → 指针 VarType: ir.Type = ir.PointerType(ElemType) if VarName not in Gen.variables and VarName not in Gen.module.globals: GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName) GlobalVar.initializer = ir.Constant(VarType, None) Gen.variables[VarName] = GlobalVar if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs: Gen.global_struct_class[VarName] = elem_type_node.id return count_node: ast.expr | None = parse_result.count_node ArrayCount: int = self.ParseArrayCount(count_node, Gen, Node.value, mode='global') VarType = ir.ArrayType(ElemType, ArrayCount) if VarName not in Gen.variables and VarName not in Gen.module.globals: GlobalVar = ir.GlobalVariable(Gen.module, VarType, name=VarName) if isinstance(ElemType, ir.IdentifiedStructType): GlobalVar.linkage = 'common' elif Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str): str_val: str = Node.value.value + '\x00' str_bytes: bytearray = bytearray(str_val, 'utf-8') if len(str_bytes) < ArrayCount: str_bytes.extend(b'\x00' * (ArrayCount - len(str_bytes))) try: GlobalVar.initializer = ir.Constant(VarType, str_bytes[:ArrayCount]) except Exception: # 回退:初始化常量失败时用零值 GlobalVar.initializer = Gen._zero_value_for_type(VarType) else: InitConstants: list[ir.Constant] | None = self.Trans._BuildArrayInitConstants(Node.value, ElemType, elem_type_node, ArrayCount, Gen, byte_order=ElemTypeInfo.ByteOrder if ElemTypeInfo else '') if InitConstants: GlobalVar.initializer = ir.Constant(VarType, InitConstants) elif ArrayCount > 256: GlobalVar.linkage = 'common' else: if self._contains_identified_struct(VarType): GlobalVar.linkage = 'common' else: GlobalVar.initializer = ir.Constant(VarType, [ir.Constant(ElemType, ir.Undefined)] * ArrayCount) Gen.variables[VarName] = GlobalVar if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs: Gen.global_struct_class[VarName] = elem_type_node.id return if isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs: StructName: str = Node.annotation.id VarType: ir.Type = Gen.structs[StructName] if VarName not in Gen.variables and VarName not in Gen.module.globals: GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName) if Node.value and isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name) and Node.value.func.id == StructName: const: ir.Constant | None = self.Trans.ClassHandler._BuildStructConstant(Node.value, StructName, Gen) if const: GlobalVar.initializer = const else: GlobalVar.initializer = ir.Constant(VarType, None) else: GlobalVar.initializer = ir.Constant(VarType, None) Gen.variables[VarName] = GlobalVar Gen.global_struct_class[VarName] = StructName return TypeInfo: CTypeInfo | None = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable) IsCDefine: bool = False if TypeInfo and TypeInfo.BaseType: if isinstance(TypeInfo.BaseType, t._CTypedef): return if isinstance(TypeInfo.BaseType, t.CDefine): IsCDefine = True if not IsCDefine and self._IsTypedefAnnotation(Node.annotation): IsCDefine = True TTypeInfo: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation) if TTypeInfo: TTypeInfo.IsTypedef = True TTypeInfo.Name = VarName self.Trans.SymbolTable.insert(VarName, TTypeInfo) if IsCDefine: if Node.value: define_constants: dict[str, int | float] = vars(Gen).setdefault('_define_constants', {}) try: const_value: int | float | None = self._eval_const_expr(Node.value, Gen) if const_value is not None: define_constants[VarName] = const_value except Exception as _e: if _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") return if TypeInfo is None: TypeInfo = CTypeInfo() TypeInfo.BaseType = t.CInt() VarType: ir.Type = Gen._ctype_to_llvm(TypeInfo) if isinstance(VarType, ir.VoidType): VarType = ir.IntType(32) if VarName in Gen.variables or VarName in Gen.module.globals: # 时序修复:第一遍创建全局时类未处理(SymbolTable 无枚举成员), # initializer 回退为 0。第二遍类已处理,尝试用解析出的枚举值更新 initializer。 if VarName in Gen.module.globals and Node.value: existing: Any = Gen.module.globals[VarName] if isinstance(existing, ir.GlobalVariable) and isinstance(VarType, ir.IntType): new_init: ir.Constant | None = self._eval_global_const(Node.value, VarType, Gen) if new_init is not None: existing.initializer = new_init return if isinstance(VarType, (ir.IdentifiedStructType, ir.LiteralStructType)): GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName) GlobalVar.initializer = ir.Constant(VarType, None) Gen.variables[VarName] = GlobalVar if TypeInfo and TypeInfo.IsStruct and TypeInfo.Name: Gen.global_struct_class[VarName] = TypeInfo.Name return GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName) # 全局变量指针元素标志:bytes|t.CPtr 或 str|t.CPtr 注解的变量, # 使 var[index] 使用 8 字节指针步长(而非 1 字节字符步长) if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr): if AnnotationContainsName(Node.annotation, 'str') or AnnotationContainsName(Node.annotation, 'bytes'): Gen.global_var_ptr_element[VarName] = True if Node.value: if isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str) and isinstance(VarType, ir.PointerType): str_val: str = Node.value.value + '\x00' str_bytes: bytes = str_val.encode('utf-8') arr_type: ir.ArrayType = ir.ArrayType(ir.IntType(8), len(str_bytes)) str_gv_name: str = VarName + '_str' str_gv: ir.GlobalVariable if str_gv_name not in Gen.module.globals: str_gv = ir.GlobalVariable(Gen.module, arr_type, name=str_gv_name) str_gv.initializer = ir.Constant(arr_type, bytearray(str_bytes)) str_gv.linkage = 'internal' else: str_gv = Gen.module.globals[str_gv_name] ptr_type: ir.PointerType = ir.PointerType(ir.IntType(8)) ptr_gv: ir.GlobalVariable if VarName not in Gen.module.globals: ptr_gv = ir.GlobalVariable(Gen.module, ptr_type, name=VarName) ptr_gv.initializer = ir.Constant(ptr_type, str_gv) ptr_gv.linkage = 'internal' else: ptr_gv = Gen.module.globals[VarName] Gen.variables[VarName] = ptr_gv elif isinstance(VarType, ir.PointerType) and isinstance(VarType.pointee, ir.FunctionType) and isinstance(Node.value, ast.Name): # 函数指针赋值:f3: t.Callable[[int], int] = f RefName: str = Node.value.id SymInfo: Any = self.Trans.SymbolTable.lookup(RefName) if SymInfo and (SymInfo.IsFunction or SymInfo.IsFuncPtr): MangledName: str = Gen._mangle_func_name(RefName) if MangledName in Gen.module.globals: func: Any = Gen.module.globals[MangledName] if isinstance(func, ir.Function): GlobalVar.initializer = func else: if isinstance(VarType, ir.ArrayType) and isinstance(Node.value, (ast.List, ast.Set)): InitConstants: list[ir.Constant] | None = self.Trans._BuildMultiDimArrayInitConstants(Node.value, VarType, Gen) if InitConstants: GlobalVar.initializer = ir.Constant(VarType, InitConstants) else: if self._contains_identified_struct(VarType): GlobalVar.linkage = 'common' else: zv: ir.Constant | None = Gen._zero_value_for_type(VarType) if zv: GlobalVar.initializer = zv else: GlobalVar.linkage = 'common' else: init_val: ir.Constant | None = self._eval_global_const(Node.value, VarType, Gen) if init_val: GlobalVar.initializer = init_val elif isinstance(VarType, ir.BaseStructType): GlobalVar.linkage = 'common' else: GlobalVar.initializer = Gen._zero_value_for_type(VarType) else: if isinstance(VarType, ir.BaseStructType) or self._contains_identified_struct(VarType): GlobalVar.linkage = 'common' else: GlobalVar.initializer = Gen._zero_value_for_type(VarType) Gen.variables[VarName] = GlobalVar def _eval_global_const(self, value_node: ast.expr, var_type: ir.Type, Gen: "Translator.LlvmGen") -> ir.Constant | None: if isinstance(value_node, ast.Constant): if isinstance(value_node.value, bool): if isinstance(var_type, ir.IntType): return ir.Constant(var_type, int(value_node.value)) elif isinstance(value_node.value, int): if isinstance(var_type, ir.IntType): return ir.Constant(var_type, value_node.value) elif isinstance(var_type, (ir.FloatType, ir.DoubleType)): return ir.Constant(var_type, float(value_node.value)) elif isinstance(value_node.value, float): if isinstance(var_type, (ir.FloatType, ir.DoubleType)): return ir.Constant(var_type, value_node.value) elif isinstance(var_type, ir.IntType): return ir.Constant(var_type, int(value_node.value)) elif isinstance(value_node.value, str): return None # Handle type constructor calls like t.CDouble(1e-9), t.CFloat(3.14), t.CInt(42) if isinstance(value_node, ast.Call): inner_val: ir.Constant | None = self._eval_type_ctor_const(value_node, var_type, Gen) if inner_val is not None: return inner_val if isinstance(value_node, ast.UnaryOp) and isinstance(value_node.op, ast.USub): inner: ir.Constant | None = self._eval_global_const(value_node.operand, var_type, Gen) if inner: return ir.Constant(var_type, -inner.constant) # Handle enum member references like ASTVType.Module (ast.Attribute) if isinstance(value_node, ast.Attribute): attr_name: str = value_node.attr # 优先用带前缀的 key 查找(避免短名被同名函数/变量覆盖) if isinstance(value_node.value, ast.Name): FullKey2: str = f"{value_node.value.id}.{attr_name}" FullInfo: Any = self.Trans.SymbolTable.lookup(FullKey2) if FullInfo and FullInfo.IsEnumMember and isinstance(FullInfo.value, int): if isinstance(var_type, ir.IntType): return ir.Constant(var_type, FullInfo.value) SymInfo: Any = self.Trans.SymbolTable.lookup(attr_name) if SymInfo: if SymInfo.IsEnumMember and isinstance(SymInfo.value, int): if isinstance(var_type, ir.IntType): return ir.Constant(var_type, SymInfo.value) return None def _eval_type_ctor_const(self, call_node: ast.Call, var_type: ir.Type, Gen: "Translator.LlvmGen") -> ir.Constant | None: """Try to evaluate t.CDouble(val), t.CFloat(val), t.CInt(val) etc. as a compile-time constant.""" if not isinstance(call_node.func, ast.Attribute): return None if not isinstance(call_node.func.value, ast.Name): return None if call_node.func.value.id != 't': return None if not call_node.args or len(call_node.args) != 1: return None arg: ast.expr = call_node.args[0] # Recursively evaluate the argument as a constant arg_val: ir.Constant | None = self._eval_global_const(arg, var_type, Gen) if arg_val is not None: return arg_val return None def _store_bitfield_member(self, struct_ptr: ir.Value, ClassName: str, field_name: str, Value: ir.Value) -> bool: Gen: "Translator.LlvmGen" = self.Trans.LlvmGen bitfield_offsets: dict[str, int] = Gen.class_member_bitoffsets.get(ClassName, {}) bitfield_widths: dict[str, int] = Gen.class_member_bitfields.get(ClassName, {}) if field_name not in bitfield_offsets: return False bit_offset: int = bitfield_offsets[field_name] bit_width: int = bitfield_widths.get(field_name, 0) if bit_width == 0: return False struct_type: ir.Type | None = Gen.structs.get(ClassName) if struct_type is None or struct_type.elements is None or len(struct_type.elements) == 0: return False storage_type: ir.Type = struct_type.elements[0] member_ptr: ir.Value = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{field_name}_storage_ptr") old_val: ir.Value = Gen._load(member_ptr, name=f"{field_name}_old_storage") mask: int = (1 << bit_width) - 1 shifted_mask: int = mask << bit_offset inverted_mask: ir.Constant = ir.Constant(storage_type, ~shifted_mask & ((1 << storage_type.width) - 1)) cleared: ir.Value = Gen.builder.and_(old_val, inverted_mask, name=f"{field_name}_cleared") if isinstance(Value.type, ir.IntType) and Value.type.width < storage_type.width: if getattr(Value.type, 'is_signed', False): Value = Gen.builder.sext(Value, storage_type, name=f"{field_name}_sext_store") else: Value = Gen.builder.zext(Value, storage_type, name=f"{field_name}_zext_store") elif Value.type.width != storage_type.width: Value = Gen.builder.trunc(Value, storage_type, name=f"{field_name}_trunc_store") if Value.type.width > storage_type.width else Gen.builder.zext(Value, storage_type, name=f"{field_name}_zext_store") shifted_value: ir.Value = Gen.builder.shl(Value, ir.Constant(storage_type, bit_offset), name=f"{field_name}_shift_store") masked_value: ir.Value = Gen.builder.and_(shifted_value, ir.Constant(storage_type, shifted_mask), name=f"{field_name}_mask_store") new_val: ir.Value = Gen.builder.or_(cleared, masked_value, name=f"{field_name}_new_storage") Gen._store(new_val, member_ptr) return True def _CheckEnumMemberAssignment(self, node: ast.expr) -> str | None: def _get_attr_path(n: ast.expr) -> str | None: if isinstance(n, ast.Name): return n.id elif isinstance(n, ast.Attribute): return f"{_get_attr_path(n.value)}.{n.attr}" return None attr_path: str | None = _get_attr_path(node) if not attr_path: return None parts: list[str] = attr_path.split('.') if len(parts) >= 2: enum_class_name: str = parts[-2] member_name: str = parts[-1] qualified_name: str = f"{enum_class_name}.{member_name}" info: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(qualified_name) if info: if info.IsEnumMember and info.EnumName: return info.EnumName under_name: str = f"{enum_class_name}_{member_name}" if self.Trans.SymbolTable.has(under_name): info: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable[under_name] if info.IsEnumMember and info.EnumName: return info.EnumName for key in self.Trans.SymbolTable: if key == member_name: info: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable[key] if info.IsEnumMember and info.EnumName and info.EnumName == enum_class_name: return enum_class_name return None def _IsTypedefAnnotation(self, annotation: ast.expr) -> bool: if isinstance(annotation, ast.Attribute): if annotation.attr in ('CTypedef', 'CDefine'): return True if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): return self._IsTypedefAnnotation(annotation.left) or self._IsTypedefAnnotation(annotation.right) if isinstance(annotation, ast.Subscript): return self._IsTypedefAnnotation(annotation.value) return False def _EmitGlobalAssignLlvm(self, Node: ast.Assign, Gen: "Translator.LlvmGen") -> None: if len(Node.targets) == 1 and isinstance(Node.targets[0], ast.Name): VarName: str = Node.targets[0].id if VarName in Gen.variables or VarName in Gen.module.globals: return if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): FuncName: str = Node.value.func.id if FuncName in Gen.structs: IsUnion: bool = False TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(FuncName) if TypeInfo: if TypeInfo.IsUnion: IsUnion = True if IsUnion: StructType: ir.Type = Gen.structs[FuncName] StructPtrType: ir.PointerType = ir.PointerType(StructType) GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, StructPtrType, name=VarName) GlobalVar.initializer = ir.Constant(StructPtrType, None) Gen.variables[VarName] = GlobalVar Gen.global_struct_class[VarName] = FuncName return StructName: str = FuncName VarType: ir.Type = Gen.structs[StructName] GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName) const: ir.Constant | None = self.Trans.ClassHandler._BuildStructConstant(Node.value, StructName, Gen) if const: GlobalVar.initializer = const else: GlobalVar.linkage = 'common' Gen.variables[VarName] = GlobalVar Gen.global_struct_class[VarName] = StructName return GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, ir.IntType(32), name=VarName) init_val: ir.Constant | None = self._eval_global_const(Node.value, ir.IntType(32), Gen) GlobalVar.initializer = init_val if init_val else ir.Constant(ir.IntType(32), 0) Gen.variables[VarName] = GlobalVar def _eval_const_expr(self, node: ast.expr, Gen: "Translator.LlvmGen") -> int | float | None: """计算常量表达式的值(委托到 ConstEvaluator)""" ctx: EvalContext = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable, translator=self.Trans) return ConstEvaluator.eval_full(node, ctx) def _eval_global_count(self, node: ast.expr, Gen: "Translator.LlvmGen") -> int | None: val: int | float | None = self._eval_const_expr(node, Gen) if val is not None: if isinstance(val, float): return int(val) if isinstance(val, int): return val return None