1157 lines
64 KiB
Python
1157 lines
64 KiB
Python
from __future__ import annotations
|
||
from typing import TYPE_CHECKING
|
||
if TYPE_CHECKING:
|
||
from lib.core.translator import Translator
|
||
from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta
|
||
import ast
|
||
import llvmlite.ir as ir
|
||
|
||
|
||
class ExprAttrHandle(BaseHandle):
|
||
|
||
# ========== 辅助方法 ==========
|
||
|
||
def _apply_bswap_on_Load(self, val, ClassName, AttrName):
|
||
Gen = self.Trans.LlvmGen
|
||
byte_order = getattr(Gen, 'class_member_byteorders', {}).get(ClassName, {}).get(AttrName, "")
|
||
if byte_order == 'big' and isinstance(val.type, ir.IntType):
|
||
if val.type.width in (16, 32, 64):
|
||
val = Gen.builder.bswap(val, name=f"bswap_Load_{AttrName}")
|
||
return val
|
||
|
||
def _gep_and_Load_member(self, Gen, ObjVal, offset, AttrName, ClassName, ST=None):
|
||
"""从结构体指针通过 GEP 取成员,处理 array/struct pointer/class_members 特殊情况"""
|
||
if offset is None:
|
||
return None
|
||
if isinstance(ObjVal.type, ir.PointerType):
|
||
pointee = ObjVal.type.pointee
|
||
if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is not None and offset >= len(pointee.elements):
|
||
return None
|
||
MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
|
||
if isinstance(MemberPtr.type, ir.PointerType) and isinstance(MemberPtr.type.pointee, ir.ArrayType):
|
||
return MemberPtr
|
||
if isinstance(MemberPtr.type, ir.PointerType) and isinstance(MemberPtr.type.pointee, ir.IdentifiedStructType):
|
||
return MemberPtr
|
||
# 检查 pointer-to-pointer 且实际元素是 ArrayType
|
||
if isinstance(MemberPtr.type, ir.PointerType) and isinstance(MemberPtr.type.pointee, ir.PointerType):
|
||
actual_elem_type = None
|
||
if ST is not None and isinstance(ST, ir.IdentifiedStructType) and ST.elements is not None and offset < len(ST.elements):
|
||
actual_elem_type = ST.elements[offset]
|
||
if isinstance(actual_elem_type, ir.ArrayType):
|
||
return Gen.builder.bitcast(MemberPtr, ir.PointerType(actual_elem_type), name=f"cast_arr_{AttrName}")
|
||
# 检查 class_members 中的 ArrayType
|
||
if ClassName in Gen.class_members:
|
||
for member_name, member_type in Gen.class_members[ClassName]:
|
||
if member_name == AttrName and isinstance(member_type, ir.ArrayType):
|
||
return Gen.builder.bitcast(MemberPtr, ir.PointerType(member_type), name=f"cast_arr_{AttrName}")
|
||
val = Gen._load(MemberPtr, name=AttrName)
|
||
return self._apply_bswap_on_Load(val, ClassName, AttrName)
|
||
|
||
def _try_Load_struct_from_stub(self, Gen, ClassName):
|
||
"""尝试从 stub 加载结构体定义,返回 (struct_type, ok)"""
|
||
if ClassName not in Gen.structs:
|
||
return None, False
|
||
st = Gen.structs[ClassName]
|
||
if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0):
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen)
|
||
st = Gen.structs.get(ClassName, st)
|
||
if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0):
|
||
return st, False
|
||
return st, True
|
||
|
||
def _make_define_constant(self, Gen, val):
|
||
"""将 CDefine 值转为 LLVM 常量"""
|
||
if isinstance(val, int):
|
||
if abs(val) > 2147483647:
|
||
return ir.Constant(ir.IntType(64), val)
|
||
return ir.Constant(ir.IntType(32), val)
|
||
elif isinstance(val, float):
|
||
return ir.Constant(ir.DoubleType(), val)
|
||
elif isinstance(val, str):
|
||
str_value = val + '\x00'
|
||
str_bytes = str_value.encode('utf-8')
|
||
str_type = ir.ArrayType(ir.IntType(8), len(str_bytes))
|
||
gv_name = f"str_const_{Gen.string_const_counter}"
|
||
gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
|
||
gv.initializer = ir.Constant(str_type, bytearray(str_bytes))
|
||
gv.linkage = 'internal'
|
||
Gen.string_const_counter += 1
|
||
return Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
|
||
return None
|
||
|
||
def _lookup_cdefine(self, Gen, VarName, AttrName):
|
||
"""在符号表和模块中查找 CDefine 常量值"""
|
||
imported_modules = getattr(self.Trans, '_ImportedModules', None)
|
||
if not imported_modules:
|
||
return None
|
||
PossibleKeys = [f"{VarName}.{AttrName}", AttrName]
|
||
for mod_name in imported_modules:
|
||
if mod_name.endswith(f".{VarName}") or mod_name == VarName:
|
||
key = f"{mod_name}.{AttrName}"
|
||
if key not in PossibleKeys:
|
||
PossibleKeys.append(key)
|
||
for lookup_key in PossibleKeys:
|
||
SymInfo = self.Trans.SymbolTable.lookup(lookup_key)
|
||
if SymInfo and SymInfo.IsDefine and SymInfo.DefineValue is not None:
|
||
return self._make_define_constant(Gen, SymInfo.DefineValue)
|
||
# 也检查 _define_constants
|
||
define_constants = getattr(Gen, '_define_constants', {})
|
||
for key in (f"{VarName}.{AttrName}", AttrName):
|
||
if key in define_constants:
|
||
return self._make_define_constant(Gen, define_constants[key])
|
||
return None
|
||
|
||
def _lookup_module_global(self, Gen, VarName, AttrName):
|
||
"""在模块全局变量中查找 import 的属性"""
|
||
imported_modules = getattr(self.Trans, '_ImportedModules', None)
|
||
if not imported_modules:
|
||
return None
|
||
resolved_mod = self.Trans.SymbolTable.resolve_alias(VarName)
|
||
if VarName not in imported_modules and resolved_mod not in imported_modules:
|
||
return None
|
||
PossibleKeys = [f"{VarName}.{AttrName}", AttrName]
|
||
for mod_name in imported_modules:
|
||
if mod_name.endswith(f".{VarName}") or mod_name == VarName:
|
||
key = f"{mod_name}.{AttrName}"
|
||
if key not in PossibleKeys:
|
||
PossibleKeys.append(key)
|
||
for key in PossibleKeys:
|
||
if key in Gen.module.globals:
|
||
GVar = Gen.module.globals[key]
|
||
if isinstance(GVar, ir.Function):
|
||
return GVar
|
||
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
|
||
return GVar
|
||
return Gen._load(GVar, name=AttrName)
|
||
# SHA1 前缀查找
|
||
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
|
||
sha1_candidates = [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 = ModuleSha1Map.get(cand)
|
||
if sha1:
|
||
prefixed = f"{sha1}.{AttrName}"
|
||
if prefixed in Gen.module.globals:
|
||
GVar2 = Gen.module.globals[prefixed]
|
||
if isinstance(GVar2, ir.Function):
|
||
return GVar2
|
||
if isinstance(GVar2.type, ir.PointerType) and isinstance(GVar2.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
|
||
return GVar2
|
||
return Gen._load(GVar2, name=AttrName)
|
||
if AttrName in Gen.module.globals:
|
||
gv = Gen.module.globals[AttrName]
|
||
if AttrName in Gen.variables and Gen.variables[AttrName] is None:
|
||
str_gv_name = AttrName + '_str'
|
||
if str_gv_name in Gen.module.globals:
|
||
str_gv = Gen.module.globals[str_gv_name]
|
||
return Gen.builder.gep(str_gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{AttrName}_str_ptr")
|
||
return Gen.builder.load(gv, name=AttrName)
|
||
return None
|
||
|
||
def _resolve_var_classname(self, Gen, VarName):
|
||
"""根据变量名解析其结构体类名"""
|
||
ClassName = Gen.var_struct_class.get(VarName)
|
||
if not ClassName and getattr(Gen, 'global_struct_class', None):
|
||
ClassName = Gen.global_struct_class.get(VarName)
|
||
if ClassName:
|
||
Gen.var_struct_class[VarName] = ClassName
|
||
if not ClassName and VarName in Gen.module.globals:
|
||
GVar = Gen.module.globals[VarName]
|
||
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
found = Gen.find_struct_by_pointee(GVar.type.pointee)
|
||
if found:
|
||
ClassName = found[0]
|
||
Gen.var_struct_class[VarName] = ClassName
|
||
if getattr(Gen, 'global_struct_class', None):
|
||
Gen.global_struct_class[VarName] = ClassName
|
||
if not ClassName and VarName in Gen.variables:
|
||
VarPtr = Gen.variables[VarName]
|
||
if VarPtr is not None and isinstance(VarPtr.type, ir.PointerType):
|
||
pointee = VarPtr.type.pointee
|
||
if isinstance(pointee, ir.PointerType):
|
||
pointee = pointee.pointee
|
||
found = Gen.find_struct_by_pointee(pointee)
|
||
if found:
|
||
ClassName = found[0]
|
||
return ClassName
|
||
|
||
def _check_struct_match(self, Gen, ObjVal, ClassName):
|
||
"""检查 ObjVal 是否指向 ClassName 对应的结构体"""
|
||
if ClassName not in Gen.structs:
|
||
return False
|
||
if isinstance(ObjVal.type, ir.PointerType):
|
||
ST = Gen.structs[ClassName]
|
||
if ObjVal.type.pointee == ST:
|
||
return True
|
||
if isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and ObjVal.type.pointee.name == ST.name:
|
||
return True
|
||
return False
|
||
|
||
# ========== _HandleAttributeLlvm 子方法 ==========
|
||
|
||
def _handle_attr_self(self, Node, VarName):
|
||
"""处理 self.xxx 属性访问"""
|
||
Gen = self.Trans.LlvmGen
|
||
ClassName = self.Trans._CurrentCpythonObjectClass
|
||
if not ClassName:
|
||
return None
|
||
# 检查 property getter
|
||
PropKey = f'{ClassName}.{Node.attr}'
|
||
PropInfo = self.Trans.SymbolTable.lookup(PropKey)
|
||
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList:
|
||
SelfVar = Gen._get_var_ptr('self')
|
||
if SelfVar:
|
||
SelfPtr = Gen._load(SelfVar, name="self")
|
||
GetterFunc = Gen._get_function(PropKey)
|
||
if GetterFunc and SelfPtr:
|
||
return Gen.builder.call(GetterFunc, [SelfPtr], name=f"prop_{PropKey}")
|
||
offset = Gen._get_member_offset(Node.attr, ClassName)
|
||
SelfVar = Gen._get_var_ptr('self')
|
||
if not SelfVar:
|
||
return None
|
||
SelfPtr = Gen._load(SelfVar, name="self")
|
||
if not isinstance(SelfPtr.type, ir.PointerType):
|
||
return None
|
||
pointee = SelfPtr.type.pointee
|
||
if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is None:
|
||
for CN2, ST2 in Gen.structs.items():
|
||
if isinstance(ST2, ir.IdentifiedStructType) and ST2.name == pointee.name and ST2.elements is not None:
|
||
pointee = ST2
|
||
break
|
||
if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is not None and offset is not None and offset < len(pointee.elements):
|
||
if isinstance(pointee.elements[offset], ir.VoidType):
|
||
return None
|
||
return self._gep_and_Load_member(Gen, SelfPtr, offset, Node.attr, ClassName, pointee)
|
||
DynamicVarName = f"self.{Node.attr}"
|
||
if DynamicVarName in Gen.variables:
|
||
return Gen._load(Gen.variables[DynamicVarName], name=Node.attr)
|
||
return None
|
||
|
||
def _handle_attr_enum(self, Node, VarName):
|
||
"""处理枚举成员访问 (VarName 是枚举类型名)"""
|
||
SymInfo = self.Trans.SymbolTable.lookup(VarName)
|
||
if not SymInfo or not SymInfo.IsEnum:
|
||
return None
|
||
if self.Trans.SymbolTable.has(Node.attr):
|
||
MemberInfo = self.Trans.SymbolTable[Node.attr]
|
||
if MemberInfo.IsEnumMember and MemberInfo.EnumName == VarName:
|
||
if isinstance(MemberInfo.value, int):
|
||
return ir.Constant(ir.IntType(32), MemberInfo.value)
|
||
for key, info in self.Trans.SymbolTable.items():
|
||
if info.IsEnumMember and info.EnumName == VarName and key == Node.attr:
|
||
if isinstance(info.value, int):
|
||
return ir.Constant(ir.IntType(32), info.value)
|
||
return None
|
||
|
||
def _handle_attr_name(self, Node, VarName):
|
||
"""处理 x.attr 形式 (x 是普通 Name)"""
|
||
Gen = self.Trans.LlvmGen
|
||
AttrName = Node.attr
|
||
|
||
# 先尝试枚举成员
|
||
result = self._handle_attr_enum(Node, VarName)
|
||
if result is not None:
|
||
return result
|
||
|
||
# 尝试 CDefine 常量
|
||
result = self._lookup_cdefine(Gen, VarName, AttrName)
|
||
if result is not None:
|
||
return result
|
||
|
||
# 尝试 import 模块全局变量
|
||
result = self._lookup_module_global(Gen, VarName, AttrName)
|
||
if result is not None:
|
||
return result
|
||
|
||
# 尝试 attr 直接作为全局变量
|
||
if AttrName in Gen.module.globals:
|
||
gv = Gen.module.globals[AttrName]
|
||
if AttrName in Gen.variables and Gen.variables[AttrName] is None:
|
||
str_gv_name = AttrName + '_str'
|
||
if str_gv_name in Gen.module.globals:
|
||
str_gv = Gen.module.globals[str_gv_name]
|
||
return Gen.builder.gep(str_gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{AttrName}_str_ptr")
|
||
return Gen.builder.load(gv, name=AttrName)
|
||
|
||
# 解析结构体类名并访问成员
|
||
ClassName = self._resolve_var_classname(Gen, VarName)
|
||
if not ClassName:
|
||
return None
|
||
|
||
# 检查 property getter
|
||
PropKey = f'{ClassName}.{AttrName}'
|
||
PropInfo = self.Trans.SymbolTable.lookup(PropKey)
|
||
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList:
|
||
ObjVal = self.HandleExprLlvm(Node.value)
|
||
GetterFunc = Gen._get_function(PropKey)
|
||
if GetterFunc and ObjVal:
|
||
if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
|
||
ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}")
|
||
return Gen.builder.call(GetterFunc, [ObjVal], name=f"prop_{PropKey}")
|
||
|
||
# 获取类型信息
|
||
TypeInfo = self.Trans.SymbolTable.lookup(ClassName)
|
||
IsUnion = TypeInfo.IsUnion if TypeInfo else False
|
||
IsCenum = TypeInfo.IsEnum if TypeInfo else False
|
||
IsRenum = TypeInfo.IsRenum if TypeInfo else False
|
||
|
||
# REnum 处理
|
||
if IsRenum:
|
||
if AttrName == 'tag':
|
||
ObjVal = self.HandleExprLlvm(Node.value)
|
||
if ObjVal:
|
||
if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
|
||
ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}")
|
||
tag_ptr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="tag_ptr")
|
||
return Gen._load(tag_ptr, name="tag_val")
|
||
NestedStructName = f"{ClassName}_{AttrName}"
|
||
if NestedStructName in Gen.structs:
|
||
NestedStructType = Gen.structs[NestedStructName]
|
||
ObjVal = self.HandleExprLlvm(Node.value)
|
||
if ObjVal:
|
||
if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
|
||
ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}")
|
||
return Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}")
|
||
|
||
# CEnum 处理
|
||
if IsCenum:
|
||
for qname in (f"{ClassName}.{AttrName}", f"{ClassName}_{AttrName}"):
|
||
if self.Trans.SymbolTable.has(qname):
|
||
info = self.Trans.SymbolTable[qname]
|
||
if info.IsEnumMember and isinstance(info.value, int):
|
||
return ir.Constant(ir.IntType(32), info.value)
|
||
for key, info in self.Trans.SymbolTable.items():
|
||
if key == AttrName:
|
||
if info.IsEnumMember and info.EnumName == ClassName:
|
||
if isinstance(info.value, int):
|
||
return ir.Constant(ir.IntType(32), info.value)
|
||
break
|
||
|
||
# CUnion 处理
|
||
if IsUnion:
|
||
NestedStructName = f"{ClassName}_{AttrName}"
|
||
if NestedStructName in Gen.structs:
|
||
NestedStructType = Gen.structs[NestedStructName]
|
||
ObjVal = self.HandleExprLlvm(Node.value)
|
||
if ObjVal:
|
||
if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
|
||
ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}")
|
||
return Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}")
|
||
|
||
# 普通结构体成员访问
|
||
ObjVal = self.HandleExprLlvm(Node.value)
|
||
if not ObjVal:
|
||
return None
|
||
# char* → struct* cast
|
||
if self._is_char_pointer(ObjVal):
|
||
if ClassName in Gen.structs:
|
||
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||
# 二级指针解引用
|
||
if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
|
||
ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}")
|
||
|
||
# 检查结构体匹配
|
||
struct_match = self._check_struct_match(Gen, ObjVal, ClassName)
|
||
if not struct_match and ClassName and VarName:
|
||
if VarName in Gen.var_struct_class:
|
||
CN = Gen.var_struct_class[VarName]
|
||
if CN != ClassName and CN in Gen.structs:
|
||
ClassName = CN
|
||
struct_match = self._check_struct_match(Gen, ObjVal, ClassName)
|
||
if not struct_match:
|
||
return None
|
||
|
||
st, ok = self._try_Load_struct_from_stub(Gen, ClassName)
|
||
if not ok:
|
||
return None
|
||
|
||
# bitfield 处理
|
||
bitfield_offsets = Gen.class_member_bitoffsets.get(ClassName, {})
|
||
bitfields = Gen.class_member_bitfields.get(ClassName, {})
|
||
if AttrName in bitfield_offsets and bitfields.get(AttrName, 0) > 0:
|
||
return self._load_bitfield_member(ObjVal, ClassName, AttrName)
|
||
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 = 0
|
||
for bf_name, bf_width in bitfields.items():
|
||
if bf_name == AttrName:
|
||
break
|
||
bo += bf_width
|
||
Gen.class_member_bitoffsets[ClassName][AttrName] = bo
|
||
return self._load_bitfield_member(ObjVal, ClassName, AttrName)
|
||
|
||
offset = Gen._get_member_offset(AttrName, ClassName)
|
||
# 检查 offset 是否超出实际结构体
|
||
if isinstance(ObjVal.type, ir.PointerType):
|
||
actual_pointee = ObjVal.type.pointee
|
||
if isinstance(actual_pointee, ir.IdentifiedStructType):
|
||
actual_elems = actual_pointee.elements
|
||
if actual_elems is not None and offset is not None and offset >= len(actual_elems):
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen)
|
||
actual_elems = actual_pointee.elements
|
||
if actual_elems is not None and offset >= len(actual_elems):
|
||
return None
|
||
return self._gep_and_Load_member(Gen, ObjVal, offset, AttrName, ClassName, st)
|
||
|
||
def _handle_attr_nested(self, Node):
|
||
"""处理 a.b.c 嵌套属性访问"""
|
||
Gen = self.Trans.LlvmGen
|
||
if isinstance(Node.value.value, ast.Name):
|
||
ParentVarName = Node.value.value.id
|
||
ParentAttrName = Node.value.attr
|
||
enum_result = self._try_resolve_cross_module_enum(ParentVarName, ParentAttrName, Node.attr)
|
||
if enum_result is not None:
|
||
return enum_result
|
||
# 尝试跨模块子模块全局变量解析: a.b.c 其中 a.b 是已知子模块, c 是该模块的全局变量
|
||
imported_modules = getattr(self.Trans, '_ImportedModules', None)
|
||
if imported_modules:
|
||
full_ModulePath = f"{ParentVarName}.{ParentAttrName}"
|
||
if full_ModulePath in imported_modules:
|
||
result = self._lookup_module_global(Gen, full_ModulePath, Node.attr)
|
||
if result is not None:
|
||
return result
|
||
cdefine_result = self._try_resolve_nested_cdefine(Node)
|
||
if cdefine_result is not None:
|
||
return cdefine_result
|
||
ObjVal = self.HandleExprLlvm(Node.value)
|
||
if not ObjVal or not isinstance(ObjVal.type, ir.PointerType):
|
||
return None
|
||
pointee = ObjVal.type.pointee
|
||
|
||
# char* → struct* cast + 成员访问
|
||
if isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||
AttrClassName = self._get_attr_class(Node.value, Gen)
|
||
if AttrClassName and AttrClassName in Gen.structs:
|
||
st, ok = self._try_Load_struct_from_stub(Gen, AttrClassName)
|
||
if not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
|
||
return None
|
||
CastedObj = Gen.builder.bitcast(ObjVal, ir.PointerType(st), name=f"cast_{AttrClassName}")
|
||
offset = Gen._get_member_offset(Node.attr, AttrClassName)
|
||
if offset is None:
|
||
return None
|
||
if offset < len(st.elements) and isinstance(st.elements[offset], ir.VoidType):
|
||
return None
|
||
return self._gep_and_Load_member(Gen, CastedObj, offset, Node.attr, AttrClassName, st)
|
||
|
||
# 已知结构体类型 → 直接成员访问
|
||
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||
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):
|
||
st, ok = self._try_Load_struct_from_stub(Gen, CN)
|
||
if not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
|
||
break
|
||
bitfield_offsets = Gen.class_member_bitoffsets.get(CN, {})
|
||
if Node.attr in bitfield_offsets:
|
||
return self._load_bitfield_member(ObjVal, CN, Node.attr)
|
||
offset = Gen._get_member_offset(Node.attr, CN)
|
||
if offset is None:
|
||
break
|
||
return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st)
|
||
return None
|
||
|
||
def _handle_attr_call_result(self, Node):
|
||
"""处理 func().attr 属性访问"""
|
||
Gen = self.Trans.LlvmGen
|
||
# Check if this is c.Deref(...) — we need the pointer, not the Loaded value
|
||
ObjVal = None
|
||
is_cderef = (isinstance(Node.value, ast.Call) and
|
||
isinstance(Node.value.func, ast.Attribute) and
|
||
isinstance(Node.value.func.value, ast.Name) and
|
||
Node.value.func.value.id == 'c' and
|
||
Node.value.func.attr == 'Deref' and
|
||
Node.value.args)
|
||
if is_cderef:
|
||
deref_arg = Node.value.args[0]
|
||
inner_val = 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.HandleExprLlvm(Node.value)
|
||
if not ObjVal or not isinstance(ObjVal.type, ir.PointerType):
|
||
return None
|
||
pointee = ObjVal.type.pointee
|
||
if isinstance(pointee, ir.PointerType):
|
||
ObjVal = Gen._load(ObjVal, name="load_ptr_for_attr")
|
||
pointee = ObjVal.type.pointee
|
||
found = Gen.find_struct_by_pointee(pointee)
|
||
if not found:
|
||
return None
|
||
CN, ST = found
|
||
st, ok = self._try_Load_struct_from_stub(Gen, CN)
|
||
if not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
|
||
return None
|
||
bitfield_offsets = Gen.class_member_bitoffsets.get(CN, {})
|
||
if Node.attr in bitfield_offsets:
|
||
return self._load_bitfield_member(ObjVal, CN, Node.attr)
|
||
offset = Gen._get_member_offset(Node.attr, CN)
|
||
if offset is None:
|
||
return None
|
||
return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st)
|
||
|
||
def _handle_attr_subscript_result(self, Node):
|
||
"""处理 arr[i].attr 属性访问"""
|
||
Gen = self.Trans.LlvmGen
|
||
ObjVal = self.HandleExprLlvm(Node.value)
|
||
if not ObjVal or not isinstance(ObjVal.type, ir.PointerType):
|
||
return None
|
||
pointee = ObjVal.type.pointee
|
||
if not isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||
return None
|
||
found = Gen.find_struct_by_pointee(pointee)
|
||
if not found:
|
||
return None
|
||
CN, ST = found
|
||
st, ok = self._try_Load_struct_from_stub(Gen, CN)
|
||
if not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
|
||
return None
|
||
offset = Gen._get_member_offset(Node.attr, CN)
|
||
if offset is None:
|
||
return None
|
||
return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st)
|
||
|
||
def _handle_attr_fallback(self, Node):
|
||
"""兜底:对任意值尝试指针解引用后查找结构体成员"""
|
||
Gen = self.Trans.LlvmGen
|
||
ObjVal = self.HandleExprLlvm(Node.value)
|
||
if not ObjVal or not isinstance(ObjVal.type, ir.PointerType):
|
||
return None
|
||
pointee = ObjVal.type.pointee
|
||
if isinstance(pointee, ir.PointerType):
|
||
ObjVal = Gen._load(ObjVal, name="load_ptr_for_attr_fallback")
|
||
pointee = ObjVal.type.pointee
|
||
if not isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
return None
|
||
found = Gen.find_struct_by_pointee(pointee)
|
||
if not found:
|
||
return None
|
||
CN, ST = found
|
||
st, ok = self._try_Load_struct_from_stub(Gen, CN)
|
||
if not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
|
||
return None
|
||
offset = Gen._get_member_offset(Node.attr, CN)
|
||
if offset is None:
|
||
return None
|
||
return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st)
|
||
|
||
# ========== 主入口 ==========
|
||
|
||
def _HandleAttributeLlvm(self, Node):
|
||
Gen = self.Trans.LlvmGen
|
||
|
||
if isinstance(Node.value, ast.Name):
|
||
VarName = Node.value.id
|
||
# 处理 t/c import 的别名重定向
|
||
t_c_imported = getattr(self.Trans, '_t_c_imported_names', {})
|
||
if VarName != 'self' and VarName in t_c_imported:
|
||
src_module, src_name = t_c_imported[VarName]
|
||
virtual_attr = ast.Attribute(
|
||
value=ast.Name(id=src_module, ctx=ast.Load()),
|
||
attr=src_name, ctx=ast.Load()
|
||
)
|
||
ast.copy_location(virtual_attr, Node)
|
||
return self._HandleAttributeLlvm(ast.Attribute(
|
||
value=virtual_attr, attr=Node.attr, ctx=ast.Load()
|
||
))
|
||
if VarName == 'self':
|
||
return self._handle_attr_self(Node, VarName)
|
||
return self._handle_attr_name(Node, VarName)
|
||
|
||
elif isinstance(Node.value, ast.Attribute):
|
||
return self._handle_attr_nested(Node)
|
||
|
||
elif isinstance(Node.value, ast.Call):
|
||
return self._handle_attr_call_result(Node)
|
||
|
||
elif isinstance(Node.value, ast.Subscript):
|
||
return self._handle_attr_subscript_result(Node)
|
||
|
||
# 兜底
|
||
return self._handle_attr_fallback(Node)
|
||
|
||
# ========== HandleSubscript 及其辅助 ==========
|
||
|
||
def _HandleSubscriptLlvm(self, Node):
|
||
Gen = self.Trans.LlvmGen
|
||
ClassName = self.Trans.ExprHandler._get_var_class(Node.value, Gen)
|
||
if ClassName and Gen._has_function(f'{ClassName}.__getitem__'):
|
||
obj_val = self.HandleExprLlvm(Node.value)
|
||
idx_val = self.HandleExprLlvm(Node.slice)
|
||
if obj_val and idx_val:
|
||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||
if isinstance(idx_val.type, ir.IntType) and idx_val.type.width < 64:
|
||
idx_val = Gen.builder.zext(idx_val, ir.IntType(64), name="zext_idx")
|
||
result = Gen.builder.call(Gen._get_function(f'{ClassName}.__getitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__getitem__")
|
||
return result
|
||
ValueVal = self.HandleExprLlvm(Node.value)
|
||
if not ValueVal:
|
||
return None
|
||
IndexVal = self.HandleExprLlvm(Node.slice)
|
||
if not IndexVal:
|
||
return None
|
||
if isinstance(IndexVal.type, ir.PointerType) and isinstance(IndexVal.type.pointee, ir.IntType) and IndexVal.type.pointee.width == 8:
|
||
Loaded_byte = Gen._load(IndexVal, name="Load_char_idx")
|
||
IndexVal = Gen.builder.zext(Loaded_byte, ir.IntType(32), name="char_to_int_idx")
|
||
if isinstance(ValueVal.type, ir.IntType):
|
||
var_ptr = self._get_int_ptr(Node.value)
|
||
if var_ptr:
|
||
i8_ptr = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr")
|
||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
|
||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index")
|
||
ptr = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr")
|
||
return Gen._load(ptr, name="int_subscript_val")
|
||
return None
|
||
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")
|
||
ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript")
|
||
if isinstance(ValueVal.type.pointee.pointee, ir.IntType) and ValueVal.type.pointee.pointee.width == 8:
|
||
return Gen._load(ElemPtr, name="subscript_val")
|
||
return Gen._load(ElemPtr, name="subscript_val")
|
||
if isinstance(ValueVal.type, ir.PointerType):
|
||
pointee = ValueVal.type.pointee
|
||
if isinstance(pointee, ir.ArrayType):
|
||
zero = ir.Constant(ir.IntType(32), 0)
|
||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
|
||
if IndexVal.type.width < 32:
|
||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
|
||
else:
|
||
IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
|
||
ElemPtr = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript")
|
||
elem_type = pointee.element
|
||
if isinstance(elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
return ElemPtr
|
||
return Gen._load(ElemPtr, name="subscript_val")
|
||
else:
|
||
if isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||
elem_class = self._infer_element_struct_class(Node.value, Gen)
|
||
if elem_class and elem_class in Gen.structs:
|
||
CastedPtr = Gen.builder.bitcast(ValueVal, ir.PointerType(Gen.structs[elem_class]), name=f"cast_{elem_class}_arr")
|
||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
|
||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_arr_index")
|
||
ElemPtr = Gen.builder.gep(CastedPtr, [IndexVal], name="subscript")
|
||
if isinstance(pointee, ir.IntType):
|
||
return Gen._load(ElemPtr, name="subscript_val")
|
||
return ElemPtr
|
||
arr_type = self._infer_array_member_type(Node.value, Gen)
|
||
if arr_type and isinstance(arr_type, ir.ArrayType):
|
||
arr_ptr = Gen.builder.bitcast(ValueVal, ir.PointerType(arr_type), name=f"cast_arr_subscript")
|
||
zero = ir.Constant(ir.IntType(32), 0)
|
||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
|
||
if IndexVal.type.width < 32:
|
||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
|
||
else:
|
||
IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
|
||
ElemPtr = Gen.builder.gep(arr_ptr, [zero, IndexVal], name="subscript")
|
||
arr_elem_type = arr_type.element
|
||
if isinstance(arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
return ElemPtr
|
||
return Gen._load(ElemPtr, name="subscript_val")
|
||
ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript")
|
||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
return ElemPtr
|
||
return Gen._load(ElemPtr, name="subscript_val")
|
||
elif isinstance(ValueVal.type, ir.ArrayType):
|
||
zero = ir.Constant(ir.IntType(32), 0)
|
||
if isinstance(Node.value, ast.Name):
|
||
VarName = Node.value.id
|
||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||
VarPtr = Gen.variables[VarName]
|
||
if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType):
|
||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
|
||
if IndexVal.type.width < 32:
|
||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
|
||
else:
|
||
IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
|
||
ElemPtr = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript")
|
||
var_arr_elem_type = VarPtr.type.pointee.element
|
||
if isinstance(var_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
return ElemPtr
|
||
return Gen._load(ElemPtr, name="subscript_val")
|
||
if isinstance(Node.value, ast.Attribute):
|
||
AttrPtr = self._get_attr_ptr(Node.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 = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript")
|
||
attr_arr_elem_type = AttrPtr.type.pointee.element
|
||
if isinstance(attr_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
return ElemPtr
|
||
return Gen._load(ElemPtr, name="subscript_val")
|
||
if isinstance(Node.value, ast.Subscript):
|
||
InnerPtr = self.HandleSubscriptPtrLlvm(Node.value)
|
||
if InnerPtr and isinstance(InnerPtr.type, ir.PointerType):
|
||
inner_pointee = InnerPtr.type.pointee
|
||
if isinstance(inner_pointee, ir.ArrayType):
|
||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
|
||
if IndexVal.type.width < 32:
|
||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
|
||
else:
|
||
IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
|
||
ElemPtr = Gen.builder.gep(InnerPtr, [zero, IndexVal], name="subscript")
|
||
inner_elem_type = inner_pointee.element
|
||
if isinstance(inner_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
return ElemPtr
|
||
return Gen._load(ElemPtr, name="subscript_val")
|
||
arr_alloc = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp")
|
||
Gen._store(ValueVal, arr_alloc)
|
||
ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript")
|
||
alloc_arr_elem_type = ValueVal.type.element
|
||
if isinstance(alloc_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
return ElemPtr
|
||
return Gen._load(ElemPtr, name="subscript_val")
|
||
return None
|
||
|
||
def HandleSubscriptPtrLlvm(self, Node):
|
||
Gen = self.Trans.LlvmGen
|
||
ValueVal = self.HandleExprLlvm(Node.value)
|
||
if not ValueVal:
|
||
return None
|
||
IndexVal = self.HandleExprLlvm(Node.slice)
|
||
if not IndexVal:
|
||
return None
|
||
if isinstance(IndexVal.type, ir.PointerType) and isinstance(IndexVal.type.pointee, ir.IntType) and IndexVal.type.pointee.width == 8:
|
||
Loaded_byte = Gen._load(IndexVal, name="Load_char_idx_ptr")
|
||
IndexVal = Gen.builder.zext(Loaded_byte, ir.IntType(32), name="char_to_int_idx_ptr")
|
||
if isinstance(ValueVal.type, ir.PointerType):
|
||
pointee = ValueVal.type.pointee
|
||
if isinstance(pointee, ir.ArrayType):
|
||
zero = ir.Constant(ir.IntType(32), 0)
|
||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
|
||
if IndexVal.type.width < 32:
|
||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
|
||
else:
|
||
IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
|
||
ElemPtr = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript_ptr")
|
||
return ElemPtr
|
||
elif isinstance(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_ptr")
|
||
ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript_ptr")
|
||
return ElemPtr
|
||
else:
|
||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
|
||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index")
|
||
ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript_ptr")
|
||
return ElemPtr
|
||
elif isinstance(ValueVal.type, ir.IntType):
|
||
var_ptr = self._get_int_ptr(Node.value)
|
||
if var_ptr:
|
||
i8_ptr = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr")
|
||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
|
||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index")
|
||
ElemPtr = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr")
|
||
return ElemPtr
|
||
elif isinstance(ValueVal.type, ir.ArrayType):
|
||
zero = ir.Constant(ir.IntType(32), 0)
|
||
if isinstance(Node.value, ast.Name):
|
||
VarName = Node.value.id
|
||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||
VarPtr = Gen.variables[VarName]
|
||
if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType):
|
||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
|
||
if IndexVal.type.width < 32:
|
||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
|
||
else:
|
||
IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
|
||
ElemPtr = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript_ptr")
|
||
return ElemPtr
|
||
if isinstance(Node.value, ast.Subscript):
|
||
InnerPtr = self.HandleSubscriptPtrLlvm(Node.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 = Gen.builder.gep(InnerPtr, [zero, IndexVal], name="subscript_ptr")
|
||
return ElemPtr
|
||
if isinstance(Node.value, ast.Attribute):
|
||
AttrPtr = self._get_attr_ptr(Node.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 = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript_ptr")
|
||
return ElemPtr
|
||
arr_alloc = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp")
|
||
Gen._store(ValueVal, arr_alloc)
|
||
ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript_ptr")
|
||
return ElemPtr
|
||
return None
|
||
|
||
# ========== _get_attr_ptr / _get_int_ptr / _get_attr_class ==========
|
||
|
||
def _get_attr_ptr(self, Node):
|
||
Gen = self.Trans.LlvmGen
|
||
if not isinstance(Node, ast.Attribute):
|
||
return None
|
||
if isinstance(Node.value, ast.Name):
|
||
VarName = Node.value.id
|
||
if VarName == 'self':
|
||
ClassName = self.Trans._CurrentCpythonObjectClass
|
||
if ClassName:
|
||
offset = Gen._get_member_offset(Node.attr, ClassName)
|
||
SelfVar = Gen._get_var_ptr('self')
|
||
if SelfVar:
|
||
SelfPtr = Gen._load(SelfVar, name="self")
|
||
if isinstance(SelfPtr.type, ir.PointerType):
|
||
MemberPtr = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr)
|
||
return MemberPtr
|
||
ClassName = Gen.var_struct_class.get(VarName)
|
||
if not ClassName and getattr(Gen, 'global_struct_class', None):
|
||
ClassName = Gen.global_struct_class.get(VarName)
|
||
if not ClassName:
|
||
imported_modules = getattr(self.Trans, '_ImportedModules', None)
|
||
resolved_mod = self.Trans.SymbolTable.resolve_alias(VarName)
|
||
if imported_modules and (VarName in imported_modules or resolved_mod in imported_modules):
|
||
AttrName = Node.attr
|
||
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
|
||
candidates = [VarName, resolved_mod]
|
||
for mod_name in imported_modules:
|
||
if mod_name.endswith(f".{VarName}") or mod_name == VarName:
|
||
if mod_name not in candidates:
|
||
candidates.append(mod_name)
|
||
for cand in candidates:
|
||
sha1 = ModuleSha1Map.get(cand)
|
||
if sha1:
|
||
prefixed = f"{sha1}.{AttrName}"
|
||
if prefixed in Gen.module.globals:
|
||
return Gen.module.globals[prefixed]
|
||
if AttrName in Gen.module.globals:
|
||
gv = Gen.module.globals[AttrName]
|
||
if isinstance(gv, ir.GlobalVariable):
|
||
return gv
|
||
if ClassName and ClassName in Gen.structs:
|
||
VarPtr = Gen.variables.get(VarName)
|
||
if VarPtr:
|
||
ObjVal = VarPtr
|
||
if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
|
||
ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}")
|
||
if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == Gen.structs[ClassName]:
|
||
ST = Gen.structs[ClassName]
|
||
if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0):
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen)
|
||
ST = Gen.structs.get(ClassName, ST)
|
||
if ST.elements is not None 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_{ClassName}")
|
||
offset = Gen._get_member_offset(Node.attr, ClassName)
|
||
if offset is not None and ST.elements is not None:
|
||
MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr)
|
||
return MemberPtr
|
||
elif isinstance(Node.value, ast.Attribute):
|
||
InnerPtr = self._get_attr_ptr(Node.value)
|
||
if InnerPtr and isinstance(InnerPtr.type, ir.PointerType):
|
||
pointee = InnerPtr.type.pointee
|
||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
found = Gen.find_struct_by_pointee(pointee)
|
||
if found:
|
||
CN, ST = found
|
||
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(InnerPtr.type, ir.PointerType) and isinstance(InnerPtr.type.pointee, ir.IdentifiedStructType) and InnerPtr.type.pointee.elements is None:
|
||
InnerPtr = Gen.builder.bitcast(InnerPtr, ir.PointerType(ST), name=f"cast_{CN}")
|
||
offset = Gen._get_member_offset(Node.attr, CN)
|
||
if offset is not None and ST.elements is not None:
|
||
MemberPtr = Gen.builder.gep(InnerPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr)
|
||
return MemberPtr
|
||
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||
AttrClassName = self._get_attr_class(Node.value, Gen)
|
||
if AttrClassName and AttrClassName in Gen.structs:
|
||
CastedObj = Gen.builder.bitcast(InnerPtr, ir.PointerType(Gen.structs[AttrClassName]), name=f"cast_{AttrClassName}")
|
||
offset = Gen._get_member_offset(Node.attr, AttrClassName)
|
||
if offset is not None:
|
||
MemberPtr = Gen.builder.gep(CastedObj, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr)
|
||
return MemberPtr
|
||
elif isinstance(Node.value, ast.Subscript):
|
||
SubPtr = self.HandleSubscriptPtrLlvm(Node.value)
|
||
if SubPtr and isinstance(SubPtr.type, ir.PointerType):
|
||
pointee = SubPtr.type.pointee
|
||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
found = Gen.find_struct_by_pointee(pointee)
|
||
if found:
|
||
CN, ST = found
|
||
offset = Gen._get_member_offset(Node.attr, CN)
|
||
if offset is not None:
|
||
MemberPtr = Gen.builder.gep(SubPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr)
|
||
return MemberPtr
|
||
return None
|
||
|
||
def _HandleSliceLlvm(self, base_val, slice_node, base_ast):
|
||
Gen = self.Trans.LlvmGen
|
||
lower_val = None
|
||
upper_val = None
|
||
step_val = None
|
||
if isinstance(slice_node, ast.Slice):
|
||
if slice_node.lower:
|
||
lower_val = self.HandleExprLlvm(slice_node.lower)
|
||
if slice_node.upper:
|
||
upper_val = self.HandleExprLlvm(slice_node.upper)
|
||
if slice_node.step:
|
||
step_val = self.HandleExprLlvm(slice_node.step)
|
||
if isinstance(slice_node, ast.Index):
|
||
return self.HandleExprLlvm(slice_node.value)
|
||
return None
|
||
|
||
def _infer_element_struct_class(self, node, Gen):
|
||
if isinstance(node, ast.Attribute):
|
||
attr_name = node.attr
|
||
if isinstance(node.value, ast.Name) and node.value.id == 'self':
|
||
current_class = self.Trans._CurrentCpythonObjectClass
|
||
if current_class:
|
||
if current_class in Gen.class_member_element_class:
|
||
elem_class = Gen.class_member_element_class[current_class].get(attr_name)
|
||
if elem_class and elem_class in Gen.structs:
|
||
return elem_class
|
||
if current_class in Gen.class_members:
|
||
for member_name, member_type in Gen.class_members[current_class]:
|
||
if member_name == attr_name:
|
||
if isinstance(member_type, ir.IdentifiedStructType):
|
||
found = Gen.find_struct_by_pointee(member_type)
|
||
if found:
|
||
return found[0]
|
||
break
|
||
class_name = Gen.var_struct_class.get(attr_name)
|
||
if class_name:
|
||
return class_name
|
||
elif isinstance(node, ast.Name):
|
||
var_name = node.id
|
||
class_name = Gen.var_struct_class.get(var_name)
|
||
if class_name:
|
||
return class_name
|
||
return None
|
||
|
||
def _get_int_ptr(self, target):
|
||
Gen = self.Trans.LlvmGen
|
||
if isinstance(target, ast.Name):
|
||
VarName = target.id
|
||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||
VarPtr = Gen.variables[VarName]
|
||
if isinstance(VarPtr.type, ir.PointerType):
|
||
pointee = 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 VarPtr
|
||
elif isinstance(target, ast.Attribute):
|
||
if isinstance(target.value, ast.Name):
|
||
obj_name = target.value.id
|
||
if obj_name in Gen.variables and Gen.variables[obj_name] is not None:
|
||
obj_ptr = Gen.variables[obj_name]
|
||
if isinstance(obj_ptr.type, ir.PointerType):
|
||
pointee = obj_ptr.type.pointee
|
||
if isinstance(pointee, ir.PointerType):
|
||
obj_ptr = Gen._load(obj_ptr, name=f"Load_{obj_name}")
|
||
pointee = obj_ptr.type.pointee
|
||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
StructName = None
|
||
if isinstance(pointee, ir.IdentifiedStructType):
|
||
StructName = pointee.name
|
||
if not StructName:
|
||
found = Gen.find_struct_by_pointee(pointee)
|
||
if found:
|
||
StructName = found[0]
|
||
if StructName and StructName in Gen.structs:
|
||
offset = Gen._get_member_offset(target.attr, StructName)
|
||
if offset is not None:
|
||
return Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{target.attr}_ptr")
|
||
obj_val = self.HandleExprLlvm(target.value)
|
||
if obj_val and isinstance(obj_val.type, ir.PointerType):
|
||
if isinstance(obj_val.type.pointee, ir.PointerType):
|
||
obj_val = Gen._load(obj_val, name="Load_attr_ptr")
|
||
pointee = obj_val.type.pointee
|
||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
StructName = None
|
||
if isinstance(pointee, ir.IdentifiedStructType):
|
||
StructName = pointee.name
|
||
if not StructName:
|
||
found = Gen.find_struct_by_pointee(pointee)
|
||
if found:
|
||
StructName = found[0]
|
||
if StructName and StructName in Gen.structs:
|
||
offset = Gen._get_member_offset(target.attr, StructName)
|
||
if offset is not None:
|
||
return Gen.builder.gep(obj_val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{target.attr}_ptr")
|
||
return None
|
||
|
||
def _resolve_struct_class_for_attr(self, Node, Gen):
|
||
if isinstance(Node, ast.Name):
|
||
VarName = Node.id
|
||
if VarName in Gen.var_struct_class:
|
||
return Gen.var_struct_class[VarName]
|
||
elif isinstance(Node, ast.Attribute):
|
||
ClassName = self._resolve_struct_class_for_attr(Node.value, Gen)
|
||
if ClassName and ClassName in Gen.class_members:
|
||
for member_name, _ in Gen.class_members[ClassName]:
|
||
if member_name == Node.attr:
|
||
return ClassName
|
||
return None
|
||
|
||
def _infer_array_member_type(self, Node, Gen):
|
||
if isinstance(Node, ast.Attribute):
|
||
parent_class = self._get_attr_class(Node, Gen)
|
||
if parent_class and parent_class in Gen.class_members:
|
||
for m_name, m_type in Gen.class_members[parent_class]:
|
||
if m_name == Node.attr and isinstance(m_type, ir.ArrayType):
|
||
return m_type
|
||
if parent_class and parent_class in Gen.structs:
|
||
st = Gen.structs[parent_class]
|
||
if isinstance(st, ir.IdentifiedStructType) and st.elements is not None:
|
||
offset = Gen._get_member_offset(Node.attr, parent_class)
|
||
if offset is not None and offset < len(st.elements):
|
||
elem = st.elements[offset]
|
||
if isinstance(elem, ir.ArrayType):
|
||
return elem
|
||
return None
|
||
|
||
def _build_attr_path(self, node):
|
||
parts = []
|
||
current = node
|
||
while isinstance(current, ast.Attribute):
|
||
parts.append(current.attr)
|
||
current = current.value
|
||
if isinstance(current, ast.Name):
|
||
parts.append(current.id)
|
||
parts.reverse()
|
||
return parts
|
||
|
||
def _try_resolve_nested_cdefine(self, Node):
|
||
Gen = self.Trans.LlvmGen
|
||
imported_modules = getattr(self.Trans, '_ImportedModules', None)
|
||
if not imported_modules:
|
||
return None
|
||
parts = self._build_attr_path(Node)
|
||
if len(parts) < 2:
|
||
return None
|
||
attr_name = parts[-1]
|
||
module_parts = parts[:-1]
|
||
possible_keys = [attr_name]
|
||
full_path = '.'.join(parts)
|
||
possible_keys.append(full_path)
|
||
if module_parts:
|
||
ModulePath = '.'.join(module_parts)
|
||
resolved_first = self.Trans.SymbolTable.resolve_alias(module_parts[0])
|
||
if resolved_first != module_parts[0]:
|
||
resolved_parts = [resolved_first] + module_parts[1:]
|
||
resolved_path = '.'.join(resolved_parts)
|
||
possible_keys.append(f"{resolved_path}.{attr_name}")
|
||
for mod_name in imported_modules:
|
||
if mod_name.endswith('.' + ModulePath) or mod_name == ModulePath:
|
||
key = f"{mod_name}.{attr_name}"
|
||
if key not in possible_keys:
|
||
possible_keys.append(key)
|
||
if module_parts and (mod_name.endswith('.' + module_parts[-1]) or mod_name == module_parts[-1]):
|
||
key = f"{mod_name}.{attr_name}"
|
||
if key not in possible_keys:
|
||
possible_keys.append(key)
|
||
for lookup_key in possible_keys:
|
||
SymInfo = self.Trans.SymbolTable.lookup(lookup_key)
|
||
if SymInfo and SymInfo.IsDefine and SymInfo.DefineValue is not None:
|
||
val = SymInfo.DefineValue
|
||
if isinstance(val, int):
|
||
if val > 0x7FFFFFFF or val < -0x80000000:
|
||
return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF)
|
||
return ir.Constant(ir.IntType(32), val)
|
||
elif isinstance(val, float):
|
||
return ir.Constant(ir.FloatType(), val)
|
||
return None
|
||
|
||
def _try_resolve_cross_module_enum(self, module_alias, enum_class_name, member_name):
|
||
Gen = self.Trans.LlvmGen
|
||
imported_modules = getattr(self.Trans, '_ImportedModules', None)
|
||
if not imported_modules:
|
||
return None
|
||
resolved_module = self.Trans.SymbolTable.resolve_alias(module_alias)
|
||
if resolved_module not in imported_modules and module_alias not in imported_modules:
|
||
return None
|
||
enum_keys = [enum_class_name, f"{resolved_module}.{enum_class_name}"]
|
||
for enum_key in enum_keys:
|
||
if self.Trans.SymbolTable.has(enum_key):
|
||
SymInfo = self.Trans.SymbolTable[enum_key]
|
||
if SymInfo.IsEnum:
|
||
for qname in (f"{enum_key}.{member_name}", f"{enum_key}_{member_name}"):
|
||
if self.Trans.SymbolTable.has(qname):
|
||
info = self.Trans.SymbolTable[qname]
|
||
if info.IsEnumMember and isinstance(info.value, int):
|
||
return ir.Constant(ir.IntType(32), info.value)
|
||
for key, info in self.Trans.SymbolTable.items():
|
||
if info.IsEnumMember and info.EnumName == enum_key and key == member_name:
|
||
if isinstance(info.value, int):
|
||
return ir.Constant(ir.IntType(32), info.value)
|
||
for key, info in self.Trans.SymbolTable.items():
|
||
if info.IsEnumMember and key == member_name:
|
||
if isinstance(info.value, int):
|
||
for enum_key in enum_keys:
|
||
if info.EnumName == enum_key:
|
||
return ir.Constant(ir.IntType(32), info.value)
|
||
return None
|
||
|
||
def _get_attr_class(self, Node, Gen):
|
||
if isinstance(Node, ast.Attribute):
|
||
# 注: 不再硬编码 ZLIB_VERSION / C_OK,它们应从符号表查找
|
||
if isinstance(Node.value, ast.Name) and Node.value.id == 'self':
|
||
ClassName = self.Trans._CurrentCpythonObjectClass
|
||
if ClassName and ClassName in Gen.class_member_element_class:
|
||
return Gen.class_member_element_class[ClassName].get(Node.attr)
|
||
if isinstance(Node.value, ast.Name):
|
||
VarName = Node.value.id
|
||
if VarName in Gen.var_struct_class:
|
||
ParentClass = Gen.var_struct_class[VarName]
|
||
if ParentClass in Gen.class_member_element_class:
|
||
return Gen.class_member_element_class[ParentClass].get(Node.attr)
|
||
if isinstance(Node.value, ast.Attribute):
|
||
ParentClass = self._get_attr_class(Node.value, Gen)
|
||
if ParentClass and ParentClass in Gen.class_member_element_class:
|
||
return Gen.class_member_element_class[ParentClass].get(Node.attr)
|
||
return None
|
||
|
||
def _get_llvm_member_offset(self, field_name, ClassName, Gen):
|
||
return Gen._get_member_offset(field_name, ClassName)
|
||
|
||
def _Load_bitfield_member(self, struct_ptr, ClassName, field_name):
|
||
Gen = self.Trans.LlvmGen
|
||
bitfield_offsets = Gen.class_member_bitoffsets.get(ClassName, {})
|
||
bitfield_widths = Gen.class_member_bitfields.get(ClassName, {})
|
||
if field_name not in bitfield_offsets:
|
||
return None
|
||
bit_offset = bitfield_offsets[field_name]
|
||
bit_width = bitfield_widths.get(field_name, 0)
|
||
if bit_width == 0:
|
||
return None
|
||
struct_type = Gen.structs.get(ClassName)
|
||
if struct_type is None or struct_type.elements is None or len(struct_type.elements) == 0:
|
||
return None
|
||
storage_type = struct_type.elements[0]
|
||
member_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{field_name}_storage_ptr")
|
||
storage_val = Gen._load(member_ptr, name=f"{field_name}_storage")
|
||
shift_amount = bit_offset
|
||
if shift_amount > 0:
|
||
shifted = Gen.builder.lshr(storage_val, ir.Constant(storage_type, shift_amount), name=f"{field_name}_shift")
|
||
else:
|
||
shifted = storage_val
|
||
mask = (1 << bit_width) - 1
|
||
masked = Gen.builder.and_(shifted, ir.Constant(storage_type, mask), name=f"{field_name}_mask")
|
||
is_signed = Gen.class_member_signeds.get(ClassName, {}).get(field_name, False)
|
||
if is_signed and bit_width > 0:
|
||
sign_bit = 1 << (bit_width - 1)
|
||
sign_masked = Gen.builder.and_(shifted, ir.Constant(storage_type, sign_bit), name=f"{field_name}_sign")
|
||
sign_extend = Gen.builder.icmp_signed('!=', sign_masked, ir.Constant(storage_type, 0), name=f"{field_name}_sign_check")
|
||
extended = Gen.builder.select(sign_extend,
|
||
Gen.builder.sext(masked, ir.IntType(32), name=f"{field_name}_sext"),
|
||
Gen.builder.zext(masked, ir.IntType(32), name=f"{field_name}_zext"),
|
||
name=f"{field_name}_extend")
|
||
return extended
|
||
return Gen.builder.zext(masked, ir.IntType(32), name=f"{field_name}_zext") |