Files
TransPyC/lib/core/Handles/HandlesExprCall.py

3447 lines
193 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 self.Trans.SymbolTable.has(FuncName):
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:
first_part = ModulePath.split('.')[0]
resolved_first = self.Trans.SymbolTable.resolve_alias(first_part)
if resolved_first != first_part:
ModulePath = resolved_first + ModulePath[len(first_part):]
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 self.Trans.SymbolTable.is_struct(Node.func.value.id))
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 self.Trans.SymbolTable.has(FuncAttr):
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 SymInfo.IsEnumMember and SymInfo.EnumName:
EnumName = SymInfo.EnumName
if self.Trans.SymbolTable.has(EnumName):
EnumInfo = self.Trans.SymbolTable[EnumName]
if EnumInfo.IsRenum:
result = self._HandleREnumConstructLlvm(Node, EnumName, FuncAttr, SymInfo.value)
if result is not None:
return result
FullAttrKey = f"{ModulePath}.{FuncAttr}"
if self.Trans.SymbolTable.has(FullAttrKey):
SymInfo = self.Trans.SymbolTable[FullAttrKey]
if SymInfo.IsStruct:
if FuncAttr not in Gen.structs:
self._ensure_struct_declared(FuncAttr)
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 self.Trans.SymbolTable.has(FullAttrKey):
SymInfo = self.Trans.SymbolTable[FullAttrKey]
if SymInfo.IsTypedef:
return ir.Constant(ir.IntType(32), 0)
if SymInfo.IsStruct:
if FuncAttr not in Gen.structs:
self._ensure_struct_declared(FuncAttr)
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 self.Trans.SymbolTable.is_struct(inner_attr):
static_result = self._HandleStaticMethodCallLlvm(Node, inner_attr, FuncAttr)
if static_result is not None:
return static_result
MethodResult_attr = self._HandleMethodCallLlvm(Node)
is_zero_attr = isinstance(MethodResult_attr, ir.Constant) and isinstance(MethodResult_attr.type, ir.IntType) and MethodResult_attr.constant == 0
if MethodResult_attr is not None and not is_zero_attr:
return MethodResult_attr
result = self._HandleExternalCallLlvm(Node, FuncAttr, ModulePath)
if result is not None:
return result
MethodResult = self._HandleMethodCallLlvm(Node)
IsZeroResult = isinstance(MethodResult, ir.Constant) and isinstance(MethodResult.type, ir.IntType) and MethodResult.constant == 0
if IsZeroResult and FuncAttr is not None:
mangled_name = Gen._mangle_func_name(FuncAttr, ModulePath if ModulePath and ModulePath != 't' else None)
if Gen._has_function(mangled_name):
CallArgs = []
for arg in Node.args:
ArgVal = self.HandleExprLlvm(arg)
if ArgVal:
CallArgs.append(ArgVal)
return Gen.builder.call(Gen._get_function(mangled_name), CallArgs, name=f"call_{FuncAttr}")
if MethodResult is None or IsZeroResult:
imported = getattr(self.Trans, '_ImportedModules', set())
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
IsKnown = (ModulePath in imported or ModulePath in self.Trans.SymbolTable.import_aliases or
ModulePath in ModuleSha1Map)
if not IsKnown and ModulePath and '.' in ModulePath:
LastPart = ModulePath.split('.')[-1]
IsKnown = (LastPart in imported or LastPart in self.Trans.SymbolTable.import_aliases or
LastPart in ModuleSha1Map)
# 最后尝试: 用 FuncAttr 直接查找 Gen.functions_find_function 会遍历 SHA1 前缀)
if FuncAttr and ModulePath and ModulePath not in {'t', 'c'}:
# 先检查 FuncAttr 是否是函数/变量,如果是则跳过 struct 声明
_attr_sym = self.Trans.SymbolTable.lookup(FuncAttr)
_is_func_or_var = _attr_sym and (_attr_sym.IsFunction or _attr_sym.IsVariable)
if not _is_func_or_var and ModulePath:
_full_key = f"{ModulePath}.{FuncAttr}"
_full_sym = self.Trans.SymbolTable.lookup(_full_key)
if _full_sym and (_full_sym.IsFunction or _full_sym.IsVariable):
_is_func_or_var = True
# 优先检查 FuncAttr 是否为 struct/类构造器
if not _is_func_or_var and FuncAttr not in Gen.structs:
self._ensure_struct_declared(FuncAttr)
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 self.Trans.SymbolTable.has(FullAttrKey):
FullSymInfo = self.Trans.SymbolTable[FullAttrKey]
if FullSymInfo.IsStruct or FullSymInfo.IsCpythonObject:
if FuncAttr not in Gen.structs:
self._ensure_struct_declared(FuncAttr)
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.lookup(class_name)
if SymInfo and (SymInfo.IsFunction or SymInfo.IsVariable):
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.lookup(class_name)
if SymInfo and SymInfo.Members:
member_types = []
if isinstance(SymInfo.Members, dict):
for member_name, member_info in SymInfo.Members.items():
if isinstance(member_info, CTypeInfo):
mt = member_info.ToLLVM(Gen)
elif isinstance(member_info, str):
mt = Gen._CType2LLVM(member_info, '*' in member_info)
else:
mt = Gen._CType2LLVM(str(member_info) if member_info else 'int', False)
if isinstance(mt, ir.VoidType):
mt = ir.IntType(8)
member_types.append(mt)
else:
for item in SymInfo.Members:
if isinstance(item, (list, tuple)) and len(item) == 2:
member_name, member_type_str = item
mt = Gen._CType2LLVM(member_type_str, '*' in member_type_str)
if isinstance(mt, ir.VoidType):
mt = ir.IntType(8)
member_types.append(mt)
if member_types:
st = Gen._get_or_create_struct(class_name)
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.lookup(SymKey) or self.Trans.SymbolTable.lookup(MethodName)
if SymInfo and SymInfo.IsFunction:
ret_type_info = SymInfo.FuncPtrReturn
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 (SymInfo.FuncPtrParams or [])]
if isinstance(ret_type, ir.VoidType):
ret_type = ir.IntType(32)
llvm_param_types = []
is_static = 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.lookup(SymKey) or self.Trans.SymbolTable.lookup(MethodName)
is_static_call = SymInfo is not None and FuncMeta.STATIC_METHOD in SymInfo.MetaList
is_classmethod_call = SymInfo is not None and FuncMeta.CLASS_METHOD in SymInfo.MetaList
# @classmethod: 在参数列表前插入 cls栈上分配的类实例指针
if is_classmethod_call and ClassName in Gen.structs:
ClsPtr = Gen._alloca(Gen.structs[ClassName], name=f"cls_{ClassName}")
CallArgs.append(ClsPtr)
for arg in Node.args:
ArgVal = self.HandleExprLlvm(arg)
if ArgVal:
CallArgs.append(ArgVal)
if ClassName 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'):
ModulePath = self.Trans.SymbolTable.resolve_alias(ModulePath)
is_user_module = (ModulePath and ModulePath not in ('c', 't') and
(ModulePath in Gen.ModuleSha1Map or
ModulePath in getattr(self.Trans, '_ImportedModules', set()) or
ModulePath in self.Trans.SymbolTable.import_aliases))
if ModulePath and ModulePath not in ('c', 't') and not is_user_module:
is_user_module = (ModulePath in Gen.ModuleSha1Map or
ModulePath.split('.')[-1] in Gen.ModuleSha1Map or
ModulePath.split('.')[-1] in getattr(self.Trans, '_ImportedModules', set()))
if is_user_module and ModulePath not in Gen.ModuleSha1Map and ModulePath not in getattr(self.Trans, '_ImportedModules', set()):
ModulePath = ModulePath.split('.')[-1]
if ModulePath and ModulePath not in ('c', 't') and not is_user_module:
return None
if is_user_module:
mangled_name = Gen._mangle_func_name(func_name, ModulePath)
sym_key = f'{ModulePath}.{func_name}'
sym_info = self.Trans.SymbolTable.lookup(sym_key) or self.Trans.SymbolTable.lookup(func_name)
is_inline = sym_info and (sym_info.IsInline or isinstance(sym_info.Storage, t.CInline))
if is_inline and sym_info.InlineBody:
self._HandleInlineExpandLlvm(Node, sym_info)
return ir.Constant(ir.IntType(32), 1)
sym_info_exact = self.Trans.SymbolTable.lookup(sym_key)
if sym_info_exact:
exact_params = sym_info_exact.FuncPtrParams
exact_param_names = [pn for pn, _ in exact_params]
if exact_param_names:
provided = len(Node.args)
kw_provided = set()
for kw in Node.keywords:
if kw.arg and kw.arg in exact_param_names:
kw_provided.add(exact_param_names.index(kw.arg))
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.lookup(sym_key)
if not sym_info:
sym_info = self.Trans.SymbolTable.lookup(func_name)
if sym_info:
is_func = sym_info.IsFunction
sym_is_variadic = sym_info.IsVariadic
if is_func:
ret_type_info = sym_info.FuncPtrReturn
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 = 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.lookup(sym_key)
if not sym_info:
sym_info = self.Trans.SymbolTable.lookup(func_name)
if sym_info:
is_func = sym_info.IsFunction
sym_is_variadic = sym_info.IsVariadic
if is_func:
ret_type_info = sym_info.FuncPtrReturn
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 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.lookup(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.lookup(SymKey)
if SymInfo and SymInfo.MetaList:
if FuncMeta.STATIC_METHOD in SymInfo.MetaList:
return self._HandleStaticMethodCallLlvm(Node, ClassName, MethodName)
if FuncMeta.CLASS_METHOD in SymInfo.MetaList:
return self._HandleStaticMethodCallLlvm(Node, ClassName, MethodName)
if isinstance(Node.func.value, ast.Name) and 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 self.Trans.SymbolTable.has(MethodName):
SymInfo = self.Trans.SymbolTable[MethodName]
if SymInfo.IsTypedef:
return self._HandleTypedefCastLlvm(Node, MethodName)
if isinstance(Node.func.value, ast.Name) and Node.func.value.id == 'c':
if MethodName == 'Asm':
return self.Trans.ExprAsmHandle._HandleAsmLlvm(Node)
if MethodName == 'Addr':
return self.Trans.CSpecialCallHandle._HandleCAddrLlvm(Node)
elif MethodName == 'Set':
return self.Trans.CSpecialCallHandle._HandleCSetLlvm(Node)
elif MethodName == 'Load':
return self.Trans.CSpecialCallHandle._HandleCLoadLlvm(Node)
elif MethodName == 'Deref':
return self.Trans.CSpecialCallHandle._HandleCDerefLlvm(Node)
elif MethodName == 'DerefAs':
return self._HandleCDerefAsLlvm(Node)
elif MethodName == 'PtrToInt':
return self.Trans.CSpecialCallHandle._HandleCPtrToIntLlvm(Node)
elif MethodName in ('CIf', 'CElif'):
if Node.args:
ArgVal = self.HandleExprLlvm(Node.args[0])
if ArgVal:
if isinstance(ArgVal, ir.Constant) and isinstance(ArgVal.type, ir.IntType):
return ir.Constant(ir.IntType(1), 1 if ArgVal.constant != 0 else 0)
if isinstance(ArgVal.type, ir.IntType):
return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond")
if isinstance(ArgVal.type, ir.PointerType):
return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond")
return ir.Constant(ir.IntType(1), 0)
elif MethodName in ('CIfdef', 'CIfndef'):
return ir.Constant(ir.IntType(1), 1)
elif MethodName == 'CError':
msg = "compile-time error"
if Node.args:
arg = Node.args[0]
if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
msg = arg.value
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
imported = getattr(self.Trans, '_ImportedModules', set())
actual_module = self.Trans.SymbolTable.resolve_alias(ModuleName)
if ModuleName in imported or actual_module in imported:
mangled_name = Gen._mangle_func_name(MethodName, actual_module)
if Gen._has_function(mangled_name):
CallArgs = []
for arg in Node.args:
ArgVal = self.HandleExprLlvm(arg)
if ArgVal:
CallArgs.append(ArgVal)
func = Gen._get_function(mangled_name)
self._fill_default_args(CallArgs, func, MethodName)
func_ft = getattr(func, 'function_type', None)
is_variadic = getattr(func_ft, 'var_arg', False) if func_ft else False
num_fixed_params = len(func_ft.args) if func_ft else 0
if is_variadic:
adjusted = []
for i, arg in enumerate(CallArgs):
if i < num_fixed_params:
param_type = func_ft.args[i]
if arg.type != param_type:
try:
if isinstance(arg.type, ir.IntType) and isinstance(param_type, ir.PointerType):
adjusted.append(self.builder.inttoptr(arg, param_type))
elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.IntType):
adjusted.append(Gen.builder.ptrtoint(arg, param_type))
elif isinstance(arg.type, ir.IntType) and arg.type.width < param_type.width:
adjusted.append(Gen.builder.zext(arg, param_type))
else:
adjusted.append(arg)
except Exception: # 回退:参数类型调整失败时使用原值
adjusted.append(arg)
else:
adjusted.append(arg)
else:
if isinstance(arg.type, ir.FloatType):
arg = Gen.builder.fpext(arg, ir.DoubleType(), name=f"fpext_vararg_{MethodName}")
elif isinstance(arg.type, ir.IntType) and arg.type.width < 64:
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 = "<class 'unknown' size=0 signed=false, ptr=false>"
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 self.Trans.SymbolTable.has(arg_name):
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 self.Trans.SymbolTable.has(LastPart):
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 self.Trans.SymbolTable.has(qname):
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"<enum '{enum_type_name}' size=4 signed=true, ptr=false>"
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"<class '{type_info['name']}' size={type_info['size']} signed={str(type_info['signed']).lower()}, ptr={str(type_info['ptr']).lower()}>"
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.lookup(arg_node.id)
if var_info and isinstance(var_info, dict):
var_type = var_info.get('type', '')
if var_type in ('double', 'float'):
type_str = 'double'
type_name = 'CDouble'
all_inferred.append((type_str, type_name))
hint_types = [(ts, tn) for ts, tn in all_inferred if tn != 'CInt' or ts != 'int']
for i in range(len(type_param_names)):
if i < len(hint_types):
type_args.append(hint_types[i][0])
type_names.append(hint_types[i][1])
elif i < len(all_inferred):
type_args.append(all_inferred[i][0])
type_names.append(all_inferred[i][1])
else:
type_args.append('int')
type_names.append('CInt')
spec_name = self.Trans.ClassHandler._specialize_generic_class(ClassName, type_args, Gen, type_names=type_names)
if spec_name is None:
return ir.Constant(ir.IntType(32), 0)
return self._HandleClassNewLlvm(Node, spec_name)