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

359 lines
20 KiB
Python

from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle
import ast
import llvmlite.ir as ir
class CSpecialCallHandle(BaseHandle):
def _HandleCIfLlvm(self, Node):
Gen = self.Trans.LlvmGen
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)
def _HandleCAddrLlvm(self, Node):
Gen = self.Trans.LlvmGen
if not Node.args:
return ir.Constant(ir.IntType(8).as_pointer(), None)
Arg = Node.args[0]
if isinstance(Arg, ast.Call):
ClassName = None
if isinstance(Arg.func, ast.Name):
ClassName = Arg.func.id
elif isinstance(Arg.func, ast.Attribute):
ClassName = Arg.func.attr
if ClassName and ClassName in Gen.structs:
StructType = Gen.structs[ClassName]
if isinstance(StructType, ir.PointerType):
StructType = StructType.pointee
ObjPtr = Gen._allocaEntry(StructType, name=f"{ClassName}_obj")
Gen.builder.store(ir.Constant(StructType, None), ObjPtr)
ConstructorName = f"{ClassName}.__init__"
if ConstructorName in Gen.functions:
func = Gen.functions[ConstructorName]
InitArgs = [ObjPtr]
for carg in Arg.args:
ArgVal = self.HandleExprLlvm(carg)
if ArgVal:
InitArgs.append(ArgVal)
for kw in Arg.keywords:
ArgVal = self.HandleExprLlvm(kw.value)
if ArgVal:
InitArgs.append(ArgVal)
if hasattr(self.Trans.ExprCallHandle, '_append_eh_msg_out_arg'):
self.Trans.ExprCallHandle._append_eh_msg_out_arg(InitArgs, func, Gen)
adjusted = Gen._adjust_args(InitArgs, func)
Gen.builder.call(func, adjusted, name=f"{ClassName}_construct")
return Gen.builder.bitcast(ObjPtr, ir.IntType(8).as_pointer(), name=f"{ClassName}_as_i8ptr")
if isinstance(Arg, ast.Subscript):
SubPtr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Arg)
if SubPtr and isinstance(SubPtr.type, ir.PointerType):
return Gen.builder.bitcast(SubPtr, ir.IntType(8).as_pointer(), name="addr_subscript_as_i8ptr")
if isinstance(Arg, ast.Attribute):
AttrPtr = self.Trans.ExprAttrHandle._get_attr_ptr(Arg)
if AttrPtr and isinstance(AttrPtr.type, ir.PointerType):
return Gen.builder.bitcast(AttrPtr, ir.IntType(8).as_pointer(), name="addr_attr_as_i8ptr")
if isinstance(Arg, ast.Name):
VarName = Arg.id
if VarName in Gen.functions:
func = Gen.functions[VarName]
return Gen.builder.bitcast(func, ir.IntType(8).as_pointer(), name="addr_func_as_i8ptr")
if VarName in Gen.variables and Gen.variables[VarName] is not None:
var_ptr = Gen.variables[VarName]
if isinstance(var_ptr.type, ir.PointerType):
# For pointer-to-pointer allocas (var_ptr is T**):
# - If T is a named struct (@t.Object class), the variable semantically
# IS the struct, so c.Addr should return the struct pointer value.
# - If T is a primitive pointer type (e.g., i8*), the variable semantically
# holds a pointer, so c.Addr should return &var (alloca address).
if isinstance(var_ptr.type.pointee, ir.PointerType):
pointee = var_ptr.type.pointee.pointee
if isinstance(pointee, ir.IdentifiedStructType):
# @t.Object class variable — return Loaded struct pointer
ArgVal = self.HandleExprLlvm(Arg)
if ArgVal and isinstance(ArgVal.type, ir.PointerType):
return Gen.builder.bitcast(ArgVal, ir.IntType(8).as_pointer(), name="addr_as_i8ptr")
# Pointer-type variable — return alloca address (&var)
return Gen.builder.bitcast(var_ptr, ir.IntType(8).as_pointer(), name="addr_as_i8ptr")
return Gen.builder.bitcast(var_ptr, ir.IntType(8).as_pointer(), name="addr_as_i8ptr")
ArgVal = self.HandleExprLlvm(Arg)
if ArgVal:
if isinstance(ArgVal.type, ir.IntType):
alloca = Gen._alloca(ArgVal.type, name="addr_tmp")
Gen._store(ArgVal, alloca)
return Gen.builder.bitcast(alloca, ir.IntType(8).as_pointer(), name="addr_as_i8ptr")
elif isinstance(ArgVal.type, ir.PointerType):
return Gen.builder.bitcast(ArgVal, ir.IntType(8).as_pointer(), name="addr_bitcast")
return ir.Constant(ir.IntType(8).as_pointer(), None)
def _HandleCSetLlvm(self, Node):
Gen = self.Trans.LlvmGen
if len(Node.args) >= 2:
target_arg = Node.args[0]
value_arg = Node.args[1]
target_ptr = None
if isinstance(target_arg, ast.Call) and isinstance(target_arg.func, ast.Attribute):
if isinstance(target_arg.func.value, ast.Name) and target_arg.func.value.id == 'c':
if target_arg.func.attr == 'Deref' and target_arg.args:
deref_arg = target_arg.args[0]
if isinstance(deref_arg, ast.Name) and deref_arg.id in Gen.variables and Gen.variables[deref_arg.id] is not None:
target_ptr = Gen._load(Gen.variables[deref_arg.id], name="deref_load_ptr")
else:
inner_value = self.HandleExprLlvm(deref_arg)
if inner_value:
if isinstance(inner_value.type, ir.PointerType):
if isinstance(inner_value.type.pointee, ir.PointerType):
inner_value = Gen._load(inner_value, name="cast_deref")
target_ptr = inner_value
elif target_arg.func.attr == 'Addr' and target_arg.args:
target_ptr = self.HandleExprLlvm(target_arg)
elif isinstance(target_arg.func.value, ast.Name) and target_arg.func.value.id == 't':
type_attr = target_arg.func.attr
resolved_cname = self.Trans.TSpecialCallHandle._ResolveTAttrToCName(type_attr)
if target_arg.args and resolved_cname is not None:
inner_val = self.HandleExprLlvm(target_arg.args[0])
if inner_val and isinstance(inner_val.type, ir.PointerType):
target_llvm_type = Gen._basic_type_to_llvm(resolved_cname)
if target_llvm_type:
target_ptr = Gen.builder.bitcast(inner_val, ir.PointerType(target_llvm_type), name="tcast_ptr")
if not target_ptr:
if isinstance(target_arg, ast.Subscript):
target_ptr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(target_arg)
else:
target_ptr = self.HandleExprLlvm(target_arg)
Val = self.HandleExprLlvm(value_arg)
if target_ptr and Val:
if isinstance(target_ptr.type, ir.PointerType):
ValToStore = Val
pointee = target_ptr.type.pointee
if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, ir.IntType) and pointee.pointee.width == 8:
if isinstance(Val.type, ir.PointerType) and isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8:
ValToStore = Val
elif isinstance(Val.type, ir.IntType):
ValToStore = Gen.builder.inttoptr(Val, pointee, name="int_to_ptr_set")
elif isinstance(pointee, ir.IntType):
if isinstance(Val.type, ir.ArrayType) and isinstance(Val.type.element, ir.IntType) and Val.type.element.width == 8:
zero = ir.Constant(ir.IntType(32), 0)
value_ptr = Gen.builder.gep(Val, [zero, zero], name="value_ptr")
ValToStore = Gen._load(value_ptr, name="Load_value")
elif isinstance(Val.type, ir.PointerType) and isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8:
ValToStore = Gen._load(Val, name="Load_char_value")
if isinstance(ValToStore.type, ir.IntType) and isinstance(pointee, ir.IntType):
if ValToStore.type.width < pointee.width:
ValToStore = Gen.builder.zext(ValToStore, pointee, name="zext_set")
elif ValToStore.type.width > pointee.width:
ValToStore = Gen.builder.trunc(ValToStore, pointee, name="trunc_set")
elif Val.type != pointee:
if isinstance(pointee, ir.PointerType) and isinstance(Val.type, ir.PointerType):
ValToStore = Gen.builder.bitcast(Val, pointee, name="bitcast_set")
Gen._store(ValToStore, target_ptr)
return ir.Constant(ir.IntType(32), 1)
def _HandleCLoadLlvm(self, Node):
Gen = self.Trans.LlvmGen
if len(Node.args) < 2:
return ir.Constant(ir.IntType(32), 0)
src_val = self.HandleExprLlvm(Node.args[0])
dst_val = self.HandleExprLlvm(Node.args[1])
if not src_val or not dst_val:
return ir.Constant(ir.IntType(32), 0)
if not isinstance(src_val.type, ir.PointerType) or not isinstance(dst_val.type, ir.PointerType):
return ir.Constant(ir.IntType(32), 0)
Loaded = Gen._load(src_val, name="cLoad_src")
if Loaded is None:
return ir.Constant(ir.IntType(32), 0)
pointee = dst_val.type.pointee
val_to_store = Loaded
if isinstance(pointee, ir.IntType) and isinstance(Loaded.type, ir.IntType):
if Loaded.type.width < pointee.width:
val_to_store = Gen.builder.zext(Loaded, pointee, name="cLoad_zext")
elif Loaded.type.width > pointee.width:
val_to_store = Gen.builder.trunc(Loaded, pointee, name="cLoad_trunc")
elif isinstance(pointee, ir.PointerType) and isinstance(Loaded.type, ir.PointerType):
val_to_store = Gen.builder.bitcast(Loaded, pointee, name="cLoad_bitcast")
elif Loaded.type != pointee:
target_ptr = Gen.builder.bitcast(src_val, ir.PointerType(pointee), name="cLoad_cast")
Loaded = Gen._load(target_ptr, name="cLoad_casted")
if Loaded is None:
return ir.Constant(ir.IntType(32), 0)
val_to_store = Loaded
Gen._store(val_to_store, dst_val)
return ir.Constant(ir.IntType(32), 1)
def _HandleCDerefLlvm(self, Node):
Gen = self.Trans.LlvmGen
if not Node.args:
return ir.Constant(ir.IntType(64), 0)
arg_val = self.HandleExprLlvm(Node.args[0])
if arg_val is None:
return ir.Constant(ir.IntType(32), 0)
if isinstance(arg_val.type, ir.PointerType):
Loaded = Gen._load(arg_val, name="deref")
if Loaded is not None:
return Loaded
return arg_val
def _HandleCPtrToIntLlvm(self, Node):
Gen = self.Trans.LlvmGen
if not Node.args:
return ir.Constant(ir.IntType(64), 0)
arg_val = self.HandleExprLlvm(Node.args[0])
if arg_val is None:
return ir.Constant(ir.IntType(64), 0)
if isinstance(arg_val.type, ir.PointerType):
return Gen.builder.ptrtoint(arg_val, ir.IntType(64), name="ptrtoint_result")
if isinstance(arg_val.type, ir.IntType):
if arg_val.type.width < 64:
return Gen.builder.zext(arg_val, ir.IntType(64), name="zext_ptrtoint")
elif arg_val.type.width > 64:
return Gen.builder.trunc(arg_val, ir.IntType(64), name="trunc_ptrtoint")
return arg_val
return ir.Constant(ir.IntType(64), 0)
class TSpecialCallHandle(BaseHandle):
@staticmethod
def _ResolveTAttrToCName(attr: str) -> str:
from lib.includes.t import CTypeRegistry
ctype_cls = CTypeRegistry.GetClassByName(attr)
if ctype_cls is not None:
try:
inst = ctype_cls()
cname = getattr(inst, 'CName', '')
if cname:
return cname
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"处理函数调用失败: {_e}", "Exception")
return None
def _HandleTSpecialCallLlvm(self, Node):
Gen = self.Trans.LlvmGen
if not Node.args:
return None
attr = Node.func.attr
if attr == 'CType':
return self._HandleCTypeLlvm(Node)
target_type = self._ResolveTAttrToCName(attr)
if target_type is not None:
IsPtr_cast = False
if len(Node.args) >= 2:
second_arg = Node.args[1]
if isinstance(second_arg, ast.Attribute) and isinstance(second_arg.value, ast.Name) and second_arg.value.id == 't' and second_arg.attr == 'CPtr':
IsPtr_cast = True
elif isinstance(second_arg, ast.Name) and second_arg.id == 'CPtr':
IsPtr_cast = True
if IsPtr_cast:
return self._HandleTPtrCastLlvm(Node, attr)
if target_type == 'void':
target_type = 'void *'
return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], target_type)
return None
def _HandleCTypeLlvm(self, Node):
Gen = self.Trans.LlvmGen
arg_val = self.HandleExprLlvm(Node.args[0])
if not arg_val:
return None
target_type_str = 'unsigned long long'
if len(Node.args) >= 2:
type_parts = []
ptr_count = 0
for i in range(1, len(Node.args)):
type_arg = Node.args[i]
if isinstance(type_arg, ast.Attribute) and isinstance(type_arg.value, ast.Name) and type_arg.value.id == 't':
type_attr = type_arg.attr
_PREFIX_MAP = {
'CUnsigned': 'unsigned', 'CSigned': 'signed',
'CConst': 'const', 'CVolatile': 'volatile',
}
if type_attr in _PREFIX_MAP:
type_parts.append(_PREFIX_MAP[type_attr])
elif type_attr in ('CPtr', 'CArrayPtr'):
ptr_count += 1
else:
resolved = self._ResolveTAttrToCName(type_attr)
if resolved is not None:
type_parts.append(resolved)
if type_parts:
target_type_str = ' '.join(type_parts)
if ptr_count > 0:
target_type_str += ' ' + '*' * ptr_count
if isinstance(arg_val.type, ir.PointerType):
int_val = Gen.builder.ptrtoint(arg_val, ir.IntType(64), name="ptr_to_int")
return int_val
return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], target_type_str)
def _HandleTPtrCastLlvm(self, Node, attr):
Gen = self.Trans.LlvmGen
from lib.includes.t import CTypeRegistry
if attr in ('CChar', 'CUnsignedChar'):
first_arg = Node.args[0]
if isinstance(first_arg, ast.Call) and isinstance(first_arg.func, ast.Attribute) and isinstance(first_arg.func.value, ast.Name) and first_arg.func.value.id == 't' and first_arg.func.attr == 'CInt' and first_arg.args:
inner_val = self.HandleExprLlvm(first_arg.args[0])
if isinstance(inner_val.type, ir.PointerType):
return Gen.builder.bitcast(inner_val, ir.PointerType(ir.IntType(8)), name=f"c{attr.lower()}_ptr_from_cint")
expr_val = self.HandleExprLlvm(Node.args[0])
if isinstance(expr_val.type, ir.IntType) and expr_val.type.width == 8:
var = Gen._alloca(ir.ArrayType(ir.IntType(8), 2), name=f"c{attr.lower()}_ptr")
zero = ir.Constant(ir.IntType(32), 0)
char_ptr = Gen.builder.gep(var, [zero, zero], name="char_ptr")
Gen._store(expr_val, char_ptr)
null_char = ir.Constant(ir.IntType(8), 0)
null_ptr = Gen.builder.gep(var, [zero, ir.Constant(ir.IntType(32), 1)], name="null_ptr")
Gen._store(null_char, null_ptr)
return char_ptr
elif isinstance(expr_val.type, ir.PointerType):
if isinstance(expr_val.type.pointee, ir.PointerType):
Loaded_ptr = Gen._load(expr_val, name="load_ptr")
if isinstance(Loaded_ptr.type, ir.PointerType) and isinstance(Loaded_ptr.type.pointee, ir.IntType) and Loaded_ptr.type.pointee.width == 8:
return Loaded_ptr
if isinstance(expr_val.type.pointee, ir.IntType) and expr_val.type.pointee.width == 8:
return expr_val
return Gen.builder.bitcast(expr_val, ir.PointerType(ir.IntType(8)), name="cast_to_char_ptr")
elif isinstance(expr_val.type, ir.IntType):
if expr_val.type.width == 32:
expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64")
return Gen.builder.inttoptr(expr_val, ir.PointerType(ir.IntType(8)), name=f"inttoptr_c{attr.lower()}")
return Gen.emit_constant(0, 'int')
elif attr == 'CVoid':
return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], 'void *')
elif attr == 'CInt':
expr_val = self.HandleExprLlvm(Node.args[0])
if expr_val:
if isinstance(expr_val.type, ir.IntType):
if expr_val.type.width < 64:
expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64")
return Gen.builder.inttoptr(expr_val, ir.PointerType(ir.IntType(32)), name="cint_ptr")
return Gen.builder.bitcast(expr_val, ir.PointerType(ir.IntType(32)), name="cint_ptr")
else:
ctype_cls = CTypeRegistry.GetClassByName(attr)
if ctype_cls is not None:
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
target_type = Gen._type_str_to_llvm(llvm_str)
if target_type and isinstance(target_type, (ir.IntType, ir.FloatType, ir.DoubleType)):
target_ptr_type = ir.PointerType(target_type)
expr_val = self.HandleExprLlvm(Node.args[0])
if expr_val:
if isinstance(expr_val.type, ir.IntType):
if expr_val.type.width < 64:
expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64")
return Gen.builder.inttoptr(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr")
return Gen.builder.bitcast(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr")
return None