from __future__ import annotations from typing import TYPE_CHECKING if TYPE_CHECKING: from lib.core.translator import Translator from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin import ast import os import re 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.constants.config import mode as _config_mode from lib.includes import t from lib.includes.t import CTypeRegistry from lib.core.SymbolUtils import IsTModule, ExtractTypeNameFromBinOp class ExprCallHandle(BaseHandle): def _append_eh_msg_out_arg(self, CallArgs: list[ir.Value], func: ir.Function | None, Gen: LlvmGeneratorMixin) -> None: if not func: return func_args: list[ir.Type] = func.function_type.args n_user_args: int = len(CallArgs) has_eh_msg: bool = False has_eh_code: bool = False if len(func_args) > n_user_args: last_type: ir.Type = func_args[-1] if (isinstance(last_type, ir.PointerType) and isinstance(last_type.pointee, ir.IntType) and last_type.pointee.width == 32): has_eh_code = True if len(func_args) > n_user_args + (1 if has_eh_code else 0): check_idx: int = len(func_args) - 1 - (1 if has_eh_code else 0) check_type: ir.Type = func_args[check_idx] if (isinstance(check_type, ir.PointerType) and isinstance(check_type.pointee, ir.PointerType) and isinstance(check_type.pointee.pointee, ir.IntType) and check_type.pointee.pointee.width == 8): has_eh_msg = True if not has_eh_msg: return eh_msg_ptr: ir.Value | None = None eh_code_ptr: ir.Value | None = None if Gen.eh_except_block_stack: _, _, exception_code, eh_message = Gen.eh_except_block_stack[-1] if eh_message is not None: eh_msg_ptr = eh_message if exception_code is not None: eh_code_ptr = exception_code if eh_msg_ptr is None and Gen.func and len(Gen.func.args) > 0: for arg in Gen.func.args: if arg.name == '__eh_msg_out__' and eh_msg_ptr is None: eh_msg_ptr = arg elif arg.name == '__eh_code_out__' and eh_code_ptr is None: eh_code_ptr = arg if eh_msg_ptr is None: eh_msg_ptr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_msg_out_null") if eh_code_ptr is None: eh_code_ptr = Gen._allocaEntry(ir.IntType(32), name="eh_code_out_null") Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_msg_ptr) Gen._store(ir.Constant(ir.IntType(32), 0), eh_code_ptr) CallArgs.append(eh_msg_ptr) if has_eh_code: CallArgs.append(eh_code_ptr) def _check_eh_return(self, result: ir.Value, func_name: str, Gen: LlvmGeneratorMixin, called_func: ir.Function | None = None) -> ir.Value: has_eh_msg_out: bool = False has_eh_code_out: bool = False if called_func and hasattr(called_func, 'args') and len(called_func.args) > 0: for arg in called_func.args: if arg.name == '__eh_msg_out__': has_eh_msg_out = True elif arg.name == '__eh_code_out__': has_eh_code_out = True if not has_eh_msg_out: return result eh_msg_ptr: ir.Value | None = None eh_code_ptr: ir.Value | None = None if Gen.eh_except_block_stack: _, _, exception_code, eh_message = Gen.eh_except_block_stack[-1] if eh_message is not None: eh_msg_ptr = eh_message if exception_code is not None: eh_code_ptr = exception_code if eh_msg_ptr is None and Gen.func and len(Gen.func.args) > 0: for arg in Gen.func.args: if arg.name == '__eh_msg_out__' and eh_msg_ptr is None: eh_msg_ptr = arg elif arg.name == '__eh_code_out__' and eh_code_ptr is None: eh_code_ptr = arg if eh_msg_ptr is not None: eh_msg_val: ir.Value = Gen._load(eh_msg_ptr, name=f"Load_eh_msg_{func_name}") null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None) is_error: ir.Value = Gen.builder.icmp_signed('!=', eh_msg_val, null_ptr, name=f"check_eh_msg_{func_name}") OkBB: ir.Block = Gen.func.append_basic_block(name=f"ok_after_{func_name}") ErrorBB: ir.Block = Gen.func.append_basic_block(name=f"error_after_{func_name}") Gen.builder.cbranch(is_error, ErrorBB, OkBB) Gen.builder.position_at_start(ErrorBB) ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None error_ret_val: ir.Constant | None = None if isinstance(ret_type, ir.IdentifiedStructType): if ret_type.elements: error_ret_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: error_ret_val = ir.Constant(ret_type, None) elif isinstance(ret_type, ir.PointerType): error_ret_val = ir.Constant(ret_type, None) elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): error_ret_val = ir.Constant(ret_type, 0.0) elif isinstance(ret_type, ir.IntType): error_ret_val = ir.Constant(ret_type, 1) elif isinstance(ret_type, ir.VoidType): pass else: error_ret_val = ir.Constant(ir.IntType(32), 1) if Gen.eh_except_block_stack: ExceptBB, _, exception_code, _ = Gen.eh_except_block_stack[-1] if ExceptBB is not None: if has_eh_code_out and eh_code_ptr is not None: eh_code_val = Gen._load(eh_code_ptr, name=f"Load_eh_code_{func_name}") Gen._store(eh_code_val, exception_code) else: Gen._store(ir.Constant(ir.IntType(32), 1), exception_code) Gen.builder.branch(ExceptBB) else: if isinstance(ret_type, ir.VoidType): Gen.builder.ret_void() else: Gen.builder.ret(error_ret_val) else: if isinstance(ret_type, ir.VoidType): Gen.builder.ret_void() else: Gen.builder.ret(error_ret_val) Gen.builder.position_at_start(OkBB) def _fill_default_args(self, CallArgs: list[ir.Value], func: ir.Function | None, func_name: str | None = None) -> None: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen global_defaults: dict = self.Trans._global_function_default_args func_defaults: list | None = None if func_name: func_defaults = global_defaults.get(func_name) if not func_defaults and func: func_defaults = global_defaults.get(func.name) if not func_defaults and func_name: for gk, gv in global_defaults.items(): if func_name in gk or gk.endswith(func_name) or gk.endswith('.' + func_name): func_defaults = gv break if func and len(CallArgs) < len(func.args): total_params: int = len(func.args) if func_defaults: num_defaults: int = len(func_defaults) default_start: int = total_params - num_defaults else: num_defaults = 0 default_start = total_params while len(CallArgs) < total_params: arg_idx: int = len(CallArgs) arg = func.args[arg_idx] param_type: ir.Type = arg.type if hasattr(arg, 'type') else arg if func_defaults and arg_idx >= default_start: def_idx: int = arg_idx - default_start if def_idx < num_defaults and func_defaults[def_idx] is not None: default_val = func_defaults[def_idx] if isinstance(param_type, ir.IntType): max_val: int = (1 << param_type.width) - 1 if isinstance(default_val, bool): default_val = 1 if default_val else 0 if isinstance(default_val, int) and default_val > max_val: default_val = default_val & max_val if isinstance(default_val, int) and default_val < 0: default_val = default_val & max_val CallArgs.append(ir.Constant(param_type, default_val)) elif isinstance(param_type, ir.PointerType): CallArgs.append(ir.Constant(param_type, None)) else: try: _zv = Gen._zero_value_for_type(param_type) CallArgs.append(_zv if _zv is not None else ir.Constant(ir.IntType(32), 0)) except (AssertionError, TypeError): CallArgs.append(ir.Constant(ir.IntType(32), 0)) else: if isinstance(param_type, ir.PointerType): CallArgs.append(ir.Constant(param_type, None)) elif isinstance(param_type, ir.IntType): CallArgs.append(ir.Constant(param_type, 0)) else: try: _zv = Gen._zero_value_for_type(param_type) CallArgs.append(_zv if _zv is not None else ir.Constant(ir.IntType(32), 0)) except (AssertionError, TypeError): CallArgs.append(ir.Constant(ir.IntType(32), 0)) else: if isinstance(param_type, ir.PointerType): CallArgs.append(ir.Constant(param_type, None)) elif isinstance(param_type, ir.IntType): CallArgs.append(ir.Constant(param_type, 0)) else: try: _zv = Gen._zero_value_for_type(param_type) CallArgs.append(_zv if _zv is not None else ir.Constant(ir.IntType(32), 0)) except (AssertionError, TypeError): CallArgs.append(ir.Constant(ir.IntType(32), 0)) def _ApplyKeywordArgs(self, Node: ast.Call, CallArgs: list[ir.Value], func: ir.Function | None, func_name: str | None, self_offset: int = 1) -> None: """在 _fill_default_args 之后调用:用 keyword args 按 param_names 覆盖 CallArgs 对应位置。 self_offset=1 表示 CallArgs[0] 是 self,参数从 CallArgs[1] 开始(__init__/__new__/__call__/method)。 self_offset=0 表示无 self,参数从 CallArgs[0] 开始(普通函数)。 """ if not Node.keywords: return global_param_names: dict = self.Trans._global_function_param_names param_names: list[str] | None = None if func_name: param_names = global_param_names.get(func_name) if not param_names and func is not None: param_names = global_param_names.get(func.name) if not param_names and func is not None and hasattr(func, 'args'): llvm_names: list[str] = [a.name for a in func.args] if func.args else [] if llvm_names and not all(n.isdigit() for n in llvm_names): param_names = llvm_names if not param_names: # 无法获取参数名,回退:按顺序追加(保持旧行为,避免静默丢弃) for kw in Node.keywords: if kw.arg is None: continue ArgVal = self.HandleExprLlvm(kw.value) if ArgVal: CallArgs.append(ArgVal) return for kw in Node.keywords: if kw.arg is None: continue ArgVal = self.HandleExprLlvm(kw.value) if not ArgVal: continue if kw.arg in param_names: idx: int = param_names.index(kw.arg) target_idx: int = idx - self_offset if 0 <= target_idx < len(CallArgs) - self_offset: CallArgs[self_offset + target_idx] = ArgVal def _HandleCallLlvm(self, Node: ast.Call) -> ir.Value: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen FuncAttr: str | None = None ModulePath: str | None = None if isinstance(Node.func, ast.Name): FuncName = Node.func.id if hasattr(self.Trans.FunctionHandler, '_generic_templates') and FuncName in self.Trans.FunctionHandler._generic_templates: return self._HandleGenericCallLlvm(Node, FuncName) result = self.Trans.ExprBuiltinHandle._HandleBuiltinCallLlvm(Node) if result is not None: return result if Gen._has_function(FuncName): return self._HandleClosureCallLlvm(Node, FuncName) SymInfo = self.Trans.SymbolTable.lookup(FuncName) if SymInfo: # 名字冲突处理:类名可能与 CEnum 成员名冲突(如 ASTKind.Name 枚举成员与 Name 类同名) # 若该名字同时是类(在 Gen.structs 中或存在 __before_init__),优先作为类构造函数处理 IsAlsoClass: bool = (FuncName in Gen.structs) or Gen._has_function(f'{FuncName}.__before_init__') if SymInfo.IsEnum and not (IsAlsoClass and getattr(SymInfo, 'IsEnumMember', False)): if Node.args: arg_val = self.HandleExprLlvm(Node.args[0]) if arg_val: if isinstance(arg_val.type, ir.IntType) and arg_val.type.width != 32: if arg_val.type.width < 32: arg_val = Gen.builder.zext(arg_val, ir.IntType(32), name="zext_enum_arg") else: arg_val = Gen.builder.trunc(arg_val, ir.IntType(32), name="trunc_enum_arg") return arg_val return ir.Constant(ir.IntType(32), 0) if SymInfo.IsTypedef: return self._HandleTypedefCastLlvm(Node, FuncName) NewFuncName = f'{FuncName}.__before_init__' InitFuncName = f'{FuncName}.__init__' if Gen._has_function(NewFuncName): return self._HandleClassNewLlvm(Node, FuncName) if Gen._has_function(InitFuncName) and FuncName in Gen.structs: return self._HandleClassNewLlvm(Node, FuncName) if FuncName in Gen.structs: return self._HandleClassNewLlvm(Node, FuncName) if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and FuncName in self.Trans.ClassHandler._generic_class_templates: return self._HandleClassNewLlvm(Node, FuncName) if self.Trans.FunctionDefCache.get(FuncName): return self._HandleClosureCallLlvm(Node, FuncName) if FuncName in self._C_LIB_FUNCS: return self._HandleClosureCallLlvm(Node, FuncName) ClassName = Gen.var_struct_class.get(FuncName) if ClassName and Gen._has_function(f'{ClassName}.__call__'): return self._HandleInstanceCallLlvm(Node, FuncName, ClassName) t_c_imported = getattr(self.Trans, '_t_c_imported_names', {}) if FuncName in t_c_imported: src_module, src_name = t_c_imported[FuncName] virtual_node = self._make_virtual_attr_call(Node, src_module, src_name) return self._HandleCallLlvm(virtual_node) # 检查是否是全局变量中的函数指针(t.Callable 类型在模块级定义) if FuncName not in Gen.variables and FuncName in Gen.global_vars: Gen._Load_var(FuncName) if FuncName not in Gen.variables and FuncName in Gen.module.globals: GVar = Gen.module.globals[FuncName] if not isinstance(GVar, ir.Function): StoredType = GVar.type.pointee if isinstance(GVar.type, ir.PointerType) else GVar.type if isinstance(StoredType, ir.PointerType) and isinstance(StoredType.pointee, ir.FunctionType): Gen.variables[FuncName] = GVar # 检查是否是闭包变量(lambda 赋值给变量后调用) if FuncName in Gen.variables and Gen.variables[FuncName] is not None: VarPtr = Gen.variables[FuncName] # 检查是否是函数指针变量(t.Callable 类型),直接加载并调用 if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(VarPtr.type.pointee.pointee, ir.FunctionType): fn_ptr = Gen._load(VarPtr, name=f"Load_fn_{FuncName}") args = [] for arg in Node.args: ArgVal = self.HandleExprLlvm(arg) if ArgVal: args.append(ArgVal) return Gen.builder.call(fn_ptr, args, name=f"call_{FuncName}") closure_ptr = Gen._load(VarPtr, name=f"Load_closure_{FuncName}") if isinstance(closure_ptr.type, ir.PointerType) and isinstance(closure_ptr.type.pointee, ir.FunctionType): fn_ptr = closure_ptr args = [] for arg in Node.args: ArgVal = self.HandleExprLlvm(arg) if ArgVal: args.append(ArgVal) return Gen.builder.call(fn_ptr, args, name=f"call_{FuncName}") if isinstance(closure_ptr.type, ir.PointerType) and isinstance(closure_ptr.type.pointee, ir.LiteralStructType): st = closure_ptr.type.pointee if len(st.elements) == 2 and isinstance(st.elements[1], ir.PointerType) and isinstance(st.elements[1].pointee, ir.FunctionType): fn_ptr_type = st.elements[1] fn_ptr = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 1)], name=f"fn_ptr_{FuncName}") fn_val = Gen._load(fn_ptr, name=f"fn_{FuncName}") args = [] for arg in Node.args: ArgVal = self.HandleExprLlvm(arg) if ArgVal: args.append(ArgVal) env_ptr = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"env_ptr_{FuncName}") env_val = Gen._load(env_ptr, name=f"env_{FuncName}") call_args = [env_val] + args expected_fn_type = fn_ptr_type.pointee if len(call_args) < len(expected_fn_type.args): while len(call_args) < len(expected_fn_type.args): call_args.append(ir.Constant(expected_fn_type.args[len(call_args)], 0)) # 如果函数期望的 env 类型与闭包中存储的 i8* 不同,做 bitcast if len(expected_fn_type.args) > 0 and call_args[0].type != expected_fn_type.args[0]: call_args[0] = Gen.builder.bitcast(call_args[0], expected_fn_type.args[0], name=f"cast_env_{FuncName}") return Gen.builder.call(fn_val, call_args, name=f"call_{FuncName}") raise Exception(f"Undefined function: '{FuncName}'") if isinstance(Node.func, ast.Subscript): # Handle list[int](mb) syntax — generic class constructor with explicit type args sub: ast.Subscript = Node.func if isinstance(sub.value, ast.Name): ClassName: str = sub.value.id if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and ClassName in self.Trans.ClassHandler._generic_class_templates: return self._HandleGenericClassNewLlvm(Node, ClassName, explicit_slice=sub.slice) if isinstance(Node.func, ast.Attribute): if Node.func.attr in ('update', 'final', 'transform'): pass if Node.func.attr == '__sizeof__': if isinstance(Node.func.value, ast.Subscript): spec_name = self._ResolveGenericSlice(Node.func.value) if spec_name: return self._HandleSizeofLlvm(ast.Name(id=spec_name, ctx=ast.Load())) # 对于 BinOp/BitOr 联合类型(如 AST | t.CPtr), # sizeof 应返回指针大小 8,而非结构体大小 # 必须在 HandleExprLlvm 之前检查,避免对类型名求值产生副作用 if isinstance(Node.func.value, ast.BinOp) and isinstance(Node.func.value.op, ast.BitOr): if self._AnnotationContainsCPtr(Node.func.value): return ir.Constant(ir.IntType(64), 8) # 对于 ast.Attribute(如 ast.ClassDef.__sizeof__() / t.CInt.__sizeof__()), # 直接调用 _HandleSizeofLlvm,不走 HandleExprLlvm # 因为 ast.Attribute 在 sizeof 上下文中一定是类型名,不是变量 if isinstance(Node.func.value, ast.Attribute): type_name = Node.func.value.attr SizeofNode = ast.Name(id=type_name, ctx=ast.Load()) _r = self._HandleSizeofLlvm(SizeofNode) return _r # 对于 ast.Name,需要区分变量和类型名: # - 如果是已知变量(Gen.variables/_reg_values/_direct_values/self), # 走 HandleExprLlvm 路径(如 myvar.__sizeof__()) # - 否则视为类型名,直接调用 _HandleSizeofLlvm # 这避免了 HandleExprLlvm 对类型名求值产生副作用 # (如修改 builder 状态、污染 variables 缓存等), # 这些副作用会导致泛型特化后 then 块为空 if isinstance(Node.func.value, ast.Name): nm: str = Node.func.value.id is_variable: bool = ( nm == 'self' or nm in Gen.variables or nm in getattr(Gen, '_reg_values', {}) or nm in getattr(Gen, '_direct_values', {}) ) if not is_variable: SizeofNode = ast.Name(id=nm, ctx=ast.Load()) _r = self._HandleSizeofLlvm(SizeofNode) return _r # 变量/实例的 sizeof: 通过 HandleExprLlvm 获取值 ObjVal = self.HandleExprLlvm(Node.func.value) if ObjVal and isinstance(ObjVal.type, ir.PointerType): pointee = ObjVal.type.pointee if isinstance(pointee, ir.ArrayType): # Calculate element size in bytes elem = pointee.element if isinstance(elem, ir.IntType): elem_size = elem.width // 8 elif isinstance(elem, ir.PointerType): elem_size = 8 # 64-bit pointers elif isinstance(elem, (ir.LiteralStructType, ir.IdentifiedStructType)): # Approximate: sum of field sizes elem_size = 0 for field in getattr(elem, 'elements', []): if isinstance(field, ir.IntType): elem_size += field.width // 8 elif isinstance(field, ir.PointerType): elem_size += 8 elif isinstance(field, ir.ArrayType): if isinstance(field.element, ir.IntType): elem_size += field.count * (field.element.width // 8) else: elem_size += field.count * 8 else: elem_size += 8 elif isinstance(elem, ir.ArrayType): if isinstance(elem.element, ir.IntType): elem_size = elem.count * (elem.element.width // 8) else: elem_size = elem.count * 8 elif isinstance(elem, ir.FloatType): elem_size = 4 elif isinstance(elem, ir.DoubleType): elem_size = 8 else: elem_size = 8 # fallback return ir.Constant(ir.IntType(64), pointee.count * elem_size) elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): # 结构体实例: 直接计算大小 self._resolve_opaque_struct_members(pointee, Gen) size = Gen._get_struct_size(pointee) if size > 0: return ir.Constant(ir.IntType(64), size) # 回退: 尝试作为类型名处理 if isinstance(Node.func.value, ast.Name): type_name = Node.func.value.id SizeofNode = ast.Name(id=type_name, ctx=ast.Load()) return self._HandleSizeofLlvm(SizeofNode) ModulePath = self._get_ModulePath(Node.func.value) if ModulePath: first_part = ModulePath.split('.')[0] resolved_first = self.Trans.SymbolTable.resolve_alias(first_part) if resolved_first != first_part: ModulePath = resolved_first + ModulePath[len(first_part):] # 统一获取模块 SHA1,用于跨模块类型引用(确保用源模块的 SHA1 而非当前模块) # 放在 ModulePath 和 alias 解析之后,供所有 _HandleClassNewLlvm/_ensure_struct_declared 调用点使用 _ctor_module_sha1: str | None = None if ModulePath and ModulePath not in {'t', 'c'}: _ctor_sha1_map: dict[str, str] = getattr(Gen, 'ModuleSha1Map', {}) _ctor_module_sha1 = _ctor_sha1_map.get(ModulePath) if not _ctor_module_sha1 and '.' in ModulePath: _ctor_module_sha1 = _ctor_sha1_map.get(ModulePath.split('.')[-1]) if ModulePath: is_instance_var = isinstance(Node.func.value, ast.Name) and ( Node.func.value.id in Gen.var_struct_class or Node.func.value.id in Gen.variables or Node.func.value.id in Gen.global_vars ) and Node.func.value.id not in Gen.ModuleSha1Map is_class_name = isinstance(Node.func.value, ast.Name) and (Node.func.value.id in Gen.structs or self.Trans.SymbolTable.is_struct(Node.func.value.id)) # 链式方法调用:如 self.__mbuddy__.alloc() 或 trans.ImportsH.HandleImport(child) # Node.func.value 是 ast.Attribute,基础是实例变量(如 self/trans) _is_chained_instance: bool = False if isinstance(Node.func.value, ast.Attribute): _base_node: ast.AST = Node.func.value while isinstance(_base_node, ast.Attribute): _base_node = _base_node.value if isinstance(_base_node, ast.Name): _base_name: str = _base_node.id # 检查基名是否为已知变量(self、局部变量、全局变量、已知 struct 变量) # 且不在 ModuleSha1Map 中(避免把模块名误判为变量) if _base_name == 'self' or ( (_base_name in Gen.var_struct_class or _base_name in Gen.variables or _base_name in Gen.global_vars) and _base_name not in Gen.ModuleSha1Map ): _is_chained_instance = True if (is_instance_var or _is_chained_instance) and not is_class_name: return self._HandleMethodCallLlvm(Node) FuncAttr = Node.func.attr if FuncAttr in Gen.structs: result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1) if result is not None: return result if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and FuncAttr in self.Trans.ClassHandler._generic_class_templates: return self._HandleGenericClassNewLlvm(Node, FuncAttr) # 跨模块 REnum 变体构造:ClassName.Variant(args) # 直接检查 Node.func.value 是否是 REnum 类名(不依赖变体短名注册) if isinstance(Node.func.value, ast.Name): RenumClassName: str = Node.func.value.id if self.Trans.SymbolTable.has(RenumClassName): RenumInfo = self.Trans.SymbolTable[RenumClassName] if RenumInfo.IsRenum and hasattr(RenumInfo, 'RenumVariants') and RenumInfo.RenumVariants: if FuncAttr in RenumInfo.RenumVariants: TagValue: int = RenumInfo.RenumVariants.index(FuncAttr) result = self._HandleREnumConstructLlvm(Node, RenumClassName, FuncAttr, TagValue) if result is not None: return result if self.Trans.SymbolTable.has(FuncAttr): SymInfo = self.Trans.SymbolTable[FuncAttr] if SymInfo.IsStruct: if FuncAttr not in Gen.structs: self._ensure_struct_declared(FuncAttr, module_sha1=_ctor_module_sha1) if FuncAttr in Gen.structs: result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1) if result is not None: return result if SymInfo.IsEnumMember and SymInfo.EnumName: # When called as module.func(args), check if module.func is a # function/variable first. If so, skip REnum construction and # let the function call path handle it. This fixes cases where # a factory function shares a name with an REnum variant # (e.g., llvmlite.Ptr vs LLVMType.Ptr). _SkipRenum: bool = False if ModulePath: _FullKey = f"{ModulePath}.{FuncAttr}" _FullSym = self.Trans.SymbolTable.lookup(_FullKey) if _FullSym and (_FullSym.IsFunction or _FullSym.IsVariable): _SkipRenum = True if not _SkipRenum: EnumName = SymInfo.EnumName if self.Trans.SymbolTable.has(EnumName): EnumInfo = self.Trans.SymbolTable[EnumName] if EnumInfo.IsRenum: result = self._HandleREnumConstructLlvm(Node, EnumName, FuncAttr, SymInfo.value) if result is not None: return result FullAttrKey = f"{ModulePath}.{FuncAttr}" if self.Trans.SymbolTable.has(FullAttrKey): SymInfo = self.Trans.SymbolTable[FullAttrKey] if SymInfo.IsStruct: if FuncAttr not in Gen.structs: self._ensure_struct_declared(FuncAttr, module_sha1=_ctor_module_sha1) if FuncAttr in Gen.structs: result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1) if result is not None: return result # 跨模块 REnum 变体构造:FullName 查找(如 LLVMType.Int) if SymInfo.IsEnumMember and SymInfo.EnumName: EnumName = SymInfo.EnumName if self.Trans.SymbolTable.has(EnumName): EnumInfo = self.Trans.SymbolTable[EnumName] if EnumInfo.IsRenum: result = self._HandleREnumConstructLlvm(Node, EnumName, FuncAttr, SymInfo.value) if result is not None: return result if is_class_name: ClassName = Node.func.value.id result = self._HandleStaticMethodCallLlvm(Node, ClassName, FuncAttr) if result is not None: return result FullAttrKey = f"{ModulePath}.{FuncAttr}" if self.Trans.SymbolTable.has(FullAttrKey): SymInfo = self.Trans.SymbolTable[FullAttrKey] if SymInfo.IsTypedef: return ir.Constant(ir.IntType(32), 0) if SymInfo.IsStruct: if FuncAttr not in Gen.structs: self._ensure_struct_declared(FuncAttr, module_sha1=_ctor_module_sha1) if FuncAttr in Gen.structs: result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1) if result is not None: return result if FuncAttr in Gen.structs: result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1) if result is not None: return result if ModulePath == 'c': if FuncAttr == 'Asm': return self.Trans.ExprAsmHandle._HandleAsmLlvm(Node) elif FuncAttr == 'Addr': return self.Trans.CSpecialCallHandle._HandleCAddrLlvm(Node) elif FuncAttr == 'Set': return self.Trans.CSpecialCallHandle._HandleCSetLlvm(Node) elif FuncAttr == 'Load': return self.Trans.CSpecialCallHandle._HandleCLoadLlvm(Node) elif FuncAttr == 'Deref': return self.Trans.CSpecialCallHandle._HandleCDerefLlvm(Node) elif FuncAttr == 'DerefAs': return self._HandleCDerefAsLlvm(Node) elif FuncAttr == 'PtrToInt': return self.Trans.CSpecialCallHandle._HandleCPtrToIntLlvm(Node) elif FuncAttr in ('CIf', 'CElif'): return self.Trans.CSpecialCallHandle._HandleCIfLlvm(Node) elif FuncAttr == 'CError': msg = "compile-time error" if Node.args: arg = Node.args[0] if isinstance(arg, ast.Constant) and isinstance(arg.value, str): msg = arg.value lineno = getattr(Node, 'lineno', 0) raise Exception(f"#error: {msg} (line {lineno})") elif FuncAttr in ('AsmInp', 'AsmOut'): return ir.Constant(ir.IntType(32), 0) elif FuncAttr == 'LLVMIR': return self._HandleLLVMIRLlvm(Node) elif FuncAttr in ('LInp', 'LOut'): return ir.Constant(ir.IntType(32), 0) if ModulePath == 't': MethodResult_t = self._HandleMethodCallLlvm(Node) if MethodResult_t is not None: return MethodResult_t raise Exception(f"Undefined method: 't.{FuncAttr}'") if isinstance(Node.func.value, ast.Attribute): inner_attr = Node.func.value.attr if inner_attr in Gen.structs or self.Trans.SymbolTable.is_struct(inner_attr): static_result = self._HandleStaticMethodCallLlvm(Node, inner_attr, FuncAttr) if static_result is not None: return static_result MethodResult_attr = self._HandleMethodCallLlvm(Node) is_zero_attr = isinstance(MethodResult_attr, ir.Constant) and isinstance(MethodResult_attr.type, ir.IntType) and MethodResult_attr.constant == 0 if MethodResult_attr is not None and not is_zero_attr: return MethodResult_attr result = self._HandleExternalCallLlvm(Node, FuncAttr, ModulePath) if result is not None: return result MethodResult = self._HandleMethodCallLlvm(Node) IsZeroResult = isinstance(MethodResult, ir.Constant) and isinstance(MethodResult.type, ir.IntType) and MethodResult.constant == 0 if IsZeroResult and FuncAttr is not None: mangled_name = Gen._mangle_func_name(FuncAttr, ModulePath if ModulePath and ModulePath != 't' else None) if Gen._has_function(mangled_name): CallArgs = [] for arg in Node.args: ArgVal = self.HandleExprLlvm(arg) if ArgVal: CallArgs.append(ArgVal) return Gen.builder.call(Gen._get_function(mangled_name), CallArgs, name=f"call_{FuncAttr}") if MethodResult is None or IsZeroResult: imported = getattr(self.Trans, '_ImportedModules', set()) ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {}) IsKnown = (ModulePath in imported or ModulePath in self.Trans.SymbolTable.import_aliases or ModulePath in ModuleSha1Map) if not IsKnown and ModulePath and '.' in ModulePath: LastPart = ModulePath.split('.')[-1] IsKnown = (LastPart in imported or LastPart in self.Trans.SymbolTable.import_aliases or LastPart in ModuleSha1Map) # 最后尝试: 用 FuncAttr 直接查找 Gen.functions(_find_function 会遍历 SHA1 前缀) if FuncAttr and ModulePath and ModulePath not in {'t', 'c'}: # _ctor_module_sha1 已在函数顶部统一获取,此处无需重复 # 先检查 FuncAttr 是否是函数/变量,如果是则跳过 struct 声明 _attr_sym = self.Trans.SymbolTable.lookup(FuncAttr) _is_func_or_var = _attr_sym and (_attr_sym.IsFunction or _attr_sym.IsVariable) if not _is_func_or_var and ModulePath: _full_key = f"{ModulePath}.{FuncAttr}" _full_sym = self.Trans.SymbolTable.lookup(_full_key) if _full_sym and (_full_sym.IsFunction or _full_sym.IsVariable): _is_func_or_var = True # 优先检查 FuncAttr 是否为 struct/类构造器 if not _is_func_or_var and FuncAttr not in Gen.structs: self._ensure_struct_declared(FuncAttr, module_sha1=_ctor_module_sha1) if not _is_func_or_var and FuncAttr in Gen.structs: result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1) if result is not None: return result # 检查 FullAttrKey 是否为 struct(如 hashlib.md5) if ModulePath: FullAttrKey = f"{ModulePath}.{FuncAttr}" if self.Trans.SymbolTable.has(FullAttrKey): FullSymInfo = self.Trans.SymbolTable[FullAttrKey] if FullSymInfo.IsStruct or FullSymInfo.IsCpythonObject: if FuncAttr not in Gen.structs: self._ensure_struct_declared(FuncAttr, module_sha1=_ctor_module_sha1) if FuncAttr in Gen.structs: result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1) if result is not None: return result fallback_func = Gen._find_function(FuncAttr) if fallback_func is not None: CallArgs = [] for arg in Node.args: ArgVal = self.HandleExprLlvm(arg) if ArgVal: CallArgs.append(ArgVal) self._append_eh_msg_out_arg(CallArgs, fallback_func, Gen) result = Gen.builder.call(fallback_func, CallArgs, name=f"call_{FuncAttr}") return self._check_eh_return(result, FuncAttr, Gen, called_func=fallback_func) # 尝试从 stub 按需加载函数声明 if ModulePath in ModuleSha1Map: sha1 = ModuleSha1Map[ModulePath] stub_mangled = f"{sha1}.{FuncAttr}" try: stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(stub_mangled, Gen) except Exception: stub_func_type = None if not stub_func_type: try: stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(FuncAttr, Gen) except Exception: stub_func_type = None if stub_func_type: decl_name = stub_mangled if stub_mangled in getattr(self.Trans.ImportHandler, '_stub_func_cache', {}) else FuncAttr func_decl = self.GetOrCreateStubFuncDecl(decl_name, stub_func_type, Gen, alias=FuncAttr) CallArgs = [] for arg in Node.args: ArgVal = self.HandleExprLlvm(arg) if ArgVal: CallArgs.append(ArgVal) self._append_eh_msg_out_arg(CallArgs, func_decl, Gen) result = Gen.builder.call(func_decl, CallArgs, name=f"call_{FuncAttr}") return self._check_eh_return(result, FuncAttr, Gen, called_func=func_decl) if ModulePath and IsKnown: raise Exception(f"Undefined symbol: '{ModulePath}.{FuncAttr}'") if ModulePath and ModulePath not in {'t', 'c'} and not IsKnown: raise Exception(f"Unknown module: '{ModulePath}' (undefined symbol: '{ModulePath}.{FuncAttr}')") if not ModulePath and FuncAttr: raise Exception(f"Undefined method: '{FuncAttr}'") return MethodResult if MethodResult is not None else ir.Constant(ir.IntType(32), 0) if isinstance(Node.func, ast.BinOp) and isinstance(Node.func.op, ast.BitOr): return self._HandleTypeUnionCastLlvm(Node) raise Exception(f"Unsupported call expression") def _ensure_struct_declared(self, class_name: str, module_sha1: str | None = None) -> None: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen # 如果名称是函数或变量,不应创建 struct SymInfo = self.Trans.SymbolTable.lookup(class_name) if SymInfo and (SymInfo.IsFunction or SymInfo.IsVariable): return # 跨模块类型引用:如果提供了 module_sha1,优先检查带 SHA1 前缀的完整名 full_key: str | None = f"{module_sha1}.{class_name}" if module_sha1 else None if full_key and full_key in Gen.structs: existing = Gen.structs[full_key] if isinstance(existing, ir.IdentifiedStructType) and (existing.elements is None or len(existing.elements) == 0): self.Trans.ImportHandler._TryLoadStructFromStub(class_name, Gen, source_sha1=module_sha1) return if class_name in Gen.structs: existing = Gen.structs[class_name] if isinstance(existing, ir.IdentifiedStructType) and (existing.elements is None or len(existing.elements) == 0): self.Trans.ImportHandler._TryLoadStructFromStub(class_name, Gen, source_sha1=module_sha1) existing = Gen.structs.get(class_name, existing) if isinstance(existing, ir.IdentifiedStructType) and existing.elements is not None and len(existing.elements) > 0: return else: # 短名已存在但 SHA1 可能不匹配:如果 module_sha1 与现有 struct 的 SHA1 不一致, # 需要用正确的 SHA1 创建独立 struct if module_sha1: _existing_sha1: str = Gen._extract_struct_sha1(existing) if _existing_sha1 and _existing_sha1 != module_sha1: # SHA1 不匹配,用正确的 SHA1 创建 correct_st = Gen._get_or_create_struct(class_name, source_sha1=module_sha1) self.Trans.ImportHandler._TryLoadStructFromStub(class_name, Gen, source_sha1=module_sha1) return SymInfo = self.Trans.SymbolTable.lookup(class_name) if SymInfo and SymInfo.Members: member_types = [] if isinstance(SymInfo.Members, dict): for member_name, member_info in SymInfo.Members.items(): if isinstance(member_info, CTypeInfo): mt = member_info.ToLLVM(Gen) elif isinstance(member_info, str): mt = Gen._CType2LLVM(member_info, '*' in member_info) else: mt = Gen._CType2LLVM(str(member_info) if member_info else 'int', False) if isinstance(mt, ir.VoidType): mt = ir.IntType(8) member_types.append(mt) else: for item in SymInfo.Members: if isinstance(item, (list, tuple)) and len(item) == 2: member_name, member_type_str = item mt = Gen._CType2LLVM(member_type_str, '*' in member_type_str) if isinstance(mt, ir.VoidType): mt = ir.IntType(8) member_types.append(mt) if member_types: st = Gen._get_or_create_struct(class_name, source_sha1=module_sha1) if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0): st.set_body(*member_types) else: Gen._get_or_create_struct(class_name, source_sha1=module_sha1) else: if class_name not in Gen.structs and not (full_key and full_key in Gen.structs): self.Trans.ImportHandler._TryLoadStructFromStub(class_name, Gen, source_sha1=module_sha1) Gen._get_or_create_struct(class_name, source_sha1=module_sha1) def _HandleStaticMethodCallLlvm(self, Node: ast.Call, ClassName: str, MethodName: str) -> ir.Value | None: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen struct_sha1_map = getattr(Gen, '_struct_sha1_map', {}) class_sha1 = struct_sha1_map.get(ClassName) if class_sha1: MangledName = f'{class_sha1}.{ClassName}.{MethodName}' else: MangledName = f'{ClassName}.{MethodName}' func = Gen._find_function(MangledName) if not func: func = Gen._find_function(f'{MangledName}__') if not func: stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(MangledName, Gen) if stub_func_type: func = self.GetOrCreateStubFuncDecl(MangledName, stub_func_type, Gen) if not func and class_sha1: plain_name = f'{ClassName}.{MethodName}' stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(plain_name, Gen) if stub_func_type: func = self.GetOrCreateStubFuncDecl(MangledName, stub_func_type, Gen) if not func: if ClassName not in Gen.structs: self._ensure_struct_declared(ClassName) SymInfo = self.LookupFunctionSymbol(MethodName, module_path=ClassName) if SymInfo and SymInfo.IsFunction: sig = self.BuildLLVMFuncTypeFromSig(SymInfo, Gen) if sig is not None: ret_type, llvm_param_types, _ = sig is_static = FuncMeta.STATIC_METHOD in SymInfo.MetaList if ClassName in Gen.structs and not is_static: llvm_param_types.insert(0, ir.PointerType(Gen.structs[ClassName])) func_type = ir.FunctionType(ret_type, llvm_param_types) func = ir.Function(Gen.module, func_type, name=MangledName) Gen.functions[MangledName] = func if not func: p = Gen.class_parent.get(ClassName) while p: parent_mangled = Gen._mangle_name(f'{p}.{MethodName}') parent_func = Gen.functions.get(parent_mangled) if parent_func: func = parent_func break parent_func = Gen._find_function(f'{p}.{MethodName}') if parent_func: func = parent_func break p = Gen.class_parent.get(p) if not func: return None CallArgs = [] SymInfo = self.LookupFunctionSymbol(MethodName, module_path=ClassName) is_static_call = SymInfo is not None and FuncMeta.STATIC_METHOD in SymInfo.MetaList is_classmethod_call = SymInfo is not None and FuncMeta.CLASS_METHOD in SymInfo.MetaList # @classmethod: 在参数列表前插入 cls(栈上分配的类实例指针) if is_classmethod_call and ClassName in Gen.structs: ClsPtr = Gen._alloca(Gen.structs[ClassName], name=f"cls_{ClassName}") CallArgs.append(ClsPtr) for arg in Node.args: ArgVal = self.HandleExprLlvm(arg) if ArgVal: CallArgs.append(ArgVal) if (ClassName not in Gen.class_vtable and ClassName not in Gen._cross_module_vtable_classes and class_sha1): self._try_register_vtable_ondemand(ClassName, class_sha1, Gen) if (ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes) and ClassName in Gen.class_methods and CallArgs and not is_static_call: methods = Gen.class_methods[ClassName] if class_sha1: FullMethodName = f'{class_sha1}.{ClassName}.{MethodName}' else: FullMethodName = f'{ClassName}.{MethodName}' method_idx = -1 for mi, mn in enumerate(methods): if mn == FullMethodName or mn == MethodName or mn.endswith(f'.{MethodName}'): method_idx = mi break if method_idx >= 0: ObjVal = CallArgs[0] if self._is_char_pointer(ObjVal): if ClassName in Gen.structs: ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}_static") CallArgs[0] = ObjVal VtableSlotPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}_static") VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}_static") VtableArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) VtableTyped = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}_static") MethodPtrAddr = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_ptr_addr_{MethodName}_static") MethodPtrI8 = Gen._load(MethodPtrAddr, name=f"vmethod_ptr_{MethodName}_static") FuncPtrType = ir.PointerType(func.function_type) MethodPtrTyped = Gen.builder.bitcast(MethodPtrI8, FuncPtrType, name=f"vmethod_typed_{MethodName}_static") self._fill_default_args(CallArgs, func, FullMethodName) self._append_eh_msg_out_arg(CallArgs, func, Gen) adjusted = Gen._adjust_args(CallArgs, func) result = Gen.builder.call(MethodPtrTyped, adjusted, name=f"vcall_{FullMethodName}") self._check_eh_return(result, FullMethodName, Gen, called_func=func) return result self._append_eh_msg_out_arg(CallArgs, func, Gen) CallArgs = Gen._apply_auto_addr(MangledName, CallArgs) adjusted = Gen._adjust_args(CallArgs, func) result = Gen.builder.call(func, adjusted, name=f"call_{MangledName}") self._check_eh_return(result, MangledName, Gen, called_func=func) return result def _HandleInstanceCallLlvm(self, Node: ast.Call, VarName: str, ClassName: str) -> ir.Value: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen ObjVal = self.HandleExprLlvm(ast.Name(id=VarName, ctx=ast.Load())) if not ObjVal: raise Exception(f"Cannot evaluate object '{VarName}' for __call__") if self._is_char_pointer(ObjVal): if ClassName in Gen.structs: ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") CallArgs = [ObjVal] for arg in Node.args: ArgVal = self.HandleExprLlvm(arg) if ArgVal: CallArgs.append(ArgVal) CallFuncName = f'{ClassName}.__call__' struct_sha1_map = getattr(Gen, '_struct_sha1_map', {}) class_sha1 = struct_sha1_map.get(ClassName) if class_sha1: CallFuncName = f'{class_sha1}.{ClassName}.__call__' if not Gen._has_function(CallFuncName): raise Exception(f"Class '{ClassName}' has no __call__ method") func = Gen._get_function(CallFuncName) self._fill_default_args(CallArgs, func, CallFuncName) self._ApplyKeywordArgs(Node, CallArgs, func, CallFuncName, self_offset=1) self._append_eh_msg_out_arg(CallArgs, func, Gen) adjusted = Gen._adjust_args(CallArgs, func) result = Gen.builder.call(func, adjusted, name=f"call_{CallFuncName}") self._check_eh_return(result, CallFuncName, Gen, called_func=func) return result def _make_virtual_attr_call(self, Node: ast.Call, module_name: str, attr_name: str) -> ast.Call: virtual_func = ast.Attribute( value=ast.Name(id=module_name, ctx=ast.Load()), attr=attr_name, ctx=ast.Load() ) new_node = ast.Call( func=virtual_func, args=Node.args, keywords=Node.keywords ) ast.copy_location(new_node, Node) return new_node def _get_ModulePath(self, node: ast.AST) -> str | None: parts = [] while isinstance(node, ast.Attribute): parts.append(node.attr) node = node.value if isinstance(node, ast.Name): parts.append(node.id) parts.reverse() return '.'.join(parts) if parts else None def _HandleLLVMIRLlvm(self, Node: ast.Call) -> ir.Value: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen if not Node.args: return ir.Constant(ir.IntType(32), 0) all_ops = [] input_ops = [] output_targets = [] operand_seq = 0 ret_type = ir.IntType(32) if len(Node.args) >= 2: ret_type_arg = Node.args[1] inferred = self.Trans.ExprAsmHandle._infer_expr_llvm_type(ret_type_arg) if inferred: ret_type = inferred ir_template = "" first_arg = Node.args[0] if isinstance(first_arg, ast.JoinedStr): parts = [] for value in first_arg.values: if isinstance(value, ast.Constant) and isinstance(value.value, str): parts.append(value.value) elif isinstance(value, ast.FormattedValue): expr = value.value if isinstance(expr, ast.Call) and isinstance(expr.func, ast.Attribute): if isinstance(expr.func.value, ast.Name) and expr.func.value.id == 'c': if expr.func.attr == 'LInp': if expr.args: val = self.HandleExprLlvm(expr.args[0]) if val: input_ops.append(val) all_ops.append(('inp', len(input_ops) - 1)) parts.append(f'%__OP{operand_seq}__') operand_seq += 1 elif expr.func.attr == 'LOut': if expr.args: target_ptr = self.Trans.ExprAsmHandle._get_var_ptr_for_asm(expr.args[0]) if target_ptr: val = target_ptr else: val = self.HandleExprLlvm(expr.args[0]) if val: output_targets.append(val) all_ops.append(('out', len(output_targets) - 1)) parts.append(f'%__OP{operand_seq}__') operand_seq += 1 else: fallback = self.HandleExprLlvm(expr) if fallback: input_ops.append(fallback) all_ops.append(('inp', len(input_ops) - 1)) parts.append(f'%__OP{operand_seq}__') operand_seq += 1 else: fallback = self.HandleExprLlvm(expr) if fallback: input_ops.append(fallback) all_ops.append(('inp', len(input_ops) - 1)) parts.append(f'%__OP{operand_seq}__') operand_seq += 1 ir_template = ''.join(parts) elif isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str): ir_template = first_arg.value return self._EmitLLVMIRInstruction(Gen, ir_template, input_ops, output_targets, all_ops, ret_type) def _EmitLLVMIRInstruction(self, Gen: LlvmGeneratorMixin, ir_template: str, input_ops: list[ir.Value], output_targets: list[ir.Value], all_ops: list[tuple], ret_type: ir.Type) -> ir.Value: template = ir_template.strip() def resolve_op(idx): if idx < len(all_ops): kind, local_idx = all_ops[idx] if kind == 'inp' and local_idx < len(input_ops): return input_ops[local_idx] elif kind == 'out' and local_idx < len(output_targets): return output_targets[local_idx] return None assign_match = re.match(r'%__OP(\d+)__\s*=\s*(.+)', template) if assign_match: template = assign_match.group(2).strip() binop_map = { 'add': 'add', 'fadd': 'fadd', 'sub': 'sub', 'fsub': 'fsub', 'mul': 'mul', 'fmul': 'fmul', 'udiv': 'udiv', 'sdiv': 'sdiv', 'fdiv': 'fdiv', 'urem': 'urem', 'srem': 'srem', 'frem': 'frem', 'shl': 'shl', 'lshr': 'lshr', 'ashr': 'ashr', 'and': 'and_', 'or': 'or_', 'xor': 'xor_', } icmp_match = re.match(r'icmp\s+(\w+)\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__', template) if icmp_match: pred = icmp_match.group(1) op1 = resolve_op(int(icmp_match.group(3))) op2 = resolve_op(int(icmp_match.group(4))) if op1 and op2: result = Gen.builder.icmp_signed(pred, op1, op2, name="llvmir_result") return self._StoreLLVMIROutputs(Gen, result, output_targets) fcmp_match = re.match(r'fcmp\s+(\w+(?:\s+fast)?)\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__', template) if fcmp_match: pred = fcmp_match.group(1) op1 = resolve_op(int(fcmp_match.group(3))) op2 = resolve_op(int(fcmp_match.group(4))) if op1 and op2: result = Gen.builder.fcmp_ordered(pred, op1, op2, name="llvmir_result") return self._StoreLLVMIROutputs(Gen, result, output_targets) for op_name, method_name in binop_map.items(): pattern = re.compile( rf'{op_name}\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__', re.IGNORECASE if op_name in ('and', 'or', 'xor') else 0 ) m = pattern.match(template) if m: op1 = resolve_op(int(m.group(2))) op2 = resolve_op(int(m.group(3))) if op1 and op2: method = getattr(Gen.builder, method_name, None) if method: result = method(op1, op2, name="llvmir_result") return self._StoreLLVMIROutputs(Gen, result, output_targets) select_match = re.match(r'select\s+i1\s+%__OP(\d+)__,\s*(\w+)\s+%__OP(\d+)__,\s*(\w+)\s+%__OP(\d+)__', template) if select_match: cond = resolve_op(int(select_match.group(1))) true_val = resolve_op(int(select_match.group(3))) false_val = resolve_op(int(select_match.group(5))) if cond and true_val and false_val: result = Gen.builder.select(cond, true_val, false_val, name="llvmir_result") return self._StoreLLVMIROutputs(Gen, result, output_targets) cast_map = { 'zext': 'zext', 'sext': 'sext', 'trunc': 'trunc', 'bitcast': 'bitcast', 'inttoptr': 'inttoptr', 'ptrtoint': 'ptrtoint', 'uitofp': 'uitofp', 'sitofp': 'sitofp', 'fptoui': 'fptoui', 'fptosi': 'fptosi', 'fpext': 'fpext', 'fptrunc': 'fptrunc', } for op_name, method_name in cast_map.items(): pattern = re.compile(rf'{op_name}\s+(\w+)\s+%__OP(\d+)__\s+to\s+(\w+)') m = pattern.match(template) if m: src_val = resolve_op(int(m.group(2))) dest_type_str = m.group(3) dest_type = self._ParseLLVMType(Gen, dest_type_str) if src_val and dest_type: method = getattr(Gen.builder, method_name, None) if method: result = method(src_val, dest_type, name="llvmir_result") return self._StoreLLVMIROutputs(Gen, result, output_targets) Load_match = re.match(r'Load\s+(\w+),\s*(\w+)\s+%__OP(\d+)__', template) if Load_match: ptr_val = resolve_op(int(Load_match.group(3))) if ptr_val: result = Gen.builder.load(ptr_val, name="llvmir_result") return self._StoreLLVMIROutputs(Gen, result, output_targets) store_match = re.match(r'store\s+(\w+)\s+%__OP(\d+)__,\s*(\w+)\s+%__OP(\d+)__', template) if store_match: val = resolve_op(int(store_match.group(2))) ptr = resolve_op(int(store_match.group(4))) if val and ptr: Gen.builder.store(val, ptr) return ir.Constant(ir.IntType(32), 0) gep_match = re.match(r'getelementptr\s+(?:inbounds\s+)?(\w+),\s*(\w+)\s+%__OP(\d+)__,\s*(.+)', template) if gep_match: ptr_val = resolve_op(int(gep_match.group(3))) indices_str = gep_match.group(4) if ptr_val: indices = [] for idx_part in re.split(r',\s*', indices_str): idx_part = idx_part.strip() idx_m = re.match(r'%__OP(\d+)__', idx_part) if idx_m: idx_op = resolve_op(int(idx_m.group(1))) if idx_op: indices.append(idx_op) else: try: indices.append(ir.Constant(ir.IntType(32), int(idx_part))) except ValueError: break if indices: result = Gen.builder.gep(ptr_val, indices, name="llvmir_result") return self._StoreLLVMIROutputs(Gen, result, output_targets) neg_match = re.match(r'sub\s+(\w+)\s+(\d+),\s*%__OP(\d+)__', template) if neg_match: op = resolve_op(int(neg_match.group(3))) if op: zero = ir.Constant(op.type, int(neg_match.group(2))) result = Gen.builder.sub(zero, op, name="llvmir_result") return self._StoreLLVMIROutputs(Gen, result, output_targets) not_match = re.match(r'xor\s+(\w+)\s+(-1|\d+),\s*%__OP(\d+)__', template) if not_match: op = resolve_op(int(not_match.group(3))) if op: mask = ir.Constant(op.type, int(not_match.group(2))) result = Gen.builder.xor_(op, mask, name="llvmir_result") return self._StoreLLVMIROutputs(Gen, result, output_targets) call_match = re.match(r'call\s+(\w+)\s+@([\w.]+)\((.+)\)', template) if call_match: call_ret_str = call_match.group(1) func_name = call_match.group(2) args_str = call_match.group(3) call_args = [] for arg_part in re.split(r',\s*', args_str): arg_part = arg_part.strip() typed_op = re.match(r'(\w+\*?)\s+%__OP(\d+)__', arg_part) if typed_op: expected_type_str = typed_op.group(1) op_idx = int(typed_op.group(2)) val = resolve_op(op_idx) if val: val = self._ConvertLLVMIRType(Gen, val, expected_type_str) if val: call_args.append(val) else: const_m = re.match(r'(\w+)\s+(-?\d+)', arg_part) if const_m: const_type = self._ParseLLVMType(Gen, const_m.group(1)) if const_type: call_args.append(ir.Constant(const_type, int(const_m.group(2)))) if call_args: call_ret_type = self._ParseLLVMType(Gen, call_ret_str) or ir.VoidType() func_type = ir.FunctionType(call_ret_type, [a.type for a in call_args]) if func_name.startswith('llvm.'): existing = Gen.module.globals.get(func_name) if existing: func = existing else: try: func = Gen.module.declare_intrinsic(func_name, [a.type for a in call_args]) except Exception: func = ir.Function(Gen.module, func_type, name=func_name) else: existing = Gen.module.globals.get(func_name) if existing: func = existing else: func = ir.Function(Gen.module, func_type, name=func_name) result = Gen.builder.call(func, call_args, name="llvmir_result") if output_targets: return self._StoreLLVMIROutputs(Gen, result, output_targets) if isinstance(call_ret_type, ir.VoidType): return ir.Constant(ir.IntType(32), 0) return result if output_targets: for i, target in enumerate(output_targets): if isinstance(target, ir.AllocaInstr): Gen.builder.store(ir.Constant(target.type.pointee, 0), target) return ir.Constant(ir.IntType(32), 0) return ir.Constant(ret_type, 0) def _StoreLLVMIROutputs(self, Gen: LlvmGeneratorMixin, result: ir.Value, output_targets: list[ir.Value]) -> ir.Value: for target in output_targets: if isinstance(target, ir.AllocaInstr): if target.type.pointee == result.type: Gen.builder.store(result, target) else: i64t = ir.IntType(64) if isinstance(result.type, ir.IntType) and result.type.width == 64 and isinstance(target.type.pointee, ir.PointerType): ptr_val = Gen.builder.inttoptr(result, target.type.pointee) Gen.builder.store(ptr_val, target) elif isinstance(result.type, ir.PointerType) and isinstance(target.type.pointee, ir.IntType) and target.type.pointee.width == 64: int_val = Gen.builder.ptrtoint(result, i64t) Gen.builder.store(int_val, target) else: try: cast_val = Gen.builder.bitcast(result, target.type.pointee) Gen.builder.store(cast_val, target) except Exception: Gen.builder.store(result, target) elif isinstance(target, (ir.GlobalVariable, ir.GEPInstr)): if isinstance(target.type, ir.PointerType): if target.type.pointee == result.type: Gen.builder.store(result, target) else: try: cast_val = Gen.builder.bitcast(result, target.type.pointee) Gen.builder.store(cast_val, target) except Exception: Gen.builder.store(result, target) return result def _ParseLLVMType(self, Gen: LlvmGeneratorMixin, type_str: str) -> ir.Type | None: type_map = { 'i1': ir.IntType(1), 'i8': ir.IntType(8), 'i16': ir.IntType(16), 'i32': ir.IntType(32), 'i64': ir.IntType(64), 'i128': ir.IntType(128), 'float': ir.FloatType(), 'double': ir.DoubleType(), 'void': ir.VoidType(), } if type_str in type_map: return type_map[type_str] if type_str.endswith('*'): pointee = self._ParseLLVMType(Gen, type_str[:-1]) if pointee: return ir.PointerType(pointee) return None def _ConvertLLVMIRType(self, Gen: LlvmGeneratorMixin, val: ir.Value, expected_type_str: str) -> ir.Value | None: expected_type = self._ParseLLVMType(Gen, expected_type_str.rstrip('*')) if not expected_type: return val IsPtr = expected_type_str.endswith('*') if IsPtr: expected_ptr_type = ir.PointerType(expected_type) if isinstance(val.type, ir.PointerType) and val.type != expected_ptr_type: try: return Gen.builder.bitcast(val, expected_ptr_type) except Exception: return val elif isinstance(val.type, ir.IntType) and val.type.width == 64: try: return Gen.builder.inttoptr(val, expected_ptr_type) except Exception: return val return val if val.type == expected_type: return val if isinstance(val.type, ir.IntType) and isinstance(expected_type, ir.IntType): if expected_type.width < val.type.width: return Gen.builder.trunc(val, expected_type) else: return Gen.builder.zext(val, expected_type) if isinstance(val.type, ir.PointerType) and isinstance(expected_type, ir.IntType): if expected_type.width == 64: return Gen.builder.ptrtoint(val, expected_type) if isinstance(val.type, ir.IntType) and isinstance(expected_type, ir.PointerType): if val.type.width == 64: return Gen.builder.inttoptr(val, expected_type) return val def _HandleExternalCallLlvm(self, Node: ast.Call, func_name: str, ModulePath: str | None) -> ir.Value | None: Gen = self.Trans.LlvmGen # 解析 import 别名: 如 window -> vpsdk.window if ModulePath and ModulePath not in ('c', 't'): ModulePath = self.Trans.SymbolTable.resolve_alias(ModulePath) is_user_module = (ModulePath and ModulePath not in ('c', 't') and (ModulePath in Gen.ModuleSha1Map or ModulePath in getattr(self.Trans, '_ImportedModules', set()) or ModulePath in self.Trans.SymbolTable.import_aliases)) if ModulePath and ModulePath not in ('c', 't') and not is_user_module: is_user_module = (ModulePath in Gen.ModuleSha1Map or ModulePath.split('.')[-1] in Gen.ModuleSha1Map or ModulePath.split('.')[-1] in getattr(self.Trans, '_ImportedModules', set())) if is_user_module and ModulePath not in Gen.ModuleSha1Map and ModulePath not in getattr(self.Trans, '_ImportedModules', set()): ModulePath = ModulePath.split('.')[-1] if ModulePath and ModulePath not in ('c', 't') and not is_user_module: return None if is_user_module: mangled_name = Gen._mangle_func_name(func_name, ModulePath) sym_info = self.LookupFunctionSymbol(func_name, module_path=ModulePath) is_inline = sym_info and (sym_info.IsInline or isinstance(sym_info.Storage, t.CInline)) if is_inline and sym_info.InlineBody: self._HandleInlineExpandLlvm(Node, sym_info) return ir.Constant(ir.IntType(32), 1) sym_info_exact = self.Trans.SymbolTable.lookup(f'{ModulePath}.{func_name}') if sym_info_exact: exact_params = sym_info_exact.FuncPtrParams exact_param_names = [pn for pn, _ in exact_params] if exact_param_names: provided = len(Node.args) kw_provided = set() for kw in Node.keywords: if kw.arg and kw.arg in exact_param_names: kw_provided.add(exact_param_names.index(kw.arg)) # 获取默认参数信息,计算必需参数数量(与 _fill_default_args 一致的查找逻辑) global_defaults: dict = self.Trans._global_function_default_args func_defaults: list | None = None if mangled_name in global_defaults: func_defaults = global_defaults[mangled_name] elif func_name in global_defaults: func_defaults = global_defaults[func_name] else: for gk, gv in global_defaults.items(): if func_name in gk or gk.endswith(func_name) or gk.endswith('.' + func_name): func_defaults = gv break total_params: int = len(exact_param_names) num_defaults: int = len(func_defaults) if func_defaults else 0 min_args: int = total_params - num_defaults # 只检查必需参数(有默认值的参数允许缺失) for i in range(min_args): if i >= provided and i not in kw_provided: raise Exception(f"调用 {ModulePath}.{func_name}() 缺少必需参数 '{exact_param_names[i]}',该参数没有默认值") elif ModulePath in Gen.ModuleSha1Map and len(Node.args) == 0: func = Gen.functions.get(mangled_name) if func and len(func.function_type.args) > 0: raise Exception(f"调用 {ModulePath}.{func_name}() 缺少必需参数,函数需要 {len(func.function_type.args)} 个参数但未传入任何参数") if Gen._has_function(mangled_name): return self._HandleClosureCallLlvm(Node, mangled_name) try: stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen) except Exception: stub_func_type = None if not stub_func_type and mangled_name != func_name: try: stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(func_name, Gen) except Exception: stub_func_type = None if stub_func_type: if is_user_module: decl_name = mangled_name else: decl_name = mangled_name if mangled_name in self.Trans.ImportHandler._stub_func_cache else func_name self.GetOrCreateStubFuncDecl(decl_name, stub_func_type, Gen, alias=func_name) return self._HandleClosureCallLlvm(Node, decl_name) sym_info = self.LookupFunctionSymbol(func_name, module_path=ModulePath) if sym_info: sig = self.BuildLLVMFuncTypeFromSig(sym_info, Gen, mangled_name=mangled_name, use_infer_fallback=True) if sig is not None: ret_type, llvm_param_types, sym_is_variadic = sig self.GetOrCreateFuncDecl(mangled_name, ret_type, llvm_param_types, Gen, is_variadic=sym_is_variadic, replace_name=func_name) return self._HandleClosureCallLlvm(Node, mangled_name) # 回退: 直接用 func_name 查找(_find_function 会遍历 SHA1 前缀) fallback_func = Gen._find_function(func_name) if fallback_func is not None: return self._HandleClosureCallLlvm(Node, func_name) return None if ModulePath == 'c': if func_name == 'Asm': return self.Trans.ExprAsmHandle._HandleAsmLlvm(Node) elif func_name == 'Addr': return self.Trans.CSpecialCallHandle._HandleCAddrLlvm(Node) elif func_name == 'Set': return self.Trans.CSpecialCallHandle._HandleCSetLlvm(Node) elif func_name == 'Load': return self.Trans.CSpecialCallHandle._HandleCLoadLlvm(Node) elif func_name == 'Deref': return self.Trans.CSpecialCallHandle._HandleCDerefLlvm(Node) elif func_name == 'DerefAs': return self._HandleCDerefAsLlvm(Node) elif func_name == 'PtrToInt': return self.Trans.CSpecialCallHandle._HandleCPtrToIntLlvm(Node) elif func_name in ('CIf', 'CElif'): return self.Trans.CSpecialCallHandle._HandleCIfLlvm(Node) elif func_name == 'CError': msg = "compile-time error" if Node.args: arg = Node.args[0] if isinstance(arg, ast.Constant) and isinstance(arg.value, str): msg = arg.value lineno = getattr(Node, 'lineno', 0) raise Exception(f"#error: {msg} (line {lineno})") elif func_name in ('AsmInp', 'AsmOut'): return ir.Constant(ir.IntType(32), 0) elif func_name == 'LLVMIR': return self._HandleLLVMIRLlvm(Node) elif func_name in ('LInp', 'LOut'): return ir.Constant(ir.IntType(32), 0) win32_apis = { 'SetConsoleOutputCP': (ir.IntType(32), [ir.IntType(32)]), 'SetConsoleCP': (ir.IntType(32), [ir.IntType(32)]), 'GetConsoleOutputCP': (ir.IntType(32), []), 'GetConsoleCP': (ir.IntType(32), []), } if ModulePath and 'win32console' in ModulePath and func_name in win32_apis: ret_type, param_types = win32_apis[func_name] if func_name not in Gen.functions: func_type = ir.FunctionType(ret_type, param_types) func_decl = ir.Function(Gen.module, func_type, name=func_name) func_decl.linkage = 'external' Gen.functions[func_name] = func_decl call_args = [] if Node.args: arg_val = self.HandleExprLlvm(Node.args[0]) if arg_val: target_type = param_types[0] if param_types else ir.IntType(32) if isinstance(arg_val.type, ir.IntType) and arg_val.type.width < target_type.width: arg_val = Gen.builder.zext(arg_val, target_type, name="zext_win32_arg") elif isinstance(arg_val.type, ir.IntType) and arg_val.type.width > target_type.width: arg_val = Gen.builder.trunc(arg_val, target_type, name="trunc_win32_arg") call_args.append(arg_val) return Gen.builder.call(Gen.functions[func_name], call_args, name=f"call_{func_name}") if Gen._has_function(func_name): return self._HandleClosureCallLlvm(Node, func_name) if func_name in self.Trans.FunctionDefCache: return self._HandleClosureCallLlvm(Node, func_name) if func_name in self._C_LIB_FUNCS: return self._HandleClosureCallLlvm(Node, func_name) mangled_name = Gen._mangle_func_name(func_name, ModulePath) try: stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen) except Exception: stub_func_type = None if not stub_func_type and mangled_name != func_name: try: stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(func_name, Gen) except Exception: stub_func_type = None if stub_func_type: decl_name = mangled_name if mangled_name in self.Trans.ImportHandler._stub_func_cache else func_name self.GetOrCreateStubFuncDecl(decl_name, stub_func_type, Gen, alias=func_name, check_existing=False) return self._HandleClosureCallLlvm(Node, decl_name) sym_info = self.LookupFunctionSymbol(func_name, module_path=ModulePath or None) if sym_info: sig = self.BuildLLVMFuncTypeFromSig(sym_info, Gen) if sig is not None: ret_type, llvm_param_types, sym_is_variadic = sig mangled_name = Gen._mangle_func_name(func_name, ModulePath) self.GetOrCreateFuncDecl(mangled_name, ret_type, llvm_param_types, Gen, is_variadic=sym_is_variadic, replace_name=func_name) return self._HandleClosureCallLlvm(Node, mangled_name) return None def _HandleTypeUnionCastLlvm(self, Node: ast.Call) -> ir.Value | None: Gen = self.Trans.LlvmGen if not Node.args: return None type_info = None try: type_info = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.func) except Exception as _e: if _config_mode == "strict": raise _vlog().warning(f"解析类型失败: {_e}", "Exception") if not isinstance(type_info, CTypeInfo): return None target_type_str = type_info.ToString() IsPtr = type_info.IsPtr if IsPtr and target_type_str and '*' not in target_type_str: target_type_str += ' *' if not target_type_str: return None if type_info.IsPtr and not IsPtr: IsPtr = True if '*' not in target_type_str: target_type_str += ' *' if isinstance(type_info.Storage, t.CExport) or isinstance(type_info.Storage, t.CExtern): pass if type_info.IsState: Gen._export_funcs.add('_type_union_cast') return self._HandleTypeCastLlvm(Node.args[0], target_type_str) def _HandleTypeCastLlvm(self, expr_node: ast.AST, target_type_str: str) -> ir.Value | None: Gen = self.Trans.LlvmGen val = self.HandleExprLlvm(expr_node) if val is None: return Gen.emit_constant(0, target_type_str) target_type = Gen._CType2LLVM(target_type_str) if not target_type: return val if val.type == target_type: if Gen._is_type_unsigned(target_type_str): Gen._unsigned_results[id(val)] = True return val src_is_float = isinstance(val.type, (ir.FloatType, ir.DoubleType)) dst_is_float = isinstance(target_type, (ir.FloatType, ir.DoubleType)) src_is_int = isinstance(val.type, ir.IntType) dst_is_int = isinstance(target_type, ir.IntType) src_IsPtr = isinstance(val.type, ir.PointerType) dst_IsPtr = isinstance(target_type, ir.PointerType) if src_is_int and dst_is_float: is_unsigned = Gen._check_node_unsigned(expr_node) if is_unsigned: return Gen.builder.uitofp(val, target_type, name="uint2float") return Gen.builder.sitofp(val, target_type, name="int2float") if src_is_float and dst_is_int: return Gen.builder.fptosi(val, target_type, name="float2int") if src_is_int and dst_is_int: is_dst_unsigned = Gen._is_type_unsigned(target_type_str) if val.type.width < target_type.width: if val.type.width == 1: # i1 是布尔值(来自 icmp/fcmp/__contains__),无符号语义,必须 zext result = Gen.builder.zext(val, target_type, name="zext_bool_cast") else: is_unsigned = Gen._check_node_unsigned(expr_node) if is_unsigned or is_dst_unsigned: result = Gen.builder.zext(val, target_type, name="zext_cast") else: result = Gen.builder.sext(val, target_type, name="sext_cast") if is_dst_unsigned: Gen._unsigned_results[id(result)] = True return result if val.type.width > target_type.width: result = Gen.builder.trunc(val, target_type, name="trunc_cast") if is_dst_unsigned: Gen._unsigned_results[id(result)] = True return result if is_dst_unsigned: Gen._unsigned_results[id(val)] = True return val if src_is_float and dst_is_float: if isinstance(val.type, ir.FloatType) and isinstance(target_type, ir.DoubleType): return Gen.builder.fpext(val, target_type, name="fpext_cast") if isinstance(val.type, ir.DoubleType) and isinstance(target_type, ir.FloatType): return Gen.builder.fptrunc(val, target_type, name="fptrunc_cast") return val if src_IsPtr and dst_is_int: if target_type.width < 64: ptr_to_i64 = Gen.builder.ptrtoint(val, ir.IntType(64), name="ptr2i64") return Gen.builder.trunc(ptr_to_i64, target_type, name="ptr2int_cast") return Gen.builder.ptrtoint(val, target_type, name="ptr2int_cast") if src_is_int and dst_IsPtr: return Gen.builder.inttoptr(val, target_type, name="int2ptr_cast") if src_IsPtr and dst_IsPtr: if isinstance(val.type.pointee, ir.PointerType) and isinstance(target_type.pointee, ir.IntType): Loaded = Gen._load(val, name="load_ptr") return Loaded return Gen.builder.bitcast(val, target_type, name="ptrcast") try: return Gen.builder.bitcast(val, target_type, name="cast") except Exception: # 回退:bitcast 失败时返回原值 return val def _HandleREnumConstructLlvm(self, Node: ast.Call, RenumName: str, VariantName: str, TagValue: int) -> ir.Value | None: Gen = self.Trans.LlvmGen if RenumName not in Gen.structs: self.Trans.ImportHandler._TryLoadStructFromStub(RenumName, Gen) if RenumName not in Gen.structs: return None RenumType = Gen.structs[RenumName] result = Gen._allocaEntry(RenumType, name=f"{RenumName}_{VariantName}") tag_ptr = Gen.builder.gep(result, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="renum_tag_ptr") Gen._store(ir.Constant(ir.IntType(32), TagValue), tag_ptr) NestedStructName = f"{RenumName}_{VariantName}" if NestedStructName in Gen.structs and Node.args: NestedStructType = Gen.structs[NestedStructName] NestedStructPtrType = ir.PointerType(NestedStructType) variant_ptr = Gen.builder.bitcast(result, NestedStructPtrType, name=f"cast_{NestedStructName}") members = Gen.class_members.get(NestedStructName, []) payLoad_members = [(n, t) for n, t in members if n != '__tag'] for i, arg in enumerate(Node.args): if i < len(payLoad_members): member_name, member_type = payLoad_members[i] ArgVal = self.HandleExprLlvm(arg) if ArgVal: Coerced = Gen._coerce_value(ArgVal, member_type) if Coerced is not None: ArgVal = Coerced elem_ptr = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i + 1)], name=f"{VariantName}_{member_name}") # REnum 嵌套结构体共享 max_variant_struct 布局,成员类型可能与 # 结构体字段类型不一致(如 Bits:i32 与 Ret:LLVMType* 重叠)。 # 需 bitcast elem_ptr 到成员类型,避免 _store 按 struct 字段类型做错误转换。 if isinstance(elem_ptr.type, ir.PointerType) and elem_ptr.type.pointee != member_type: elem_ptr = Gen.builder.bitcast(elem_ptr, ir.PointerType(member_type), name=f"{VariantName}_{member_name}_cast") Gen._store(ArgVal, elem_ptr) return result def _HandleTypedefCastLlvm(self, Node: ast.Call, TypedefName: str) -> ir.Value: Gen = self.Trans.LlvmGen SymInfo = self.Trans.SymbolTable.lookup(TypedefName) if not SymInfo or not SymInfo.IsTypedef: return ir.Constant(ir.IntType(32), 0) # 确保 Name 已设置,以便 _resolve_typedef_ctype 能正确解析 if not SymInfo.Name: SymInfo.Name = TypedefName TargetType = Gen._ctype_to_llvm(SymInfo) if not Node.args: if isinstance(TargetType, ir.IntType): return ir.Constant(TargetType, 0) elif isinstance(TargetType, ir.PointerType): return ir.Constant(TargetType, None) return ir.Constant(ir.IntType(32), 0) ArgVal = self.HandleExprLlvm(Node.args[0]) if not ArgVal: if isinstance(TargetType, ir.IntType): return ir.Constant(TargetType, 0) return ir.Constant(ir.IntType(32), 0) if ArgVal.type == TargetType: return ArgVal if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, ir.IntType): if ArgVal.type.width < TargetType.width: return Gen.builder.zext(ArgVal, TargetType, name=f"zext_{TypedefName}_cast") elif ArgVal.type.width > TargetType.width: return Gen.builder.trunc(ArgVal, TargetType, name=f"trunc_{TypedefName}_cast") return ArgVal if isinstance(TargetType, ir.PointerType): if isinstance(ArgVal.type, ir.PointerType): return Gen.builder.bitcast(ArgVal, TargetType, name=f"bitcast_{TypedefName}_cast") if isinstance(ArgVal.type, ir.IntType): return Gen.builder.inttoptr(ArgVal, TargetType, name=f"inttoptr_{TypedefName}_cast") # 如果参数是结构体值,需要 alloca 并返回指针 if isinstance(ArgVal.type, ir.BaseStructType): alloca = Gen.builder.alloca(ArgVal.type, name=f"struct_alloca_{TypedefName}") Gen.builder.store(ArgVal, alloca, align=8) return Gen.builder.bitcast(alloca, TargetType, name=f"bitcast_struct_{TypedefName}") if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, ir.PointerType): return Gen.builder.ptrtoint(ArgVal, TargetType, name=f"ptrtoint_{TypedefName}_cast") if isinstance(TargetType, (ir.FloatType, ir.DoubleType)) and isinstance(ArgVal.type, ir.IntType): return Gen.builder.sitofp(ArgVal, TargetType, name=f"sitofp_{TypedefName}_cast") if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, (ir.FloatType, ir.DoubleType)): return Gen.builder.fptosi(ArgVal, TargetType, name=f"fptosi_{TypedefName}_cast") return ArgVal def _HandleInlineExpandLlvm(self, Node: ast.Call, sym_info: CTypeInfo) -> None: Gen = self.Trans.LlvmGen inline_body = sym_info.InlineBody inline_params = sym_info.InlineParams or [] call_args = [] for arg in Node.args: call_args.append(self.Trans.ExprHandler.HandleExprLlvm(arg)) saved_vars = {} for i, param_name in enumerate(inline_params): if i < len(call_args): saved_vars[param_name] = call_args[i] old_var_scopes = list(self.Trans.VarScopes) for param_name, val in saved_vars.items(): if val is not None: alloca = Gen._allocaEntry(val.type, name=f"inline_arg_{param_name}") Gen._store(val, alloca) self.Trans.VarScopes.append((param_name, alloca)) self.Trans.BodyHandler.HandleBodyLlvm(inline_body) for param_name, _ in saved_vars.items(): if self.Trans.VarScopes and self.Trans.VarScopes[-1][0] == param_name: self.Trans.VarScopes.pop() self.Trans.VarScopes = old_var_scopes return None def _HandleClosureCallLlvm(self, Node: ast.Call, FuncName: str) -> ir.Value: Gen = self.Trans.LlvmGen func = Gen.functions.get(FuncName) if not func: if FuncName in self.Trans.FunctionDefCache: FuncDef = self.Trans.FunctionDefCache[FuncName] self.Trans.FunctionHandler._EmitFunctionForwardDeclLlvm(FuncDef, Gen) func = Gen.functions.get(FuncName) if not func: func = self._try_declare_c_lib_func(FuncName, Gen) if not func: raise Exception(f"Undefined function: '{FuncName}'") FuncDef = self.Trans.FunctionDefCache.get(FuncName) param_names = [] FuncDef_args = getattr(FuncDef, 'args', None) if FuncDef else None if FuncDef_args: param_names = [arg.arg for arg in FuncDef.args.args] # 回退到全局参数名表(支持跨模块 include 函数) if not param_names: global_param_names = getattr(self.Trans, '_global_function_param_names', {}) param_names = global_param_names.get(FuncName) or [] num_params = len(func.function_type.args) nonlocal_param_count = len(Gen.nonlocal_params.get(FuncName, [])) eh_msg_out_count = 0 if num_params > 0 and func.args: for arg in func.args: if arg.name in ('__eh_msg_out__', '__eh_code_out__'): eh_msg_out_count += 1 regular_param_count = num_params - nonlocal_param_count - eh_msg_out_count is_variadic = False func_ft = getattr(func, 'function_type', None) is_variadic = getattr(func_ft, 'var_arg', False) if func_ft else False if not is_variadic and len(Node.args) > regular_param_count: raise Exception(f"调用 {FuncName}() 传入了 {len(Node.args)} 个参数,但函数只需要 {regular_param_count} 个参数") max_args = len(Node.args) if is_variadic else regular_param_count resolved = [None] * max_args for i, arg in enumerate(Node.args): if i < max_args: arg_var_type = None if i < num_params: arg_var_type = func.function_type.args[i] ArgVal = self.HandleExprLlvm(arg, VarType=arg_var_type) if ArgVal: resolved[i] = ArgVal for kw in Node.keywords: if kw.arg is None: if isinstance(kw.value, ast.Dict): pass elif isinstance(kw.value, ast.Call): pass continue ArgVal = self.HandleExprLlvm(kw.value) if not ArgVal: continue kw_name = kw.arg if kw_name in param_names: idx = param_names.index(kw_name) if idx < regular_param_count: resolved[idx] = ArgVal FuncDef_args_defaults = getattr(getattr(FuncDef, 'args', None), 'defaults', []) if FuncDef else [] if FuncDef_args_defaults: defaults = FuncDef.args.defaults num_defaults = len(defaults) if num_defaults > 0: min_args = regular_param_count - num_defaults for i in range(regular_param_count): if resolved[i] is None and i >= min_args: default_idx = i - min_args if default_idx < len(defaults): default_node = defaults[default_idx] default_val = self.HandleExprLlvm(default_node) if default_val: param_type = func.function_type.args[i] if default_val.type != param_type: if isinstance(param_type, ir.IntType) and isinstance(default_val.type, ir.IntType): if default_val.type.width < param_type.width: default_val = Gen.builder.zext(default_val, param_type, name=f"zext_default_{i}") elif default_val.type.width > param_type.width: default_val = Gen.builder.trunc(default_val, param_type, name=f"trunc_default_{i}") elif isinstance(param_type, ir.PointerType) and isinstance(default_val.type, ir.IntType): default_val = Gen.builder.inttoptr(default_val, param_type, name=f"inttoptr_default_{i}") resolved[i] = default_val if FuncDef and param_names: min_args = regular_param_count - num_defaults if FuncDef_args_defaults else regular_param_count provided = len(Node.args) kw_provided = set() for kw in Node.keywords: if kw.arg and kw.arg in param_names: kw_provided.add(param_names.index(kw.arg)) for i in range(min(min_args, len(param_names))): if i >= provided and i not in kw_provided: raise Exception(f"调用 {FuncName}() 缺少必需参数 '{param_names[i]}',该参数没有默认值") CallArgs = [] for i in range(max_args): if resolved[i] is not None: CallArgs.append(resolved[i]) elif i < regular_param_count: arg_type = func.function_type.args[i] if isinstance(arg_type, ir.PointerType): CallArgs.append(ir.Constant(arg_type, None)) elif isinstance(arg_type, (ir.IdentifiedStructType, ir.LiteralStructType)): zero_val = Gen._zero_value_for_type(arg_type) if zero_val is not None: CallArgs.append(zero_val) else: CallArgs.append(ir.Constant(ir.PointerType(arg_type), None)) elif isinstance(arg_type, ir.ArrayType): zero_val = Gen._zero_value_for_type(arg_type) if zero_val is not None: CallArgs.append(zero_val) else: CallArgs.append(ir.Constant(arg_type, 0)) else: CallArgs.append(ir.Constant(arg_type, 0)) if FuncName in Gen.nonlocal_params: for var_name, ptr_type in Gen.nonlocal_params[FuncName]: if var_name in Gen.variables and Gen.variables[var_name] is not None: CallArgs.append(Gen.variables[var_name]) elif var_name in Gen._reg_values: OldVal = Gen._reg_values[var_name] var = Gen._allocaEntry(OldVal.type, name=var_name) Gen._store(OldVal, var) Gen.variables[var_name] = var del Gen._reg_values[var_name] CallArgs.append(var) self._append_eh_msg_out_arg(CallArgs, func, Gen) if is_variadic: # 对于可变参数函数,需要手动处理参数类型转换 adjusted = [] for i, arg in enumerate(CallArgs): if i < num_params: # 固定参数:尝试类型转换 param_type = func.function_type.args[i] if arg.type != param_type: try: if isinstance(arg.type, ir.IntType) and isinstance(param_type, ir.PointerType): adjusted.append(self.builder.inttoptr(arg, param_type)) elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.IntType): adjusted.append(Gen.builder.ptrtoint(arg, param_type)) elif isinstance(arg.type, ir.IntType) and arg.type.width < param_type.width: adjusted.append(Gen.builder.zext(arg, param_type)) elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.PointerType): adjusted.append(Gen.builder.bitcast(arg, param_type, name=f"cast_arg_{i}")) else: adjusted.append(arg) except Exception: # 回退:参数类型调整失败时使用原值 if isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.PointerType): try: adjusted.append(Gen.builder.bitcast(arg, param_type, name=f"cast_arg_{i}")) except Exception: adjusted.append(arg) else: adjusted.append(arg) else: adjusted.append(arg) else: # 可变参数:应用默认参数提升(float -> double, i32 -> i64) if isinstance(arg.type, ir.FloatType): arg = Gen.builder.fpext(arg, ir.DoubleType(), name=f"fpext_vararg_{FuncName}") elif isinstance(arg.type, ir.IntType) and arg.type.width < 64: # i1 是布尔值(来自 icmp/fcmp/__contains__),无符号语义,必须 zext if arg.type.width == 1: arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_bool_vararg_{FuncName}") else: # 有符号整数用 sext,无符号整数用 zext is_signed = True arg_node = Node.args[i] if i < len(Node.args) else None if arg_node is not None: is_u = Gen._check_node_unsigned(arg_node) if is_u: is_signed = False if is_signed: arg = Gen.builder.sext(arg, ir.IntType(64), name=f"sext_vararg_{FuncName}") else: arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_vararg_{FuncName}") adjusted.append(arg) result = Gen.builder.call(func, adjusted, name=f"call_{FuncName}") else: CallArgs = Gen._apply_auto_addr(FuncName, CallArgs) adjusted = Gen._adjust_args(CallArgs, func) # 兜底:确保所有指针类型参数与函数签名匹配(如 struct* -> i8*) for i, (arg, param) in enumerate(zip(adjusted, func.args)): if arg.type != param.type: if isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.PointerType): adjusted[i] = Gen.builder.bitcast(arg, param.type, name=f"cast_arg_{i}") result = Gen.builder.call(func, adjusted, name=f"call_{FuncName}") self._check_eh_return(result, FuncName, Gen, called_func=func) return result def _try_register_vtable_ondemand(self, ClassName: str, class_sha1: str, Gen: "LlvmGeneratorMixin") -> None: """按需 vtable 注册:从 .pyi stub 检查 @t.CVTable 并注册到 vtable 集合。 当 vcall 决策点发现 ClassName 不在 vtable 集合中时调用。 读取 temp/{sha1}.pyi 文件,查找 ClassName 的 ClassDef, 检查 @t.CVTable 装饰器,注册 vtable 和方法列表。 """ try: import_handler = self.Trans.ImportHandler project_root = import_handler._find_project_root() pyi_path = os.path.join(project_root, 'temp', f'{class_sha1}.pyi') if not os.path.isfile(pyi_path): return with open(pyi_path, 'r', encoding='utf-8') as f: pyi_code = f.read() pyi_tree = ast.parse(pyi_code) # 查找目标 ClassDef target_node: ast.ClassDef | None = None for node in ast.iter_child_nodes(pyi_tree): if isinstance(node, ast.ClassDef) and node.name == ClassName: target_node = node break if target_node is None: return # 检查 @t.CVTable 装饰器 is_cvtable: bool = False for decorator in target_node.decorator_list: if isinstance(decorator, ast.Attribute) and getattr(decorator.value, 'id', None) == 't' and decorator.attr == 'CVTable': is_cvtable = True break if isinstance(decorator, ast.Call): inner = decorator.func if isinstance(inner, ast.Attribute) and getattr(inner.value, 'id', None) == 't' and inner.attr == 'CVTable': is_cvtable = True break if isinstance(inner, ast.Name) and inner.id == 'CVTable': is_cvtable = True break if isinstance(decorator, ast.Name) and decorator.id == 'CVTable': is_cvtable = True break if not is_cvtable: return # 注册到 vtable 集合(共享集合) Gen._cross_module_vtable_classes.add(ClassName) Gen.class_vtable.add(ClassName) # 预注册方法列表(与 prescan 逻辑一致) if ClassName not in Gen.class_methods: Gen.class_methods[ClassName] = [] for item in target_node.body: if isinstance(item, ast.FunctionDef): method_name = item.name # 构造函数不放入 vtable(避免子类与基类 vtable 大小不一致破坏多态分派) if method_name in ('__new__', '__init__', '__before_init__'): continue if method_name == '__init__': full_name = f"{ClassName}.__init__" elif method_name == '__call__': full_name = f"{ClassName}.__call__" else: full_name = f"{ClassName}.{method_name}" if full_name not in Gen.class_methods[ClassName]: Gen.class_methods[ClassName].append(full_name) except Exception: pass def _HandleMethodCallLlvm(self, Node: ast.Call) -> ir.Value: Gen = self.Trans.LlvmGen MethodName = Node.func.attr # 检查是否为 @staticmethod 或 @classmethod,如果是则走特殊路径 if isinstance(Node.func.value, ast.Name): VarName = Node.func.value.id ClassName = Gen.var_struct_class.get(VarName) if ClassName: SymKey = f'{ClassName}.{MethodName}' SymInfo = self.Trans.SymbolTable.lookup(SymKey) if SymInfo and SymInfo.MetaList: if FuncMeta.STATIC_METHOD in SymInfo.MetaList: return self._HandleStaticMethodCallLlvm(Node, ClassName, MethodName) if FuncMeta.CLASS_METHOD in SymInfo.MetaList: return self._HandleStaticMethodCallLlvm(Node, ClassName, MethodName) if isinstance(Node.func.value, ast.Name) and IsTModule(Node.func.value.id, self.Trans.SymbolTable): result = self.Trans.TSpecialCallHandle._HandleTSpecialCallLlvm(Node) if result is not None: return result ctype_cls = CTypeRegistry.GetClassByName(MethodName) if ctype_cls is not None: try: ctype_inst = ctype_cls() except Exception: ctype_inst = None target_bits = getattr(ctype_inst, 'Size', None) if ctype_inst else None if target_bits is None: target_bits = 0 is_float = getattr(ctype_inst, 'IsSigned', False) is None and target_bits > 0 if ctype_inst else False IsPtr_cast = len(Node.args) >= 2 and ( (isinstance(Node.args[1], ast.Attribute) and Node.args[1].attr == 'CPtr' and isinstance(Node.args[1].value, ast.Name) and IsTModule(Node.args[1].value.id, self.Trans.SymbolTable)) or (isinstance(Node.args[1], ast.Name) and Node.args[1].id == 'CPtr') ) if Node.args: ArgNode = Node.args[0] if isinstance(ArgNode, ast.Subscript): SubscriptPtr = self._HandleSubscriptPtrLlvm(ArgNode) if SubscriptPtr: if MethodName == 'CPtr' or IsPtr_cast: return SubscriptPtr if isinstance(SubscriptPtr.type, ir.PointerType): val = Gen._load(SubscriptPtr, name="Load_subscript_val") else: val = SubscriptPtr if target_bits > 0 and isinstance(val.type, ir.IntType) and not is_float: if val.type.width < target_bits: val = Gen.builder.zext(val, ir.IntType(target_bits), name="zext_cast") elif val.type.width > target_bits: val = Gen.builder.trunc(val, ir.IntType(target_bits), name="trunc_cast") return val val = self.HandleExprLlvm(ArgNode) if IsPtr_cast: if target_bits > 0 and not is_float: target_ptr_type = ir.PointerType(ir.IntType(target_bits)) elif is_float and target_bits == 32: target_ptr_type = ir.PointerType(ir.FloatType()) elif is_float and target_bits == 64: target_ptr_type = ir.PointerType(ir.DoubleType()) else: target_ptr_type = ir.PointerType(ir.IntType(8)) if isinstance(val.type, ir.PointerType): if val.type != target_ptr_type: val = Gen.builder.bitcast(val, target_ptr_type, name="ptr_cast") elif isinstance(val.type, ir.IntType): if val.type.width < 64: val = Gen.builder.zext(val, ir.IntType(64), name="zext_ptr_cast") val = Gen.builder.inttoptr(val, target_ptr_type, name="int_to_ptr_cast") return val if val and target_bits > 0 and not is_float: if isinstance(val.type, ir.IntType): if val.type.width < target_bits: val = Gen.builder.zext(val, ir.IntType(target_bits), name="zext_cast") elif val.type.width > target_bits: val = Gen.builder.trunc(val, ir.IntType(target_bits), name="trunc_cast") elif isinstance(val.type, ir.PointerType): val = Gen.builder.ptrtoint(val, ir.IntType(target_bits), name="ptrtoint_cast") return val if is_float: return ir.Constant(ir.FloatType() if target_bits == 32 else ir.DoubleType(), 0.0) return ir.Constant(ir.IntType(target_bits) if target_bits > 0 else ir.IntType(32), 0) if self.Trans.SymbolTable.has(MethodName): SymInfo = self.Trans.SymbolTable[MethodName] if SymInfo.IsTypedef: return self._HandleTypedefCastLlvm(Node, MethodName) if isinstance(Node.func.value, ast.Name) and Node.func.value.id == 'c': if MethodName == 'Asm': return self.Trans.ExprAsmHandle._HandleAsmLlvm(Node) if MethodName == 'Addr': return self.Trans.CSpecialCallHandle._HandleCAddrLlvm(Node) elif MethodName == 'Set': return self.Trans.CSpecialCallHandle._HandleCSetLlvm(Node) elif MethodName == 'Load': return self.Trans.CSpecialCallHandle._HandleCLoadLlvm(Node) elif MethodName == 'Deref': return self.Trans.CSpecialCallHandle._HandleCDerefLlvm(Node) elif MethodName == 'DerefAs': return self._HandleCDerefAsLlvm(Node) elif MethodName == 'PtrToInt': return self.Trans.CSpecialCallHandle._HandleCPtrToIntLlvm(Node) elif MethodName in ('CIf', 'CElif'): if Node.args: ArgVal = self.HandleExprLlvm(Node.args[0]) if ArgVal: if isinstance(ArgVal, ir.Constant) and isinstance(ArgVal.type, ir.IntType): return ir.Constant(ir.IntType(1), 1 if ArgVal.constant != 0 else 0) if isinstance(ArgVal.type, ir.IntType): return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond") if isinstance(ArgVal.type, ir.PointerType): return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond") return ir.Constant(ir.IntType(1), 0) elif MethodName in ('CIfdef', 'CIfndef'): return ir.Constant(ir.IntType(1), 1) elif MethodName == 'CError': msg = "compile-time error" if Node.args: arg = Node.args[0] if isinstance(arg, ast.Constant) and isinstance(arg.value, str): msg = arg.value else: try: val = self.HandleExprLlvm(arg) if isinstance(val, str): msg = val except Exception as _e: if _config_mode == "strict": raise _vlog().warning(f"处理函数调用失败: {_e}", "Exception") lineno = getattr(Node, 'lineno', 0) raise Exception(f"#error: {msg} (line {lineno})") elif MethodName in ('CElse', 'CEndif', 'CPragma', 'CUndef'): return ir.Constant(ir.IntType(1), 1) elif MethodName in ('LLVMIR', 'LInp', 'LOut'): return None ObjVal = self.HandleExprLlvm(Node.func.value) if not ObjVal: return None if isinstance(ObjVal.type, (ir.IdentifiedStructType, ir.LiteralStructType)): if isinstance(Node.func.value, ast.Name): var_name = Node.func.value.id if var_name in Gen.variables: var_ptr = Gen.variables[var_name] if isinstance(var_ptr.type, ir.PointerType) and isinstance(var_ptr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): ObjVal = var_ptr else: tmp = Gen._allocaEntry(ObjVal.type, name="chain_method_tmp") Gen._store(ObjVal, tmp) ObjVal = tmp else: tmp = Gen._allocaEntry(ObjVal.type, name="chain_method_tmp") Gen._store(ObjVal, tmp) ObjVal = tmp else: tmp = Gen._allocaEntry(ObjVal.type, name="chain_method_tmp") Gen._store(ObjVal, tmp) ObjVal = tmp if isinstance(Node.func.value, ast.Name): ModuleName = Node.func.value.id imported = getattr(self.Trans, '_ImportedModules', set()) actual_module = self.Trans.SymbolTable.resolve_alias(ModuleName) if ModuleName in imported or actual_module in imported: mangled_name = Gen._mangle_func_name(MethodName, actual_module) if Gen._has_function(mangled_name): CallArgs = [] for arg in Node.args: ArgVal = self.HandleExprLlvm(arg) if ArgVal: CallArgs.append(ArgVal) func = Gen._get_function(mangled_name) self._fill_default_args(CallArgs, func, MethodName) func_ft = getattr(func, 'function_type', None) is_variadic = getattr(func_ft, 'var_arg', False) if func_ft else False num_fixed_params = len(func_ft.args) if func_ft else 0 if is_variadic: adjusted = [] for i, arg in enumerate(CallArgs): if i < num_fixed_params: param_type = func_ft.args[i] if arg.type != param_type: try: if isinstance(arg.type, ir.IntType) and isinstance(param_type, ir.PointerType): adjusted.append(self.builder.inttoptr(arg, param_type)) elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.IntType): adjusted.append(Gen.builder.ptrtoint(arg, param_type)) elif isinstance(arg.type, ir.IntType) and arg.type.width < param_type.width: adjusted.append(Gen.builder.zext(arg, param_type)) else: adjusted.append(arg) except Exception: # 回退:参数类型调整失败时使用原值 adjusted.append(arg) else: adjusted.append(arg) else: if isinstance(arg.type, ir.FloatType): arg = Gen.builder.fpext(arg, ir.DoubleType(), name=f"fpext_vararg_{MethodName}") elif isinstance(arg.type, ir.IntType) and arg.type.width < 64: if arg.type.width == 1: arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_bool_vararg_{MethodName}") else: is_signed = True arg_node = Node.args[i] if i < len(Node.args) else None if arg_node is not None: is_u = Gen._check_node_unsigned(arg_node) if is_u: is_signed = False if is_signed: arg = Gen.builder.sext(arg, ir.IntType(64), name=f"sext_vararg_{MethodName}") else: arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_vararg_{MethodName}") adjusted.append(arg) result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}") else: CallArgs = Gen._apply_auto_addr(MethodName, CallArgs) adjusted = Gen._adjust_args(CallArgs, func) result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}") return result if Gen._has_function(MethodName): _mf = Gen._get_function(MethodName) if '.' not in _mf.name: CallArgs = [] for arg in Node.args: ArgVal = self.HandleExprLlvm(arg) if ArgVal: CallArgs.append(ArgVal) func = _mf self._fill_default_args(CallArgs, func, MethodName) func_ft = getattr(func, 'function_type', None) is_variadic = getattr(func_ft, 'var_arg', False) if func_ft else False num_fixed_params = len(func_ft.args) if func_ft else 0 if is_variadic: adjusted = [] for i, arg in enumerate(CallArgs): if i < num_fixed_params: param_type = func_ft.args[i] if arg.type != param_type: try: if isinstance(arg.type, ir.IntType) and isinstance(param_type, ir.PointerType): adjusted.append(self.builder.inttoptr(arg, param_type)) elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.IntType): adjusted.append(Gen.builder.ptrtoint(arg, param_type)) elif isinstance(arg.type, ir.IntType) and arg.type.width < param_type.width: adjusted.append(Gen.builder.zext(arg, param_type)) else: adjusted.append(arg) except Exception: # 回退:参数类型调整失败时使用原值 adjusted.append(arg) else: adjusted.append(arg) else: if isinstance(arg.type, ir.FloatType): arg = Gen.builder.fpext(arg, ir.DoubleType(), name=f"fpext_vararg_{MethodName}") elif isinstance(arg.type, ir.IntType) and arg.type.width < 64: if arg.type.width == 1: arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_bool_vararg_{MethodName}") else: is_signed = True arg_node = Node.args[i] if i < len(Node.args) else None if arg_node is not None: is_u = Gen._check_node_unsigned(arg_node) if is_u: is_signed = False if is_signed: arg = Gen.builder.sext(arg, ir.IntType(64), name=f"sext_vararg_{MethodName}") else: arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_vararg_{MethodName}") adjusted.append(arg) result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}") else: CallArgs = Gen._apply_auto_addr(MethodName, CallArgs) adjusted = Gen._adjust_args(CallArgs, func) result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}") return result stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen) if not stub_func_type: stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(MethodName, Gen) if not stub_func_type and mangled_name != MethodName: for sha1 in getattr(Gen, 'ModuleSha1Map', {}).values(): alt_name = f"{sha1}.{MethodName}" stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(alt_name, Gen) if stub_func_type: mangled_name = alt_name break if stub_func_type: func = self.GetOrCreateStubFuncDecl(mangled_name, stub_func_type, Gen) CallArgs = [] for arg in Node.args: ArgVal = self.HandleExprLlvm(arg) if ArgVal: CallArgs.append(ArgVal) self._fill_default_args(CallArgs, func, mangled_name) self._append_eh_msg_out_arg(CallArgs, func, Gen) CallArgs = Gen._apply_auto_addr(mangled_name, CallArgs) adjusted = Gen._adjust_args(CallArgs, func) result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}") self._check_eh_return(result, mangled_name, Gen, called_func=func) return result return ir.Constant(ir.IntType(32), 0) CallArgs = [] for arg in Node.args: ArgVal = self.HandleExprLlvm(arg) if ArgVal: CallArgs.append(ArgVal) ClassName = None if isinstance(Node.func.value, ast.Name): ClassName = Gen.var_struct_class.get(Node.func.value.id) if not ClassName and isinstance(Node.func.value, ast.Attribute): # 链式属性访问(如 func.Params.append):通过 _get_var_class 推导泛型特化类名 ClassName = self.Trans.ExprHandler._get_var_class(Node.func.value, Gen) if not ClassName: for CN, ST in Gen.structs.items(): if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == ST: ClassName = CN break if not ClassName and self._is_char_pointer(ObjVal): MethodName = Node.func.attr # FakeDuck: 检查是否有影子结构体 a__meta__ (per-instance 字段存储) meta_ptr: ir.Value | None = None if isinstance(Node.func.value, ast.Name): meta_name = f"{Node.func.value.id}__meta__" if meta_name in Gen.variables: meta_ptr = Gen.variables[meta_name] for CN, ST in Gen.structs.items(): method_key = f'{CN}.{MethodName}' if not Gen._has_function(method_key): continue # FakeDuck: 不跳过空结构体 (扩展类可能没有数据成员只有方法) try: # 如果有影子结构体且该类有字段, 使用影子结构体作为 self (而非 bitcast char*) if meta_ptr is not None and hasattr(ST, 'elements') and len(ST.elements) > 0: ObjVal = meta_ptr elif CN == '_str' and hasattr(ST, 'elements') and len(ST.elements) > 0: # FakeDuck: 字符串字面量/匿名 str 表达式调用 _str 方法时, # 创建临时影子结构体 (栈上), 设置 __data__ 和 __mbuddy__ 字段。 # bitcast i8* → _str* 会导致读取垃圾指针 → ACCESS_VIOLATION tmp_meta: ir.AllocaInstr = Gen._allocaEntry(ST, name="tmp_str_meta") _data_off = Gen._get_member_offset('__data__', '_str') if _data_off is not None: _data_ptr = Gen.builder.gep(tmp_meta, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _data_off)], name="tmp_str_data") Gen._store(ObjVal, _data_ptr) _mpool_off = Gen._get_member_offset('__mbuddy__', '_str') if _mpool_off is not None: _mpool_ptr = Gen.builder.gep(tmp_meta, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _mpool_off)], name="tmp_str_mbuddy") Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), _mpool_ptr) # 从 with 上下文自动注入 requires 字段 (如 __mbuddy__) self._InjectRequiresFields(tmp_meta, '_str', Gen) ObjVal = tmp_meta else: casted = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}") ObjVal = casted ClassName = CN break except Exception: # 回退:bitcast 失败时尝试下一个类 continue if not ClassName and isinstance(Node.func.value, ast.Call): if isinstance(Node.func.value.func, ast.Attribute): InnerAttrName = Node.func.value.func.attr for CN in Gen.structs: if CN.endswith(f'__{InnerAttrName}') or f'__{InnerAttrName}' in CN: continue method_name = f'{CN}__{InnerAttrName}' if Gen._has_function(method_name): func = Gen._get_function(method_name) ret_type = func.fnty.return_type if isinstance(ret_type, ir.PointerType): for CN2, ST in Gen.structs.items(): if ret_type.pointee == ST: ClassName = CN2 break elif isinstance(ret_type, ir.IdentifiedStructType): for CN2, ST in Gen.structs.items(): if ret_type == ST: ClassName = CN2 break if ClassName: break if not ClassName: return ir.Constant(ir.IntType(32), 0) struct_sha1_map = getattr(Gen, '_struct_sha1_map', {}) class_sha1 = struct_sha1_map.get(ClassName) if class_sha1: FullMethodName = f'{class_sha1}.{ClassName}.{MethodName}' else: FullMethodName = f'{ClassName}.{MethodName}' # 提前查找函数以获取参数信息 func_for_kw = Gen._find_function(FullMethodName) if not func_for_kw: func_for_kw = Gen._find_function(f'{FullMethodName}__') if not func_for_kw and class_sha1: func_for_kw = Gen._find_function(f'{ClassName}.{MethodName}') # 处理关键字参数: 先用 _fill_default_args 填充默认值,再用 keyword args 覆盖 if Node.keywords and func_for_kw: # 优先从全局参数名表获取 Python 参数名(支持跨模块 include 函数) global_param_names = getattr(self.Trans, '_global_function_param_names', {}) param_names = global_param_names.get(FullMethodName) if not param_names: param_names = global_param_names.get(f'{ClassName}.{MethodName}') if not param_names: # 回退到 LLVM 函数参数名(仅当参数名不是自动生成的数字名时有效) llvm_names = [arg.name for arg in func_for_kw.args] if func_for_kw.args else [] # 检测是否为 LLVM 自动生成的数字名(如 "0", "1", "2") if llvm_names and not all(n.isdigit() for n in llvm_names): param_names = llvm_names if param_names: # 构造临时 call_args (含 self) 调用 _fill_default_args 填充默认值 temp_call_args = [ObjVal] + list(CallArgs) self._fill_default_args(temp_call_args, func_for_kw, FullMethodName) # 提取回非 self 参数 (现在已填充默认值) CallArgs.clear() CallArgs.extend(temp_call_args[1:]) # 用 keyword args 覆盖对应位置 for kw in Node.keywords: if kw.arg is None: continue ArgVal = self.HandleExprLlvm(kw.value) if not ArgVal: continue kw_name = kw.arg if kw_name in param_names: idx = param_names.index(kw_name) # idx 0 是 self, 所以 CallArgs 中的偏移是 idx-1 target_idx = idx - 1 if 0 <= target_idx < len(CallArgs): CallArgs[target_idx] = ArgVal # 按需 vtable 注册:当 ClassName 不在 vtable 集合中但有 class_sha1 时, # 从 .pyi stub 检查 @t.CVTable 装饰器并注册。 # 修复场景:list[str].__new__ 中 pool.alloc(48) 编译时, # MemManager 可能因导入时序问题未注册到当前 Gen 的 vtable 集合, # 导致生成 call_(直接调用)而非 vcall_(虚分派),运行时段错误。 if (ClassName not in Gen.class_vtable and ClassName not in Gen._cross_module_vtable_classes and class_sha1): self._try_register_vtable_ondemand(ClassName, class_sha1, Gen) if (ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes) and ClassName in Gen.class_methods: methods = Gen.class_methods[ClassName] method_idx = -1 for mi, mn in enumerate(methods): if mn == FullMethodName or mn == MethodName or mn.endswith(f'.{MethodName}'): method_idx = mi break if method_idx >= 0: func = Gen._find_function(FullMethodName) if not func: func = Gen._find_function(f'{FullMethodName}__') if not func: p = Gen.class_parent.get(ClassName) while p: parent_full = f'{p}.{MethodName}' func = Gen._find_function(parent_full) if not func: func = Gen._find_function(f'{parent_full}__') if func: break p = Gen.class_parent.get(p) if func: VtableSlotPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}") VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}") VtableArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) VtableTyped = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}") MethodPtrAddr = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_ptr_addr_{MethodName}") MethodPtrI8 = Gen._load(MethodPtrAddr, name=f"vmethod_ptr_{MethodName}") FuncPtrType = ir.PointerType(func.function_type) MethodPtrTyped = Gen.builder.bitcast(MethodPtrI8, FuncPtrType, name=f"vmethod_typed_{MethodName}") call_args = [ObjVal] + CallArgs self._fill_default_args(call_args, func, FullMethodName) self._append_eh_msg_out_arg(call_args, func, Gen) adjusted = Gen._adjust_args(call_args, func) result = Gen.builder.call(MethodPtrTyped, adjusted, name=f"vcall_{FullMethodName}") self._check_eh_return(result, FullMethodName, Gen, called_func=func) return result func = Gen._find_function(FullMethodName) if not func: func = Gen._find_function(f'{FullMethodName}__') if not func and class_sha1: stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(FullMethodName, Gen) if stub_func_type: func = self.GetOrCreateStubFuncDecl(FullMethodName, stub_func_type, Gen) if not func and class_sha1: plain_name = f'{ClassName}.{MethodName}' stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(plain_name, Gen) if stub_func_type: func = self.GetOrCreateStubFuncDecl(FullMethodName, stub_func_type, Gen) # 最终回退:尝试无 sha1 前缀的函数名(与 func_for_kw 的双路径回退一致) if not func: plain_name = f'{ClassName}.{MethodName}' func = Gen._find_function(plain_name) if func: call_args = [ObjVal] + CallArgs self._fill_default_args(call_args, func, FullMethodName) self._append_eh_msg_out_arg(call_args, func, Gen) call_args = Gen._apply_auto_addr(FullMethodName, call_args) adjusted = Gen._adjust_args(call_args, func) result = Gen.builder.call(func, adjusted, name=f"call_{FullMethodName}") self._check_eh_return(result, FullMethodName, Gen, called_func=func) return result i8ptr = ir.PointerType(ir.IntType(8)) member_idx = -1 if ClassName in Gen.class_members: for mi, (mn, mt) in enumerate(Gen.class_members[ClassName]): if mn == MethodName: member_idx = mi break if member_idx >= 0 and isinstance(ObjVal.type, ir.PointerType): has_vtable = ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes base = 1 if has_vtable else 0 member_ptr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), base + member_idx)], name=f"funcptr_{MethodName}_ptr") raw_ptr = Gen._load(member_ptr, name=f"funcptr_{MethodName}_raw") func_ptr_type = ir.PointerType(ir.FunctionType(ir.IntType(32), [i8ptr] + [a.type for a in CallArgs])) typed_ptr = Gen.builder.bitcast(raw_ptr, func_ptr_type, name=f"funcptr_{MethodName}_typed") obj_as_i8 = Gen.builder.bitcast(ObjVal, i8ptr, name=f"funcptr_self_{ClassName}") call_args = [obj_as_i8] + CallArgs result = Gen.builder.call(typed_ptr, call_args, name=f"call_funcptr_{ClassName}.{MethodName}") return result if class_sha1 and ClassName in Gen.structs: struct_type = Gen.structs[ClassName] self_ptr_type = ir.PointerType(struct_type) param_types = [self_ptr_type] + [a.type for a in CallArgs] func_type = ir.FunctionType(ir.IntType(32), param_types) func = ir.Function(Gen.module, func_type, name=FullMethodName) Gen.functions[FullMethodName] = func if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == struct_type: call_self = ObjVal else: call_self = Gen.builder.bitcast(ObjVal, self_ptr_type, name=f"method_self_{ClassName}") adjusted = Gen._adjust_args([call_self] + CallArgs, func) result = Gen.builder.call(func, adjusted, name=f"call_{FullMethodName}") return result raise Exception(f"Undefined method '{MethodName}' in class '{ClassName}' (no function declaration found for '{FullMethodName}')") _C_LIB_FUNCS = { 'malloc': lambda: (ir.PointerType(ir.IntType(8)), [ir.IntType(64)]), 'calloc': lambda: (ir.PointerType(ir.IntType(8)), [ir.IntType(64), ir.IntType(64)]), 'realloc': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(64)]), 'free': lambda: (ir.VoidType(), [ir.PointerType(ir.IntType(8))]), 'strlen': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]), 'strlength': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]), 'memset': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.IntType(64)]), 'memcpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), 'memmove': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), 'memcmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), 'strcmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]), 'strncmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), 'strcpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]), 'strncpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), 'strcat': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]), 'puts': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]), 'atoi': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]), 'atol': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]), 'abs': lambda: (ir.IntType(32), [ir.IntType(32)]), 'labs': lambda: (ir.IntType(64), [ir.IntType(64)]), 'system': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]), } def _try_declare_c_lib_func(self, func_name: str, Gen: LlvmGeneratorMixin) -> ir.Function | None: if func_name not in self._C_LIB_FUNCS: return None ret_type, param_types = self._C_LIB_FUNCS[func_name]() func_type = ir.FunctionType(ret_type, param_types) func = ir.Function(Gen.module, func_type, name=func_name) Gen.functions[func_name] = func return func def _HandleLenLlvm(self, arg_node: ast.AST) -> ir.Value | None: Gen = self.Trans.LlvmGen if isinstance(arg_node, ast.Attribute) and isinstance(arg_node.value, ast.Name) and arg_node.value.id == 'self': attr_name = arg_node.attr len_member = f'{attr_name}__len' current_class = self.Trans._CurrentCpythonObjectClass if current_class and current_class in Gen.class_members: for m_name, m_type in Gen.class_members[current_class]: if m_name == len_member: self_val = Gen._get_var_ptr('self') if self_val: self_ptr = Gen._load(self_val, name="self_for_len") offset = Gen._get_member_offset(len_member, current_class) len_ptr = Gen.builder.gep(self_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"self_{len_member}_ptr") return Gen._load(len_ptr, name=f"self_{len_member}") val = self.HandleExprLlvm(arg_node) if not val: return None if isinstance(val.type, ir.PointerType): pointee = val.type.pointee if isinstance(pointee, ir.PointerType): val = Gen._load(val, name="len_deref") pointee = val.type.pointee if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): for CN, ST in Gen.structs.items(): if pointee == ST: result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__len__', val, Gen) if result is not None: return result break if isinstance(pointee, ir.ArrayType): return ir.Constant(ir.IntType(64), pointee.count) if isinstance(pointee, (ir.FloatType, ir.DoubleType, ir.IntType)) and pointee.width != 8: return ir.Constant(ir.IntType(64), 0) if val.type != ir.PointerType(ir.IntType(8)): val = Gen.builder.bitcast(val, ir.PointerType(ir.IntType(8)), name="str_ptr_cast") correct_strlen_type = ir.FunctionType(ir.IntType(64), [ir.PointerType(ir.IntType(8))]) strlen_func = None if 'strlen' in Gen.functions: existing = Gen.functions['strlen'] if existing.ftype == correct_strlen_type: strlen_func = existing if not strlen_func: try: strlen_func = ir.Function(Gen.module, correct_strlen_type, name='strlen') Gen.functions['strlen'] = strlen_func except Exception as _e: if _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") if strlen_func: result = Gen.builder.call(strlen_func, [val], name="strlen_call") return result elif isinstance(val.type, ir.ArrayType): return ir.Constant(ir.IntType(64), val.type.count) return ir.Constant(ir.IntType(64), 0) def _resolve_opaque_struct_members(self, struct_type: ir.Type, Gen: LlvmGeneratorMixin, _visited: set | None = None) -> None: """Recursively resolve opaque struct members by loading from stub files.""" if _visited is None: _visited = set() if not isinstance(struct_type, ir.IdentifiedStructType): return # 防止循环引用导致无限递归 try: st_id = id(struct_type) except Exception: st_id = struct_type if st_id in _visited: return _visited.add(st_id) if struct_type.elements is None or len(struct_type.elements) == 0: # Find the class name for this opaque struct and try to resolve for cn, st in Gen.structs.items(): try: if st == struct_type or (hasattr(st, 'name') and hasattr(struct_type, 'name') and st.name == struct_type.name): self.Trans.ImportHandler._TryLoadStructFromStub(cn, Gen) break except (AssertionError, RuntimeError): pass # Re-get the struct in case it was resolved if struct_type.elements: for elem in struct_type.elements: if isinstance(elem, ir.IdentifiedStructType): self._resolve_opaque_struct_members(elem, Gen, _visited) elif isinstance(elem, ir.PointerType): pointee = elem.pointee if isinstance(pointee, ir.IdentifiedStructType): self._resolve_opaque_struct_members(pointee, Gen, _visited) def _resolve_type_arg_str(self, node: ast.AST) -> str: """将类型参数 AST 节点解析为规范化的类型字符串(用于泛型特化的 mangling)。 走和普通类型签名同样的规范化路径(不单独创建规则): - ast.Name: 若为已注册结构体,加 SHA1 前缀(如 'AST' → '9ada227b160c07a1.AST'), 与 DeclarationGenerator._get_type_str 对 ast.Name 的处理一致 - ast.Attribute: t.CPtr → 'ptr'(指针标记,等价于普通签名中 t.CPtr → i8* 的指针语义; 用 'ptr' 而非 '*' 是因为 _get_or_create_struct 的 clean_name 会移除 '*', 导致 Phase2 直接编译与 .stub.ll 加载路径的 mangled 名不一致); 其他 t 模块类型按 CTypeRegistry.NameToLLVM 解析 - ast.BinOp: 递归处理左右操作数并直接拼接(如 AST | t.CPtr → 'sha1.ASTptr'), 避免空格/管道符导致 _get_or_create_struct 的 clean_name 清洗不一致 """ if isinstance(node, ast.Name): tn: str = node.id t_c_imported = getattr(self.Trans, '_t_c_imported_names', {}) if tn in t_c_imported: src_module, src_name = t_c_imported[tn] return f'{src_module}.{src_name}' # 若为已注册结构体,加 SHA1 前缀(和普通签名路径一致) Gen = self.Trans.LlvmGen struct_sha1_map = getattr(Gen, '_struct_sha1_map', {}) if Gen is not None else {} if tn in struct_sha1_map: return f'{struct_sha1_map[tn]}.{tn}' return tn if isinstance(node, ast.Attribute): if isinstance(node.value, ast.Name): full_name: str = f'{node.value.id}.{node.attr}' # t.CPtr → 'ptr'(指针标记,和普通签名中 t.CPtr 被解析为指针类型 i8* 语义一致) if full_name == 't.CPtr': return 'ptr' # 其他 t 模块类型按 CTypeRegistry 解析(和普通签名路径一致) llvm_str: str | None = CTypeRegistry.NameToLLVM(node.attr) if llvm_str is not None: return llvm_str return full_name return ast.unparse(node) if isinstance(node, ast.BinOp): left_str: str = self._resolve_type_arg_str(node.left) right_str: str = self._resolve_type_arg_str(node.right) # 直接拼接(如 'sha1.AST' + 'ptr' = 'sha1.ASTptr'),避免空格导致清洗不一致 return f'{left_str}{right_str}' return ast.unparse(node) def _get_raw_type_name(self, node: ast.AST) -> str: """获取类型节点的原始名称(不带模块前缀),用于泛型 T 替换。 ast.Name → sn.id (如 'AST', 'CInt') ast.Attribute → sn.attr (如 t.CInt → 'CInt') ast.BinOp → 左侧的原始名称 (如 AST | CPtr → 'AST') """ if isinstance(node, ast.Name): return node.id if isinstance(node, ast.Attribute): return node.attr if isinstance(node, ast.BinOp): return self._get_raw_type_name(node.left) return ast.unparse(node) def _resolve_generic_slice_type(self, sn: ast.AST) -> tuple[str, str] | None: """解析泛型 slice 中的单个类型参数节点,返回 (type_arg, type_name) 或 None。 type_arg: 用于 mangling,走和普通签名同样的规范化路径 (如 'AST | t.CPtr' → '9ada227b160c07a1.ASTptr',AST 加 SHA1 前缀,t.CPtr 处理为 ptr) type_name: 用于替换泛型类型参数 T(如 'AST' 或 'CInt',_specialize_generic_class 会自动加 | t.CPtr 给类名) """ if isinstance(sn, ast.Name): tn: str = sn.id ts: str = 'int' if tn == 'int': ts, tn = 'int', 'CInt' elif tn == 'double': ts, tn = 'double', 'CDouble' elif tn == 'float': ts, tn = 'float', 'CFloat' elif tn == 'char': ts, tn = 'i8', 'CChar' elif tn == 'bool': ts, tn = 'i8', 'CBool' elif tn in ('CInt', 'CUInt', 'CInt32T', 'CUInt32T', 'CInt64T', 'CUInt64T', 'CInt16T', 'CUInt16T', 'CInt8T', 'CUInt8T', 'CChar', 'CShort', 'CLong'): ts = 'int' elif tn in ('CDouble', 'CFloat', 'CFloat64T', 'CFloat32T'): ts = 'double' else: ts = tn return (ts, tn) # BinOp (如 AST | CPtr) 或 Attribute (如 t.CPtr / t.CInt) type_str: str = self._resolve_type_arg_str(sn) # type_name 取原始名称(不带模块前缀),用于 T 替换 raw_name: str = self._get_raw_type_name(sn) return (type_str, raw_name) def _ResolveGenericSlice(self, Sub: ast.Subscript) -> str | None: """从泛型 Subscript (如 Stack[int]) 解析特化名,确保特化类型已生成。""" if not isinstance(Sub.value, ast.Name): return None ClassName: str = Sub.value.id if not (hasattr(self.Trans.ClassHandler, '_generic_class_templates') and ClassName in self.Trans.ClassHandler._generic_class_templates): return None Gen = self.Trans.LlvmGen # 共享符号表构建阶段(_build_shared_symbol_data / ParsePythonFile)LlvmGen 为 None, # 此时不应发射特化 IR;调用方(GetCTypeInfo)已用 mangled 名设置符号表信息 if Gen is None: return None template: dict = self.Trans.ClassHandler._generic_class_templates[ClassName] type_param_names: list[str] = template['type_params'] type_args: list[str] = [] type_names: list[str] = [] slice_nodes: list[ast.AST] = [] if isinstance(Sub.slice, ast.Tuple): slice_nodes = list(Sub.slice.elts) else: slice_nodes = [Sub.slice] for sn in slice_nodes: result = self._resolve_generic_slice_type(sn) if result is not None: type_args.append(result[0]) type_names.append(result[1]) while len(type_args) < len(type_param_names): type_args.append('int') type_names.append('CInt') return self.Trans.ClassHandler._specialize_generic_class(ClassName, type_args, Gen, type_names=type_names) @staticmethod def _AnnotationContainsCPtr(Node: ast.AST) -> bool: """检查类型注解 AST 是否包含 t.CPtr(即是否为指针类型)""" if isinstance(Node, ast.Attribute): if Node.attr == 'CPtr': return True if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr): return (ExprCallHandle._AnnotationContainsCPtr(Node.left) or ExprCallHandle._AnnotationContainsCPtr(Node.right)) return False @staticmethod def _is_sizeof_type_name(name: str, Gen: "LlvmGeneratorMixin") -> bool: """检查名称是否是已知的类型名(用于 __sizeof__ 上下文)。 检查顺序: Gen.structs → SHA1 前缀 → 内建类型 → CTypeRegistry """ if not name: return False # 1. 直接在 Gen.structs 中查找 if name in Gen.structs: return True # 2. 带 SHA1 前缀查找(如 ClassDef → 657e182b27c2a022.ClassDef) struct_sha1_map = getattr(Gen, '_struct_sha1_map', {}) if name in struct_sha1_map: return True # 遍历所有 SHA1 前缀 for sha1 in struct_sha1_map.values(): prefixed = f"{sha1}.{name}" if prefixed in Gen.structs: return True # 3. 内建类型名 if name in ('str', 'bytes', 'int', 'double', 'float', 'char', 'bool', 'void', 'i8', 'i16', 'i32', 'i64', 'half', 'fp128'): return True # 4. CTypeRegistry 中的类型 if CTypeRegistry.GetClassByName(name) is not None: return True if CTypeRegistry.ResolveName(name): return True return False def _HandleSizeofLlvm(self, Node: ast.AST) -> ir.Constant: Gen = self.Trans.LlvmGen if isinstance(Node, ast.Name): type_name = Node.id elif isinstance(Node, ast.Attribute): type_name = Node.attr else: return ir.Constant(ir.IntType(64), 0) if type_name not in Gen.structs: # SHA1 前缀查找:如 ClassDef → 657e182b27c2a022.ClassDef struct_sha1_map = getattr(Gen, '_struct_sha1_map', {}) resolved_name: str | None = None if type_name in struct_sha1_map: resolved_name = f"{struct_sha1_map[type_name]}.{type_name}" else: for sha1 in struct_sha1_map.values(): prefixed = f"{sha1}.{type_name}" if prefixed in Gen.structs: resolved_name = prefixed break if resolved_name is not None and resolved_name in Gen.structs: type_name = resolved_name if type_name not in Gen.structs: # str/bytes 是指针类型 (char*/void*),sizeof = 指针大小 if type_name in ('str', 'bytes'): return ir.Constant(ir.IntType(64), 8) ctype_cls = CTypeRegistry.GetClassByName(type_name) if ctype_cls is not None: try: ctype_inst = ctype_cls() size_bits = getattr(ctype_inst, 'Size', 0) or 0 size_bytes = size_bits // 8 return ir.Constant(ir.IntType(64), size_bytes) except Exception as _e: if _config_mode == "strict": raise _vlog().warning(f"解析类型失败: {_e}", "Exception") resolved = CTypeRegistry.ResolveName(type_name) if resolved: ctype_cls, ptr_level = resolved try: ctype_inst = ctype_cls() size_bits = getattr(ctype_inst, 'Size', 0) or 0 size_bytes = size_bits // 8 if ptr_level > 0: size_bytes = 8 return ir.Constant(ir.IntType(64), size_bytes) except Exception as _e: if _config_mode == "strict": raise _vlog().warning(f"解析类型失败: {_e}", "Exception") # 所有查找策略均失败(不在 Gen.structs、SHA1 前缀查找失败、CTypeRegistry 也找不到): # 报错终止,拒绝静默返回 0(会导致 malloc(0)/alloc(0) 堆溢出) raise ValueError( f"[FATAL][__sizeof__] 类型 '{type_name}' 无法解析" f"(不在 Gen.structs、SHA1 前缀查找失败、CTypeRegistry 也找不到)," f"拒绝静默返回 0" ) struct_type = Gen.structs[type_name] if isinstance(struct_type, ir.PointerType): struct_type = struct_type.pointee # 保存 builder 状态:_TryLoadStructFromStub / _resolve_opaque_struct_members # 可能触发重入编译(编译其他模块的函数),这会改变 Gen.func/Gen.builder, # 导致当前函数的指令被写到错误函数的 block 中(then 块为空的根因) _saved_func = Gen.func _saved_builder = Gen.builder _saved_block = Gen.builder.block if (Gen.builder and Gen.builder.block) else None _saved_variables = dict(Gen.variables) if Gen.variables else {} _saved_reg_values = dict(getattr(Gen, '_reg_values', {})) _saved_direct_values = dict(getattr(Gen, '_direct_values', {})) _saved_var_type_info = dict(getattr(Gen, 'var_type_info', {})) _saved_var_signedness = dict(getattr(Gen, 'var_signedness', {})) _saved_global_vars = set(getattr(Gen, 'global_vars', set())) _saved_var_scopes = [dict(s) for s in getattr(self.Trans, 'VarScopes', [])] try: if isinstance(struct_type, ir.IdentifiedStructType) and (struct_type.elements is None or len(struct_type.elements) == 0): self.Trans.ImportHandler._TryLoadStructFromStub(type_name, Gen) struct_type = Gen.structs.get(type_name, struct_type) # Recursively resolve opaque struct members self._resolve_opaque_struct_members(struct_type, Gen) finally: Gen.func = _saved_func Gen.builder = _saved_builder if _saved_block is not None and Gen.builder is not None: Gen.builder.position_at_end(_saved_block) Gen.variables = _saved_variables Gen._reg_values = _saved_reg_values Gen._direct_values = _saved_direct_values Gen.var_type_info = _saved_var_type_info Gen.var_signedness = _saved_var_signedness Gen.global_vars = _saved_global_vars self.Trans.VarScopes = _saved_var_scopes size = Gen._get_struct_size(struct_type) if size > 0: return ir.Constant(ir.IntType(64), size) return ir.Constant(ir.IntType(64), 0) def _HandleAbsLlvm(self, arg_node: ast.AST) -> ir.Value | None: Gen = self.Trans.LlvmGen val = self.HandleExprLlvm(arg_node) if not val: return None if isinstance(val.type, ir.PointerType): pointee = val.type.pointee if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): for CN, ST in Gen.structs.items(): if pointee == ST: result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__abs__', val, Gen) if result is not None: return result break if isinstance(val.type, ir.IntType): neg_val = Gen.builder.neg(val, name="abs_neg") is_neg = Gen.builder.icmp_signed('<', val, ir.Constant(val.type, 0), name="is_neg") return Gen.builder.select(is_neg, neg_val, val, name="abs_result") elif isinstance(val.type, (ir.FloatType, ir.DoubleType)): zero = ir.Constant(val.type, 0.0) neg_val = Gen.builder.fneg(val, name="fabs_neg") is_neg = Gen.builder.fcmp_ordered('<', val, zero, name="f_is_neg") return Gen.builder.select(is_neg, neg_val, val, name="fabs_result") return None def _HandleDirLlvm(self, Node: ast.Call) -> ir.Constant: Gen = self.Trans.LlvmGen return ir.Constant(ir.IntType(8).as_pointer(), None) def _HandleTypeLlvm(self, Node: ast.Call) -> ir.Value: Gen = self.Trans.LlvmGen if not Node.args: type_str = "" else: arg = Node.args[0] enum_type_name = None def _get_attr_path(node): if isinstance(node, ast.Name): return node.id elif isinstance(node, ast.Attribute): return f"{_get_attr_path(node.value)}.{node.attr}" return None if isinstance(arg, ast.Name): arg_name = arg.id Gen = self.Trans.LlvmGen if arg_name in Gen.var_type_info: type_info = Gen.var_type_info[arg_name] if isinstance(type_info, dict) and type_info.get('type') == 'enum': enum_type_name = type_info.get('name') if not enum_type_name: TypeInfo = self.Trans.SymbolTable.lookup(arg_name) if TypeInfo and TypeInfo.IsEnum: enum_type_name = arg_name elif isinstance(arg, ast.Attribute): LastPart = None enum_class_name = None if isinstance(arg.value, ast.Name): LastPart = arg.attr AttrInfo = self.Trans.SymbolTable.lookup(LastPart) if AttrInfo and AttrInfo.IsEnumMember and AttrInfo.EnumName: enum_type_name = AttrInfo.EnumName elif isinstance(arg.value, ast.Attribute): attr_path = _get_attr_path(arg) if attr_path: parts = attr_path.split('.') if len(parts) >= 2: enum_class_name = parts[-2] LastPart = parts[-1] qualified_name_dot = f"{enum_class_name}.{LastPart}" qualified_name_under = f"{enum_class_name}_{LastPart}" enum_member_found = None for qname in (qualified_name_dot, qualified_name_under): info = self.Trans.SymbolTable.lookup(qname) if info and info.IsEnumMember and info.EnumName == enum_class_name: enum_member_found = info break if not enum_member_found: for key in self.Trans.SymbolTable: if key == LastPart: info = self.Trans.SymbolTable[key] if info.IsEnumMember and info.EnumName == enum_class_name: enum_member_found = info break if enum_member_found: enum_type_name = enum_class_name if enum_type_name: type_str = f"" else: llvm_type = self.Trans.ExprUtils._infer_expr_llvm_type_full(arg) if isinstance(llvm_type, ir.PointerType): pointee = llvm_type.pointee if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): llvm_type = pointee type_info = self.Trans.ExprUtils._llvm_type_to_detailed_string(llvm_type) type_str = f"" return Gen.emit_constant(type_str, 'string') def _HandleInputLlvm(self, Node: ast.Call) -> ir.Value: Gen = self.Trans.LlvmGen if Node.args and isinstance(Node.args[0], ast.Constant) and isinstance(Node.args[0].value, str): prompt = Node.args[0].value prompt_ptr = Gen.emit_constant(prompt, 'string') printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) Gen.builder.call(printf_func, [prompt_ptr]) scanf_func = Gen.get_or_declare_c_func('scanf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) input_buffer = Gen._alloca(ir.ArrayType(ir.IntType(8), 256), name="input_buffer") result = Gen.builder.call(scanf_func, [Gen.emit_constant("%255s", 'string'), input_buffer]) return Gen.builder.gep(input_buffer, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="input_result") def _HandleAtoiLlvm(self, str_ptr: ir.Value) -> ir.Value: Gen = self.Trans.LlvmGen atoi_func = Gen.get_or_declare_c_func('atoi', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))])) return Gen.builder.call(atoi_func, [str_ptr], name="atoi_result") def _HandleOrdLlvm(self, expr_node: ast.AST) -> ir.Value: Gen = self.Trans.LlvmGen val = self.HandleExprLlvm(expr_node) if val and self._is_char_pointer(val): return Gen._load(val, name="ord_result") return ir.Constant(ir.IntType(32), 0) def _HandleChrLlvm(self, expr_node: ast.AST) -> ir.Value: Gen = self.Trans.LlvmGen val = self.HandleExprLlvm(expr_node) if val: char_ptr = Gen._alloca(ir.IntType(8), name="chr_char") Gen.builder.store(Gen.builder.trunc(val, ir.IntType(8), name="trunc_chr"), char_ptr) return Gen.builder.gep(char_ptr, [ir.Constant(ir.IntType(32), 0)], name="chr_result") return ir.Constant(ir.IntType(8).as_pointer(), None) def _EmitStringFromValue(self, val: ir.Value) -> ir.Value: Gen = self.Trans.LlvmGen if isinstance(val.type, ir.IntType): buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 32)) snprintf_func = Gen.get_or_declare_c_func('snprintf', ir.FunctionType(ir.IntType(32), [ ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.PointerType(ir.IntType(8)) ])) fmt_ptr = Gen.emit_constant("%d", 'string') Gen.builder.call(snprintf_func, [buf, ir.Constant(ir.IntType(32), 32), fmt_ptr, val]) return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result") return ir.Constant(ir.IntType(8).as_pointer(), None) def _HandleMallocLlvm(self, args: list[ast.AST]) -> ir.Value: Gen = self.Trans.LlvmGen malloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)]) malloc_func = Gen._get_or_declare_func('malloc', malloc_type) param_type = malloc_func.type.pointee.args[0] size_val = None if args: size_val = self.HandleExprLlvm(args[0]) if size_val and isinstance(size_val.type, ir.IntType): if isinstance(param_type, ir.IntType) and size_val.type.width != param_type.width: if size_val.type.width < param_type.width: size_val = Gen.builder.zext(size_val, param_type, name="zext_malloc_size") else: size_val = Gen.builder.trunc(size_val, param_type, name="trunc_malloc_size") if not size_val: size_val = ir.Constant(param_type, 1) result = Gen.builder.call(malloc_func, [size_val], name="malloc_result") return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name="malloc_cast") def _HandleReallocLlvm(self, args: list[ast.AST]) -> ir.Value: Gen = self.Trans.LlvmGen realloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(64)]) realloc_func = Gen._get_or_declare_func('realloc', realloc_type) size_param_type = realloc_func.type.pointee.args[1] ptr_val = None size_val = None if len(args) >= 2: ptr_val = self.HandleExprLlvm(args[0]) size_val = self.HandleExprLlvm(args[1]) elif len(args) == 1: size_val = self.HandleExprLlvm(args[0]) if not ptr_val: ptr_val = ir.Constant(ir.PointerType(ir.IntType(8)), None) if isinstance(ptr_val.type, ir.PointerType) and not self._is_char_pointer(ptr_val): ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name="realloc_cast_ptr") if size_val and isinstance(size_val.type, ir.IntType): if isinstance(size_param_type, ir.IntType) and size_val.type.width != size_param_type.width: if size_val.type.width < size_param_type.width: size_val = Gen.builder.zext(size_val, size_param_type, name="zext_realloc_size") else: size_val = Gen.builder.trunc(size_val, size_param_type, name="trunc_realloc_size") if not size_val: size_val = ir.Constant(size_param_type, 0) result = Gen.builder.call(realloc_func, [ptr_val, size_val], name="realloc_result") return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name="realloc_cast") def _HandleFreeLlvm(self, args: list[ast.AST]) -> ir.Constant: Gen = self.Trans.LlvmGen free_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]) free_func = Gen._get_or_declare_func('free', free_type) if args: var_name = None if isinstance(args[0], ast.Name): var_name = args[0].id ptr_val = self.HandleExprLlvm(args[0]) if ptr_val: if var_name and hasattr(Gen, '_var_to_heap_ptr') and var_name in Gen._var_to_heap_ptr: registered_val = Gen._var_to_heap_ptr[var_name] Gen._unregister_local_heap_ptr(registered_val) del Gen._var_to_heap_ptr[var_name] if isinstance(ptr_val.type, ir.PointerType) and not self._is_char_pointer(ptr_val): ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name="free_cast_ptr") Gen.builder.call(free_func, [ptr_val], name="free_call") return ir.Constant(ir.IntType(32), 0) def _HandleMemcpyLlvm(self, args: list[ast.AST]) -> None: Gen = self.Trans.LlvmGen if 'llvm.memcpy' not in Gen.functions: memcpy_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)]) Gen.functions['llvm.memcpy'] = ir.Function(Gen.module, memcpy_type, name='llvm.memcpy') if len(args) >= 3: dst = self.HandleExprLlvm(args[0]) src = self.HandleExprLlvm(args[1]) size = self.HandleExprLlvm(args[2]) if dst and src and size: i8ptr = ir.PointerType(ir.IntType(8)) if isinstance(dst.type, ir.PointerType) and dst.type != i8ptr: dst = Gen.builder.bitcast(dst, i8ptr, name="memcpy_dst_cast") elif isinstance(dst.type, ir.IntType): if dst.type.width < 64: dst = Gen.builder.zext(dst, ir.IntType(64), name="zext_dst_ptr") dst = Gen.builder.inttoptr(dst, i8ptr, name="dst_int2ptr") if isinstance(src.type, ir.PointerType) and src.type != i8ptr: src = Gen.builder.bitcast(src, i8ptr, name="memcpy_src_cast") elif isinstance(src.type, ir.IntType): if src.type.width < 64: src = Gen.builder.zext(src, ir.IntType(64), name="zext_src_ptr") src = Gen.builder.inttoptr(src, i8ptr, name="src_int2ptr") if isinstance(size.type, ir.IntType) and size.type.width < 64: size = Gen.builder.zext(size, ir.IntType(64), name="zext_memcpy_size") isvolatile = ir.Constant(ir.IntType(1), 0) Gen.builder.call(Gen.functions['llvm.memcpy'], [dst, src, size, isvolatile], name="memcpy_call") return None def _HandleMemsetLlvm(self, args: list[ast.AST]) -> None: Gen = self.Trans.LlvmGen memset_func = Gen.get_or_declare_c_func('memset', ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.IntType(64)])) if len(args) >= 3: dst = self.HandleExprLlvm(args[0]) val = self.HandleExprLlvm(args[1]) size = self.HandleExprLlvm(args[2]) if dst and val is not None and size: if isinstance(dst.type, ir.PointerType) and not self._is_char_pointer(dst): dst = Gen.builder.bitcast(dst, ir.PointerType(ir.IntType(8)), name="memset_dst_cast") if isinstance(val.type, ir.IntType) and val.type.width != 32: if val.type.width < 32: val = Gen.builder.zext(val, ir.IntType(32), name="zext_memset_val") else: val = Gen.builder.trunc(val, ir.IntType(32), name="trunc_memset_val") if isinstance(size.type, ir.IntType) and size.type.width < 64: size = Gen.builder.zext(size, ir.IntType(64), name="zext_memset_size") elif isinstance(size.type, ir.IntType) and size.type.width > 64: size = Gen.builder.trunc(size, ir.IntType(64), name="trunc_memset_size") Gen.builder.call(memset_func, [dst, val, size], name="memset_call") return None def _HandleVaStartLlvm(self, args: list[ast.AST]) -> None: Gen = self.Trans.LlvmGen return None def _HandleVaEndLlvm(self, args: list[ast.AST]) -> None: Gen = self.Trans.LlvmGen return None def _HandleArgLlvm(self, args: list[ast.AST], CallNode: ast.Call | None = None) -> ir.Value | None: Gen = self.Trans.LlvmGen va_list_ptr = None variadic_info = getattr(Gen, '_va_arg_info', None) if not variadic_info: variadic_info = getattr(Gen, '_variadic_info', None) if variadic_info: va_list_ptr = variadic_info.get('va_list_ptr') if not va_list_ptr: vararg_name = variadic_info.get('vararg_name', 'args') if variadic_info else 'args' if vararg_name in Gen._direct_values: va_list_ptr = Gen._direct_values[vararg_name] elif vararg_name in Gen.variables: va_list_ptr = Gen.variables[vararg_name] if not va_list_ptr: return ir.Constant(ir.IntType(32), 0) target_type = ir.IntType(32) if args: type_arg = args[0] if isinstance(type_arg, ast.Name): type_name = type_arg.id if type_name in ('str', 'bytes'): target_type = ir.PointerType(ir.IntType(8)) elif type_name == 'CPtr': target_type = ir.PointerType(ir.IntType(8)) elif type_name in Gen.structs: target_type = ir.PointerType(Gen.structs[type_name]) else: ctype_cls = CTypeRegistry.GetClassByName(type_name) if ctype_cls is not None: llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) resolved = Gen._type_str_to_llvm(llvm_str) if resolved: target_type = resolved else: resolved = CTypeRegistry.ResolveName(type_name) if resolved is not None: ctype_cls, ptr_level = resolved llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) if llvm_str: base = Gen._type_str_to_llvm(llvm_str) if base is not None: for _ in range(ptr_level): if isinstance(base, ir.VoidType): base = ir.IntType(8).as_pointer() else: base = ir.PointerType(base) target_type = base elif isinstance(type_arg, ast.Attribute): if isinstance(type_arg.value, ast.Name) and IsTModule(type_arg.value.id, self.Trans.SymbolTable): attr_name = type_arg.attr ctype_cls = CTypeRegistry.GetClassByName(attr_name) if ctype_cls is not None: llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) resolved = Gen._type_str_to_llvm(llvm_str) if resolved: target_type = resolved else: assign_node = getattr(self.Trans, '_current_assign_node', None) if assign_node: ann = getattr(assign_node, 'annotation', None) if ann: ann_name = None if isinstance(ann, ast.Name): ann_name = ann.id elif isinstance(ann, ast.Attribute): ann_name = ann.attr elif isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr): ann_name = ExtractTypeNameFromBinOp(ann) if ann_name: ctype_cls = CTypeRegistry.GetClassByName(ann_name) if ctype_cls is not None: llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) resolved = Gen._type_str_to_llvm(llvm_str) if resolved: target_type = resolved elif ann_name in Gen.structs: target_type = ir.PointerType(Gen.structs[ann_name]) va_arg_counter = getattr(Gen, '_va_arg_counter', 0) Gen._va_arg_counter = va_arg_counter + 1 result = Gen.emit_va_arg(va_list_ptr, target_type) if result is not None and getattr(result, 'name', ''): result.name = f"va_arg_result_{Gen._va_arg_counter}" return result def _HandleVaArgLlvm(self, args: list[ast.AST]) -> ir.Constant: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen return ir.Constant(ir.IntType(32), 0) def _HandleCDerefAsLlvm(self, Node: ast.Call) -> ir.Constant: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen if len(Node.args) < 2: return ir.Constant(ir.IntType(32), 0) ptr_val: ir.Value | None = self.HandleExprLlvm(Node.args[0]) val_val: ir.Value | None = self.HandleExprLlvm(Node.args[1]) if ptr_val is None or val_val is None: return ir.Constant(ir.IntType(32), 0) if isinstance(ptr_val.type, ir.PointerType): store_val: ir.Value = val_val # 两端均为指向同一结构体类型的指针时执行结构体拷贝(*ptr = *val), # 而非存储指针值。这对 REnum 变体构造(c.DerefAs(ptr, LLVMType.Int(32))) 至关重要。 if (isinstance(val_val.type, ir.PointerType) and isinstance(ptr_val.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)) and ptr_val.type.pointee == val_val.type.pointee): loaded: ir.Value = Gen._load(val_val, name="deref_as_struct_load") Gen._store(loaded, ptr_val) return ir.Constant(ir.IntType(32), 0) if isinstance(val_val.type, ir.PointerType): void_pp: ir.PointerType = ir.PointerType(ir.PointerType(ir.IntType(8))) if ptr_val.type != void_pp: ptr_val = Gen.builder.bitcast(ptr_val, void_pp, name="deref_as_pp") if val_val.type.pointee != ir.IntType(8): store_val = Gen.builder.bitcast(val_val, ir.PointerType(ir.IntType(8)), name="deref_as_vp") elif isinstance(val_val.type, ir.IntType) and isinstance(ptr_val.type.pointee, ir.IntType): if val_val.type.width != ptr_val.type.pointee.width: if ptr_val.type.pointee.width == 8 and val_val.type.width > 8: target_ptr_type = ir.PointerType(val_val.type) ptr_val = Gen.builder.bitcast(ptr_val, target_ptr_type, name="deref_as_cast") elif val_val.type.width < ptr_val.type.pointee.width: store_val = Gen.builder.zext(val_val, ptr_val.type.pointee, name="deref_as_zext") else: store_val = Gen.builder.trunc(val_val, ptr_val.type.pointee, name="deref_as_trunc") elif isinstance(val_val.type, ir.IntType) and isinstance(ptr_val.type.pointee, ir.PointerType): if val_val.type.width == 64: store_val = Gen.builder.inttoptr(val_val, ptr_val.type.pointee, name="deref_as_inttoptr") else: ext = Gen.builder.zext(val_val, ir.IntType(64), name="deref_as_zext") store_val = Gen.builder.inttoptr(ext, ptr_val.type.pointee, name="deref_as_inttoptr") elif val_val.type != ptr_val.type.pointee: target_ptr_type = ir.PointerType(val_val.type) ptr_val = Gen.builder.bitcast(ptr_val, target_ptr_type, name="deref_as_cast") Gen.builder.store(store_val, ptr_val) return ir.Constant(ir.IntType(32), 0) def _InjectRequiresFields(self, result: ir.Value, ClassName: str, Gen: LlvmGeneratorMixin) -> None: """在 __new__ 后、__init__ 前自动注入 __requires__/__require_must__ 字段。 - 编译期:对 __require_must__ 做纯静态可达性检查(遍历 _with_provides_stack) - 运行时:对每个 requires 字段调用 _find_provider,非 NULL 则 bitcast 写入 """ requires_all: list[str] = [] requires_all.extend(Gen.class_requires.get(ClassName, [])) requires_all.extend(Gen.class_require_must.get(ClassName, [])) if not requires_all: return # 编译期 __require_must__ 静态检查 must_fields: list[str] = Gen.class_require_must.get(ClassName, []) if must_fields: # 跳过类自身方法内的检查(类的实现内部不需要 with 上下文) current_class = getattr(Gen, '_current_class_name', None) if current_class != ClassName: available: set[str] = set() for provides_list in Gen._with_provides_stack: available.update(provides_list) for field in must_fields: if field not in available: raise SyntaxError( f"[TransPyC] Class '{ClassName}' __require_must__ field '{field}' " f"not provided by any enclosing 'with' context" ) # 运行时注入 find_func = Gen.functions.get('_find_provider') if not find_func: return members = Gen.class_members.get(ClassName, []) has_vtable = ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes base = 1 if has_vtable else 0 field_map: dict[str, tuple[int, ir.Type]] = {} for i, (mname, mtype) in enumerate(members): if mname in requires_all: field_map[mname] = (base + i, mtype) for field_name in requires_all: if field_name not in field_map: continue field_idx, field_type = field_map[field_name] field_str = Gen._create_string_global(field_name) ptr_val = Gen.builder.call(find_func, [field_str], name=f"find_{field_name}") null_ptr = ir.Constant(ptr_val.type, None) is_null = Gen.builder.icmp_unsigned('==', ptr_val, null_ptr, name=f"is_null_{field_name}") skip_bb = Gen.func.append_basic_block(f"skip_inject_{field_name}") inject_bb = Gen.func.append_basic_block(f"inject_{field_name}") Gen.builder.cbranch(is_null, skip_bb, inject_bb) Gen.builder.position_at_end(inject_bb) if isinstance(field_type, ir.PointerType): casted = Gen.builder.bitcast(ptr_val, field_type, name=f"cast_{field_name}") elif isinstance(field_type, ir.IntType): casted = Gen.builder.ptrtoint(ptr_val, field_type, name=f"cast_{field_name}") else: casted = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name=f"cast_{field_name}") elem_ptr = Gen.builder.gep(result, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), field_idx)], name=f"field_{field_name}_ptr") Gen._store(casted, elem_ptr) Gen.builder.branch(skip_bb) Gen.builder.position_at_end(skip_bb) def _HandleClassNewLlvm(self, Node: ast.Call, ClassName: str, module_sha1: str | None = None) -> ir.Value: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen # 跨模块类型引用:优先用 {module_sha1}.{ClassName} 查找 struct _struct_full_key: str | None = f"{module_sha1}.{ClassName}" if module_sha1 else None def _get_struct_type(name: str) -> ir.Type | None: """优先用 SHA1 前缀完整名查找,回退到短名""" if _struct_full_key and _struct_full_key in Gen.structs: return Gen.structs[_struct_full_key] return Gen.structs.get(name) if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and ClassName in self.Trans.ClassHandler._generic_class_templates: return self._HandleGenericClassNewLlvm(Node, ClassName) NewFuncName = f'{ClassName}.__before_init__' InitFuncName = f'{ClassName}.__init__' NewMethodFuncName = f'{ClassName}.__new__' has_new_method = Gen._find_function(NewMethodFuncName) is not None if Gen._has_function(NewFuncName): NewFunc = Gen._get_function(NewFuncName) StructType = _get_struct_type(ClassName) if StructType: result = Gen._allocaEntry(StructType, name=f"{ClassName}_alloca") else: return ir.Constant(ir.IntType(32), 0) Gen.builder.call(NewFunc, [result], name=f"before_init_{ClassName}") if has_new_method: NewMethodFunc = Gen._find_function(NewMethodFuncName) if NewMethodFunc: NewMethodArgs = [result] for arg in Node.args: ArgVal = self.HandleExprLlvm(arg) if ArgVal: NewMethodArgs.append(ArgVal) self._fill_default_args(NewMethodArgs, NewMethodFunc, NewMethodFuncName) self._ApplyKeywordArgs(Node, NewMethodArgs, NewMethodFunc, NewMethodFuncName, self_offset=1) NewMethodArgs = Gen._apply_auto_addr(NewMethodFuncName, NewMethodArgs) adjusted_new = Gen._adjust_args(NewMethodArgs, NewMethodFunc) heap_ptr = Gen.builder.call(NewMethodFunc, adjusted_new, name=f"new_{ClassName}") if heap_ptr: target_ptr_type = ir.PointerType(StructType) if StructType else None if isinstance(heap_ptr.type, ir.PointerType): # Bitcast the returned pointer to the struct pointer type if needed if target_ptr_type and heap_ptr.type != target_ptr_type: result = Gen.builder.bitcast(heap_ptr, target_ptr_type, name=f"new_{ClassName}_cast") else: result = heap_ptr elif isinstance(heap_ptr.type, ir.IntType) and target_ptr_type: # __new__ returned an integer (pointer as int), convert back to pointer if heap_ptr.type.width < 64: i64_val = Gen.builder.zext(heap_ptr, ir.IntType(64), name=f"new_{ClassName}_i64") result = Gen.builder.inttoptr(i64_val, target_ptr_type, name=f"new_{ClassName}_ptr") else: result = Gen.builder.inttoptr(heap_ptr, target_ptr_type, name=f"new_{ClassName}_ptr") # __new__ 后:对堆指针重新调用 __before_init__ 初始化默认值(alloca 的默认值已随 alloca 丢弃) if has_new_method: Gen.builder.call(NewFunc, [result], name=f"before_init_{ClassName}_heap") # __new__ 后、__init__ 前:自动注入 requires 字段 self._InjectRequiresFields(result, ClassName, Gen) if Gen._has_function(InitFuncName): InitFunc = Gen._get_function(InitFuncName) InitArgs = [result] for arg in Node.args: ArgVal = self.HandleExprLlvm(arg) if ArgVal: InitArgs.append(ArgVal) self._fill_default_args(InitArgs, InitFunc, InitFuncName) self._ApplyKeywordArgs(Node, InitArgs, InitFunc, InitFuncName, self_offset=1) self._append_eh_msg_out_arg(InitArgs, InitFunc, Gen) InitArgs = Gen._apply_auto_addr(InitFuncName, InitArgs) adjusted_init = Gen._adjust_args(InitArgs, InitFunc) Gen.builder.call(InitFunc, adjusted_init, name=f"init_{ClassName}") return result if _struct_full_key and _struct_full_key in Gen.structs: StructType = Gen.structs[_struct_full_key] if isinstance(StructType, ir.PointerType): StructType = StructType.pointee is_opaque = isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0) if is_opaque: self._ensure_struct_declared(ClassName, module_sha1=module_sha1) StructType = Gen.structs.get(_struct_full_key, Gen.structs.get(ClassName, StructType)) if isinstance(StructType, ir.PointerType): StructType = StructType.pointee is_opaque = isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0) if is_opaque: return None elif ClassName in Gen.structs: StructType = Gen.structs[ClassName] if isinstance(StructType, ir.PointerType): StructType = StructType.pointee is_opaque = isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0) if is_opaque: self._ensure_struct_declared(ClassName, module_sha1=module_sha1) StructType = Gen.structs.get(ClassName, StructType) if isinstance(StructType, ir.PointerType): StructType = StructType.pointee is_opaque = isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0) if is_opaque: return None result = Gen._allocaEntry(StructType, name=f"{ClassName}_alloca") # Call __new__ method if it exists (may replace self with heap pointer) if has_new_method: NewMethodFunc = Gen._find_function(NewMethodFuncName) if NewMethodFunc: NewMethodArgs = [result] for arg in Node.args: ArgVal = self.HandleExprLlvm(arg) if ArgVal: NewMethodArgs.append(ArgVal) self._fill_default_args(NewMethodArgs, NewMethodFunc, NewMethodFuncName) self._ApplyKeywordArgs(Node, NewMethodArgs, NewMethodFunc, NewMethodFuncName, self_offset=1) NewMethodArgs = Gen._apply_auto_addr(NewMethodFuncName, NewMethodArgs) adjusted_new = Gen._adjust_args(NewMethodArgs, NewMethodFunc) heap_ptr = Gen.builder.call(NewMethodFunc, adjusted_new, name=f"new_{ClassName}") if heap_ptr: target_ptr_type = ir.PointerType(StructType) if StructType else None if isinstance(heap_ptr.type, ir.PointerType): # Bitcast the returned pointer to the struct pointer type if needed if target_ptr_type and heap_ptr.type != target_ptr_type: result = Gen.builder.bitcast(heap_ptr, target_ptr_type, name=f"new_{ClassName}_cast") else: result = heap_ptr elif isinstance(heap_ptr.type, ir.IntType) and target_ptr_type: # __new__ returned an integer (pointer as int), convert back to pointer if heap_ptr.type.width < 64: i64_val = Gen.builder.zext(heap_ptr, ir.IntType(64), name=f"new_{ClassName}_i64") result = Gen.builder.inttoptr(i64_val, target_ptr_type, name=f"new_{ClassName}_ptr") else: result = Gen.builder.inttoptr(heap_ptr, target_ptr_type, name=f"new_{ClassName}_ptr") # __new__ 后:对堆指针调用 __before_init__ 初始化默认值 if has_new_method and Gen._has_function(NewFuncName): NewFunc = Gen._get_function(NewFuncName) Gen.builder.call(NewFunc, [result], name=f"before_init_{ClassName}_heap") # __new__ 后、__init__ 前:自动注入 requires 字段 self._InjectRequiresFields(result, ClassName, Gen) InitFunc = Gen.functions.get(InitFuncName) if not InitFunc: g = Gen.module.globals.get(InitFuncName) if g and isinstance(g, ir.Function): Gen.functions[InitFuncName] = g InitFunc = g if InitFunc: InitArgs = [result] init_param_types = InitFunc.function_type.args if hasattr(InitFunc, 'function_type') else [] for i, arg in enumerate(Node.args): arg_var_type = init_param_types[i + 1] if i + 1 < len(init_param_types) else None ArgVal = self.HandleExprLlvm(arg, VarType=arg_var_type) if ArgVal: InitArgs.append(ArgVal) self._fill_default_args(InitArgs, InitFunc, InitFuncName) self._ApplyKeywordArgs(Node, InitArgs, InitFunc, InitFuncName, self_offset=1) self._append_eh_msg_out_arg(InitArgs, InitFunc, Gen) InitArgs = Gen._apply_auto_addr(InitFuncName, InitArgs) adjusted_init = Gen._adjust_args(InitArgs, InitFunc) Gen.builder.call(InitFunc, adjusted_init, name=f"init_{ClassName}") elif Node.args or Node.keywords: self._InitStructDefaults(result, ClassName, StructType) self._InitStructFromArgs(result, Node, ClassName, StructType) else: self._InitStructDefaults(result, ClassName, StructType) return result return ir.Constant(ir.IntType(32), 0) def _ZeroInitStruct(self, struct_ptr: ir.Value, StructType: ir.Type) -> None: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen if isinstance(StructType, ir.IdentifiedStructType) and StructType.elements: for i, elem_type in enumerate(StructType.elements): elem_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i)], name=f"zero_elem_{i}") zero_val = self._GetZeroValue(elem_type) if zero_val is not None: Gen._store(zero_val, elem_ptr) elif isinstance(StructType, ir.IntType): Gen._store(ir.Constant(StructType, 0), struct_ptr) elif isinstance(StructType, ir.ArrayType) and isinstance(StructType.pointee, ir.IntType): zero_arr = ir.Constant(StructType, None) Gen._store(zero_arr, struct_ptr) def _GetZeroValue(self, typ: ir.Type) -> ir.Constant | None: if isinstance(typ, ir.IntType): return ir.Constant(typ, 0) elif isinstance(typ, ir.PointerType): return ir.Constant(typ, None) elif isinstance(typ, (ir.FloatType, ir.DoubleType)): return ir.Constant(typ, 0.0) elif isinstance(typ, ir.ArrayType): return ir.Constant(typ, None) return None def _InitStructDefaults(self, struct_ptr: ir.Value, ClassName: str, StructType: ir.Type) -> None: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen defaults: dict = Gen.class_member_defaults.get(ClassName, {}) members: list[tuple] = Gen.class_members.get(ClassName, []) if not defaults or not members: return if not isinstance(StructType, ir.IdentifiedStructType): return has_vtable = ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes base = 1 if has_vtable else 0 for i, (member_name, member_type) in enumerate(members): if member_name in defaults: default_val = defaults[member_name] if isinstance(default_val, ir.Constant): elem_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), base + i)], name=f"default_{ClassName}_{member_name}") Gen._store(default_val, elem_ptr) def _InitStructFromArgs(self, struct_ptr: ir.Value, Node: ast.Call, ClassName: str, StructType: ir.Type) -> None: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen if not isinstance(StructType, ir.IdentifiedStructType): return members = Gen.class_members.get(ClassName, []) has_vtable = ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes base = 1 if has_vtable else 0 for i, arg in enumerate(Node.args): if i >= len(members): break val = self.HandleExprLlvm(arg) if not val: continue member_name, member_type = members[i] elem_idx = base + i if StructType.elements is None or elem_idx >= len(StructType.elements): break elem_type = StructType.elements[elem_idx] if isinstance(elem_type, ir.IntType) and isinstance(val.type, ir.IntType): if val.type.width < elem_type.width: val = Gen.builder.zext(val, elem_type, name=f"zext_init_{ClassName}_{i}") elif val.type.width > elem_type.width: val = Gen.builder.trunc(val, elem_type, name=f"trunc_init_{ClassName}_{i}") elif isinstance(elem_type, ir.PointerType) and isinstance(val.type, ir.PointerType): if val.type.pointee != elem_type.pointee: val = Gen.builder.bitcast(val, elem_type, name=f"bitcast_init_{ClassName}_{i}") elem_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), elem_idx)], name=f"init_elem_{ClassName}_{member_name}") Gen._store(val, elem_ptr) if Node.keywords: member_map = {name: (base + i) for i, (name, _) in enumerate(members)} for kw in Node.keywords: if kw.arg in member_map: val = self.HandleExprLlvm(kw.value) if not val: continue elem_idx = member_map[kw.arg] if StructType.elements is None or elem_idx >= len(StructType.elements): continue elem_type = StructType.elements[elem_idx] if isinstance(elem_type, ir.IntType) and isinstance(val.type, ir.IntType): if val.type.width < elem_type.width: val = Gen.builder.zext(val, elem_type, name=f"zext_init_{ClassName}_{kw.arg}") elif val.type.width > elem_type.width: val = Gen.builder.trunc(val, elem_type, name=f"trunc_init_{ClassName}_{kw.arg}") elif isinstance(elem_type, ir.PointerType) and isinstance(val.type, ir.PointerType): if val.type.pointee != elem_type.pointee: val = Gen.builder.bitcast(val, elem_type, name=f"bitcast_init_{ClassName}_{kw.arg}") elem_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), elem_idx)], name=f"init_elem_{ClassName}_{kw.arg}") Gen._store(val, elem_ptr) def _HandleSubscriptPtrLlvm(self, Node: ast.Subscript) -> ir.Value | None: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.value, Gen) if ClassName and ClassName in Gen.structs and Gen._has_function(f'{ClassName}.__getitem__'): obj_val = self.HandleExprLlvm(Node.value) idx_val = self.HandleExprLlvm(Node.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 self._is_char_pointer(obj_val): obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") if isinstance(idx_val.type, ir.IntType) and idx_val.type.width < 64: idx_val = Gen.builder.zext(idx_val, ir.IntType(64), name="zext_idx") result = Gen.builder.call(Gen._get_function(f'{ClassName}.__getitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__getitem__") return result ValueVal = self.HandleExprLlvm(Node.value) if not ValueVal: return None IndexVal = self.HandleExprLlvm(Node.slice) if not IndexVal: return None if isinstance(ValueVal.type, ir.IntType): var_ptr = self._get_int_ptr(Node.value) if var_ptr: i8_ptr = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr") if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index") ptr = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr") return ptr return None if isinstance(ValueVal.type, ir.PointerType) and isinstance(ValueVal.type.pointee, ir.PointerType): LoadedValueVal = Gen._load(ValueVal, name="Load_subscript") if isinstance(LoadedValueVal.type, ir.PointerType): ElemPtr = Gen.builder.gep(LoadedValueVal, [IndexVal], name="subscript") return ElemPtr if isinstance(ValueVal.type, ir.PointerType): pointee = ValueVal.type.pointee if isinstance(pointee, ir.ArrayType): zero = 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 = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript") return Gen._load(ElemPtr, name="arr_subscript_val") else: if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index") ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript") if isinstance(pointee, ir.IntType): return Gen._load(ElemPtr, name="subscript_val") return ElemPtr elif isinstance(ValueVal.type, ir.ArrayType): zero = ir.Constant(ir.IntType(32), 0) if isinstance(Node.value, ast.Name): VarName = Node.value.id if VarName in Gen.variables and Gen.variables[VarName] is not None: VarPtr = 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 = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript") return ElemPtr arr_alloc = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp") Gen._store(ValueVal, arr_alloc) ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript") return ElemPtr return None def _HandleGenericCallLlvm(self, Node: ast.Call, FuncName: str) -> ir.Value | None: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen template: dict = self.Trans.FunctionHandler._generic_templates[FuncName] type_param_names: list[str] = template['type_params'] type_args: list[str] = [] CallArgs: list[ir.Value] = [] for i, arg_node in enumerate(Node.args): arg_val = self.HandleExprLlvm(arg_node) if arg_val: CallArgs.append(arg_val) type_str = self.Trans.FunctionHandler._infer_type_arg_from_value(arg_val, Gen) type_args.append(type_str) else: type_args.append('int') while len(type_args) < len(type_param_names): type_args.append('int') type_args = type_args[:len(type_param_names)] spec_name = self.Trans.FunctionHandler._specialize_generic_function(FuncName, type_args, Gen) if spec_name is None: return None mangled_spec = Gen._mangle_func_name(spec_name) func = None if mangled_spec in Gen.functions: func = Gen.functions[mangled_spec] elif spec_name in Gen.functions: func = Gen.functions[spec_name] else: for fname, fobj in Gen.functions.items(): if spec_name in fname or fname.endswith(spec_name): func = fobj break if func is None: return None if not CallArgs: CallArgs = [ir.Constant(ir.IntType(32), 0) for _ in func.args] CallArgs = Gen._apply_auto_addr(spec_name, CallArgs) adjusted = Gen._adjust_args(CallArgs, func) return Gen.builder.call(func, adjusted, name=f"call_{spec_name}") def _HandleGenericClassNewLlvm(self, Node: ast.Call, ClassName: str, explicit_slice: ast.AST | None = None) -> ir.Value: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen template: dict = self.Trans.ClassHandler._generic_class_templates[ClassName] type_param_names: list[str] = template['type_params'] type_args: list[str] = [] type_names: list[str] = [] # 如果有显式类型参数 (如 list[int](mb)),直接从 slice 提取 if explicit_slice is not None: slice_nodes: list[ast.AST] = [] if isinstance(explicit_slice, ast.Tuple): slice_nodes = list(explicit_slice.elts) else: slice_nodes = [explicit_slice] for sn in slice_nodes: result = self._resolve_generic_slice_type(sn) if result is not None: type_args.append(result[0]) type_names.append(result[1]) # 补齐缺少的类型参数 while len(type_args) < len(type_param_names): type_args.append('int') type_names.append('CInt') spec_name = self.Trans.ClassHandler._specialize_generic_class(ClassName, type_args, Gen, type_names=type_names) if spec_name is None: return ir.Constant(ir.IntType(32), 0) return self._HandleClassNewLlvm(Node, spec_name) all_inferred: list[tuple[str, str]] = [] for i, arg_node in enumerate(Node.args): type_str = 'int' type_name = 'CInt' if isinstance(arg_node, ast.Constant): if isinstance(arg_node.value, float): type_str = 'double' type_name = 'CDouble' elif isinstance(arg_node.value, int): type_str = 'int' type_name = 'CInt' elif isinstance(arg_node.value, bool): type_str = 'i8' type_name = 'CBool' elif isinstance(arg_node, ast.Call): if isinstance(arg_node.func, ast.Name): func_id = arg_node.func.id if func_id == 'float': type_str = 'double' type_name = 'CDouble' elif func_id == 'int': type_str = 'int' type_name = 'CInt' else: float_types = {'CDouble', 'CFloat', 'CFloat64T', 'CFloat32T'} int_types = {'CInt', 'CUInt', 'CInt32T', 'CUInt32T', 'CInt64T', 'CUInt64T', 'CInt16T', 'CUInt16T', 'CInt8T', 'CUInt8T', 'CChar', 'CShort', 'CLong'} if func_id in float_types: type_str = 'double' type_name = func_id elif func_id in int_types: type_str = 'int' type_name = func_id elif isinstance(arg_node.func, ast.Attribute): attr_name = arg_node.func.attr float_types = {'CDouble', 'CFloat', 'CFloat64T', 'CFloat32T'} int_types = {'CInt', 'CUInt', 'CInt32T', 'CUInt32T', 'CInt64T', 'CUInt64T', 'CInt16T', 'CUInt16T', 'CInt8T', 'CUInt8T', 'CChar', 'CShort', 'CLong'} if attr_name in float_types: type_str = 'double' type_name = attr_name elif attr_name in int_types: type_str = 'int' type_name = attr_name elif isinstance(arg_node, ast.Name): var_info = self.Trans.SymbolTable.lookup(arg_node.id) if var_info and isinstance(var_info, dict): var_type = var_info.get('type', '') if var_type in ('double', 'float'): type_str = 'double' type_name = 'CDouble' all_inferred.append((type_str, type_name)) hint_types = [(ts, tn) for ts, tn in all_inferred if tn != 'CInt' or ts != 'int'] for i in range(len(type_param_names)): if i < len(hint_types): type_args.append(hint_types[i][0]) type_names.append(hint_types[i][1]) elif i < len(all_inferred): type_args.append(all_inferred[i][0]) type_names.append(all_inferred[i][1]) else: type_args.append('int') type_names.append('CInt') spec_name = self.Trans.ClassHandler._specialize_generic_class(ClassName, type_args, Gen, type_names=type_names) if spec_name is None: return ir.Constant(ir.IntType(32), 0) return self._HandleClassNewLlvm(Node, spec_name)