from __future__ import annotations from typing import TYPE_CHECKING if TYPE_CHECKING: from lib.core.translator import Translator from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta from lib.core.Handles.HandlesAssign import AssignHandle from lib.includes import t import ast import llvmlite.ir as ir class ExprCallHandle(BaseHandle): def _append_eh_msg_out_arg(self, CallArgs, func, Gen): if not func: return func_args = func.function_type.args n_user_args = len(CallArgs) has_eh_msg = False has_eh_code = False if len(func_args) > n_user_args: last_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 = len(func_args) - 1 - (1 if has_eh_code else 0) check_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 = None eh_code_ptr = 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, func_name, Gen, called_func=None): has_eh_msg_out = False has_eh_code_out = 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 eh_msg_ptr = None eh_code_ptr = 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 = Gen._load(eh_msg_ptr, name=f"Load_eh_msg_{func_name}") null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) is_error = Gen.builder.icmp_signed('!=', eh_msg_val, null_ptr, name=f"check_eh_msg_{func_name}") OkBB = Gen.func.append_basic_block(name=f"ok_after_{func_name}") ErrorBB = 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 = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None error_ret_val = 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, func, func_name=None): global_defaults = getattr(self.Trans, '_global_function_default_args', {}) func_defaults = 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 = len(func.args) if func_defaults: num_defaults = len(func_defaults) default_start = total_params - num_defaults else: num_defaults = 0 default_start = total_params while len(CallArgs) < total_params: arg_idx = len(CallArgs) arg = func.args[arg_idx] param_type = arg.type if hasattr(arg, 'type') else arg if func_defaults and arg_idx >= default_start: def_idx = 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 = (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: CallArgs.append(AssignHandle._zero_value(param_type)) 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: CallArgs.append(AssignHandle._zero_value(param_type)) 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: CallArgs.append(AssignHandle._zero_value(param_type)) except (AssertionError, TypeError): CallArgs.append(ir.Constant(ir.IntType(32), 0)) def _HandleCallLlvm(self, Node): Gen = self.Trans.LlvmGen FuncAttr = None ModulePath = 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 FuncName == 'print': return self._HandlePrintLlvm(Node) elif FuncName == 'len': if Node.args: return self._HandleLenLlvm(Node.args[0]) return ir.Constant(ir.IntType(32), 0) elif FuncName == 'sizeof': if Node.args: return self._HandleSizeofLlvm(Node.args[0]) return ir.Constant(ir.IntType(32), 0) elif FuncName == 'abs': if Node.args: return self._HandleAbsLlvm(Node.args[0]) return ir.Constant(ir.IntType(32), 0) elif FuncName == 'arg': return self._HandleArgLlvm(Node.args, CallNode=Node) elif FuncName == 'bool': if Node.args: Val = self.HandleExprLlvm(Node.args[0]) if Val: if isinstance(Val.type, ir.IntType): if Val.type.width == 1: return Val return Gen.builder.icmp_signed('!=', Val, Gen._ZeroConst(Val.type), name="bool_result") elif isinstance(Val.type, ir.PointerType): return Gen.builder.icmp_signed('!=', Val, Gen._ZeroConst(Val.type), name="bool_result") return Val return ir.Constant(ir.IntType(1), 0) elif FuncName == 'int': if Node.args: Val = self.HandleExprLlvm(Node.args[0]) if Val: if isinstance(Val.type, ir.IntType): if Val.type.width < 32: return Gen.builder.zext(Val, ir.IntType(32), name="cast_int") elif Val.type.width > 32: return Gen.builder.trunc(Val, ir.IntType(32), name="trunc_int") return Val elif isinstance(Val.type, (ir.FloatType, ir.DoubleType)): return Gen.builder.fptosi(Val, ir.IntType(32), name="fptosi_int") elif isinstance(Val.type, ir.PointerType): if self._is_char_pointer(Val): result = self._HandleAtoiLlvm(Val) if result: return result return ir.Constant(ir.IntType(32), 0) elif FuncName == 'float' or FuncName == 'double': if Node.args: Val = self.HandleExprLlvm(Node.args[0]) if Val: target_type = ir.DoubleType() if isinstance(Val.type, (ir.FloatType, ir.DoubleType)): if Val.type != target_type: return Gen.builder.fpext(Val, target_type, name="fpext_double") return Val elif isinstance(Val.type, ir.IntType): if Val.type.width == 1: return Gen.builder.uitofp(Val, target_type, name="uitofp_double") return Gen.builder.sitofp(Val, target_type, name="sitofp_double") return ir.Constant(ir.DoubleType(), 0.0) elif FuncName == 'str': if Node.args: arg_node = Node.args[0] arg_val = self.HandleExprLlvm(arg_node) if arg_val: if isinstance(arg_val.type, ir.PointerType): ClassName = self.Trans.ExprHandler._get_var_class(arg_node, Gen) if ClassName and Gen._has_function(f'{ClassName}.__str__'): if self._is_char_pointer(arg_val): if ClassName in Gen.structs: arg_val = Gen.builder.bitcast(arg_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}_str") str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [arg_val], name=f"call_{ClassName}.__str__") return str_val return arg_val return self._EmitStringFromValue(arg_val) return ir.Constant(ir.IntType(8).as_pointer(), None) elif FuncName == 'input': return self._HandleInputLlvm(Node) elif FuncName == 'ord': if Node.args: return self._HandleOrdLlvm(Node.args[0]) return ir.Constant(ir.IntType(32), 0) elif FuncName == 'chr': if Node.args: return self._HandleChrLlvm(Node.args[0]) return ir.Constant(ir.IntType(8), 0) elif FuncName == 'malloc': return self._HandleMallocLlvm(Node.args) elif FuncName == 'realloc': return self._HandleReallocLlvm(Node.args) elif FuncName == 'free': return self._HandleFreeLlvm(Node.args) elif FuncName == 'memcpy': return self._HandleMemcpyLlvm(Node.args) elif FuncName == 'memset': return self._HandleMemsetLlvm(Node.args) elif FuncName == 'va_start': return self._HandleVaStartLlvm(Node.args) elif FuncName == 'va_end': return self._HandleVaEndLlvm(Node.args) elif FuncName == 'va_arg': return self._HandleVaArgLlvm(Node.args) elif FuncName == 'dir': return self._HandleDirLlvm(Node) elif FuncName == 'type': return self._HandleTypeLlvm(Node) if Gen._has_function(FuncName): return self._HandleClosureCallLlvm(Node, FuncName) if FuncName in self.Trans.SymbolTable: SymInfo = self.Trans.SymbolTable[FuncName] if SymInfo.IsEnum: 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) # 检查是否是闭包变量(lambda 赋值给变量后调用) if FuncName in Gen.variables and Gen.variables[FuncName] is not None: closure_ptr = Gen._load(Gen.variables[FuncName], name=f"Load_closure_{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.Attribute): if Node.func.attr in ('update', 'final', 'transform'): pass if Node.func.attr == '__sizeof__': 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) 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) elif isinstance(Node.func.value, ast.Attribute): type_name = Node.func.value.attr SizeofNode = ast.Name(id=type_name, ctx=ast.Load()) return self._HandleSizeofLlvm(SizeofNode) ModulePath = self._get_ModulePath(Node.func.value) if ModulePath: aliases = getattr(self.Trans, '_ImportAliases', {}) first_part = ModulePath.split('.')[0] if first_part in aliases: ModulePath = aliases[first_part] + ModulePath[len(first_part):] is_instance_var = isinstance(Node.func.value, ast.Name) and Node.func.value.id in Gen.var_struct_class 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 (Node.func.value.id in self.Trans.SymbolTable and getattr(self.Trans.SymbolTable[Node.func.value.id], 'IsStruct', False))) if is_instance_var and not is_class_name: return self._HandleMethodCallLlvm(Node) FuncAttr = Node.func.attr if FuncAttr in Gen.structs: result = self._HandleClassNewLlvm(Node, FuncAttr) 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) if FuncAttr in self.Trans.SymbolTable: SymInfo = self.Trans.SymbolTable[FuncAttr] if SymInfo.IsStruct: if FuncAttr not in Gen.structs: self._ensure_struct_declared(FuncAttr) if FuncAttr in Gen.structs: result = self._HandleClassNewLlvm(Node, FuncAttr) if result is not None: return result if getattr(SymInfo, 'IsEnumMember', False) and getattr(SymInfo, 'EnumName', None): EnumName = SymInfo.EnumName if EnumName in self.Trans.SymbolTable: EnumInfo = self.Trans.SymbolTable[EnumName] if getattr(EnumInfo, 'IsRenum', False): result = self._HandleREnumConstructLlvm(Node, EnumName, FuncAttr, SymInfo.value) if result is not None: return result FullAttrKey = f"{ModulePath}.{FuncAttr}" if FullAttrKey in self.Trans.SymbolTable: SymInfo = self.Trans.SymbolTable[FullAttrKey] if SymInfo.IsStruct: if FuncAttr not in Gen.structs: self._ensure_struct_declared(FuncAttr) if FuncAttr in Gen.structs: result = self._HandleClassNewLlvm(Node, FuncAttr) 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 FullAttrKey in self.Trans.SymbolTable: SymInfo = self.Trans.SymbolTable[FullAttrKey] if getattr(SymInfo, 'IsTypedef', False): return ir.Constant(ir.IntType(32), 0) if getattr(SymInfo, 'IsStruct', False): if FuncAttr not in Gen.structs: self._ensure_struct_declared(FuncAttr) if FuncAttr in Gen.structs: result = self._HandleClassNewLlvm(Node, FuncAttr) if result is not None: return result if FuncAttr in Gen.structs: result = self._HandleClassNewLlvm(Node, FuncAttr) 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 elif isinstance(arg, ast.Str): msg = arg.s 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 (inner_attr in self.Trans.SymbolTable and getattr(self.Trans.SymbolTable[inner_attr], 'IsStruct', False)): 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()) aliases = getattr(self.Trans, '_ImportAliases', {}) ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {}) IsKnown = (ModulePath in imported or ModulePath in aliases or ModulePath in ModuleSha1Map) if not IsKnown and ModulePath and '.' in ModulePath: LastPart = ModulePath.split('.')[-1] IsKnown = (LastPart in imported or LastPart in aliases or LastPart in ModuleSha1Map) # 最后尝试: 用 FuncAttr 直接查找 Gen.functions(_find_function 会遍历 SHA1 前缀) if FuncAttr and ModulePath and ModulePath not in {'t', 'c'}: # 先检查 FuncAttr 是否是函数/变量,如果是则跳过 struct 声明 _attr_sym = self.Trans.SymbolTable.get(FuncAttr) _is_func_or_var = _attr_sym and (getattr(_attr_sym, 'IsFunction', False) or getattr(_attr_sym, 'IsVariable', False)) if not _is_func_or_var and ModulePath: _full_key = f"{ModulePath}.{FuncAttr}" _full_sym = self.Trans.SymbolTable.get(_full_key) if _full_sym and (getattr(_full_sym, 'IsFunction', False) or getattr(_full_sym, 'IsVariable', False)): _is_func_or_var = True # 优先检查 FuncAttr 是否为 struct/类构造器 if not _is_func_or_var and FuncAttr not in Gen.structs: self._ensure_struct_declared(FuncAttr) if not _is_func_or_var and FuncAttr in Gen.structs: result = self._HandleClassNewLlvm(Node, FuncAttr) if result is not None: return result # 检查 FullAttrKey 是否为 struct(如 hashlib.md5) if ModulePath: FullAttrKey = f"{ModulePath}.{FuncAttr}" if FullAttrKey in self.Trans.SymbolTable: FullSymInfo = self.Trans.SymbolTable[FullAttrKey] if getattr(FullSymInfo, 'IsStruct', False) or getattr(FullSymInfo, 'IsCpythonObject', False): if FuncAttr not in Gen.structs: self._ensure_struct_declared(FuncAttr) if FuncAttr in Gen.structs: result = self._HandleClassNewLlvm(Node, FuncAttr) 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 if decl_name not in Gen.functions: func_decl = ir.Function(Gen.module, stub_func_type, name=decl_name) Gen.functions[decl_name] = func_decl if decl_name != FuncAttr and FuncAttr not in Gen.functions: Gen.functions[FuncAttr] = func_decl else: func_decl = Gen.functions[decl_name] 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): Gen = self.Trans.LlvmGen # 如果名称是函数或变量,不应创建 struct SymInfo = self.Trans.SymbolTable.get(class_name) if SymInfo and (getattr(SymInfo, 'IsFunction', False) or getattr(SymInfo, 'IsVariable', False)): 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) 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: return SymInfo = self.Trans.SymbolTable.get(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) 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) else: if class_name not in Gen.structs: self.Trans.ImportHandler._TryLoadStructFromStub(class_name, Gen) Gen._get_or_create_struct(class_name) def _HandleStaticMethodCallLlvm(self, Node, ClassName, MethodName): Gen = 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 = ir.Function(Gen.module, stub_func_type, name=MangledName) Gen.functions[MangledName] = func 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 = ir.Function(Gen.module, stub_func_type, name=MangledName) Gen.functions[MangledName] = func if not func: if ClassName not in Gen.structs: self._ensure_struct_declared(ClassName) SymKey = f'{ClassName}.{MethodName}' SymInfo = self.Trans.SymbolTable.get(SymKey) or self.Trans.SymbolTable.get(MethodName) if SymInfo and SymInfo.IsFunction: ret_type_info = getattr(SymInfo, 'FuncPtrReturn', None) if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType: ret_type = ret_type_info.ToLLVM(Gen) else: ret_type = Gen._CType2LLVM('i32', False) param_type_infos = [pt for _, pt in (getattr(SymInfo, 'FuncPtrParams', None) or [])] if isinstance(ret_type, ir.VoidType): ret_type = ir.IntType(32) llvm_param_types = [] is_static = hasattr(SymInfo, 'MetaList') and FuncMeta.STATIC_METHOD in SymInfo.MetaList if ClassName in Gen.structs and not is_static: llvm_param_types.append(ir.PointerType(Gen.structs[ClassName])) for pt in param_type_infos: if isinstance(pt, CTypeInfo) and pt.BaseType: lp = pt.ToLLVM(Gen) else: lp = Gen._CType2LLVM(pt if isinstance(pt, str) else 'i32', '*' in pt if isinstance(pt, str) else False) if isinstance(lp, ir.VoidType): lp = ir.IntType(8).as_pointer() llvm_param_types.append(lp) func_type = ir.FunctionType(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 = [] SymKey = f'{ClassName}.{MethodName}' SymInfo = self.Trans.SymbolTable.get(SymKey) or self.Trans.SymbolTable.get(MethodName) is_static_call = SymInfo is not None and hasattr(SymInfo, 'MetaList') and FuncMeta.STATIC_METHOD in SymInfo.MetaList is_classmethod_call = SymInfo is not None and hasattr(SymInfo, 'MetaList') 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 in Gen.class_vtable 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) 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, VarName, ClassName): Gen = 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._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, module_name, attr_name): 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): 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): Gen = 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, ir_template, input_ops, output_targets, all_ops, ret_type): import re 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, result, output_targets): 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, type_str): 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, val, expected_type_str): 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, func_name, ModulePath): Gen = self.Trans.LlvmGen # 解析 import 别名: 如 window -> vpsdk.window if ModulePath and ModulePath not in ('c', 't'): import_aliases = getattr(self.Trans, '_ImportAliases', {}) if ModulePath in import_aliases: ModulePath = import_aliases[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 getattr(self.Trans, '_ImportAliases', {}))) 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_key = f'{ModulePath}.{func_name}' sym_info = self.Trans.SymbolTable.get(sym_key) or self.Trans.SymbolTable.get(func_name) is_inline = sym_info and (getattr(sym_info, 'IsInline', False) or isinstance(getattr(sym_info, 'Storage', None), t.CInline)) if is_inline and getattr(sym_info, 'InlineBody', None): self._HandleInlineExpandLlvm(Node, sym_info) return ir.Constant(ir.IntType(32), 1) sym_info_exact = self.Trans.SymbolTable.get(sym_key) if sym_info_exact: exact_params = getattr(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)) for i in range(len(exact_param_names)): 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 if decl_name in Gen.functions: func_decl = Gen.functions[decl_name] else: func_decl = ir.Function(Gen.module, stub_func_type, name=decl_name) Gen.functions[decl_name] = func_decl if decl_name != func_name and func_name not in Gen.functions: Gen.functions[func_name] = func_decl return self._HandleClosureCallLlvm(Node, decl_name) sym_key = f'{ModulePath}.{func_name}' sym_info = self.Trans.SymbolTable.get(sym_key) if not sym_info: sym_info = self.Trans.SymbolTable.get(func_name) if sym_info: is_func = getattr(sym_info, 'IsFunction', False) sym_is_variadic = getattr(sym_info, 'IsVariadic', False) if is_func: ret_type_info = getattr(sym_info, 'FuncPtrReturn', None) if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType: ret_type = ret_type_info.ToLLVM(Gen) else: ret_type = Gen._CType2LLVM('i32', False) sym_params = getattr(sym_info, 'FuncPtrParams', []) param_type_infos = [pt for _, pt in sym_params] if isinstance(ret_type, ir.VoidType): ret_type = ir.IntType(32) llvm_param_types = [] for pi, pt in enumerate(param_type_infos): if isinstance(pt, CTypeInfo) and pt.BaseType: lp = pt.ToLLVM(Gen) else: lp = Gen._CType2LLVM(pt if isinstance(pt, str) else 'i32', '*' in pt if isinstance(pt, str) else False) if isinstance(lp, ir.VoidType): lp = ir.IntType(8).as_pointer() llvm_param_types.append(lp) if mangled_name not in Gen.functions: func_type = ir.FunctionType(ret_type, llvm_param_types, var_arg=sym_is_variadic) func_decl = ir.Function(Gen.module, func_type, name=mangled_name) Gen.functions[mangled_name] = func_decl else: existing = Gen.functions[mangled_name] existing_type = getattr(existing, 'ftype', None) new_type = ir.FunctionType(ret_type, llvm_param_types, var_arg=sym_is_variadic) if existing_type and existing_type != new_type: replaced = self.Trans.FunctionHandler._replace_function_decl(Gen, func_name, new_type) if replaced and replaced != existing: Gen.functions[mangled_name] = replaced 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 elif isinstance(arg, ast.Str): msg = arg.s 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 func_decl = ir.Function(Gen.module, stub_func_type, name=decl_name) Gen.functions[decl_name] = func_decl if decl_name != func_name: Gen.functions[func_name] = func_decl return self._HandleClosureCallLlvm(Node, decl_name) sym_key = f'{ModulePath}.{func_name}' if ModulePath else func_name sym_info = self.Trans.SymbolTable.get(sym_key) if not sym_info: sym_info = self.Trans.SymbolTable.get(func_name) if sym_info: is_func = getattr(sym_info, 'IsFunction', False) sym_is_variadic = getattr(sym_info, 'IsVariadic', False) if is_func: ret_type_info = getattr(sym_info, 'FuncPtrReturn', None) if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType: ret_type = ret_type_info.ToLLVM(Gen) else: ret_type = Gen._CType2LLVM('i32', False) param_type_infos = [pt for _, pt in getattr(sym_info, 'FuncPtrParams', [])] if isinstance(ret_type, ir.VoidType): ret_type = ir.IntType(32) llvm_param_types = [] for pt in param_type_infos: if isinstance(pt, CTypeInfo) and pt.BaseType: lp = pt.ToLLVM(Gen) else: lp = Gen._CType2LLVM(pt if isinstance(pt, str) else 'i32', '*' in pt if isinstance(pt, str) else False) if isinstance(lp, ir.VoidType): lp = ir.IntType(8).as_pointer() llvm_param_types.append(lp) mangled_name = Gen._mangle_func_name(func_name, ModulePath) if mangled_name not in Gen.functions: func_type = ir.FunctionType(ret_type, llvm_param_types, var_arg=sym_is_variadic) func_decl = ir.Function(Gen.module, func_type, name=mangled_name) Gen.functions[mangled_name] = func_decl else: existing = Gen.functions[mangled_name] existing_type = getattr(existing, 'ftype', None) new_type = ir.FunctionType(ret_type, llvm_param_types, var_arg=sym_is_variadic) if existing_type and existing_type != new_type: replaced = self.Trans.FunctionHandler._replace_function_decl(Gen, func_name, new_type) if replaced and replaced != existing: Gen.functions[mangled_name] = replaced return self._HandleClosureCallLlvm(Node, mangled_name) return None def _HandleTypeUnionCastLlvm(self, Node): Gen = self.Trans.LlvmGen if not Node.args: return None from lib.core.Handles.HandlesBase import CTypeInfo type_info = None try: type_info = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.func) except Exception as _e: from lib.core.VLogger import get_logger as _vlog from lib.constants.config import mode as _config_mode if _config_mode == "strict": raise _vlog().warning(f"解析类型失败: {_e}", "Exception") if 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, target_type_str): 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: 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, RenumName, VariantName, TagValue): Gen = self.Trans.LlvmGen 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}") Gen._store(ArgVal, elem_ptr) return result def _HandleTypedefCastLlvm(self, Node, TypedefName): Gen = self.Trans.LlvmGen SymInfo = self.Trans.SymbolTable.get(TypedefName) if not SymInfo or not SymInfo.IsTypedef: return ir.Constant(ir.IntType(32), 0) 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, sym_info): 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, FuncName): 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] 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)) else: adjusted.append(arg) except Exception: # 回退:参数类型调整失败时使用原值 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: # 有符号整数用 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: adjusted = Gen._adjust_args(CallArgs, func) result = Gen.builder.call(func, adjusted, name=f"call_{FuncName}") self._check_eh_return(result, FuncName, Gen, called_func=func) return result def _HandleMethodCallLlvm(self, Node): 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.get(SymKey) if SymInfo and hasattr(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 Node.func.value.id == 't': result = self.Trans.TSpecialCallHandle._HandleTSpecialCallLlvm(Node) if result is not None: return result from lib.includes.t import CTypeRegistry 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 Node.args[1].value.id == 't') 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 MethodName in self.Trans.SymbolTable: 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 elif isinstance(arg, ast.Str): msg = arg.s else: try: val = self.HandleExprLlvm(arg) if isinstance(val, str): msg = val except Exception as _e: from lib.core.VLogger import get_logger as _vlog from lib.constants.config import mode as _config_mode if _config_mode == "strict": raise _vlog().warning(f"处理函数调用失败: {_e}", "Exception") 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 aliases = getattr(self.Trans, '_ImportAliases', {}) imported = getattr(self.Trans, '_ImportedModules', set()) actual_module = aliases.get(ModuleName, 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: 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: 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: 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: 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 = ir.Function(Gen.module, stub_func_type, name=mangled_name) Gen.functions[mangled_name] = func 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) 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: 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 for CN, ST in Gen.structs.items(): if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): continue method_key = f'{CN}.{MethodName}' if not Gen._has_function(method_key): continue try: casted = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}") ClassName = CN ObjVal = casted 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}' if ClassName in Gen.class_vtable 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 = ir.Function(Gen.module, stub_func_type, name=FullMethodName) Gen.functions[FullMethodName] = func 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 = ir.Function(Gen.module, stub_func_type, name=FullMethodName) Gen.functions[FullMethodName] = func if func: 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(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}')") def _HandlePrintLlvm(self, Node): Gen = self.Trans.LlvmGen printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) args = Node.args end_arg = None sep_arg = None if Node.keywords: for kw in Node.keywords: if kw.arg == 'end': end_arg = kw.value elif kw.arg == 'sep': sep_arg = kw.value sep_str = ' ' if sep_arg and isinstance(sep_arg, ast.Constant) and isinstance(sep_arg.value, str): sep_str = sep_arg.value end_str = '\n' if end_arg: if isinstance(end_arg, ast.Constant) and isinstance(end_arg.value, str): end_str = end_arg.value elif isinstance(end_arg, ast.Constant) and end_arg.value is None: end_str = '' if not args: if end_str: nl_fmt = Gen.emit_constant(end_str, 'string') Gen.builder.call(printf_func, [nl_fmt], name="print_nl") return has_fstring = any(isinstance(arg, ast.JoinedStr) for arg in args) if has_fstring: self._HandlePrintWithFString(Node, printf_func, args, sep_str, end_str) return fmt_parts = [] fmt_args = [] for i, arg in enumerate(args): if i > 0: fmt_parts.append(sep_str) val = self.HandleExprLlvm(arg) if not val: fmt_parts.append('(null)') continue if isinstance(val, ir.Constant) and isinstance(val.type, ir.PointerType) and val.constant is None: fmt_parts.append('nil') continue if isinstance(val.type, ir.PointerType): pointee = val.type.pointee if self._is_char_pointer(val): fmt_parts.append('%s') fmt_args.append(val) elif isinstance(pointee, ir.ArrayType) and isinstance(pointee.element, ir.IntType) and pointee.element.width == 8: elem_ptr = Gen.builder.gep(val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="print_arr_to_ptr") fmt_parts.append('%s') fmt_args.append(elem_ptr) elif isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): ClassName = self.Trans.ExprHandler._get_var_class(arg, Gen) if not ClassName and isinstance(arg, ast.Name): ClassName = Gen.var_struct_class.get(arg.id) if ClassName and Gen._has_function(f'{ClassName}.__str__'): if self._is_char_pointer(val): if ClassName in Gen.structs: val = Gen.builder.bitcast(val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [val], name=f"call_{ClassName}.__str__") fmt_parts.append('%s') fmt_args.append(str_val) else: int_val = Gen.builder.ptrtoint(val, ir.IntType(64), name="print_ptr_to_int") fmt_parts.append('0x%llx') fmt_args.append(int_val) else: int_val = Gen.builder.ptrtoint(val, ir.IntType(64), name="print_ptr_to_int") fmt_parts.append('%lld') fmt_args.append(int_val) elif isinstance(val.type, ir.IntType): is_unsigned = self._is_val_unsigned(arg, val) if val.type.width == 1: fmt_parts.append('%d') val = Gen.builder.zext(val, ir.IntType(32), name="zext_bool_print") elif val.type.width == 8: if self._is_char_type(arg): char_var = Gen._allocaEntry(ir.IntType(8), name="print_char_buf") Gen.builder.store(val, char_var) fmt_parts.append('%c') fmt_args.append(char_var) continue fmt_parts.append('%d') if is_unsigned: val = Gen.builder.zext(val, ir.IntType(32), name="zext_i8_print") else: val = Gen.builder.sext(val, ir.IntType(32), name="sext_i8_print") elif val.type.width == 16: fmt_parts.append('%u' if is_unsigned else '%d') if is_unsigned: val = Gen.builder.zext(val, ir.IntType(32), name="zext_i16_print") else: val = Gen.builder.sext(val, ir.IntType(32), name="sext_i16_print") elif val.type.width == 32: fmt_parts.append('%u' if is_unsigned else '%d') elif val.type.width == 64: fmt_parts.append('%llu' if is_unsigned else '%lld') else: fmt_parts.append('%d') val = Gen.builder.zext(val, ir.IntType(32), name="zext_int_print") fmt_args.append(val) elif isinstance(val.type, ir.FloatType): fmt_parts.append('%f') fmt_args.append(Gen.builder.fpext(val, ir.DoubleType(), name="fpext_printf_float")) elif isinstance(val.type, ir.DoubleType): fmt_parts.append('%f') fmt_args.append(val) else: fmt_parts.append('(unknown)') fmt_parts.append(end_str) fmt_str = ''.join(fmt_parts) fmt_bytes = fmt_str.encode('utf-8') + b'\x00' fmt_type = ir.ArrayType(ir.IntType(8), len(fmt_bytes)) fmt_const = ir.Constant(fmt_type, bytearray(fmt_bytes)) fmt_gvar = ir.GlobalVariable(Gen.module, fmt_type, name=f"str_const_{Gen.string_const_counter}") Gen.string_const_counter += 1 fmt_gvar.initializer = fmt_const fmt_gvar.linkage = 'internal' fmt_ptr = Gen.builder.bitcast(fmt_gvar, ir.PointerType(ir.IntType(8)), name="print_fmt") call_args = [fmt_ptr] + fmt_args Gen.builder.call(printf_func, call_args, name="print_call") def _HandlePrintWithFString(self, Node, printf_func, args, sep_str, end_str): Gen = self.Trans.LlvmGen for i, arg in enumerate(args): if i > 0: sep_const = Gen.emit_constant(sep_str, 'string') Gen.builder.call(printf_func, [sep_const], name="print_sep") if isinstance(arg, ast.JoinedStr): self.HandleExprLlvm(arg) else: ClassName = self.Trans.ExprHandler._get_var_class(arg, Gen) if not ClassName and isinstance(arg, ast.Name): ClassName = Gen.var_struct_class.get(arg.id) if ClassName and Gen._has_function(f'{ClassName}.__str__'): obj_val = self.HandleExprLlvm(arg) if obj_val: if self._is_char_pointer(obj_val): if ClassName in Gen.structs: obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [obj_val], name=f"call_{ClassName}.__str__") Gen._RegisterTempPtr(str_val) Gen._emit_printf([str_val], unsigned_flags=[False], sep=None, end=None) elif isinstance(arg, ast.Name) and arg.id in Gen.var_struct_class: ClassName = Gen.var_struct_class[arg.id] obj_val = self.HandleExprLlvm(arg) if obj_val and ClassName in Gen.structs: str_func = Gen._find_function(f'{ClassName}.__str__') if str_func: if isinstance(obj_val.type, ir.PointerType) and not isinstance(obj_val.type.pointee, type(Gen.structs[ClassName])): obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") str_val = Gen.builder.call(str_func, [obj_val], name=f"call_{ClassName}.__str__") Gen._RegisterTempPtr(str_val) Gen._emit_printf([str_val], unsigned_flags=[False], sep=None, end=None) else: val = self.HandleExprLlvm(arg) self._print_value(val=val, arg=arg, Gen=Gen, fmt_parts=fmt_parts, fmt_args=fmt_args) else: val = self.HandleExprLlvm(arg) self._print_value(val=val, arg=arg, Gen=Gen, fmt_parts=fmt_parts, fmt_args=fmt_args) else: val = self.HandleExprLlvm(arg) if val: if isinstance(val.type, ir.PointerType): pointee = val.type.pointee if not self._is_char_pointer(val): try: val = Gen._load(val, name="print_Load") except Exception as _e: if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") is_u = Gen._check_node_unsigned(arg) if not is_u and id(val) in Gen._unsigned_results: is_u = True Gen._emit_printf([val], unsigned_flags=[is_u], sep=None, end=None) if end_str: end_const = Gen.emit_constant(end_str, 'string') Gen.builder.call(printf_func, [end_const], name="print_end") def _is_char_type(self, arg_node): if isinstance(arg_node, ast.Call): if isinstance(arg_node.func, ast.Name): return arg_node.func.id in ('CChar', 'CUInt8T', 'CInt8T') if isinstance(arg_node.func, ast.Attribute): return arg_node.func.attr in ('CChar', 'CUInt8T', 'CInt8T') return False def _is_val_unsigned(self, arg_node, val): Gen = self.Trans.LlvmGen if isinstance(arg_node, ast.Name): var_name = arg_node.id signedness = Gen.var_signedness.get(var_name) if signedness: if isinstance(signedness, bool): return signedness return 'unsigned' in signedness if isinstance(val.type, ir.IntType): return False return False _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)]), } def _try_declare_c_lib_func(self, func_name, Gen): 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): 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 __import__('lib.constants.config', fromlist=['mode']).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 _HandleSizeofLlvm(self, Node): 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: from lib.includes.t import CTypeRegistry 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: from lib.core.VLogger import get_logger as _vlog from lib.constants.config import mode as _config_mode if _config_mode == "strict": raise _vlog().warning(f"解析类型失败: {_e}", "Exception") 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: from lib.core.VLogger import get_logger as _vlog from lib.constants.config import mode as _config_mode if _config_mode == "strict": raise _vlog().warning(f"解析类型失败: {_e}", "Exception") return ir.Constant(ir.IntType(64), 0) struct_type = Gen.structs[type_name] if isinstance(struct_type, ir.PointerType): struct_type = struct_type.pointee 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) 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): 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): Gen = self.Trans.LlvmGen return ir.Constant(ir.IntType(8).as_pointer(), None) def _HandleTypeLlvm(self, Node): 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 and arg_name in self.Trans.SymbolTable: TypeInfo = self.Trans.SymbolTable[arg_name] if 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 if LastPart in self.Trans.SymbolTable: AttrInfo = self.Trans.SymbolTable[LastPart] if 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): if qname in self.Trans.SymbolTable: info = self.Trans.SymbolTable[qname] if 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): 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): 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): 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): 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): 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): 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): 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): 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): 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): 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): Gen = self.Trans.LlvmGen return None def _HandleVaEndLlvm(self, args): Gen = self.Trans.LlvmGen return None def _HandleArgLlvm(self, args, CallNode=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.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 from lib.includes.t import CTypeRegistry 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 type_arg.value.id == 't': attr_name = type_arg.attr from lib.includes.t import CTypeRegistry 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): left = ann.left if isinstance(left, ast.Name): ann_name = left.id elif isinstance(left, ast.Attribute): ann_name = left.attr if ann_name: from lib.includes.t import CTypeRegistry 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): Gen = self.Trans.LlvmGen return ir.Constant(ir.IntType(32), 0) def _HandleCDerefAsLlvm(self, Node): Gen = self.Trans.LlvmGen if len(Node.args) < 2: return ir.Constant(ir.IntType(32), 0) ptr_val = self.HandleExprLlvm(Node.args[0]) val_val = 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 = val_val if isinstance(val_val.type, ir.PointerType): void_pp = 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 _HandleClassNewLlvm(self, Node, ClassName): Gen = self.Trans.LlvmGen 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 = Gen.structs.get(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) for kw in Node.keywords: ArgVal = self.HandleExprLlvm(kw.value) if ArgVal: NewMethodArgs.append(ArgVal) self._fill_default_args(NewMethodArgs, NewMethodFunc, NewMethodFuncName) 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") 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) for kw in Node.keywords: ArgVal = self.HandleExprLlvm(kw.value) if ArgVal: InitArgs.append(ArgVal) self._fill_default_args(InitArgs, InitFunc, InitFuncName) self._append_eh_msg_out_arg(InitArgs, InitFunc, Gen) adjusted_init = Gen._adjust_args(InitArgs, InitFunc) Gen.builder.call(InitFunc, adjusted_init, name=f"init_{ClassName}") return result if 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) 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: result = Gen._allocaEntry(StructType, name=f"{ClassName}_alloca") Gen.builder.store(ir.Constant(StructType, None), result) 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] for arg in Node.args: ArgVal = self.HandleExprLlvm(arg) if ArgVal: InitArgs.append(ArgVal) for kw in Node.keywords: ArgVal = self.HandleExprLlvm(kw.value) if ArgVal: InitArgs.append(ArgVal) self._fill_default_args(InitArgs, InitFunc, InitFuncName) self._append_eh_msg_out_arg(InitArgs, InitFunc, Gen) adjusted_init = Gen._adjust_args(InitArgs, InitFunc) Gen.builder.call(InitFunc, adjusted_init, name=f"init_{ClassName}") return result 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) for kw in Node.keywords: ArgVal = self.HandleExprLlvm(kw.value) if ArgVal: NewMethodArgs.append(ArgVal) self._fill_default_args(NewMethodArgs, NewMethodFunc, NewMethodFuncName) 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") 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) for kw in Node.keywords: kw_idx = None if hasattr(InitFunc, 'args'): for j, a in enumerate(InitFunc.args): if a.name == kw.arg: kw_idx = j break kw_var_type = init_param_types[kw_idx] if kw_idx is not None and kw_idx < len(init_param_types) else None ArgVal = self.HandleExprLlvm(kw.value, VarType=kw_var_type) if ArgVal: InitArgs.append(ArgVal) self._fill_default_args(InitArgs, InitFunc, InitFuncName) self._append_eh_msg_out_arg(InitArgs, InitFunc, Gen) 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, StructType): Gen = 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): 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, ClassName, StructType): Gen = self.Trans.LlvmGen defaults = Gen.class_member_defaults.get(ClassName, {}) members = 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 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, Node, ClassName, StructType): Gen = self.Trans.LlvmGen if not isinstance(StructType, ir.IdentifiedStructType): return members = Gen.class_members.get(ClassName, []) has_vtable = ClassName in Gen.class_vtable 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): Gen = self.Trans.LlvmGen ClassName = 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: 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, FuncName): Gen = self.Trans.LlvmGen template = self.Trans.FunctionHandler._generic_templates[FuncName] type_param_names = template['type_params'] type_args = [] CallArgs = [] 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] adjusted = Gen._adjust_args(CallArgs, func) return Gen.builder.call(func, adjusted, name=f"call_{spec_name}") def _HandleGenericClassNewLlvm(self, Node, ClassName): Gen = self.Trans.LlvmGen template = self.Trans.ClassHandler._generic_class_templates[ClassName] type_param_names = template['type_params'] type_args = [] type_names = [] all_inferred = [] 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.get(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)