3447 lines
193 KiB
Python
3447 lines
193 KiB
Python
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)
|
||
|