Files
TransPyV/App/lib/core/Handles/HandlesSpecialCall.py

468 lines
27 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from typing import TYPE_CHECKING
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 = *ba 是目标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