1696 lines
117 KiB
Python
1696 lines
117 KiB
Python
from __future__ import annotations
|
||
from typing import TYPE_CHECKING, Any
|
||
if TYPE_CHECKING:
|
||
from lib.core.translator import Translator
|
||
import ast
|
||
import sys
|
||
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.core.ConstEvaluator import ConstEvaluator, EvalContext
|
||
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, ParseListAnnotation, AnnotationContainsName
|
||
|
||
class AssignHandle(BaseHandle):
|
||
def __init__(self, translator: "Translator") -> None:
|
||
super().__init__(translator)
|
||
self._CurrentCpythonObjectClass: str | None = None
|
||
|
||
@staticmethod
|
||
def _contains_identified_struct(var_type: ir.Type) -> bool:
|
||
if isinstance(var_type, ir.IdentifiedStructType):
|
||
return True
|
||
if isinstance(var_type, ir.ArrayType):
|
||
return AssignHandle._contains_identified_struct(var_type.element)
|
||
if isinstance(var_type, ir.PointerType):
|
||
return AssignHandle._contains_identified_struct(var_type.pointee)
|
||
if isinstance(var_type, ir.BaseStructType):
|
||
if var_type.elements:
|
||
return any(AssignHandle._contains_identified_struct(e) for e in var_type.elements)
|
||
return False
|
||
|
||
def HandleExprLlvm(self, Node: ast.expr, VarType: ir.Type | None = None) -> ir.Value | None:
|
||
return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType)
|
||
|
||
def _HandleAssignLlvm(self, Node: ast.Assign) -> None:
|
||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||
Gen._set_node_info(Node, "Assign")
|
||
if len(Node.targets) == 1:
|
||
Target: ast.expr = Node.targets[0]
|
||
if isinstance(Target, ast.Name):
|
||
VarName: str = Target.id
|
||
if VarName in Gen.var_const_flags:
|
||
src_info: str = Gen._get_node_info()
|
||
_vlog().error(f"不能对 const 变量 '{VarName}' 赋值{src_info}")
|
||
sys.exit(1)
|
||
if isinstance(Node.value, ast.Attribute) and isinstance(Node.value.value, ast.Name) and IsTModule(Node.value.value.id, self.Trans.SymbolTable):
|
||
AttrName: str = Node.value.attr
|
||
Gen.var_type_info[VarName] = {'type': 't_type', 'name': AttrName}
|
||
Gen.var_type_assignments.setdefault(VarName, []).append({'type': 't_type', 'name': AttrName})
|
||
c_type_name: str = ''
|
||
resolved: tuple[type, int] | None = CTypeRegistry.ResolveName(AttrName)
|
||
if resolved is not None:
|
||
ctype_cls: type = resolved[0]
|
||
ptr_level: int = resolved[1]
|
||
c_type_name = CTypeRegistry.CTypeToName(ctype_cls)
|
||
if ptr_level > 0 and c_type_name:
|
||
c_type_name = c_type_name + ' *'
|
||
if not c_type_name:
|
||
if AttrName == 'CPtr':
|
||
c_type_name = 'void *'
|
||
is_unsigned: bool = Gen._is_type_unsigned(c_type_name) if c_type_name else False
|
||
fmt_str: str = "%u\n" if is_unsigned else "%d\n"
|
||
fmt_ptr: ir.Value = Gen._create_string_global(fmt_str)
|
||
fmt_var_name: str = f"__{VarName}_fmt"
|
||
if fmt_var_name not in Gen.variables:
|
||
fmt_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=fmt_var_name)
|
||
Gen.variables[fmt_var_name] = fmt_alloca
|
||
Gen.builder.store(fmt_ptr, Gen.variables[fmt_var_name])
|
||
kind_var_name: str = f"__{VarName}_kind"
|
||
if kind_var_name not in Gen.variables:
|
||
kind_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=kind_var_name)
|
||
Gen.variables[kind_var_name] = kind_alloca
|
||
Gen.builder.store(ir.Constant(ir.IntType(32), 0), Gen.variables[kind_var_name])
|
||
if VarName not in Gen.variables:
|
||
dummy_var: ir.AllocaInstr = Gen._alloca(ir.IntType(8), name=VarName)
|
||
Gen.variables[VarName] = dummy_var
|
||
return
|
||
if isinstance(Node.value, ast.Name) and Node.value.id in Gen.structs:
|
||
ClassName: str = Node.value.id
|
||
Gen.var_type_info[VarName] = {'type': 'class_cast', 'name': ClassName}
|
||
Gen.var_type_assignments.setdefault(VarName, []).append({'type': 'class_cast', 'name': ClassName})
|
||
fmt_str: str = "%p\n"
|
||
fmt_ptr: ir.Value = Gen._create_string_global(fmt_str)
|
||
fmt_var_name: str = f"__{VarName}_fmt"
|
||
if fmt_var_name not in Gen.variables:
|
||
fmt_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=fmt_var_name)
|
||
Gen.variables[fmt_var_name] = fmt_alloca
|
||
Gen.builder.store(fmt_ptr, Gen.variables[fmt_var_name])
|
||
kind_var_name: str = f"__{VarName}_kind"
|
||
if kind_var_name not in Gen.variables:
|
||
kind_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=kind_var_name)
|
||
Gen.variables[kind_var_name] = kind_alloca
|
||
Gen.builder.store(ir.Constant(ir.IntType(32), 1), Gen.variables[kind_var_name])
|
||
if VarName not in Gen.variables:
|
||
dummy_var: ir.AllocaInstr = Gen._alloca(ir.IntType(8), name=VarName)
|
||
Gen.variables[VarName] = dummy_var
|
||
return
|
||
if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name) and Node.value.func.id == 'va_list':
|
||
va_list_ptr: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(8).as_pointer(), name="va_list")
|
||
Gen.variables[VarName] = va_list_ptr
|
||
return
|
||
IsStructCtor: bool = (isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name)
|
||
and Node.value.func.id in Gen.structs)
|
||
if IsStructCtor:
|
||
ClassName: str = Node.value.func.id
|
||
StructType: ir.Type = Gen.structs[ClassName]
|
||
|
||
IsUnion: bool = False
|
||
TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(ClassName)
|
||
if TypeInfo and TypeInfo.IsUnion:
|
||
IsUnion = True
|
||
|
||
if IsUnion:
|
||
Value: ir.Value | None = self.HandleExprLlvm(Node.value)
|
||
if Value:
|
||
var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName)
|
||
Gen._store(Value, var)
|
||
Gen.variables[VarName] = var
|
||
return
|
||
|
||
ExistingPtr: ir.Value | None = None
|
||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||
VarPtr: ir.Value = Gen.variables[VarName]
|
||
if isinstance(VarPtr.type.pointee, ir.PointerType):
|
||
ExistingPtr = VarPtr
|
||
elif VarName in Gen._reg_values:
|
||
OldVal: ir.Value = Gen._reg_values[VarName]
|
||
if isinstance(OldVal.type, ir.PointerType):
|
||
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName)
|
||
Gen._store(OldVal, var)
|
||
Gen.variables[VarName] = var
|
||
del Gen._reg_values[VarName]
|
||
ExistingPtr = var
|
||
elif VarName in Gen._direct_values:
|
||
OldVal: ir.Value = Gen._direct_values.pop(VarName)
|
||
if isinstance(OldVal.type, ir.PointerType):
|
||
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName)
|
||
Gen._store(OldVal, var)
|
||
Gen.variables[VarName] = var
|
||
ExistingPtr = var
|
||
if ExistingPtr:
|
||
pointee: ir.Type = ExistingPtr.type.pointee
|
||
# 仅当 alloca 直接存储结构体值(pointee 不是指针)时才 in-place 初始化。
|
||
# 当 pointee 是 PointerType 时,alloca 存储的是堆对象指针:
|
||
# - 若 AnnAssign 分支未执行,alloca 内容是未初始化的栈垃圾
|
||
# (可能恰好等于 pool 地址),_InitStructAtPtr 会向垃圾地址写字段 → 内存损坏
|
||
# - 即使指针有效,node = Class(...) 的语义也是创建新对象并更新指针,
|
||
# 而非在旧对象位置 in-place 重初始化
|
||
# 此时必须 fall through 到通用路径 HandleExprLlvm → _HandleClassNewLlvm
|
||
# 以正确调用 __new__/__before_init__/__init__ 构造新对象。
|
||
if not isinstance(pointee, ir.PointerType) and pointee == StructType:
|
||
self._InitStructAtPtr(Node.value, ClassName, ExistingPtr)
|
||
return
|
||
if isinstance(Node.value, ast.Attribute):
|
||
enum_type_name: str | None = self._CheckEnumMemberAssignment(Node.value)
|
||
if enum_type_name:
|
||
Gen.var_type_info[VarName] = {'type': 'enum', 'name': enum_type_name}
|
||
var_type_for_list: ir.Type | None = None
|
||
if isinstance(Node.value, ast.List) and VarName in Gen.var_type_info:
|
||
type_info: dict[str, str] = Gen.var_type_info[VarName]
|
||
if type_info.get('type') == 'CArray':
|
||
var_type_for_list = type_info.get('full_type')
|
||
Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=var_type_for_list)
|
||
if not Value:
|
||
return
|
||
if isinstance(Value.type, ir.VoidType):
|
||
return
|
||
Gen._UnregisterTempPtr(Value)
|
||
# 大端局部变量:赋值时 bswap
|
||
Value = Gen._apply_bswap_if_big(Value, Gen.local_var_byteorders.get(VarName, ""), f"bswap_assign_{VarName}")
|
||
if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||
found_class: str | None = None
|
||
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(Value.type.pointee)
|
||
if found:
|
||
CN: str = found[0]
|
||
ST: ir.Type = found[1]
|
||
found_class = CN
|
||
Gen.var_struct_class[VarName] = CN
|
||
Gen._var_to_heap_ptr[VarName] = Value
|
||
if found_class is None and isinstance(Value.type.pointee, ir.IdentifiedStructType):
|
||
pointee_name: str = Value.type.pointee.name
|
||
pointee_short: str = Gen._extract_short_name(pointee_name)
|
||
best_elem_count: int = 0
|
||
for CN, ST in Gen.structs.items():
|
||
if isinstance(ST, ir.IdentifiedStructType):
|
||
st_short: str = Gen._extract_short_name(ST.name)
|
||
if st_short == pointee_short:
|
||
elem_count: int = len(ST.elements) if ST.elements else 0
|
||
if elem_count > best_elem_count:
|
||
found_class = CN
|
||
best_elem_count = elem_count
|
||
if found_class:
|
||
Gen.var_struct_class[VarName] = found_class
|
||
Gen._var_to_heap_ptr[VarName] = Value
|
||
# 泛型类特化触发:返回类型是泛型类特化(如 list[str])但结构体尚未创建,
|
||
# 或虽然找到了结构体但它是 opaque(来自 stub 声明,尚未发射方法体)
|
||
_fd_struct_opaque: bool = False
|
||
if found_class and found_class in Gen.structs:
|
||
_fd_st: ir.IdentifiedStructType = Gen.structs[found_class]
|
||
if isinstance(_fd_st, ir.IdentifiedStructType) and (_fd_st.elements is None or len(_fd_st.elements) == 0):
|
||
_fd_struct_opaque = True
|
||
if (found_class is None or _fd_struct_opaque) and isinstance(Value.type.pointee, ir.IdentifiedStructType):
|
||
pn: str = Value.type.pointee.name
|
||
short_pn: str = pn
|
||
if '.' in pn:
|
||
pn_parts: list[str] = pn.split('.', 1)
|
||
if len(pn_parts[0]) >= 8 and all(c in '0123456789abcdef' for c in pn_parts[0]):
|
||
short_pn = pn_parts[1]
|
||
if '[' in short_pn and short_pn.endswith(']'):
|
||
gc_base: str = short_pn.split('[')[0]
|
||
gc_args_raw: str = short_pn[len(gc_base):]
|
||
gc_type_args: list[str] = []
|
||
for gc_arg_part in gc_args_raw.split(']['):
|
||
gc_arg_part = gc_arg_part.strip('[]')
|
||
if gc_arg_part:
|
||
gc_type_args.append(gc_arg_part)
|
||
if (gc_type_args
|
||
and hasattr(self.Trans.ClassHandler, '_generic_class_templates')
|
||
and gc_base in self.Trans.ClassHandler._generic_class_templates):
|
||
gc_type_names: list[str] = []
|
||
for gc_ta in gc_type_args:
|
||
gc_tn: str = gc_ta
|
||
if gc_ta == 'int':
|
||
gc_tn = 'CInt'
|
||
elif gc_ta == 'double':
|
||
gc_tn = 'CDouble'
|
||
elif gc_ta == 'float':
|
||
gc_tn = 'CFloat'
|
||
elif gc_ta == 'char':
|
||
gc_tn = 'CChar'
|
||
elif gc_ta == 'bool':
|
||
gc_tn = 'CBool'
|
||
gc_type_names.append(gc_tn)
|
||
gc_spec: str | None = self.Trans.ClassHandler._specialize_generic_class(
|
||
gc_base, gc_type_args, Gen, type_names=gc_type_names)
|
||
if gc_spec and gc_spec in Gen.structs:
|
||
found_class = gc_spec
|
||
Gen.var_struct_class[VarName] = gc_spec
|
||
Gen._var_to_heap_ptr[VarName] = Value
|
||
else:
|
||
if VarName in ('mctx', 's1ctx', 's2ctx', 's5ctx'):
|
||
pass
|
||
if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||
Gen._store(Value, Gen.variables[VarName])
|
||
else:
|
||
var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName)
|
||
Gen._store(Value, var)
|
||
Gen.variables[VarName] = var
|
||
if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name):
|
||
call_func_name: str = Node.value.func.id
|
||
if call_func_name in Gen.var_type_info:
|
||
type_info: dict[str, str] = Gen.var_type_info[call_func_name]
|
||
if type_info['type'] in ('t_type', 'class_cast'):
|
||
src_fmt_var: str = f"__{call_func_name}_fmt"
|
||
dst_fmt_var: str = f"__{VarName}_fmt"
|
||
if src_fmt_var in Gen.variables:
|
||
if dst_fmt_var not in Gen.variables:
|
||
dst_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var)
|
||
Gen.variables[dst_fmt_var] = dst_alloca
|
||
src_fmt_ptr: ir.Value = Gen._load(Gen.variables[src_fmt_var], name=f"Load_{call_func_name}_fmt_for_{VarName}")
|
||
Gen.builder.store(src_fmt_ptr, Gen.variables[dst_fmt_var])
|
||
src_kind_var: str = f"__{call_func_name}_kind"
|
||
dst_kind_var: str = f"__{VarName}_kind"
|
||
if src_kind_var in Gen.variables:
|
||
if dst_kind_var not in Gen.variables:
|
||
dst_kind_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=dst_kind_var)
|
||
Gen.variables[dst_kind_var] = dst_kind_alloca
|
||
src_kind_val: ir.Value = Gen._load(Gen.variables[src_kind_var], name=f"Load_{call_func_name}_kind_for_{VarName}")
|
||
Gen.builder.store(src_kind_val, Gen.variables[dst_kind_var])
|
||
Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name}
|
||
return
|
||
if VarName in Gen.global_vars:
|
||
if VarName in Gen.module.globals:
|
||
GVar: ir.GlobalVariable = Gen.module.globals[VarName]
|
||
Gen._store(Value, GVar)
|
||
Gen.variables[VarName] = GVar
|
||
if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(Value.type.pointee)
|
||
if found:
|
||
CN: str = found[0]
|
||
ST: ir.Type = found[1]
|
||
Gen.var_struct_class[VarName] = CN
|
||
elif VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||
Gen._store(Value, Gen.variables[VarName])
|
||
return
|
||
if VarName in Gen._reg_values:
|
||
OldVal: ir.Value = Gen._reg_values[VarName]
|
||
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName)
|
||
Gen._store(OldVal, var)
|
||
Gen.variables[VarName] = var
|
||
del Gen._reg_values[VarName]
|
||
if VarName in Gen._direct_values:
|
||
OldVal: ir.Value = Gen._direct_values.pop(VarName)
|
||
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName)
|
||
Gen._store(OldVal, var)
|
||
Gen.variables[VarName] = var
|
||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||
VarPtr: ir.Value = Gen.variables[VarName]
|
||
TargetType: ir.Type | None = VarPtr.type.pointee if isinstance(VarPtr.type, ir.PointerType) else None
|
||
types_differ: bool
|
||
try:
|
||
types_differ = TargetType and Value.type != TargetType
|
||
except AssertionError:
|
||
types_differ = False
|
||
if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.PointerType):
|
||
LoadedValue: ir.Value = Gen._load(Value, name=f"Load_{VarName}")
|
||
Loaded_differ: bool
|
||
try:
|
||
Loaded_differ = TargetType and LoadedValue.type != TargetType
|
||
except AssertionError:
|
||
Loaded_differ = False
|
||
if Loaded_differ:
|
||
try:
|
||
Coerced: ir.Value | None = Gen._coerce_value(LoadedValue, TargetType)
|
||
if Coerced is not None:
|
||
LoadedValue = Coerced
|
||
except AssertionError:
|
||
pass
|
||
Gen._store(LoadedValue, VarPtr)
|
||
elif types_differ:
|
||
try:
|
||
Coerced: ir.Value | None = Gen._coerce_value(Value, TargetType)
|
||
if Coerced is not None:
|
||
Gen._store(Coerced, VarPtr)
|
||
else:
|
||
Gen._store(Value, VarPtr)
|
||
except AssertionError:
|
||
Gen._store(Value, VarPtr)
|
||
else:
|
||
Gen._store(Value, VarPtr)
|
||
if VarName not in Gen.variables:
|
||
# 检查是否为模块级全局变量
|
||
# main 函数代表模块级作用域,直接修改全局变量
|
||
# 其他函数中,未声明 global 且未先读取的赋值创建局部变量(Python 作用域语义)
|
||
# 先读取过的变量已通过 HandleExprLlvm 加入 Gen.variables,会走 L289 分支存储到全局
|
||
CurrentFuncName: str = getattr(Gen.func, 'name', '') if Gen.func else ''
|
||
IsMainScope: bool = CurrentFuncName == 'main' or CurrentFuncName.endswith('.main')
|
||
if VarName in Gen.module.globals and (VarName in Gen.global_vars or IsMainScope):
|
||
GVar: ir.GlobalVariable = Gen.module.globals[VarName]
|
||
Gen._store(Value, GVar)
|
||
Gen.variables[VarName] = GVar
|
||
elif isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.PointerType):
|
||
LoadedValue: ir.Value = Gen._load(Value, name=f"Load_{VarName}")
|
||
var: ir.AllocaInstr = Gen._allocaEntry(LoadedValue.type, name=VarName)
|
||
Gen._store(LoadedValue, var)
|
||
Gen.variables[VarName] = var
|
||
else:
|
||
var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName)
|
||
Gen._store(Value, var)
|
||
Gen.variables[VarName] = var
|
||
is_u: bool = Gen._check_node_unsigned(Node.value)
|
||
Gen._record_var_signedness(VarName, 'unsigned int' if is_u else 'int')
|
||
if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name):
|
||
call_func_name: str = Node.value.func.id
|
||
if call_func_name in Gen.var_type_info:
|
||
type_info: dict[str, str] = Gen.var_type_info[call_func_name]
|
||
if type_info['type'] in ('t_type', 'class_cast'):
|
||
src_fmt_var: str = f"__{call_func_name}_fmt"
|
||
dst_fmt_var: str = f"__{VarName}_fmt"
|
||
if src_fmt_var in Gen.variables:
|
||
if dst_fmt_var not in Gen.variables:
|
||
dst_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var)
|
||
Gen.variables[dst_fmt_var] = dst_alloca
|
||
src_fmt_ptr: ir.Value = Gen._load(Gen.variables[src_fmt_var], name=f"Load_{call_func_name}_fmt_for_{VarName}")
|
||
Gen.builder.store(src_fmt_ptr, Gen.variables[dst_fmt_var])
|
||
src_kind_var: str = f"__{call_func_name}_kind"
|
||
dst_kind_var: str = f"__{VarName}_kind"
|
||
if src_kind_var in Gen.variables:
|
||
if dst_kind_var not in Gen.variables:
|
||
dst_kind_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=dst_kind_var)
|
||
Gen.variables[dst_kind_var] = dst_kind_alloca
|
||
src_kind_val: ir.Value = Gen._load(Gen.variables[src_kind_var], name=f"Load_{call_func_name}_kind_for_{VarName}")
|
||
Gen.builder.store(src_kind_val, Gen.variables[dst_kind_var])
|
||
Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name}
|
||
else:
|
||
Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name}
|
||
elif isinstance(Target, ast.Attribute):
|
||
TargetType: ir.Type | None = None
|
||
AttrName: str = Target.attr
|
||
VarName: str | None = None
|
||
if isinstance(Target.value, ast.Name):
|
||
VarName = Target.value.id
|
||
if VarName:
|
||
ClassName: str | None = Gen.var_struct_class.get(VarName)
|
||
if not ClassName and Gen.global_struct_class:
|
||
ClassName = Gen.global_struct_class.get(VarName)
|
||
if ClassName:
|
||
Gen.var_struct_class[VarName] = ClassName
|
||
if not ClassName:
|
||
for CN in Gen.structs:
|
||
if VarName == CN.lower() or VarName.startswith(CN):
|
||
ClassName = CN
|
||
break
|
||
if ClassName and ClassName in Gen.class_members:
|
||
for m_name, m_type in Gen.class_members[ClassName]:
|
||
if m_name == AttrName:
|
||
TargetType = m_type
|
||
break
|
||
Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=TargetType)
|
||
if Value:
|
||
self._HandleAttributeStoreLlvm(Target, Value)
|
||
elif isinstance(Target, ast.Subscript):
|
||
TargetType: ir.Type | None = None
|
||
SubVarName: str | None = None
|
||
if isinstance(Target.value, ast.Name):
|
||
SubVarName = Target.value.id
|
||
if SubVarName in Gen.var_struct_class:
|
||
ClassName: str = Gen.var_struct_class[SubVarName]
|
||
if ClassName in Gen.class_members:
|
||
for m_name, m_type in Gen.class_members[ClassName]:
|
||
if m_name == SubVarName:
|
||
if isinstance(m_type, ir.PointerType):
|
||
pointee: ir.Type = m_type.pointee
|
||
if isinstance(pointee, ir.ArrayType):
|
||
TargetType = pointee.element
|
||
elif isinstance(m_type, ir.ArrayType):
|
||
TargetType = m_type.element
|
||
break
|
||
if not TargetType and isinstance(Target.value, ast.Name):
|
||
SubVarName = Target.value.id
|
||
var_val: ir.Value | None = Gen.variables.get(SubVarName)
|
||
if var_val is None and SubVarName in Gen._direct_values:
|
||
var_val = Gen._direct_values[SubVarName]
|
||
if var_val is not None:
|
||
var_type: ir.Type = var_val.type
|
||
if isinstance(var_type, ir.PointerType):
|
||
pointee: ir.Type = var_type.pointee
|
||
if isinstance(pointee, ir.ArrayType):
|
||
TargetType = pointee.element
|
||
elif isinstance(var_type, ir.ArrayType):
|
||
TargetType = var_type.element
|
||
Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=TargetType)
|
||
if Value:
|
||
self._HandleSubscriptStoreLlvm(Target, Value)
|
||
elif isinstance(Target, ast.Tuple):
|
||
if isinstance(Node.value, ast.Call):
|
||
FuncName: str | None = None
|
||
ModulePath: str | None = None
|
||
if isinstance(Node.value.func, ast.Name):
|
||
FuncName = Node.value.func.id
|
||
elif isinstance(Node.value.func, ast.Attribute):
|
||
FuncName = Node.value.func.attr
|
||
ModulePath = self.Trans.ExprCallHandle._get_ModulePath(Node.value.func.value)
|
||
CReturnTypes: list[ast.expr] = []
|
||
FuncDef: ast.FunctionDef | None = self.Trans.FunctionDefCache.get(FuncName) if FuncName else None
|
||
if FuncDef:
|
||
if FuncDef.returns and isinstance(FuncDef.returns, ast.Subscript):
|
||
if isinstance(FuncDef.returns.value, ast.Name) and FuncDef.returns.value.id == 'tuple':
|
||
slice_node: ast.expr = FuncDef.returns.slice
|
||
if isinstance(slice_node, ast.Tuple):
|
||
CReturnTypes = slice_node.elts
|
||
else:
|
||
CReturnTypes = [slice_node]
|
||
if FuncDef.decorator_list:
|
||
for decorator in FuncDef.decorator_list:
|
||
if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute):
|
||
if decorator.func.attr == 'CReturn':
|
||
for arg in decorator.args:
|
||
CReturnTypes.append(arg)
|
||
if not CReturnTypes and FuncName:
|
||
func: ir.Function | None = Gen.functions.get(FuncName)
|
||
if func:
|
||
func_ft: ir.FunctionType | None = getattr(func, 'ftype', None)
|
||
if func_ft:
|
||
ret_type: ir.Type = func_ft.return_type
|
||
if isinstance(ret_type, ir.LiteralStructType):
|
||
CReturnTypes = [None] * len(ret_type.elements)
|
||
if not CReturnTypes:
|
||
sym_key: str = FuncName
|
||
if not self.Trans.SymbolTable.has(sym_key):
|
||
if ModulePath:
|
||
sym_key = f"{ModulePath}.{FuncName}"
|
||
sym_info: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(sym_key)
|
||
if sym_info and sym_info.IsFunction:
|
||
ret_type_info: CTypeInfo | None = sym_info.FuncPtrReturn
|
||
param_type_infos: list[tuple[str, CTypeInfo]] = [pt for _, pt in (sym_info.FuncPtrParams or [])]
|
||
if ret_type_info:
|
||
if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType:
|
||
ret_type: ir.Type = ret_type_info.ToLLVM(Gen)
|
||
else:
|
||
ret_type = Gen._type_str_to_llvm(str(ret_type_info) if ret_type_info else 'i32', False)
|
||
if isinstance(ret_type, ir.LiteralStructType):
|
||
CReturnTypes = [None] * len(ret_type.elements)
|
||
if FuncName not in Gen.functions:
|
||
if isinstance(ret_type, ir.VoidType):
|
||
ret_type = ir.IntType(32)
|
||
llvm_param_types: list[ir.Type] = []
|
||
for pt in param_type_infos:
|
||
if isinstance(pt, CTypeInfo) and pt.BaseType:
|
||
lp: ir.Type = pt.ToLLVM(Gen)
|
||
else:
|
||
lp = Gen._type_str_to_llvm(str(pt) if pt else 'i32', '*' in str(pt) if isinstance(pt, str) else False)
|
||
if isinstance(lp, ir.VoidType):
|
||
lp = ir.IntType(8).as_pointer()
|
||
llvm_param_types.append(lp)
|
||
func_type: ir.FunctionType = ir.FunctionType(ret_type, llvm_param_types)
|
||
MangledName: str = Gen._mangle_func_name(FuncName)
|
||
func_decl: ir.Function = ir.Function(Gen.module, func_type, name=MangledName)
|
||
Gen.functions[MangledName] = func_decl
|
||
Gen.functions[FuncName] = func_decl
|
||
if not CReturnTypes and FuncName:
|
||
func: ir.Function | None = Gen.functions.get(FuncName)
|
||
if func:
|
||
func_ft: ir.FunctionType | None = getattr(func, 'ftype', None)
|
||
if func_ft:
|
||
ret_type: ir.Type = func_ft.return_type
|
||
if isinstance(ret_type, ir.LiteralStructType):
|
||
CReturnTypes = [None] * len(ret_type.elements)
|
||
if CReturnTypes and len(Target.elts) == len(CReturnTypes):
|
||
CallArgs: list[ir.Value | None] = []
|
||
for arg in Node.value.args:
|
||
ArgVal: ir.Value | None = self.HandleExprLlvm(arg)
|
||
if ArgVal:
|
||
CallArgs.append(ArgVal)
|
||
for kw in Node.value.keywords:
|
||
pass
|
||
func: ir.Function | None = Gen.functions.get(FuncName)
|
||
func_ft: ir.FunctionType | None = getattr(func, 'ftype', None) if func else None
|
||
func_params: list[ir.Type] = list(getattr(func_ft, 'args', []) or []) if func_ft else []
|
||
while len(CallArgs) < len(func_params):
|
||
FuncDef: ast.FunctionDef | None = self.Trans.FunctionDefCache.get(FuncName)
|
||
if FuncDef and len(CallArgs) < len(FuncDef.args.args):
|
||
arg_def: list[ast.expr] = FuncDef.args.defaults
|
||
arg_idx: int = len(CallArgs)
|
||
total_args: int = len(FuncDef.args.args)
|
||
default_start: int = total_args - len(arg_def)
|
||
if arg_idx >= default_start:
|
||
def_idx: int = arg_idx - default_start
|
||
if def_idx < len(arg_def):
|
||
DefVal: ir.Value | None = self.HandleExprLlvm(arg_def[def_idx])
|
||
if DefVal:
|
||
expected_type: ir.Type = func_params[arg_idx]
|
||
if DefVal.type != expected_type:
|
||
if isinstance(expected_type, ir.IntType) and isinstance(DefVal.type, ir.IntType):
|
||
if DefVal.type.width < expected_type.width:
|
||
if DefVal.type.width == 1:
|
||
# i1 是布尔值,无符号语义,必须 zext
|
||
DefVal = Gen.builder.zext(DefVal, expected_type, name=f"zext_default_{arg_idx}")
|
||
else:
|
||
is_unsigned: bool = Gen._check_node_unsigned(arg_def[def_idx]) or id(DefVal) in Gen._unsigned_results
|
||
if is_unsigned:
|
||
DefVal = Gen.builder.zext(DefVal, expected_type, name=f"zext_default_{arg_idx}")
|
||
else:
|
||
DefVal = Gen.builder.sext(DefVal, expected_type, name=f"sext_default_{arg_idx}")
|
||
elif DefVal.type.width > expected_type.width:
|
||
DefVal = Gen.builder.trunc(DefVal, expected_type, name=f"trunc_default_{arg_idx}")
|
||
CallArgs.append(DefVal)
|
||
continue
|
||
if len(CallArgs) < len(func_params):
|
||
CallArgs.append(ir.Constant(func_params[len(CallArgs)], 0))
|
||
else:
|
||
break
|
||
adjusted: list[ir.Value] = Gen._adjust_args(CallArgs, func)
|
||
call_result: ir.Value = Gen.builder.call(func, adjusted, name=f"call_{FuncName}")
|
||
func_ft: ir.FunctionType | None = getattr(func, 'ftype', None)
|
||
ret_type: ir.Type | None = getattr(func_ft, 'return_type', None) if func_ft else None
|
||
for j, elt in enumerate(Target.elts):
|
||
if isinstance(elt, ast.Name):
|
||
VarName: str = elt.id
|
||
field_val: ir.Value = Gen.builder.extract_value(call_result, j, name=f"extract_{FuncName}_{j}")
|
||
VarType: ir.Type
|
||
if CReturnTypes[j] is not None:
|
||
ReturnTypeInfo: CTypeInfo | None = CTypeInfo.FromNode(CReturnTypes[j], self.Trans.SymbolTable)
|
||
if ReturnTypeInfo is None:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CInt()
|
||
VarType = Gen._ctype_to_llvm(ReturnTypeInfo)
|
||
elif ret_type and isinstance(ret_type, ir.LiteralStructType) and j < len(ret_type.elements):
|
||
VarType = ret_type.elements[j]
|
||
else:
|
||
VarType = field_val.type
|
||
if isinstance(VarType, ir.VoidType):
|
||
VarType = ir.IntType(32)
|
||
var: ir.AllocaInstr = Gen._alloca(VarType, name=VarName)
|
||
Gen.variables[VarName] = var
|
||
if CReturnTypes[j] is not None:
|
||
Gen._record_var_signedness(VarName, ReturnTypeStr)
|
||
elif ret_type and isinstance(ret_type, ir.LiteralStructType) and j < len(ret_type.elements):
|
||
elem_type: ir.Type = ret_type.elements[j]
|
||
if isinstance(elem_type, ir.IntType):
|
||
if elem_type.width == 16:
|
||
Gen._record_var_signedness(VarName, 'unsigned short')
|
||
elif elem_type.width == 32:
|
||
Gen._record_var_signedness(VarName, 'unsigned int')
|
||
elif elem_type.width == 64:
|
||
Gen._record_var_signedness(VarName, 'unsigned long long')
|
||
Gen._store(field_val, var)
|
||
return
|
||
|
||
def _InitStructAtPtr(self, call_node: ast.Call, ClassName: str, VarPtr: ir.Value) -> None:
|
||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||
if ClassName not in Gen.structs:
|
||
return
|
||
StructType: ir.Type = Gen.structs[ClassName]
|
||
StructPtrType: ir.PointerType = ir.PointerType(StructType)
|
||
RawPtr: ir.Value = Gen._load(VarPtr, name=getattr(VarPtr, 'name', 'ptr'))
|
||
StructPtr: ir.Value = Gen.builder.bitcast(RawPtr, StructPtrType, name=ClassName)
|
||
members: list[tuple[str, ir.Type]] = Gen.class_members.get(ClassName, [])
|
||
defaults: dict[str, ir.Value] = Gen.class_member_defaults.get(ClassName, {})
|
||
member_values: dict[str, ir.Value] = {}
|
||
for member_name, member_type in members:
|
||
if member_name in defaults:
|
||
member_values[member_name] = defaults[member_name]
|
||
if call_node.args:
|
||
for i, arg in enumerate(call_node.args):
|
||
if i < len(members):
|
||
member_name: str = members[i][0]
|
||
val: ir.Value | None = self.HandleExprLlvm(arg)
|
||
if val:
|
||
member_values[member_name] = val
|
||
if call_node.keywords:
|
||
for kw in call_node.keywords:
|
||
val: ir.Value | None = self.HandleExprLlvm(kw.value)
|
||
if val:
|
||
member_values[kw.arg] = val
|
||
has_vtable: bool = ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes
|
||
base: int = 1 if has_vtable else 0
|
||
for i, (member_name, member_type) in enumerate(members):
|
||
if isinstance(member_type, ir.VoidType):
|
||
continue
|
||
if member_name in member_values:
|
||
ElemPtr: ir.Value = Gen.builder.gep(StructPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), base + i)], name=f"{ClassName}_{member_name}")
|
||
try:
|
||
Gen._store(member_values[member_name], ElemPtr)
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
InitFuncName: str = f'{ClassName}.__init__'
|
||
if Gen._has_function(InitFuncName):
|
||
Args: list[ir.Value | None] = [self.HandleExprLlvm(arg) for arg in call_node.args]
|
||
Args = [a for a in Args if a]
|
||
Gen.builder.call(Gen._get_function(InitFuncName), [StructPtr] + Args, name=f"call_{InitFuncName}")
|
||
|
||
def _HandleAttributeStoreLlvm(self, Target: ast.Attribute, Value: ir.Value) -> None:
|
||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||
AttrName: str = Target.attr
|
||
if isinstance(Target.value, ast.Name) and Target.value.id == 'self':
|
||
ClassName: str | None = self.Trans._CurrentCpythonObjectClass
|
||
if ClassName and ClassName in Gen.structs:
|
||
PropKey: str = f'{ClassName}.{AttrName}'
|
||
PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey)
|
||
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList:
|
||
SelfVar: ir.Value | None = Gen._get_var_ptr('self')
|
||
if SelfVar:
|
||
SelfPtr: ir.Value = Gen._load(SelfVar, name="self")
|
||
SetterFunc: ir.Function | None = Gen._get_function(PropKey + '$set')
|
||
if SetterFunc and SelfPtr:
|
||
Gen.builder.call(SetterFunc, [SelfPtr, Value], name=f"prop_set_{PropKey}")
|
||
return
|
||
SelfVar: ir.Value | None = Gen._get_var_ptr('self')
|
||
if not SelfVar:
|
||
return
|
||
if SelfVar:
|
||
SelfPtr: ir.Value = Gen._load(SelfVar, name="self")
|
||
is_vtable_method: bool = False
|
||
method_idx: int = 0
|
||
if ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes:
|
||
if ClassName in Gen.class_methods:
|
||
for mi, mn in enumerate(Gen.class_methods[ClassName]):
|
||
method_short: str = mn.split('.')[-1] if '.' in mn else mn
|
||
if method_short == AttrName or mn == AttrName:
|
||
is_vtable_method = True
|
||
method_idx = mi
|
||
break
|
||
if is_vtable_method:
|
||
VtableSlotPtr: ir.Value = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}")
|
||
VtablePtr: ir.Value = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}")
|
||
methods: list[str] = Gen.class_methods[ClassName]
|
||
VtableArrayType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods))
|
||
ClassVtable: ir.GlobalVariable | None = Gen.Vtables.get(ClassName)
|
||
if ClassVtable:
|
||
ClassVtableAddr: ir.Value = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"class_vtable_addr_{ClassName}")
|
||
IsSameVtable: ir.Value = Gen.builder.icmp_unsigned('==', VtablePtr, ClassVtableAddr, name=f"is_same_vtable_{ClassName}")
|
||
CopyBlock: ir.Block = Gen.func.append_basic_block(name=f"vtable_copy_self_{AttrName}")
|
||
SkipBlock: ir.Block = Gen.func.append_basic_block(name=f"vtable_skip_self_{AttrName}")
|
||
Gen.builder.cbranch(IsSameVtable, CopyBlock, SkipBlock)
|
||
Gen.builder.position_at_end(CopyBlock)
|
||
Gen._vtable_copy_counter += 1
|
||
CopyName: str = f"{Gen._mangle_name(ClassName)}_vtable_copy_self_{Gen._vtable_copy_counter}"
|
||
VtableCopyGlobal: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VtableArrayType, name=CopyName)
|
||
VtableCopyGlobal.linkage = 'internal'
|
||
VtableCopyGlobal.initializer = ir.Constant(VtableArrayType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods))
|
||
VtableCopyTyped: ir.Value = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_typed")
|
||
SrcTyped: ir.Value = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"src_vtable_typed")
|
||
VtableSize: int = len(methods) * Gen.ptr_size
|
||
MemcpyFunc: ir.Function | None = Gen._find_function('llvm.memcpy.p0i8.p0i8.i64')
|
||
if not MemcpyFunc:
|
||
MemcpyType: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)])
|
||
MemcpyFunc = ir.Function(Gen.module, MemcpyType, name='llvm.memcpy.p0i8.p0i8.i64')
|
||
Gen.functions['llvm.memcpy.p0i8.p0i8.i64'] = MemcpyFunc
|
||
Gen.builder.call(MemcpyFunc, [VtableCopyTyped, SrcTyped, ir.Constant(ir.IntType(64), VtableSize), ir.Constant(ir.IntType(1), 0)])
|
||
VtableCopyGlobalAddr: ir.Value = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_addr")
|
||
Gen._store(VtableCopyGlobalAddr, VtableSlotPtr)
|
||
Gen.builder.branch(SkipBlock)
|
||
Gen.builder.position_at_end(SkipBlock)
|
||
VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}_after_copy")
|
||
VtableTyped: ir.Value = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}")
|
||
MethodPtrAddr: ir.Value = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_slot_{AttrName}")
|
||
FuncPtrI8: ir.Value = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"func_ptr_i8_{AttrName}")
|
||
Gen._store(FuncPtrI8, MethodPtrAddr)
|
||
return
|
||
offset: int = Gen._get_member_offset(AttrName, ClassName)
|
||
struct_type: ir.Type = Gen.structs[ClassName]
|
||
max_offset: int = len(struct_type.elements) if isinstance(struct_type, ir.IdentifiedStructType) else 0
|
||
if offset >= max_offset:
|
||
VarName: str = f"self.{AttrName}"
|
||
if VarName not in Gen.variables:
|
||
NewVar: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=AttrName)
|
||
Gen.variables[VarName] = NewVar
|
||
Gen._store(Value, Gen.variables[VarName])
|
||
return
|
||
MemberPtr: ir.Value = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
|
||
self._StoreWithCoerce(Value, MemberPtr)
|
||
elif isinstance(Target.value, ast.Name):
|
||
VarName: str = Target.value.id
|
||
|
||
# FakeDuck: 检查是否有影子结构体 a__meta__ (str 变量的 per-instance 字段存储)
|
||
# 直接通过 a.__field__ = value 访问影子结构体字段 (语法糖)
|
||
_fd_meta_name: str = f"{VarName}__meta__"
|
||
if _fd_meta_name in Gen.variables and '_str' in Gen.structs:
|
||
_fd_offset = Gen._get_member_offset(AttrName, '_str')
|
||
if _fd_offset is not None:
|
||
_fd_meta_ptr: ir.Value = Gen.variables[_fd_meta_name]
|
||
_fd_field_ptr: ir.Value = Gen.builder.gep(_fd_meta_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _fd_offset)], name=f"{VarName}_{AttrName}_ptr")
|
||
self._StoreWithCoerce(Value, _fd_field_ptr)
|
||
return
|
||
|
||
ClassName: str | None = Gen.var_struct_class.get(VarName)
|
||
|
||
if not ClassName and Gen.global_struct_class:
|
||
ClassName = Gen.global_struct_class.get(VarName)
|
||
if ClassName:
|
||
Gen.var_struct_class[VarName] = ClassName
|
||
|
||
if not ClassName:
|
||
for CN in Gen.structs:
|
||
if VarName == CN.lower() or VarName.startswith(CN):
|
||
ClassName = CN
|
||
break
|
||
|
||
if not ClassName and VarName in Gen.module.globals:
|
||
GVar: ir.GlobalVariable = Gen.module.globals[VarName]
|
||
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(GVar.type.pointee)
|
||
if found:
|
||
ClassName = found[0]
|
||
Gen.var_struct_class[VarName] = ClassName
|
||
if Gen.global_struct_class:
|
||
Gen.global_struct_class[VarName] = ClassName
|
||
|
||
if not ClassName and VarName in Gen.variables:
|
||
VarPtr: ir.Value = Gen.variables[VarName]
|
||
if isinstance(VarPtr.type, ir.PointerType):
|
||
pointee: ir.Type = VarPtr.type.pointee
|
||
if isinstance(pointee, ir.PointerType):
|
||
pointee = pointee.pointee
|
||
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(pointee)
|
||
if found:
|
||
CN: str = found[0]
|
||
ST: ir.Type = found[1]
|
||
ClassName = CN
|
||
elif isinstance(pointee, ir.IdentifiedStructType):
|
||
# sha1 冲突 fallback:find_struct_by_pointee 因 sha1 前缀不匹配失败时,
|
||
# 用短名(去掉 sha1 前缀)匹配,优先选字段最多的完整版本
|
||
pointee_short: str = Gen._extract_short_name(pointee.name)
|
||
best_elem_count: int = 0
|
||
for CN, ST in Gen.structs.items():
|
||
if isinstance(ST, ir.IdentifiedStructType):
|
||
st_short: str = Gen._extract_short_name(ST.name)
|
||
if st_short == pointee_short:
|
||
elem_count: int = len(ST.elements) if ST.elements else 0
|
||
if elem_count > best_elem_count:
|
||
ClassName = CN
|
||
best_elem_count = elem_count
|
||
|
||
IsUnion: bool = False
|
||
if ClassName:
|
||
TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(ClassName)
|
||
if TypeInfo and TypeInfo.IsUnion:
|
||
IsUnion = True
|
||
|
||
if ClassName and ClassName in Gen.structs:
|
||
PropKey: str = f'{ClassName}.{AttrName}'
|
||
PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey)
|
||
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList:
|
||
ObjVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value)
|
||
SetterFunc: ir.Function | None = Gen._get_function(PropKey + '$set')
|
||
if SetterFunc and ObjVal:
|
||
if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
|
||
ObjVal = Gen._load(ObjVal, name=f"Load_{ClassName}")
|
||
Gen.builder.call(SetterFunc, [ObjVal, Value], name=f"prop_set_{PropKey}")
|
||
return
|
||
ObjVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value)
|
||
if ObjVal:
|
||
if BaseHandle._is_char_pointer(ObjVal):
|
||
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||
if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
|
||
ObjVal = Gen._load(ObjVal, name=f"Load_{ClassName}")
|
||
# 跨模块 opaque 类型:ObjVal.type.pointee 与 Gen.structs[ClassName] 可能是
|
||
# 不同的 IdentifiedStructType 对象(虽然 name 相同),== 返回 False。
|
||
# 使用 name 匹配作为 fallback,与链式赋值路径(第 926-927 行)一致。
|
||
# sha1 冲突时还需短名匹配(如 6bc91356c652f8ca.Function vs 8ad0c0a2934ca5b4.Function)
|
||
_ObjPointee = ObjVal.type.pointee if isinstance(ObjVal.type, ir.PointerType) else None
|
||
_TargetStruct = Gen.structs.get(ClassName)
|
||
_MatchesStruct = (_ObjPointee is not None and _TargetStruct is not None and
|
||
(_ObjPointee == _TargetStruct or
|
||
(isinstance(_ObjPointee, ir.IdentifiedStructType) and isinstance(_TargetStruct, ir.IdentifiedStructType) and
|
||
(_ObjPointee.name == _TargetStruct.name or
|
||
Gen._extract_short_name(_ObjPointee.name) == Gen._extract_short_name(_TargetStruct.name)))))
|
||
# opaque 泛型结构体 → 特化版本 bitcast
|
||
# 当 ObjVal 的 pointee 是 opaque 基础泛型结构体(如 GSList,来自跨模块 stub),
|
||
# 而 ClassName 是特化版本(如 GSList[BasicBlock])时,两者 short name 不同
|
||
# (GSList vs GSList[BasicBlock]),_MatchesStruct 失败。
|
||
# 验证特化 short name 以 基础名+'[' 开头,bitcast 到特化版本使后续 GEP 能正确访问字段。
|
||
if (not _MatchesStruct
|
||
and isinstance(ObjVal.type, ir.PointerType)
|
||
and isinstance(_ObjPointee, ir.IdentifiedStructType)
|
||
and isinstance(_TargetStruct, ir.IdentifiedStructType)
|
||
and '[' in ClassName):
|
||
_BaseShort: str = Gen._extract_short_name(_ObjPointee.name)
|
||
_SpecShort: str = Gen._extract_short_name(_TargetStruct.name)
|
||
if _BaseShort and _SpecShort.startswith(_BaseShort + '['):
|
||
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(_TargetStruct), name=f"cast_spec_{ClassName}")
|
||
_MatchesStruct = True
|
||
if isinstance(ObjVal.type, ir.PointerType) and _MatchesStruct:
|
||
if IsUnion:
|
||
NestedStructName: str = f"{ClassName}_{AttrName}"
|
||
if NestedStructName in Gen.structs:
|
||
NestedStructType: ir.Type = Gen.structs[NestedStructName]
|
||
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}")
|
||
offset: int | None = Gen._get_member_offset(AttrName, NestedStructName)
|
||
if offset is not None and offset < len(NestedStructType.elements):
|
||
MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
|
||
self._StoreWithCoerce(Value, MemberPtr)
|
||
return
|
||
bitfield_offsets: dict[str, int] = Gen.class_member_bitoffsets.get(ClassName, {})
|
||
if AttrName in bitfield_offsets:
|
||
self._store_bitfield_member(ObjVal, ClassName, AttrName, Value)
|
||
return
|
||
bitfields: dict[str, int] = Gen.class_member_bitfields.get(ClassName, {})
|
||
if AttrName in bitfields and bitfields[AttrName] > 0:
|
||
if ClassName not in Gen.class_member_bitoffsets:
|
||
Gen.class_member_bitoffsets[ClassName] = {}
|
||
if AttrName not in Gen.class_member_bitoffsets[ClassName]:
|
||
bo: int = 0
|
||
for bf_name, bf_width in bitfields.items():
|
||
if bf_name == AttrName:
|
||
break
|
||
bo += bf_width
|
||
Gen.class_member_bitoffsets[ClassName][AttrName] = bo
|
||
self._store_bitfield_member(ObjVal, ClassName, AttrName, Value)
|
||
return
|
||
is_vtable_method: bool = False
|
||
method_idx: int = 0
|
||
if ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes:
|
||
if ClassName in Gen.class_methods:
|
||
for mi, mn in enumerate(Gen.class_methods[ClassName]):
|
||
method_short: str = mn.split('.')[-1] if '.' in mn else mn
|
||
if method_short == AttrName or mn == AttrName:
|
||
is_vtable_method = True
|
||
method_idx = mi
|
||
break
|
||
if is_vtable_method:
|
||
VtableSlotPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}")
|
||
VtablePtr: ir.Value = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}")
|
||
methods: list[str] = Gen.class_methods[ClassName]
|
||
VtableArrayType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods))
|
||
ClassVtable: ir.GlobalVariable | None = Gen.Vtables.get(ClassName)
|
||
if ClassVtable:
|
||
ClassVtableAddr: ir.Value = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"class_vtable_addr_{ClassName}")
|
||
IsSameVtable: ir.Value = Gen.builder.icmp_unsigned('==', VtablePtr, ClassVtableAddr, name=f"is_same_vtable_{ClassName}")
|
||
CopyBlock: ir.Block = Gen.func.append_basic_block(name=f"vtable_copy_{AttrName}")
|
||
SkipBlock: ir.Block = Gen.func.append_basic_block(name=f"vtable_skip_{AttrName}")
|
||
Gen.builder.cbranch(IsSameVtable, CopyBlock, SkipBlock)
|
||
Gen.builder.position_at_end(CopyBlock)
|
||
Gen._vtable_copy_counter += 1
|
||
CopyName: str = f"{Gen._mangle_name(ClassName)}_vtable_copy_{Gen._vtable_copy_counter}"
|
||
VtableCopyGlobal: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VtableArrayType, name=CopyName)
|
||
VtableCopyGlobal.linkage = 'internal'
|
||
VtableCopyGlobal.initializer = ir.Constant(VtableArrayType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods))
|
||
VtableCopyTyped: ir.Value = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_typed")
|
||
SrcTyped: ir.Value = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"src_vtable_typed")
|
||
VtableSize: int = len(methods) * Gen.ptr_size
|
||
MemcpyFunc: ir.Function | None = Gen._find_function('llvm.memcpy.p0i8.p0i8.i64')
|
||
if not MemcpyFunc:
|
||
MemcpyType: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)])
|
||
MemcpyFunc = ir.Function(Gen.module, MemcpyType, name='llvm.memcpy.p0i8.p0i8.i64')
|
||
Gen.functions['llvm.memcpy.p0i8.p0i8.i64'] = MemcpyFunc
|
||
Gen.builder.call(MemcpyFunc, [VtableCopyTyped, SrcTyped, ir.Constant(ir.IntType(64), VtableSize), ir.Constant(ir.IntType(1), 0)])
|
||
VtableCopyGlobalAddr: ir.Value = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_addr")
|
||
Gen._store(VtableCopyGlobalAddr, VtableSlotPtr)
|
||
Gen.builder.branch(SkipBlock)
|
||
Gen.builder.position_at_end(SkipBlock)
|
||
VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}_after_copy")
|
||
VtableTyped: ir.Value = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}")
|
||
MethodPtrAddr: ir.Value = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_slot_{AttrName}")
|
||
FuncPtrI8: ir.Value = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"func_ptr_i8_{AttrName}")
|
||
Gen._store(FuncPtrI8, MethodPtrAddr)
|
||
return
|
||
offset: int | None = Gen._get_member_offset(AttrName, ClassName)
|
||
StructType: ir.Type | None = Gen.structs.get(ClassName)
|
||
if isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0):
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen)
|
||
StructType = Gen.structs.get(ClassName)
|
||
if isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0):
|
||
return
|
||
# 重新计算 offset:_TryLoadStructFromStub 刚加载了 struct body,
|
||
# 之前 offset 可能因 struct opaque / class_members 不完整而返回 None
|
||
offset = Gen._get_member_offset(AttrName, ClassName)
|
||
# sha1 冲突修复:Gen.structs[ClassName] 可能是字段不全的版本(如 2 字段 Function
|
||
# 来自 MetaType.py scope,而正确版本是 8 字段 Function 来自 __function.py)。
|
||
# _get_member_offset 通过 class_sha1_map 已返回正确的 offset(如 5),
|
||
# 但 StructType 可能只有 2 个 elements,导致 offset < len(elements) 失败。
|
||
# 在所有 structs 中查找同短名且字段最多的版本。
|
||
if offset is not None and isinstance(StructType, ir.IdentifiedStructType) and StructType.elements is not None and offset >= len(StructType.elements):
|
||
_short: str = Gen._extract_short_name(StructType.name)
|
||
_best: int = len(StructType.elements)
|
||
for _cn, _st in Gen.structs.items():
|
||
if isinstance(_st, ir.IdentifiedStructType) and _st.elements is not None:
|
||
if Gen._extract_short_name(_st.name) == _short and len(_st.elements) > _best:
|
||
StructType = _st
|
||
_best = len(_st.elements)
|
||
# bitcast:当 ObjVal 的 pointee 是 opaque 或与 StructType 不是同一个类型对象
|
||
# (sha1 前缀不同但短名相同)时,需要 bitcast 到 StructType 才能正确 GEP
|
||
if StructType is not None and StructType.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and (ObjVal.type.pointee.elements is None or ObjVal.type.pointee != StructType):
|
||
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(StructType), name=f"cast_{ClassName}")
|
||
if offset is not None and StructType is not None and StructType.elements is not None and offset < len(StructType.elements):
|
||
MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
|
||
else:
|
||
return
|
||
|
||
byte_order: str = Gen.class_member_byteorders.get(ClassName, {}).get(AttrName, "")
|
||
|
||
if byte_order == 'big':
|
||
if StructType is None or StructType.elements is None or len(StructType.elements) == 0:
|
||
return
|
||
member_type: ir.Type = StructType.elements[offset]
|
||
if isinstance(member_type, ir.IntType):
|
||
Value = Gen._apply_bswap_if_big(Value, byte_order, f"bswap_store_{AttrName}")
|
||
|
||
self._StoreWithCoerce(Value, MemberPtr)
|
||
if not ClassName:
|
||
imported_modules: list[str] | None = getattr(self.Trans, '_ImportedModules', None)
|
||
resolved_mod: str = self.Trans.SymbolTable.resolve_alias(VarName)
|
||
if imported_modules and (VarName in imported_modules or resolved_mod in imported_modules):
|
||
PossibleKeys: list[str] = [f"{VarName}.{AttrName}", AttrName]
|
||
for mod_name in imported_modules:
|
||
if mod_name.endswith(f".{VarName}") or mod_name == VarName:
|
||
key: str = f"{mod_name}.{AttrName}"
|
||
if key not in PossibleKeys:
|
||
PossibleKeys.append(key)
|
||
for key in PossibleKeys:
|
||
if key in Gen.module.globals:
|
||
GVar: ir.GlobalVariable = Gen.module.globals[key]
|
||
if isinstance(GVar, ir.Function):
|
||
return
|
||
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
|
||
return
|
||
self._StoreWithCoerce(Value, GVar)
|
||
return
|
||
ModuleSha1Map: dict[str, str] = Gen.ModuleSha1Map
|
||
sha1_candidates: list[str] = [VarName, resolved_mod]
|
||
for mod_name in imported_modules:
|
||
if mod_name.endswith(f".{VarName}") or mod_name == VarName:
|
||
if mod_name not in sha1_candidates:
|
||
sha1_candidates.append(mod_name)
|
||
for cand in sha1_candidates:
|
||
sha1: str | None = ModuleSha1Map.get(cand)
|
||
if sha1:
|
||
prefixed: str = f"{sha1}.{AttrName}"
|
||
if prefixed in Gen.module.globals:
|
||
GVar2: ir.GlobalVariable = Gen.module.globals[prefixed]
|
||
if isinstance(GVar2, ir.Function):
|
||
return
|
||
if isinstance(GVar2.type, ir.PointerType) and isinstance(GVar2.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
|
||
return
|
||
self._StoreWithCoerce(Value, GVar2)
|
||
return
|
||
elif isinstance(Target.value, ast.Attribute):
|
||
ObjVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value)
|
||
if ObjVal and isinstance(ObjVal.type, ir.PointerType):
|
||
pointee: ir.Type = ObjVal.type.pointee
|
||
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||
if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is None:
|
||
for CN, ST in Gen.structs.items():
|
||
if isinstance(ST, ir.IdentifiedStructType) and ST.name == pointee.name and ST.elements is not None:
|
||
pointee = ST
|
||
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}")
|
||
break
|
||
found_match: bool = False
|
||
for CN, ST in Gen.structs.items():
|
||
if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name):
|
||
found_match = True
|
||
if ST.elements is None:
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen)
|
||
ST = Gen.structs.get(CN, ST)
|
||
if ST.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None:
|
||
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}")
|
||
bitfield_offsets: dict[str, int] = Gen.class_member_bitoffsets.get(CN, {})
|
||
if AttrName in bitfield_offsets:
|
||
self._store_bitfield_member(ObjVal, CN, AttrName, Value)
|
||
return
|
||
offset: int = Gen._get_member_offset(AttrName, CN)
|
||
if offset is not None and ST.elements is not None and offset < len(ST.elements):
|
||
MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
|
||
self._StoreWithCoerce(Value, MemberPtr)
|
||
break
|
||
if not found_match:
|
||
if isinstance(pointee, ir.IdentifiedStructType):
|
||
matched_cn: str | None = None
|
||
for CN in Gen.class_members:
|
||
members: list[tuple[str, ir.Type]] = Gen.class_members[CN]
|
||
for mname, mtype in members:
|
||
if mname == AttrName:
|
||
matched_cn = CN
|
||
break
|
||
if matched_cn:
|
||
break
|
||
if matched_cn and matched_cn in Gen.structs:
|
||
ST: ir.Type = Gen.structs[matched_cn]
|
||
if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0):
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(matched_cn, Gen)
|
||
ST = Gen.structs.get(matched_cn, ST)
|
||
if ST.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None:
|
||
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{matched_cn}")
|
||
offset: int = Gen._get_member_offset(AttrName, matched_cn)
|
||
if offset is not None and ST.elements is not None and offset < len(ST.elements):
|
||
MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
|
||
self._StoreWithCoerce(Value, MemberPtr)
|
||
return
|
||
elif isinstance(Target.value, ast.Call):
|
||
# Check if this is c.Deref(...) — we need the pointer, not the Loaded value
|
||
ObjVal: ir.Value | None = None
|
||
is_cderef: bool = (isinstance(Target.value.func, ast.Attribute) and
|
||
isinstance(Target.value.func.value, ast.Name) and
|
||
Target.value.func.value.id == 'c' and
|
||
Target.value.func.attr == 'Deref' and
|
||
Target.value.args)
|
||
if is_cderef:
|
||
# Get the pointer from c.Deref argument, don't Load the value
|
||
deref_arg: ast.expr = Target.value.args[0]
|
||
inner_val: ir.Value | None = self.HandleExprLlvm(deref_arg)
|
||
if inner_val and isinstance(inner_val.type, ir.PointerType):
|
||
if isinstance(inner_val.type.pointee, ir.PointerType):
|
||
ObjVal = Gen._load(inner_val, name="deref_load_ptr")
|
||
else:
|
||
ObjVal = inner_val
|
||
if ObjVal is None:
|
||
ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value)
|
||
if ObjVal and isinstance(ObjVal.type, ir.PointerType):
|
||
pointee: ir.Type = ObjVal.type.pointee
|
||
if isinstance(pointee, ir.PointerType):
|
||
ObjVal = Gen._load(ObjVal, name="load_ptr_for_attr")
|
||
pointee = ObjVal.type.pointee
|
||
for CN, ST in Gen.structs.items():
|
||
if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name):
|
||
if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0):
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen)
|
||
ST = Gen.structs.get(CN, ST)
|
||
if ST.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None:
|
||
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}")
|
||
bitfield_offsets: dict[str, int] = Gen.class_member_bitoffsets.get(CN, {})
|
||
if AttrName in bitfield_offsets:
|
||
self._store_bitfield_member(ObjVal, CN, AttrName, Value)
|
||
return
|
||
offset: int = Gen._get_member_offset(AttrName, CN)
|
||
if offset is not None and ST.elements is not None and offset < len(ST.elements):
|
||
MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
|
||
self._StoreWithCoerce(Value, MemberPtr)
|
||
break
|
||
elif isinstance(Target.value, ast.Subscript):
|
||
SubPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Target.value)
|
||
if SubPtr and isinstance(SubPtr.type, ir.PointerType):
|
||
pointee: ir.Type = SubPtr.type.pointee
|
||
|
||
if isinstance(Target.value.value, ast.Attribute):
|
||
AttrNameSub: str = Target.value.value.attr
|
||
if AttrNameSub == 'items' and 'Item' in Gen.structs:
|
||
ObjValCast: ir.Value = Gen.builder.bitcast(SubPtr, ir.PointerType(Gen.structs['Item']), name=f"cast_Item")
|
||
offset: int = Gen._get_member_offset(AttrName, 'Item')
|
||
MemberPtr: ir.Value = Gen.builder.gep(ObjValCast, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
|
||
self._StoreWithCoerce(Value, MemberPtr)
|
||
return
|
||
|
||
if BaseHandle._is_char_pointer(SubPtr):
|
||
for CN, ST in Gen.structs.items():
|
||
ObjValCast: ir.Value = Gen.builder.bitcast(SubPtr, ir.PointerType(ST), name=f"cast_{CN}")
|
||
offset: int = Gen._get_member_offset(AttrName, CN)
|
||
MemberPtr: ir.Value = Gen.builder.gep(ObjValCast, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
|
||
self._StoreWithCoerce(Value, MemberPtr)
|
||
break
|
||
elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(pointee)
|
||
if found:
|
||
CN: str = found[0]
|
||
ST: ir.Type = found[1]
|
||
if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0):
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen)
|
||
ST = Gen.structs.get(CN, ST)
|
||
if ST.elements is not None and isinstance(SubPtr.type, ir.PointerType) and isinstance(SubPtr.type.pointee, ir.IdentifiedStructType) and SubPtr.type.pointee.elements is None:
|
||
SubPtr = Gen.builder.bitcast(SubPtr, ir.PointerType(ST), name=f"cast_{CN}")
|
||
offset: int = Gen._get_member_offset(AttrName, CN)
|
||
if offset is not None and ST.elements is not None and offset < len(ST.elements):
|
||
MemberPtr: ir.Value = Gen.builder.gep(SubPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
|
||
self._StoreWithCoerce(Value, MemberPtr)
|
||
elif isinstance(pointee, ir.PointerType):
|
||
LoadedPtr: ir.Value = Gen._load(SubPtr, name=f"Load_{AttrName}_ptr")
|
||
if isinstance(LoadedPtr.type, ir.PointerType) and isinstance(LoadedPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(LoadedPtr.type.pointee)
|
||
if found:
|
||
CN: str = found[0]
|
||
ST: ir.Type = found[1]
|
||
offset: int = Gen._get_member_offset(AttrName, CN)
|
||
MemberPtr: ir.Value = Gen.builder.gep(LoadedPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
|
||
self._StoreWithCoerce(Value, MemberPtr)
|
||
|
||
def _StoreArrElemWithCoerceBswap(self, Value: ir.Value, Ptr: ir.Value, arr_byte_order: str) -> None:
|
||
"""对数组元素存储应用 bswap 后再 coerce 存储"""
|
||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||
Value = Gen._apply_bswap_if_big(Value, arr_byte_order, "bswap_arr_store")
|
||
self._StoreWithCoerce(Value, Ptr)
|
||
|
||
def _HandleSubscriptStoreLlvm(self, Target: ast.Subscript, Value: ir.Value) -> None:
|
||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||
# 查询数组元素字节序
|
||
arr_byte_order: str = ''
|
||
if isinstance(Target.value, ast.Name) and Target.value.id in Gen.local_var_byteorders:
|
||
arr_byte_order = Gen.local_var_byteorders[Target.value.id]
|
||
if isinstance(Target.value, ast.Name):
|
||
SubVarName: str = Target.value.id
|
||
if SubVarName in Gen.var_const_flags:
|
||
src_info: str = Gen._get_node_info()
|
||
self.Trans.LogError(f"不能对 const 变量 '{SubVarName}' 的元素赋值{src_info}")
|
||
ClassName: str | None = self.Trans.ExprHandler._get_var_class(Target.value, Gen)
|
||
if ClassName and Gen._has_function(f'{ClassName}.__setitem__'):
|
||
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value)
|
||
idx_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.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 BaseHandle._is_char_pointer(obj_val):
|
||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||
setitem_args: list[ir.Value] = [obj_val, idx_val, Value]
|
||
setitem_func_name: str = f'{ClassName}.__setitem__'
|
||
setitem_args = Gen._apply_auto_addr(setitem_func_name, setitem_args)
|
||
setitem_func: ir.Function = Gen._get_function(setitem_func_name)
|
||
setitem_args = Gen._adjust_args(setitem_args, setitem_func)
|
||
Gen.builder.call(setitem_func, setitem_args, name=f"call_{setitem_func_name}")
|
||
return
|
||
ValueVal: ir.Value | None = self.HandleExprLlvm(Target.value)
|
||
IndexVal: ir.Value | None = self.HandleExprLlvm(Target.slice)
|
||
if not ValueVal or not IndexVal:
|
||
return
|
||
# 当变量本身是二级指针(如 elem_ptr: T | t.CPtr = AST**),
|
||
# 且存储的值也是指针时,elem_ptr[i] = item 应直接存储指针(8 字节),
|
||
# 而非解引用后复制结构体(如 48 字节的 AST),避免对象切片
|
||
if isinstance(Target.value, ast.Name):
|
||
VarName: str = Target.value.id
|
||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||
VarAlloca: ir.Value = Gen.variables[VarName]
|
||
if isinstance(VarAlloca.type, ir.PointerType) and isinstance(VarAlloca.type.pointee, ir.PointerType):
|
||
if (isinstance(ValueVal.type, ir.PointerType) and isinstance(Value.type, ir.PointerType)
|
||
and isinstance(Value.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType))):
|
||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
|
||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index_store")
|
||
# ValueVal 是 AST*(加载自 elem_ptr 的基指针),
|
||
# 但 GEP 默认将其视为 AST 结构体数组。需要先 bitcast 为
|
||
# AST**(指向 AST* 的指针),让 GEP 正确索引 AST* 指针数组,
|
||
# 而非 AST 结构体数组。然后用 builder.store 直接存储指针,
|
||
# 避免 _store 的类型强制转换将指针解引用为结构体。
|
||
PtrToStruct: ir.Type = Value.type.pointee
|
||
BaseAsPP: ir.Value = Gen.builder.bitcast(ValueVal,
|
||
ir.PointerType(ir.PointerType(PtrToStruct)), name="cast_base_pp")
|
||
ElemPtr: ir.Value = Gen.builder.gep(BaseAsPP, [IndexVal], name="subscript")
|
||
Gen.builder.store(Value, ElemPtr)
|
||
return
|
||
if BaseHandle._is_char_pointer(IndexVal):
|
||
Loaded_byte: ir.Value = Gen._load(IndexVal, name="Load_char_idx_store")
|
||
IndexVal = Gen.builder.zext(Loaded_byte, ir.IntType(32), name="char_to_int_idx_store")
|
||
if isinstance(ValueVal.type, ir.IntType):
|
||
var_ptr: ir.Value | None = self._get_int_ptr(Target.value)
|
||
if var_ptr:
|
||
i8_ptr: ir.Value = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr_store")
|
||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
|
||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index_store")
|
||
ptr: ir.Value = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr_store")
|
||
self._StoreWithCoerce(Value, ptr)
|
||
return
|
||
if isinstance(ValueVal.type, ir.PointerType) and isinstance(ValueVal.type.pointee, ir.PointerType):
|
||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
|
||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index_store")
|
||
ElemPtr: ir.Value = Gen.builder.gep(ValueVal, [IndexVal], name="subscript")
|
||
self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order)
|
||
return
|
||
if isinstance(ValueVal.type, ir.PointerType):
|
||
pointee: ir.Type = ValueVal.type.pointee
|
||
if isinstance(pointee, ir.ArrayType):
|
||
zero: ir.Constant = 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: ir.Value = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript")
|
||
elif (isinstance(pointee, ir.IntType) and pointee.width == 8
|
||
and isinstance(Target.value, ast.Name)
|
||
and (Gen.var_ptr_element.get(Target.value.id, False)
|
||
or Gen.global_var_ptr_element.get(Target.value.id, False))):
|
||
# 指针到 str/bytes 的变量 (BinOp 注解如 str | t.CPtr)
|
||
# elem_ptr 是 i8* 但实际指向 i8* (字符串指针), elem_ptr[0] = item 应存储 8 字节
|
||
CastedPtrPtr: ir.Value = Gen.builder.bitcast(ValueVal, ir.PointerType(ir.PointerType(ir.IntType(8))), name="cast_pp_str_store")
|
||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
|
||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_pp_str_index_store")
|
||
ElemPtr = Gen.builder.gep(CastedPtrPtr, [IndexVal], name="subscript")
|
||
self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order)
|
||
return
|
||
else:
|
||
ElemPtr: ir.Value = Gen.builder.gep(ValueVal, [IndexVal], name="subscript")
|
||
self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order)
|
||
elif isinstance(ValueVal.type, ir.ArrayType):
|
||
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
|
||
if isinstance(Target.value, ast.Name):
|
||
VarName: str = Target.value.id
|
||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||
VarPtr: ir.Value = 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: ir.Value = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript")
|
||
self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order)
|
||
return
|
||
if isinstance(Target.value, ast.Subscript):
|
||
InnerPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Target.value)
|
||
if InnerPtr:
|
||
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: ir.Value = Gen.builder.gep(InnerPtr, [zero, IndexVal], name="subscript")
|
||
self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order)
|
||
return
|
||
if isinstance(Target.value, ast.Attribute):
|
||
AttrPtr: ir.Value | None = self.Trans.ExprAttrHandle._get_attr_ptr(Target.value)
|
||
if AttrPtr and isinstance(AttrPtr.type, ir.PointerType) and isinstance(AttrPtr.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: ir.Value = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript")
|
||
self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order)
|
||
return
|
||
arr_alloc: ir.AllocaInstr = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp")
|
||
Gen._store(ValueVal, arr_alloc)
|
||
ElemPtr: ir.Value = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript")
|
||
self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order)
|
||
ModifiedArr: ir.Value = Gen._load(arr_alloc, name="modified_arr")
|
||
if isinstance(Target.value, ast.Subscript):
|
||
OuterPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Target.value)
|
||
if OuterPtr:
|
||
Gen._store(ModifiedArr, OuterPtr)
|
||
elif isinstance(Target.value, ast.Attribute):
|
||
OuterPtr: ir.Value | None = self.Trans.ExprAttrHandle._get_attr_ptr(Target.value)
|
||
if OuterPtr:
|
||
Gen._store(ModifiedArr, OuterPtr)
|
||
|
||
def _StoreWithCoerce(self, Value: ir.Value, Ptr: ir.Value) -> None:
|
||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||
if isinstance(Ptr.type, ir.PointerType):
|
||
TargetType: ir.Type = Ptr.type.pointee
|
||
if Value.type != TargetType:
|
||
if isinstance(TargetType, ir.ArrayType) and isinstance(Value.type, ir.PointerType):
|
||
ElemType: ir.Type = TargetType.element
|
||
ElemSize: int = Gen._get_struct_size(ElemType)
|
||
for i in range(TargetType.count):
|
||
DstElem: ir.Value = Gen.builder.gep(Ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i)], name=f"arr_dst_{i}")
|
||
SrcPtr: ir.Value
|
||
if ElemSize == 1:
|
||
SrcPtr = Gen.builder.gep(Value, [ir.Constant(ir.IntType(32), i)], name=f"arr_src_{i}")
|
||
else:
|
||
PtrInt: ir.Value = Gen.builder.ptrtoint(Value, ir.IntType(64))
|
||
Offset: ir.Constant = ir.Constant(ir.IntType(64), i * ElemSize)
|
||
NewPtrInt: ir.Value = Gen.builder.add(PtrInt, Offset)
|
||
SrcPtr = Gen.builder.inttoptr(NewPtrInt, ir.PointerType(ElemType), name=f"arr_src_{i}")
|
||
SrcVal: ir.Value = Gen._load(SrcPtr, name=f"arr_elem_{i}")
|
||
if SrcVal.type != ElemType:
|
||
try:
|
||
SrcVal = Gen.builder.bitcast(SrcVal, ElemType, name=f"arr_cast_{i}")
|
||
except Exception: # 回退:bitcast 失败时跳过该元素
|
||
continue
|
||
Gen._store(SrcVal, DstElem)
|
||
return
|
||
if isinstance(TargetType, ir.PointerType) and isinstance(Value, ir.Constant) and Value.constant is None:
|
||
Value = ir.Constant(TargetType, None)
|
||
elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.PointerType):
|
||
try:
|
||
Value = Gen.builder.bitcast(Value, TargetType, name="null_ptr_bitcast")
|
||
except Exception: # 回退:bitcast 失败时设为 null 常量
|
||
Value = ir.Constant(TargetType, None)
|
||
else:
|
||
Coerced: ir.Value | None = Gen._coerce_value(Value, TargetType)
|
||
if Coerced is not None:
|
||
Value = Coerced
|
||
Gen._store(Value, Ptr)
|
||
|
||
|
||
def _get_int_ptr(self, target: ast.expr) -> ir.Value | None:
|
||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||
if isinstance(target, ast.Name):
|
||
VarName: str = target.id
|
||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||
VarPtr: ir.Value = Gen.variables[VarName]
|
||
if isinstance(VarPtr.type, ir.PointerType):
|
||
pointee: ir.Type = VarPtr.type.pointee
|
||
if isinstance(pointee, ir.ArrayType):
|
||
return Gen.builder.gep(VarPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"arr_start_{VarName}")
|
||
return None
|
||
|
||
def _EmitGlobalAnnAssignLlvm(self, Node: ast.AnnAssign, Gen: "Translator.LlvmGen") -> None:
|
||
if isinstance(Node.target, ast.Name):
|
||
VarName: str = Node.target.id
|
||
Info: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(VarName)
|
||
if Info:
|
||
if Info.IsTypedef:
|
||
return
|
||
parse_result = ParseListAnnotation(Node.annotation)
|
||
if parse_result:
|
||
elem_type_node: ast.expr = parse_result.elem_type_node
|
||
ElemType, ElemTypeInfo = self.ResolveListElementType(
|
||
elem_type_node, Gen,
|
||
check_func_ptr=True, void_fallback_width=32, fallback_to_cint=True,
|
||
)
|
||
if parse_result.is_pointer:
|
||
# 单参数 list[type] → 指针
|
||
VarType: ir.Type = ir.PointerType(ElemType)
|
||
if VarName not in Gen.variables and VarName not in Gen.module.globals:
|
||
GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName)
|
||
GlobalVar.initializer = ir.Constant(VarType, None)
|
||
Gen.variables[VarName] = GlobalVar
|
||
if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs:
|
||
Gen.global_struct_class[VarName] = elem_type_node.id
|
||
return
|
||
count_node: ast.expr | None = parse_result.count_node
|
||
ArrayCount: int = self.ParseArrayCount(count_node, Gen, Node.value, mode='global')
|
||
VarType = ir.ArrayType(ElemType, ArrayCount)
|
||
if VarName not in Gen.variables and VarName not in Gen.module.globals:
|
||
GlobalVar = ir.GlobalVariable(Gen.module, VarType, name=VarName)
|
||
if isinstance(ElemType, ir.IdentifiedStructType):
|
||
GlobalVar.linkage = 'common'
|
||
elif Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str):
|
||
str_val: str = Node.value.value + '\x00'
|
||
str_bytes: bytearray = bytearray(str_val, 'utf-8')
|
||
if len(str_bytes) < ArrayCount:
|
||
str_bytes.extend(b'\x00' * (ArrayCount - len(str_bytes)))
|
||
try:
|
||
GlobalVar.initializer = ir.Constant(VarType, str_bytes[:ArrayCount])
|
||
except Exception: # 回退:初始化常量失败时用零值
|
||
GlobalVar.initializer = Gen._zero_value_for_type(VarType)
|
||
else:
|
||
InitConstants: list[ir.Constant] | None = self.Trans._BuildArrayInitConstants(Node.value, ElemType, elem_type_node, ArrayCount, Gen, byte_order=ElemTypeInfo.ByteOrder if ElemTypeInfo else '')
|
||
if InitConstants:
|
||
GlobalVar.initializer = ir.Constant(VarType, InitConstants)
|
||
elif ArrayCount > 256:
|
||
GlobalVar.linkage = 'common'
|
||
else:
|
||
if self._contains_identified_struct(VarType):
|
||
GlobalVar.linkage = 'common'
|
||
else:
|
||
GlobalVar.initializer = ir.Constant(VarType, [ir.Constant(ElemType, ir.Undefined)] * ArrayCount)
|
||
Gen.variables[VarName] = GlobalVar
|
||
if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs:
|
||
Gen.global_struct_class[VarName] = elem_type_node.id
|
||
return
|
||
if isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs:
|
||
StructName: str = Node.annotation.id
|
||
VarType: ir.Type = Gen.structs[StructName]
|
||
if VarName not in Gen.variables and VarName not in Gen.module.globals:
|
||
GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName)
|
||
if Node.value and isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name) and Node.value.func.id == StructName:
|
||
const: ir.Constant | None = self.Trans.ClassHandler._BuildStructConstant(Node.value, StructName, Gen)
|
||
if const:
|
||
GlobalVar.initializer = const
|
||
else:
|
||
GlobalVar.initializer = ir.Constant(VarType, None)
|
||
else:
|
||
GlobalVar.initializer = ir.Constant(VarType, None)
|
||
Gen.variables[VarName] = GlobalVar
|
||
Gen.global_struct_class[VarName] = StructName
|
||
return
|
||
TypeInfo: CTypeInfo | None = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable)
|
||
IsCDefine: bool = False
|
||
if TypeInfo and TypeInfo.BaseType:
|
||
if isinstance(TypeInfo.BaseType, t._CTypedef):
|
||
return
|
||
if isinstance(TypeInfo.BaseType, t.CDefine):
|
||
IsCDefine = True
|
||
if not IsCDefine and self._IsTypedefAnnotation(Node.annotation):
|
||
IsCDefine = True
|
||
TTypeInfo: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation)
|
||
if TTypeInfo:
|
||
TTypeInfo.IsTypedef = True
|
||
TTypeInfo.Name = VarName
|
||
self.Trans.SymbolTable.insert(VarName, TTypeInfo)
|
||
if IsCDefine:
|
||
if Node.value:
|
||
define_constants: dict[str, int | float] = vars(Gen).setdefault('_define_constants', {})
|
||
try:
|
||
const_value: int | float | None = self._eval_const_expr(Node.value, Gen)
|
||
if const_value is not None:
|
||
define_constants[VarName] = const_value
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
return
|
||
if TypeInfo is None:
|
||
TypeInfo = CTypeInfo()
|
||
TypeInfo.BaseType = t.CInt()
|
||
VarType: ir.Type = Gen._ctype_to_llvm(TypeInfo)
|
||
if isinstance(VarType, ir.VoidType):
|
||
VarType = ir.IntType(32)
|
||
if VarName in Gen.variables or VarName in Gen.module.globals:
|
||
# 时序修复:第一遍创建全局时类未处理(SymbolTable 无枚举成员),
|
||
# initializer 回退为 0。第二遍类已处理,尝试用解析出的枚举值更新 initializer。
|
||
if VarName in Gen.module.globals and Node.value:
|
||
existing: Any = Gen.module.globals[VarName]
|
||
if isinstance(existing, ir.GlobalVariable) and isinstance(VarType, ir.IntType):
|
||
new_init: ir.Constant | None = self._eval_global_const(Node.value, VarType, Gen)
|
||
if new_init is not None:
|
||
existing.initializer = new_init
|
||
return
|
||
if isinstance(VarType, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName)
|
||
GlobalVar.initializer = ir.Constant(VarType, None)
|
||
Gen.variables[VarName] = GlobalVar
|
||
if TypeInfo and TypeInfo.IsStruct and TypeInfo.Name:
|
||
Gen.global_struct_class[VarName] = TypeInfo.Name
|
||
return
|
||
GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName)
|
||
# 全局变量指针元素标志:bytes|t.CPtr 或 str|t.CPtr 注解的变量,
|
||
# 使 var[index] 使用 8 字节指针步长(而非 1 字节字符步长)
|
||
if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr):
|
||
if AnnotationContainsName(Node.annotation, 'str') or AnnotationContainsName(Node.annotation, 'bytes'):
|
||
Gen.global_var_ptr_element[VarName] = True
|
||
if Node.value:
|
||
if isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str) and isinstance(VarType, ir.PointerType):
|
||
str_val: str = Node.value.value + '\x00'
|
||
str_bytes: bytes = str_val.encode('utf-8')
|
||
arr_type: ir.ArrayType = ir.ArrayType(ir.IntType(8), len(str_bytes))
|
||
str_gv_name: str = VarName + '_str'
|
||
str_gv: ir.GlobalVariable
|
||
if str_gv_name not in Gen.module.globals:
|
||
str_gv = ir.GlobalVariable(Gen.module, arr_type, name=str_gv_name)
|
||
str_gv.initializer = ir.Constant(arr_type, bytearray(str_bytes))
|
||
str_gv.linkage = 'internal'
|
||
else:
|
||
str_gv = Gen.module.globals[str_gv_name]
|
||
ptr_type: ir.PointerType = ir.PointerType(ir.IntType(8))
|
||
ptr_gv: ir.GlobalVariable
|
||
if VarName not in Gen.module.globals:
|
||
ptr_gv = ir.GlobalVariable(Gen.module, ptr_type, name=VarName)
|
||
ptr_gv.initializer = ir.Constant(ptr_type, str_gv)
|
||
ptr_gv.linkage = 'internal'
|
||
else:
|
||
ptr_gv = Gen.module.globals[VarName]
|
||
Gen.variables[VarName] = ptr_gv
|
||
elif isinstance(VarType, ir.PointerType) and isinstance(VarType.pointee, ir.FunctionType) and isinstance(Node.value, ast.Name):
|
||
# 函数指针赋值:f3: t.Callable[[int], int] = f
|
||
RefName: str = Node.value.id
|
||
SymInfo: Any = self.Trans.SymbolTable.lookup(RefName)
|
||
if SymInfo and (SymInfo.IsFunction or SymInfo.IsFuncPtr):
|
||
MangledName: str = Gen._mangle_func_name(RefName)
|
||
if MangledName in Gen.module.globals:
|
||
func: Any = Gen.module.globals[MangledName]
|
||
if isinstance(func, ir.Function):
|
||
GlobalVar.initializer = func
|
||
else:
|
||
if isinstance(VarType, ir.ArrayType) and isinstance(Node.value, (ast.List, ast.Set)):
|
||
InitConstants: list[ir.Constant] | None = self.Trans._BuildMultiDimArrayInitConstants(Node.value, VarType, Gen)
|
||
if InitConstants:
|
||
GlobalVar.initializer = ir.Constant(VarType, InitConstants)
|
||
else:
|
||
if self._contains_identified_struct(VarType):
|
||
GlobalVar.linkage = 'common'
|
||
else:
|
||
zv: ir.Constant | None = Gen._zero_value_for_type(VarType)
|
||
if zv:
|
||
GlobalVar.initializer = zv
|
||
else:
|
||
GlobalVar.linkage = 'common'
|
||
else:
|
||
init_val: ir.Constant | None = self._eval_global_const(Node.value, VarType, Gen)
|
||
if init_val:
|
||
GlobalVar.initializer = init_val
|
||
elif isinstance(VarType, ir.BaseStructType):
|
||
GlobalVar.linkage = 'common'
|
||
else:
|
||
GlobalVar.initializer = Gen._zero_value_for_type(VarType)
|
||
else:
|
||
if isinstance(VarType, ir.BaseStructType) or self._contains_identified_struct(VarType):
|
||
GlobalVar.linkage = 'common'
|
||
else:
|
||
GlobalVar.initializer = Gen._zero_value_for_type(VarType)
|
||
Gen.variables[VarName] = GlobalVar
|
||
|
||
def _eval_global_const(self, value_node: ast.expr, var_type: ir.Type, Gen: "Translator.LlvmGen") -> ir.Constant | None:
|
||
if isinstance(value_node, ast.Constant):
|
||
if isinstance(value_node.value, bool):
|
||
if isinstance(var_type, ir.IntType):
|
||
return ir.Constant(var_type, int(value_node.value))
|
||
elif isinstance(value_node.value, int):
|
||
if isinstance(var_type, ir.IntType):
|
||
return ir.Constant(var_type, value_node.value)
|
||
elif isinstance(var_type, (ir.FloatType, ir.DoubleType)):
|
||
return ir.Constant(var_type, float(value_node.value))
|
||
elif isinstance(value_node.value, float):
|
||
if isinstance(var_type, (ir.FloatType, ir.DoubleType)):
|
||
return ir.Constant(var_type, value_node.value)
|
||
elif isinstance(var_type, ir.IntType):
|
||
return ir.Constant(var_type, int(value_node.value))
|
||
elif isinstance(value_node.value, str):
|
||
return None
|
||
# Handle type constructor calls like t.CDouble(1e-9), t.CFloat(3.14), t.CInt(42)
|
||
if isinstance(value_node, ast.Call):
|
||
inner_val: ir.Constant | None = self._eval_type_ctor_const(value_node, var_type, Gen)
|
||
if inner_val is not None:
|
||
return inner_val
|
||
if isinstance(value_node, ast.UnaryOp) and isinstance(value_node.op, ast.USub):
|
||
inner: ir.Constant | None = self._eval_global_const(value_node.operand, var_type, Gen)
|
||
if inner:
|
||
return ir.Constant(var_type, -inner.constant)
|
||
# Handle enum member references like ASTVType.Module (ast.Attribute)
|
||
if isinstance(value_node, ast.Attribute):
|
||
attr_name: str = value_node.attr
|
||
# 优先用带前缀的 key 查找(避免短名被同名函数/变量覆盖)
|
||
if isinstance(value_node.value, ast.Name):
|
||
FullKey2: str = f"{value_node.value.id}.{attr_name}"
|
||
FullInfo: Any = self.Trans.SymbolTable.lookup(FullKey2)
|
||
if FullInfo and FullInfo.IsEnumMember and isinstance(FullInfo.value, int):
|
||
if isinstance(var_type, ir.IntType):
|
||
return ir.Constant(var_type, FullInfo.value)
|
||
SymInfo: Any = self.Trans.SymbolTable.lookup(attr_name)
|
||
if SymInfo:
|
||
if SymInfo.IsEnumMember and isinstance(SymInfo.value, int):
|
||
if isinstance(var_type, ir.IntType):
|
||
return ir.Constant(var_type, SymInfo.value)
|
||
return None
|
||
|
||
def _eval_type_ctor_const(self, call_node: ast.Call, var_type: ir.Type, Gen: "Translator.LlvmGen") -> ir.Constant | None:
|
||
"""Try to evaluate t.CDouble(val), t.CFloat(val), t.CInt(val) etc. as a compile-time constant."""
|
||
if not isinstance(call_node.func, ast.Attribute):
|
||
return None
|
||
if not isinstance(call_node.func.value, ast.Name):
|
||
return None
|
||
if call_node.func.value.id != 't':
|
||
return None
|
||
if not call_node.args or len(call_node.args) != 1:
|
||
return None
|
||
arg: ast.expr = call_node.args[0]
|
||
# Recursively evaluate the argument as a constant
|
||
arg_val: ir.Constant | None = self._eval_global_const(arg, var_type, Gen)
|
||
if arg_val is not None:
|
||
return arg_val
|
||
return None
|
||
|
||
def _store_bitfield_member(self, struct_ptr: ir.Value, ClassName: str, field_name: str, Value: ir.Value) -> bool:
|
||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||
bitfield_offsets: dict[str, int] = Gen.class_member_bitoffsets.get(ClassName, {})
|
||
bitfield_widths: dict[str, int] = Gen.class_member_bitfields.get(ClassName, {})
|
||
if field_name not in bitfield_offsets:
|
||
return False
|
||
bit_offset: int = bitfield_offsets[field_name]
|
||
bit_width: int = bitfield_widths.get(field_name, 0)
|
||
if bit_width == 0:
|
||
return False
|
||
struct_type: ir.Type | None = Gen.structs.get(ClassName)
|
||
if struct_type is None or struct_type.elements is None or len(struct_type.elements) == 0:
|
||
return False
|
||
storage_type: ir.Type = struct_type.elements[0]
|
||
member_ptr: ir.Value = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{field_name}_storage_ptr")
|
||
old_val: ir.Value = Gen._load(member_ptr, name=f"{field_name}_old_storage")
|
||
mask: int = (1 << bit_width) - 1
|
||
shifted_mask: int = mask << bit_offset
|
||
inverted_mask: ir.Constant = ir.Constant(storage_type, ~shifted_mask & ((1 << storage_type.width) - 1))
|
||
cleared: ir.Value = Gen.builder.and_(old_val, inverted_mask, name=f"{field_name}_cleared")
|
||
if isinstance(Value.type, ir.IntType) and Value.type.width < storage_type.width:
|
||
if getattr(Value.type, 'is_signed', False):
|
||
Value = Gen.builder.sext(Value, storage_type, name=f"{field_name}_sext_store")
|
||
else:
|
||
Value = Gen.builder.zext(Value, storage_type, name=f"{field_name}_zext_store")
|
||
elif Value.type.width != storage_type.width:
|
||
Value = Gen.builder.trunc(Value, storage_type, name=f"{field_name}_trunc_store") if Value.type.width > storage_type.width else Gen.builder.zext(Value, storage_type, name=f"{field_name}_zext_store")
|
||
shifted_value: ir.Value = Gen.builder.shl(Value, ir.Constant(storage_type, bit_offset), name=f"{field_name}_shift_store")
|
||
masked_value: ir.Value = Gen.builder.and_(shifted_value, ir.Constant(storage_type, shifted_mask), name=f"{field_name}_mask_store")
|
||
new_val: ir.Value = Gen.builder.or_(cleared, masked_value, name=f"{field_name}_new_storage")
|
||
Gen._store(new_val, member_ptr)
|
||
return True
|
||
|
||
def _CheckEnumMemberAssignment(self, node: ast.expr) -> str | None:
|
||
def _get_attr_path(n: ast.expr) -> str | None:
|
||
if isinstance(n, ast.Name):
|
||
return n.id
|
||
elif isinstance(n, ast.Attribute):
|
||
return f"{_get_attr_path(n.value)}.{n.attr}"
|
||
return None
|
||
attr_path: str | None = _get_attr_path(node)
|
||
if not attr_path:
|
||
return None
|
||
parts: list[str] = attr_path.split('.')
|
||
if len(parts) >= 2:
|
||
enum_class_name: str = parts[-2]
|
||
member_name: str = parts[-1]
|
||
qualified_name: str = f"{enum_class_name}.{member_name}"
|
||
info: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(qualified_name)
|
||
if info:
|
||
if info.IsEnumMember and info.EnumName:
|
||
return info.EnumName
|
||
under_name: str = f"{enum_class_name}_{member_name}"
|
||
if self.Trans.SymbolTable.has(under_name):
|
||
info: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable[under_name]
|
||
if info.IsEnumMember and info.EnumName:
|
||
return info.EnumName
|
||
for key in self.Trans.SymbolTable:
|
||
if key == member_name:
|
||
info: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable[key]
|
||
if info.IsEnumMember and info.EnumName and info.EnumName == enum_class_name:
|
||
return enum_class_name
|
||
return None
|
||
|
||
def _IsTypedefAnnotation(self, annotation: ast.expr) -> bool:
|
||
if isinstance(annotation, ast.Attribute):
|
||
if annotation.attr in ('CTypedef', 'CDefine'):
|
||
return True
|
||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||
return self._IsTypedefAnnotation(annotation.left) or self._IsTypedefAnnotation(annotation.right)
|
||
if isinstance(annotation, ast.Subscript):
|
||
return self._IsTypedefAnnotation(annotation.value)
|
||
return False
|
||
|
||
def _EmitGlobalAssignLlvm(self, Node: ast.Assign, Gen: "Translator.LlvmGen") -> None:
|
||
if len(Node.targets) == 1 and isinstance(Node.targets[0], ast.Name):
|
||
VarName: str = Node.targets[0].id
|
||
if VarName in Gen.variables or VarName in Gen.module.globals:
|
||
return
|
||
if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name):
|
||
FuncName: str = Node.value.func.id
|
||
if FuncName in Gen.structs:
|
||
IsUnion: bool = False
|
||
TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(FuncName)
|
||
if TypeInfo:
|
||
if TypeInfo.IsUnion:
|
||
IsUnion = True
|
||
if IsUnion:
|
||
StructType: ir.Type = Gen.structs[FuncName]
|
||
StructPtrType: ir.PointerType = ir.PointerType(StructType)
|
||
GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, StructPtrType, name=VarName)
|
||
GlobalVar.initializer = ir.Constant(StructPtrType, None)
|
||
Gen.variables[VarName] = GlobalVar
|
||
Gen.global_struct_class[VarName] = FuncName
|
||
return
|
||
StructName: str = FuncName
|
||
VarType: ir.Type = Gen.structs[StructName]
|
||
GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName)
|
||
const: ir.Constant | None = self.Trans.ClassHandler._BuildStructConstant(Node.value, StructName, Gen)
|
||
if const:
|
||
GlobalVar.initializer = const
|
||
else:
|
||
GlobalVar.linkage = 'common'
|
||
Gen.variables[VarName] = GlobalVar
|
||
Gen.global_struct_class[VarName] = StructName
|
||
return
|
||
GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, ir.IntType(32), name=VarName)
|
||
init_val: ir.Constant | None = self._eval_global_const(Node.value, ir.IntType(32), Gen)
|
||
GlobalVar.initializer = init_val if init_val else ir.Constant(ir.IntType(32), 0)
|
||
Gen.variables[VarName] = GlobalVar
|
||
|
||
def _eval_const_expr(self, node: ast.expr, Gen: "Translator.LlvmGen") -> int | float | None:
|
||
"""计算常量表达式的值(委托到 ConstEvaluator)"""
|
||
ctx: EvalContext = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable, translator=self.Trans)
|
||
return ConstEvaluator.eval_full(node, ctx)
|
||
|
||
def _eval_global_count(self, node: ast.expr, Gen: "Translator.LlvmGen") -> int | None:
|
||
val: int | float | None = self._eval_const_expr(node, Gen)
|
||
if val is not None:
|
||
if isinstance(val, float):
|
||
return int(val)
|
||
if isinstance(val, int):
|
||
return val
|
||
return None |