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