from __future__ import annotations from typing import TYPE_CHECKING import ast import llvmlite.ir as ir if TYPE_CHECKING: from lib.core.translator import Translator from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin from lib.core.Handles.HandlesBase import BaseHandle, BuiltinTypeMap from lib.includes.t import CTypeRegistry from lib.core.SymbolUtils import IsTModule from lib.core.VLogger import get_logger as _vlog from lib.constants.config import mode as _config_mode class CSpecialCallHandle(BaseHandle): def _HandleCIfLlvm(self, Node: ast.Call) -> ir.Value: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen if Node.args: ArgVal: ir.Value | None = 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: ast.Call) -> ir.Value: Gen: LlvmGeneratorMixin = 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") zero_val = Gen._zero_value_for_type(StructType) if zero_val is not None: Gen.builder.store(zero_val, 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: ast.Call) -> ir.Value: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen if len(Node.args) >= 2: target_arg: ast.expr = Node.args[0] value_arg: ast.expr = Node.args[1] target_ptr: ir.Value | None = 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 IsTModule(target_arg.func.value.id, self.Trans.SymbolTable): 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: ast.Call) -> ir.Value: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen if len(Node.args) < 2: return ir.Constant(ir.IntType(32), 0) # c.Load(a, b) 语义: *a = *b(a 是目标,b 是源) # wiki 文档: c.Load(ptr, value) -> *ptr = *value; dst_val: ir.Value | None = self.HandleExprLlvm(Node.args[0]) src_val: ir.Value | None = 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) pointee = dst_val.type.pointee # c.Addr 统一返回 i8* 通用指针,丢失原始类型信息。 # 若 dst 是 c.Addr(var),从 var 的 alloca 类型推断真实 pointee(如 i64), # 否则 c.Load 只会按 i8 加载 1 字节(IEEE 754 double→u64 位重解释 bug)。 if (isinstance(pointee, ir.IntType) and pointee.width == 8 and isinstance(Node.args[0], ast.Call) and isinstance(Node.args[0].func, ast.Attribute) and Node.args[0].func.attr == 'Addr' and Node.args[0].args and isinstance(Node.args[0].args[0], ast.Name)): var_name = Node.args[0].args[0].id if var_name in Gen.variables and Gen.variables[var_name] is not None: var_ptr = Gen.variables[var_name] if isinstance(var_ptr.type, ir.PointerType): pointee = var_ptr.type.pointee # 按 pointee 类型 bitcast src 加载,bitcast dst 存储 if src_val.type.pointee != pointee: src_cast = Gen.builder.bitcast(src_val, ir.PointerType(pointee), name="cLoad_src_cast") else: src_cast = src_val Loaded = Gen._load(src_cast, name="cLoad_loaded") if Loaded is None: return ir.Constant(ir.IntType(32), 0) if dst_val.type.pointee != pointee: dst_cast = Gen.builder.bitcast(dst_val, ir.PointerType(pointee), name="cLoad_dst_cast") else: dst_cast = dst_val Gen._store(Loaded, dst_cast) return ir.Constant(ir.IntType(32), 1) def _HandleCDerefLlvm(self, Node: ast.Call) -> ir.Value: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen if not Node.args: return ir.Constant(ir.IntType(64), 0) # 检测嵌套 c.Deref(c.Deref(...)):设置标志让内层 Deref 加载为指针 IsNestedDeref: bool = ( isinstance(Node.args[0], ast.Call) and isinstance(Node.args[0].func, ast.Attribute) and Node.args[0].func.attr == 'Deref' ) if IsNestedDeref: Gen._nested_deref_load_ptr = True try: arg_val: ir.Value | None = self.HandleExprLlvm(Node.args[0]) finally: if IsNestedDeref: Gen._nested_deref_load_ptr = False if arg_val is None: return ir.Constant(ir.IntType(32), 0) if isinstance(arg_val.type, ir.PointerType): pointee: ir.Type = arg_val.type.pointee # 嵌套 Deref 的内层:加载为指针 (i8*),不推断目标类型 # 因为结果会被外层 Deref 再次解引用 NestedLoadPtr: bool = getattr(Gen, '_nested_deref_load_ptr', False) if NestedLoadPtr: PtrType: ir.Type = ir.PointerType(ir.IntType(8)) casted: ir.Value = Gen.builder.bitcast(arg_val, ir.PointerType(PtrType), name="deref_cast") Loaded = Gen._load(casted, name="deref") if Loaded is not None: return Loaded # void* (i8*) 需要根据赋值目标类型推断加载类型 elif isinstance(pointee, ir.IntType) and pointee.width == 8: target_type: ir.Type | None = self._infer_deref_target_type(Gen, Node) if target_type is not None and not isinstance(target_type, ir.IntType): # bitcast i8* -> target_type* then load casted: ir.Value = Gen.builder.bitcast(arg_val, ir.PointerType(target_type), name="deref_cast") Loaded = Gen._load(casted, name="deref") if Loaded is not None: return Loaded elif target_type is not None and isinstance(target_type, ir.IntType): # 目标是整数类型 (如 i32/i64): bitcast 并加载 if target_type.width != 8: casted: ir.Value = Gen.builder.bitcast(arg_val, ir.PointerType(target_type), name="deref_cast") Loaded = Gen._load(casted, name="deref") if Loaded is not None: return Loaded Loaded = Gen._load(arg_val, name="deref") if Loaded is not None: return Loaded return arg_val def _infer_deref_target_type(self, Gen: LlvmGeneratorMixin, DerefNode: ast.Call | None = None) -> ir.Type | None: """从当前赋值上下文推断 c.Deref 的目标加载类型。 当用户写 v: int = c.Deref(ptr) 时,从赋值注解推断目标类型。 注意:仅当 c.Deref 是赋值的直接 RHS 时才推断;若 c.Deref 嵌套在 ifexp/compare/binop 中(如 `a = 1 if c.Deref(p) == 65 else 0`), 不应推断,否则会把 i8* 错误 bitcast 为 i32* 加载 4 字节。""" assign_node: ast.AST | None = getattr(self.Trans, '_current_assign_node', None) if not assign_node: return None # 仅当 c.Deref 是赋值的直接 RHS 时才推断类型 if DerefNode is not None and getattr(assign_node, 'value', None) is not DerefNode: return None ann: ast.AST | None = getattr(assign_node, 'annotation', None) if not ann: return None ann_name: str | None = 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): # 处理 int | t.CPtr 形式的联合类型注解 for side in (ann.left, ann.right): if isinstance(side, ast.Name): ann_name = side.id break elif isinstance(side, ast.Attribute): ann_name = side.attr break if not ann_name: return None # 使用 BuiltinTypeMap 统一查询(同时支持 Python 类名和字符串速记) entry: tuple[type, int] | None = BuiltinTypeMap.Get(ann_name) if entry is not None: ctype_cls: type = entry[0] llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls) if llvm_str: resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str) if resolved: return resolved # 检查是否是已注册的结构体类型 if ann_name in Gen.structs: return Gen.structs[ann_name] return None def _HandleCPtrToIntLlvm(self, Node: ast.Call) -> ir.Value: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen if not Node.args: return ir.Constant(ir.IntType(64), 0) arg_val: ir.Value | None = 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 | None: ctype_cls: type | None = CTypeRegistry.GetClassByName(attr) if ctype_cls is not None: try: inst = ctype_cls() cname = type(inst).__name__ if cname: return cname except Exception as _e: if _config_mode == "strict": raise _vlog().warning(f"处理函数调用失败: {_e}", "Exception") return None def _HandleTSpecialCallLlvm(self, Node: ast.Call) -> ir.Value | None: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen if not Node.args: return None attr: str = Node.func.attr if attr == 'CType': return self._HandleCTypeLlvm(Node) target_type: str | None = 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 IsTModule(second_arg.value.id, self.Trans.SymbolTable) 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: ast.Call) -> ir.Value | None: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen arg_val: ir.Value | None = self.HandleExprLlvm(Node.args[0]) if not arg_val: return None target_type_str: str = 'unsigned long long' if len(Node.args) >= 2: type_parts: list[str] = [] ptr_count: int = 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 IsTModule(type_arg.value.id, self.Trans.SymbolTable): type_attr = type_arg.attr _PREFIX_MAP: dict[str, str] = { '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: ast.Call, attr: str) -> ir.Value | None: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen 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 IsTModule(first_arg.func.value.id, self.Trans.SymbolTable) 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: # 基础类型 (int/float) → 加一层指针 → T* if 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") # 指针类型 (如 CPtr → i8*) → 再加一层指针 → i8** elif isinstance(target_type, ir.PointerType): 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